001package org.apache.archiva.metadata.repository.file; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.archiva.checksum.ChecksumAlgorithm; 023import org.apache.archiva.configuration.ArchivaConfiguration; 024import org.apache.archiva.configuration.ManagedRepositoryConfiguration; 025import org.apache.archiva.metadata.QueryParameter; 026import org.apache.archiva.metadata.model.ArtifactMetadata; 027import org.apache.archiva.metadata.model.CiManagement; 028import org.apache.archiva.metadata.model.Dependency; 029import org.apache.archiva.metadata.model.IssueManagement; 030import org.apache.archiva.metadata.model.License; 031import org.apache.archiva.metadata.model.MailingList; 032import org.apache.archiva.metadata.model.MetadataFacet; 033import org.apache.archiva.metadata.model.MetadataFacetFactory; 034import org.apache.archiva.metadata.model.Organization; 035import org.apache.archiva.metadata.model.ProjectMetadata; 036import org.apache.archiva.metadata.model.ProjectVersionMetadata; 037import org.apache.archiva.metadata.model.ProjectVersionReference; 038import org.apache.archiva.metadata.model.Scm; 039import org.apache.archiva.metadata.repository.AbstractMetadataRepository; 040import org.apache.archiva.metadata.repository.MetadataRepository; 041import org.apache.archiva.metadata.repository.MetadataRepositoryException; 042import org.apache.archiva.metadata.repository.MetadataResolutionException; 043import org.apache.archiva.metadata.repository.MetadataService; 044import org.apache.archiva.metadata.repository.RepositorySession; 045import org.apache.commons.lang3.StringUtils; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049import javax.annotation.ParametersAreNonnullByDefault; 050import java.io.FileNotFoundException; 051import java.io.IOException; 052import java.io.InputStream; 053import java.io.OutputStream; 054import java.nio.file.FileVisitOption; 055import java.nio.file.Files; 056import java.nio.file.NoSuchFileException; 057import java.nio.file.Path; 058import java.nio.file.Paths; 059import java.time.Instant; 060import java.time.ZoneId; 061import java.time.ZonedDateTime; 062import java.util.ArrayList; 063import java.util.Arrays; 064import java.util.Collection; 065import java.util.Collections; 066import java.util.Comparator; 067import java.util.HashMap; 068import java.util.HashSet; 069import java.util.LinkedHashSet; 070import java.util.List; 071import java.util.Map; 072import java.util.Objects; 073import java.util.Properties; 074import java.util.Set; 075import java.util.StringTokenizer; 076import java.util.stream.Collectors; 077import java.util.stream.Stream; 078 079/** 080 * File implementation of the metadata repository. It uses property files in a separate directory tree. 081 * The implementation has no fulltext index. So fulltext queries are not supported. 082 * 083 * Some retrieval methods may not be very efficient. 084 */ 085@ParametersAreNonnullByDefault 086public class FileMetadataRepository 087 extends AbstractMetadataRepository implements MetadataRepository { 088 089 private final ArchivaConfiguration configuration; 090 091 private Logger log = LoggerFactory.getLogger(FileMetadataRepository.class); 092 093 private static final String PROJECT_METADATA_KEY = "project-metadata"; 094 095 private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata"; 096 097 private static final String NAMESPACE_METADATA_KEY = "namespace-metadata"; 098 099 private static final String METADATA_KEY = "metadata"; 100 101 private Map<String, Path> baseDirectory = new HashMap<>(); 102 103 public FileMetadataRepository(MetadataService metadataService, 104 ArchivaConfiguration configuration) { 105 super(metadataService); 106 this.configuration = configuration; 107 } 108 109 private Path getBaseDirectory(String repoId) 110 throws IOException { 111 if (!baseDirectory.containsKey(repoId)) { 112 Path baseDir; 113 ManagedRepositoryConfiguration managedRepositoryConfiguration = 114 configuration.getConfiguration().getManagedRepositoriesAsMap().get(repoId); 115 if (managedRepositoryConfiguration == null) { 116 baseDir = Files.createTempDirectory(repoId); 117 } else { 118 baseDir = Paths.get(managedRepositoryConfiguration.getLocation()); 119 } 120 baseDirectory.put(repoId, baseDir.resolve(".archiva")); 121 } 122 return baseDirectory.get(repoId); 123 } 124 125 private Path getDirectory(String repoId) 126 throws IOException { 127 return getBaseDirectory(repoId).resolve("content"); 128 } 129 130 @Override 131 public void updateProject(RepositorySession session, String repoId, ProjectMetadata project) { 132 updateProject(session, repoId, project.getNamespace(), project.getId()); 133 } 134 135 private void updateProject(RepositorySession session, String repoId, String namespace, String id) { 136 // TODO: this is a more braindead implementation than we would normally expect, for prototyping purposes 137 updateNamespace(session, repoId, namespace); 138 139 try { 140 Path namespaceDirectory = getDirectory(repoId).resolve(namespace); 141 Properties properties = new Properties(); 142 properties.setProperty("namespace", namespace); 143 properties.setProperty("id", id); 144 writeProperties(properties, namespaceDirectory.resolve(id), PROJECT_METADATA_KEY); 145 } catch (IOException e) { 146 log.error("Could not update project {}, {}, {}: {}", repoId, namespace, id, e.getMessage(), e); 147 } 148 } 149 150 @Override 151 public void updateProjectVersion(RepositorySession session, String repoId, String namespace, String projectId, 152 ProjectVersionMetadata versionMetadata) { 153 154 try { 155 updateProject(session, repoId, namespace, projectId); 156 157 Path directory = 158 getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + versionMetadata.getId()); 159 160 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 161 // remove properties that are not references or artifacts 162 for (Object key : new ArrayList<>(properties.keySet())) { 163 String name = (String) key; 164 if (!name.contains(":") && !name.equals("facetIds")) { 165 properties.remove(name); 166 } 167 168 // clear the facet contents so old properties are no longer written 169 clearMetadataFacetProperties(versionMetadata.getFacetList(), properties, ""); 170 } 171 properties.setProperty("id", versionMetadata.getId()); 172 setProperty(properties, "name", versionMetadata.getName()); 173 setProperty(properties, "description", versionMetadata.getDescription()); 174 setProperty(properties, "url", versionMetadata.getUrl()); 175 setProperty(properties, "incomplete", String.valueOf(versionMetadata.isIncomplete())); 176 if (versionMetadata.getScm() != null) { 177 setProperty(properties, "scm.connection", versionMetadata.getScm().getConnection()); 178 setProperty(properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection()); 179 setProperty(properties, "scm.url", versionMetadata.getScm().getUrl()); 180 } 181 if (versionMetadata.getCiManagement() != null) { 182 setProperty(properties, "ci.system", versionMetadata.getCiManagement().getSystem()); 183 setProperty(properties, "ci.url", versionMetadata.getCiManagement().getUrl()); 184 } 185 if (versionMetadata.getIssueManagement() != null) { 186 setProperty(properties, "issue.system", versionMetadata.getIssueManagement().getSystem()); 187 setProperty(properties, "issue.url", versionMetadata.getIssueManagement().getUrl()); 188 } 189 if (versionMetadata.getOrganization() != null) { 190 setProperty(properties, "org.name", versionMetadata.getOrganization().getName()); 191 setProperty(properties, "org.url", versionMetadata.getOrganization().getUrl()); 192 } 193 int i = 0; 194 for (License license : versionMetadata.getLicenses()) { 195 setProperty(properties, "license." + i + ".name", license.getName()); 196 setProperty(properties, "license." + i + ".url", license.getUrl()); 197 i++; 198 } 199 i = 0; 200 for (MailingList mailingList : versionMetadata.getMailingLists()) { 201 setProperty(properties, "mailingList." + i + ".archive", mailingList.getMainArchiveUrl()); 202 setProperty(properties, "mailingList." + i + ".name", mailingList.getName()); 203 setProperty(properties, "mailingList." + i + ".post", mailingList.getPostAddress()); 204 setProperty(properties, "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress()); 205 setProperty(properties, "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress()); 206 setProperty(properties, "mailingList." + i + ".otherArchives", 207 join(mailingList.getOtherArchives())); 208 i++; 209 } 210 i = 0; 211 ProjectVersionReference reference = new ProjectVersionReference(); 212 reference.setNamespace(namespace); 213 reference.setProjectId(projectId); 214 reference.setProjectVersion(versionMetadata.getId()); 215 reference.setReferenceType(ProjectVersionReference.ReferenceType.DEPENDENCY); 216 for (Dependency dependency : versionMetadata.getDependencies()) { 217 setProperty(properties, "dependency." + i + ".classifier", dependency.getClassifier()); 218 setProperty(properties, "dependency." + i + ".scope", dependency.getScope()); 219 setProperty(properties, "dependency." + i + ".systemPath", dependency.getSystemPath()); 220 setProperty(properties, "dependency." + i + ".artifactId", dependency.getArtifactId()); 221 setProperty(properties, "dependency." + i + ".groupId", dependency.getNamespace()); 222 setProperty(properties, "dependency." + i + ".version", dependency.getVersion()); 223 setProperty(properties, "dependency." + i + ".type", dependency.getType()); 224 setProperty(properties, "dependency." + i + ".optional", String.valueOf(dependency.isOptional())); 225 226 updateProjectReference(repoId, dependency.getNamespace(), dependency.getArtifactId(), 227 dependency.getVersion(), reference); 228 229 i++; 230 } 231 Set<String> facetIds = new LinkedHashSet<>(versionMetadata.getFacetIds()); 232 facetIds.addAll(Arrays.asList(properties.getProperty("facetIds", "").split(","))); 233 properties.setProperty("facetIds", join(facetIds)); 234 235 updateProjectVersionFacets(versionMetadata, properties); 236 237 writeProperties(properties, directory, PROJECT_VERSION_METADATA_KEY); 238 } catch (IOException e) { 239 log.error("Could not update project version {}, {}, {}: {}", repoId, namespace, versionMetadata.getId(), e.getMessage(), e); 240 } 241 } 242 243 private void updateProjectVersionFacets(ProjectVersionMetadata versionMetadata, Properties properties) { 244 for (MetadataFacet facet : versionMetadata.getFacetList()) { 245 for (Map.Entry<String, String> entry : facet.toProperties().entrySet()) { 246 properties.setProperty(facet.getFacetId() + ":" + entry.getKey(), entry.getValue()); 247 } 248 } 249 } 250 251 private static void clearMetadataFacetProperties(Collection<MetadataFacet> facetList, Properties properties, 252 String prefix) { 253 List<Object> propsToRemove = new ArrayList<>(); 254 for (MetadataFacet facet : facetList) { 255 for (Object key : new ArrayList<>(properties.keySet())) { 256 String keyString = (String) key; 257 if (keyString.startsWith(prefix + facet.getFacetId() + ":")) { 258 propsToRemove.add(key); 259 } 260 } 261 } 262 263 for (Object key : propsToRemove) { 264 properties.remove(key); 265 } 266 } 267 268 private void updateProjectReference(String repoId, String namespace, String projectId, String projectVersion, 269 ProjectVersionReference reference) { 270 try { 271 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + projectVersion); 272 273 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 274 int i = Integer.parseInt(properties.getProperty("ref:lastReferenceNum", "-1")) + 1; 275 setProperty(properties, "ref:lastReferenceNum", Integer.toString(i)); 276 setProperty(properties, "ref:reference." + i + ".namespace", reference.getNamespace()); 277 setProperty(properties, "ref:reference." + i + ".projectId", reference.getProjectId()); 278 setProperty(properties, "ref:reference." + i + ".projectVersion", reference.getProjectVersion()); 279 setProperty(properties, "ref:reference." + i + ".referenceType", reference.getReferenceType().toString()); 280 281 writeProperties(properties, directory, PROJECT_VERSION_METADATA_KEY); 282 } catch (IOException e) { 283 log.error("Could not update project reference {}, {}, {}, {}: {}", repoId, namespace, projectId, projectVersion, e.getMessage(), e); 284 } 285 } 286 287 @Override 288 public void updateNamespace(RepositorySession session, String repoId, String namespace) { 289 try { 290 Path namespaceDirectory = getDirectory(repoId).resolve(namespace); 291 Properties properties = new Properties(); 292 properties.setProperty("namespace", namespace); 293 writeProperties(properties, namespaceDirectory, NAMESPACE_METADATA_KEY); 294 295 } catch (IOException e) { 296 log.error("Could not update namespace of {}, {}: {}", repoId, namespace, e.getMessage(), e); 297 } 298 } 299 300 @Override 301 public List<String> getMetadataFacets(RepositorySession session, String repoId, String facetId) 302 throws MetadataRepositoryException { 303 try { 304 Path directory = getMetadataDirectory(repoId, facetId); 305 if (!(Files.exists(directory) && Files.isDirectory(directory))) { 306 return Collections.emptyList(); 307 } 308 List<String> facets; 309 final String searchFile = METADATA_KEY + ".properties"; 310 try (Stream<Path> fs = Files.walk(directory, FileVisitOption.FOLLOW_LINKS)) { 311 facets = fs.filter(Files::isDirectory).filter(path -> Files.exists(path.resolve(searchFile))) 312 .map(path -> directory.relativize(path).toString()).collect(Collectors.toList()); 313 } 314 return facets; 315 } catch (IOException e) { 316 throw new MetadataRepositoryException(e.getMessage(), e); 317 } 318 } 319 320 @Override 321 public <T extends MetadataFacet> Stream<T> getMetadataFacetStream(RepositorySession session, String repositoryId, Class<T> facetClazz, QueryParameter queryParameter) throws MetadataRepositoryException { 322 final MetadataFacetFactory<T> metadataFacetFactory = getFacetFactory(facetClazz); 323 if (metadataFacetFactory == null) { 324 return null; 325 } 326 final String facetId = metadataFacetFactory.getFacetId(); 327 final String searchFile = METADATA_KEY + ".properties"; 328 try { 329 Path directory = getMetadataDirectory(repositoryId, facetId); 330 return Files.walk(directory, FileVisitOption.FOLLOW_LINKS).filter(Files::isDirectory) 331 .filter(path -> Files.exists(path.resolve(searchFile))) 332 .map(path -> directory.relativize(path).toString()) 333 .sorted() 334 .skip(queryParameter.getOffset()) 335 .limit(queryParameter.getLimit()) 336 .map(name -> getMetadataFacet(session, repositoryId, facetClazz, name)); 337 } catch (IOException e) { 338 throw new MetadataRepositoryException(e.getMessage(), e); 339 } 340 } 341 342 @Override 343 public boolean hasMetadataFacet(RepositorySession session, String repositoryId, String facetId) 344 throws MetadataRepositoryException { 345 346 try { 347 Path directory = getMetadataDirectory(repositoryId, facetId); 348 if (!(Files.exists(directory) && Files.isDirectory(directory))) { 349 return false; 350 } 351 final String searchFile = METADATA_KEY + ".properties"; 352 try (Stream<Path> fs = Files.walk(directory, FileVisitOption.FOLLOW_LINKS)) { 353 return fs.filter(Files::isDirectory).anyMatch(path -> Files.exists(path.resolve(searchFile))); 354 } 355 } catch (IOException e) { 356 log.error("Could not retrieve facet metatadata {}, {}: {}", repositoryId, facetId, e.getMessage(), e); 357 throw new MetadataRepositoryException(e.getMessage(), e); 358 } 359 360 } 361 362 363 @Override 364 public <T extends MetadataFacet> T getMetadataFacet(RepositorySession session, String repositoryId, Class<T> facetClazz, String name) { 365 final MetadataFacetFactory<T> metadataFacetFactory = getFacetFactory(facetClazz); 366 if (metadataFacetFactory == null) { 367 return null; 368 } 369 final String facetId = metadataFacetFactory.getFacetId(); 370 371 Properties properties; 372 try { 373 properties = 374 readProperties(getMetadataDirectory(repositoryId, facetId).resolve(name), METADATA_KEY); 375 } catch (NoSuchFileException | FileNotFoundException e) { 376 return null; 377 } catch (IOException e) { 378 log.error("Could not read properties from {}, {}: {}", repositoryId, facetId, e.getMessage(), e); 379 return null; 380 } 381 T metadataFacet = null; 382 if (metadataFacetFactory != null) { 383 metadataFacet = metadataFacetFactory.createMetadataFacet(repositoryId, name); 384 Map<String, String> map = new HashMap<>(); 385 for (Object key : new ArrayList<>(properties.keySet())) { 386 String property = (String) key; 387 map.put(property, properties.getProperty(property)); 388 } 389 metadataFacet.fromProperties(map); 390 } 391 return metadataFacet; 392 } 393 394 395 @Override 396 public void addMetadataFacet(RepositorySession session, String repositoryId, MetadataFacet metadataFacet) { 397 Properties properties = new Properties(); 398 properties.putAll(metadataFacet.toProperties()); 399 400 try { 401 Path directory = 402 getMetadataDirectory(repositoryId, metadataFacet.getFacetId()).resolve(metadataFacet.getName()); 403 writeProperties(properties, directory, METADATA_KEY); 404 } catch (IOException e) { 405 // TODO! 406 log.error(e.getMessage(), e); 407 } 408 } 409 410 @Override 411 public void removeMetadataFacets(RepositorySession session, String repositoryId, String facetId) 412 throws MetadataRepositoryException { 413 try { 414 Path dir = getMetadataDirectory(repositoryId, facetId); 415 org.apache.archiva.common.utils.FileUtils.deleteDirectory(dir); 416 } catch (IOException e) { 417 throw new MetadataRepositoryException(e.getMessage(), e); 418 } 419 } 420 421 @Override 422 public void removeMetadataFacet(RepositorySession session, String repoId, String facetId, String name) 423 throws MetadataRepositoryException { 424 try { 425 Path dir = getMetadataDirectory(repoId, facetId).resolve(name); 426 org.apache.archiva.common.utils.FileUtils.deleteDirectory(dir); 427 } catch (IOException e) { 428 throw new MetadataRepositoryException(e.getMessage(), e); 429 } 430 } 431 432 @Override 433 public List<ArtifactMetadata> getArtifactsByDateRange(RepositorySession session, String repoId, ZonedDateTime startTime, ZonedDateTime endTime) 434 throws MetadataRepositoryException { 435 try { 436 List<ArtifactMetadata> artifacts = new ArrayList<>(); 437 for (String ns : getRootNamespaces(session, repoId)) { 438 getArtifactsByDateRange(session, artifacts, repoId, ns, startTime, endTime); 439 } 440 artifacts.sort(new ArtifactComparator()); 441 return artifacts; 442 } catch (MetadataResolutionException e) { 443 throw new MetadataRepositoryException(e.getMessage(), e); 444 } 445 } 446 447 448 /** 449 * Result is sorted by date, 450 * 451 * @param session The repository session 452 * @param repositoryId The repository id 453 * @param startTime The start time, can be <code>null</code> 454 * @param endTime The end time, can be <code>null</code> 455 * @param queryParameter Additional parameters for the query that affect ordering and number of returned results. 456 * @return 457 * @throws MetadataRepositoryException 458 */ 459 @Override 460 public Stream<ArtifactMetadata> getArtifactByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, QueryParameter queryParameter) throws MetadataRepositoryException { 461 try { 462 List<ArtifactMetadata> artifacts = new ArrayList<>(); 463 for (String ns : getRootNamespaces(session, repositoryId)) { 464 getArtifactsByDateRange(session, artifacts, repositoryId, ns, startTime, endTime); 465 } 466 Comparator<ArtifactMetadata> comp = getArtifactMetadataComparator(queryParameter, "whenGathered"); 467 return artifacts.stream().sorted(comp).skip(queryParameter.getOffset()).limit(queryParameter.getLimit()); 468 469 } catch (MetadataResolutionException e) { 470 throw new MetadataRepositoryException(e.getMessage(), e); 471 } 472 } 473 474 475 private void getArtifactsByDateRange(RepositorySession session, List<ArtifactMetadata> artifacts, String repoId, String ns, ZonedDateTime startTime, 476 ZonedDateTime endTime) 477 throws MetadataRepositoryException { 478 try { 479 for (String namespace : this.getChildNamespaces(session, repoId, ns)) { 480 getArtifactsByDateRange(session, artifacts, repoId, ns + "." + namespace, startTime, endTime); 481 } 482 483 for (String project : getProjects(session, repoId, ns)) { 484 for (String version : getProjectVersions(session, repoId, ns, project)) { 485 for (ArtifactMetadata artifact : getArtifacts(session, repoId, ns, project, version)) { 486 if (startTime == null || startTime.isBefore(ZonedDateTime.from(artifact.getWhenGathered().toInstant().atZone(ZoneId.systemDefault())))) { 487 if (endTime == null || endTime.isAfter(ZonedDateTime.from(artifact.getWhenGathered().toInstant().atZone(ZoneId.systemDefault())))) { 488 artifacts.add(artifact); 489 } 490 } 491 } 492 } 493 } 494 } catch (MetadataResolutionException e) { 495 throw new MetadataRepositoryException(e.getMessage(), e); 496 } 497 } 498 499 500 @Override 501 public List<ArtifactMetadata> getArtifacts( RepositorySession session, String repoId, String namespace, String projectId, 502 String projectVersion) 503 throws MetadataResolutionException { 504 try { 505 Map<String, ArtifactMetadata> artifacts = new HashMap<>(); 506 507 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + projectVersion); 508 509 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 510 511 for (Map.Entry entry : properties.entrySet()) { 512 String name = (String) entry.getKey(); 513 StringTokenizer tok = new StringTokenizer(name, ":"); 514 if (tok.hasMoreTokens() && "artifact".equals(tok.nextToken())) { 515 String field = tok.nextToken(); 516 String id = tok.nextToken(); 517 518 ArtifactMetadata artifact = artifacts.get(id); 519 if (artifact == null) { 520 artifact = new ArtifactMetadata(); 521 artifact.setRepositoryId(repoId); 522 artifact.setNamespace(namespace); 523 artifact.setProject(projectId); 524 artifact.setProjectVersion(projectVersion); 525 artifact.setVersion(projectVersion); 526 artifact.setId(id); 527 artifacts.put(id, artifact); 528 } 529 530 String value = (String) entry.getValue(); 531 if ("updated".equals(field)) { 532 artifact.setFileLastModified(Long.parseLong(value)); 533 } else if ("size".equals(field)) { 534 artifact.setSize(Long.valueOf(value)); 535 } else if ("whenGathered".equals(field)) { 536 artifact.setWhenGathered(ZonedDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(value)), ZoneId.of("GMT"))); 537 } else if ("version".equals(field)) { 538 artifact.setVersion(value); 539 } else if (field.startsWith("checksum")) { 540 String algorithmStr = StringUtils.removeStart( name, "artifact:checksum:"+id+":"); 541 artifact.setChecksum( ChecksumAlgorithm.valueOf( algorithmStr ), value ); 542 } else if ("facetIds".equals(field)) { 543 if (value.length() > 0) { 544 String propertyPrefix = "artifact:facet:" + id + ":"; 545 for (String facetId : value.split(",")) { 546 MetadataFacetFactory factory = getFacetFactory(facetId); 547 if (factory == null) { 548 log.error("Attempted to load unknown artifact metadata facet: {}", facetId); 549 } else { 550 MetadataFacet facet = factory.createMetadataFacet(); 551 String prefix = propertyPrefix + facet.getFacetId(); 552 Map<String, String> map = new HashMap<>(); 553 for (Object key : new ArrayList<>(properties.keySet())) { 554 String property = (String) key; 555 if (property.startsWith(prefix)) { 556 map.put(property.substring(prefix.length() + 1), 557 properties.getProperty(property)); 558 } 559 } 560 facet.fromProperties(map); 561 artifact.addFacet(facet); 562 } 563 } 564 } 565 566 updateArtifactFacets(artifact, properties); 567 } 568 } 569 } 570 return new ArrayList<>(artifacts.values()); 571 } catch (IOException e) { 572 throw new MetadataResolutionException(e.getMessage(), e); 573 } 574 } 575 576 577 @Override 578 public void close() { 579 // nothing additional to close 580 } 581 582 583 private void updateArtifactFacets(ArtifactMetadata artifact, Properties properties) { 584 String propertyPrefix = "artifact:facet:" + artifact.getId() + ":"; 585 for (MetadataFacet facet : artifact.getFacetList()) { 586 for (Map.Entry<String, String> e : facet.toProperties().entrySet()) { 587 String key = propertyPrefix + facet.getFacetId() + ":" + e.getKey(); 588 properties.setProperty(key, e.getValue()); 589 } 590 } 591 } 592 593 @Override 594 public List<ArtifactMetadata> getArtifactsByChecksum(RepositorySession session, String repositoryId, String checksum) 595 throws MetadataRepositoryException { 596 try { 597 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index 598 // of this information (eg. in Lucene, as before) 599 // alternatively, we could build a referential tree in the content repository, however it would need some levels 600 // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567) 601 602 return getArtifactStream( session, repositoryId ).filter( 603 a -> a.hasChecksum( checksum ) 604 ).collect( Collectors.toList() ); 605 } catch (MetadataResolutionException e) { 606 throw new MetadataRepositoryException(e.getMessage(), e); 607 } 608 } 609 610 @Override 611 public void removeNamespace(RepositorySession session, String repositoryId, String project) 612 throws MetadataRepositoryException { 613 try { 614 Path namespaceDirectory = getDirectory(repositoryId).resolve(project); 615 org.apache.archiva.common.utils.FileUtils.deleteDirectory(namespaceDirectory); 616 //Properties properties = new Properties(); 617 //properties.setProperty( "namespace", namespace ); 618 //writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY ); 619 620 } catch (IOException e) { 621 throw new MetadataRepositoryException(e.getMessage(), e); 622 } 623 } 624 625 @Override 626 public void removeTimestampedArtifact( RepositorySession session, ArtifactMetadata artifactMetadata, String baseVersion) 627 throws MetadataRepositoryException { 628 629 try { 630 Path directory = getDirectory(artifactMetadata.getRepositoryId()).resolve( 631 artifactMetadata.getNamespace() + "/" + artifactMetadata.getProject() + "/" 632 + baseVersion); 633 634 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 635 636 String id = artifactMetadata.getId(); 637 638 properties.remove("artifact:updated:" + id); 639 properties.remove("artifact:whenGathered:" + id); 640 properties.remove("artifact:size:" + id); 641 artifactMetadata.getChecksums().entrySet().stream().forEach( entry -> 642 properties.remove( "artifact:checksum:"+id+":"+entry.getKey().name() )); 643 properties.remove("artifact:version:" + id); 644 properties.remove("artifact:facetIds:" + id); 645 646 String prefix = "artifact:facet:" + id + ":"; 647 for (Object key : new ArrayList<>(properties.keySet())) { 648 String property = (String) key; 649 if (property.startsWith(prefix)) { 650 properties.remove(property); 651 } 652 } 653 654 writeProperties(properties, directory, PROJECT_VERSION_METADATA_KEY); 655 } catch (IOException e) { 656 throw new MetadataRepositoryException(e.getMessage(), e); 657 } 658 659 } 660 661 @Override 662 public void removeArtifact(RepositorySession session, String repoId, String namespace, String project, String version, String id) 663 throws MetadataRepositoryException { 664 try { 665 Path directory = getDirectory(repoId).resolve(namespace + "/" + project + "/" + version); 666 667 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 668 669 properties.remove("artifact:updated:" + id); 670 properties.remove("artifact:whenGathered:" + id); 671 properties.remove("artifact:size:" + id); 672 properties.remove("artifact:version:" + id); 673 properties.remove("artifact:facetIds:" + id); 674 675 String facetPrefix = "artifact:facet:" + id + ":"; 676 String checksumPrefix = "artifact:checksum:"+id+":"; 677 for (String property : properties.stringPropertyNames()) { 678 if (property.startsWith( checksumPrefix )) { 679 properties.remove( property ); 680 } else if (property.startsWith(facetPrefix)) { 681 properties.remove(property); 682 } 683 } 684 685 org.apache.archiva.common.utils.FileUtils.deleteDirectory(directory); 686 //writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY ); 687 } catch (IOException e) { 688 throw new MetadataRepositoryException(e.getMessage(), e); 689 } 690 } 691 692 /** 693 * FIXME implements this !!!! 694 * 695 * @param session 696 * @param repositoryId 697 * @param namespace 698 * @param project 699 * @param projectVersion 700 * @param metadataFacet will remove artifacts which have this {@link MetadataFacet} using equals 701 * @throws MetadataRepositoryException 702 */ 703 @Override 704 public void removeFacetFromArtifact( RepositorySession session, String repositoryId, String namespace, String project, String projectVersion, 705 MetadataFacet metadataFacet) 706 throws MetadataRepositoryException { 707 throw new UnsupportedOperationException("not implemented"); 708 } 709 710 @Override 711 public void removeRepository(RepositorySession session, String repoId) 712 throws MetadataRepositoryException { 713 try { 714 Path dir = getDirectory(repoId); 715 org.apache.archiva.common.utils.FileUtils.deleteDirectory(dir); 716 } catch (IOException e) { 717 throw new MetadataRepositoryException(e.getMessage(), e); 718 } 719 } 720 721 722 @Override 723 public List<ArtifactMetadata> getArtifactsByProjectVersionFacet( RepositorySession session, String key, String value, String repositoryId) 724 throws MetadataRepositoryException { 725 throw new UnsupportedOperationException("not yet implemented in File backend"); 726 } 727 728 @Override 729 public List<ArtifactMetadata> getArtifactsByAttribute( RepositorySession session, String key, String value, String repositoryId) 730 throws MetadataRepositoryException { 731 throw new UnsupportedOperationException("not yet implemented in File backend"); 732 } 733 734 @Override 735 public List<ArtifactMetadata> getArtifactsByProjectVersionAttribute( RepositorySession session, String key, String value, String repositoryId) 736 throws MetadataRepositoryException { 737 throw new UnsupportedOperationException("getArtifactsByProjectVersionAttribute not yet implemented in File backend"); 738 } 739 740 private Path getMetadataDirectory(String repoId, String facetId) 741 throws IOException { 742 return getBaseDirectory(repoId).resolve("facets/" + facetId); 743 } 744 745 private String join(Collection<String> ids) { 746 if (ids != null && !ids.isEmpty()) { 747 StringBuilder s = new StringBuilder(); 748 for (String id : ids) { 749 s.append(id); 750 s.append(","); 751 } 752 return s.substring(0, s.length() - 1); 753 } 754 return ""; 755 } 756 757 private void setProperty(Properties properties, String name, String value) { 758 if (value != null) { 759 properties.setProperty(name, value); 760 } 761 } 762 763 @Override 764 public void updateArtifact(RepositorySession session, String repoId, String namespace, String projectId, String projectVersion, 765 ArtifactMetadata artifact) { 766 try { 767 ProjectVersionMetadata metadata = new ProjectVersionMetadata(); 768 metadata.setId(projectVersion); 769 updateProjectVersion(session, repoId, namespace, projectId, metadata); 770 771 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + projectVersion); 772 773 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 774 775 clearMetadataFacetProperties(artifact.getFacetList(), properties, 776 "artifact:facet:" + artifact.getId() + ":"); 777 778 String id = artifact.getId(); 779 properties.setProperty("artifact:updated:" + id, 780 Long.toString(artifact.getFileLastModified().toInstant().toEpochMilli())); 781 properties.setProperty("artifact:whenGathered:" + id, 782 Long.toString(artifact.getWhenGathered().toInstant().toEpochMilli())); 783 properties.setProperty("artifact:size:" + id, Long.toString(artifact.getSize())); 784 artifact.getChecksums().entrySet().stream().forEach( entry -> 785 properties.setProperty( "artifact:checksum:"+id+":"+entry.getKey().name(), entry.getValue() )); 786 properties.setProperty("artifact:version:" + id, artifact.getVersion()); 787 788 Set<String> facetIds = new LinkedHashSet<>(artifact.getFacetIds()); 789 String property = "artifact:facetIds:" + id; 790 facetIds.addAll(Arrays.asList(properties.getProperty(property, "").split(","))); 791 properties.setProperty(property, join(facetIds)); 792 793 updateArtifactFacets(artifact, properties); 794 795 writeProperties(properties, directory, PROJECT_VERSION_METADATA_KEY); 796 } catch (IOException e) { 797 // TODO 798 log.error(e.getMessage(), e); 799 } 800 } 801 802 private Properties readOrCreateProperties(Path directory, String propertiesKey) { 803 try { 804 return readProperties(directory, propertiesKey); 805 } catch (FileNotFoundException | NoSuchFileException e) { 806 // ignore and return new properties 807 } catch (IOException e) { 808 // TODO 809 log.error(e.getMessage(), e); 810 } 811 return new Properties(); 812 } 813 814 private Properties readProperties(Path directory, String propertiesKey) 815 throws IOException { 816 Properties properties = new Properties(); 817 try (InputStream in = Files.newInputStream(directory.resolve(propertiesKey + ".properties"))) { 818 819 properties.load(in); 820 } 821 return properties; 822 } 823 824 @Override 825 public ProjectMetadata getProject(RepositorySession session, String repoId, String namespace, String projectId) 826 throws MetadataResolutionException { 827 try { 828 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId); 829 830 Properties properties = readOrCreateProperties(directory, PROJECT_METADATA_KEY); 831 832 ProjectMetadata project = null; 833 834 String id = properties.getProperty("id"); 835 if (id != null) { 836 project = new ProjectMetadata(); 837 project.setNamespace(properties.getProperty("namespace")); 838 project.setId(id); 839 } 840 841 return project; 842 } catch (IOException e) { 843 throw new MetadataResolutionException(e.getMessage(), e); 844 } 845 } 846 847 @Override 848 public ProjectVersionMetadata getProjectVersion(RepositorySession session, String repoId, String namespace, String projectId, 849 String projectVersion) 850 throws MetadataResolutionException { 851 try { 852 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + projectVersion); 853 854 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 855 String id = properties.getProperty("id"); 856 ProjectVersionMetadata versionMetadata = null; 857 if (id != null) { 858 versionMetadata = new ProjectVersionMetadata(); 859 versionMetadata.setId(id); 860 versionMetadata.setName(properties.getProperty("name")); 861 versionMetadata.setDescription(properties.getProperty("description")); 862 versionMetadata.setUrl(properties.getProperty("url")); 863 versionMetadata.setIncomplete(Boolean.valueOf(properties.getProperty("incomplete", "false"))); 864 865 String scmConnection = properties.getProperty("scm.connection"); 866 String scmDeveloperConnection = properties.getProperty("scm.developerConnection"); 867 String scmUrl = properties.getProperty("scm.url"); 868 if (scmConnection != null || scmDeveloperConnection != null || scmUrl != null) { 869 Scm scm = new Scm(); 870 scm.setConnection(scmConnection); 871 scm.setDeveloperConnection(scmDeveloperConnection); 872 scm.setUrl(scmUrl); 873 versionMetadata.setScm(scm); 874 } 875 876 String ciSystem = properties.getProperty("ci.system"); 877 String ciUrl = properties.getProperty("ci.url"); 878 if (ciSystem != null || ciUrl != null) { 879 CiManagement ci = new CiManagement(); 880 ci.setSystem(ciSystem); 881 ci.setUrl(ciUrl); 882 versionMetadata.setCiManagement(ci); 883 } 884 885 String issueSystem = properties.getProperty("issue.system"); 886 String issueUrl = properties.getProperty("issue.url"); 887 if (issueSystem != null || issueUrl != null) { 888 IssueManagement issueManagement = new IssueManagement(); 889 issueManagement.setSystem(issueSystem); 890 issueManagement.setUrl(issueUrl); 891 versionMetadata.setIssueManagement(issueManagement); 892 } 893 894 String orgName = properties.getProperty("org.name"); 895 String orgUrl = properties.getProperty("org.url"); 896 if (orgName != null || orgUrl != null) { 897 Organization org = new Organization(); 898 org.setName(orgName); 899 org.setUrl(orgUrl); 900 versionMetadata.setOrganization(org); 901 } 902 903 boolean done = false; 904 int i = 0; 905 while (!done) { 906 String licenseName = properties.getProperty("license." + i + ".name"); 907 String licenseUrl = properties.getProperty("license." + i + ".url"); 908 if (licenseName != null || licenseUrl != null) { 909 License license = new License(); 910 license.setName(licenseName); 911 license.setUrl(licenseUrl); 912 versionMetadata.addLicense(license); 913 } else { 914 done = true; 915 } 916 i++; 917 } 918 919 done = false; 920 i = 0; 921 while (!done) { 922 String mailingListName = properties.getProperty("mailingList." + i + ".name"); 923 if (mailingListName != null) { 924 MailingList mailingList = new MailingList(); 925 mailingList.setName(mailingListName); 926 mailingList.setMainArchiveUrl(properties.getProperty("mailingList." + i + ".archive")); 927 String p = properties.getProperty("mailingList." + i + ".otherArchives"); 928 if (p != null && p.length() > 0) { 929 mailingList.setOtherArchives(Arrays.asList(p.split(","))); 930 } else { 931 mailingList.setOtherArchives(Collections.emptyList()); 932 } 933 mailingList.setPostAddress(properties.getProperty("mailingList." + i + ".post")); 934 mailingList.setSubscribeAddress(properties.getProperty("mailingList." + i + ".subscribe")); 935 mailingList.setUnsubscribeAddress( 936 properties.getProperty("mailingList." + i + ".unsubscribe")); 937 versionMetadata.addMailingList(mailingList); 938 } else { 939 done = true; 940 } 941 i++; 942 } 943 944 done = false; 945 i = 0; 946 while (!done) { 947 String dependencyArtifactId = properties.getProperty("dependency." + i + ".artifactId"); 948 if (dependencyArtifactId != null) { 949 Dependency dependency = new Dependency(); 950 dependency.setArtifactId(dependencyArtifactId); 951 dependency.setNamespace(properties.getProperty("dependency." + i + ".groupId")); 952 dependency.setClassifier(properties.getProperty("dependency." + i + ".classifier")); 953 dependency.setOptional( 954 Boolean.valueOf(properties.getProperty("dependency." + i + ".optional"))); 955 dependency.setScope(properties.getProperty("dependency." + i + ".scope")); 956 dependency.setSystemPath(properties.getProperty("dependency." + i + ".systemPath")); 957 dependency.setType(properties.getProperty("dependency." + i + ".type")); 958 dependency.setVersion(properties.getProperty("dependency." + i + ".version")); 959 dependency.setOptional( 960 Boolean.valueOf(properties.getProperty("dependency." + i + ".optional"))); 961 versionMetadata.addDependency(dependency); 962 } else { 963 done = true; 964 } 965 i++; 966 } 967 968 String facetIds = properties.getProperty("facetIds", ""); 969 if (facetIds.length() > 0) { 970 for (String facetId : facetIds.split(",")) { 971 MetadataFacetFactory factory = getFacetFactory(facetId); 972 if (factory == null) { 973 log.error("Attempted to load unknown project version metadata facet: {}", facetId); 974 } else { 975 MetadataFacet facet = factory.createMetadataFacet(); 976 Map<String, String> map = new HashMap<>(); 977 for (Object key : new ArrayList<>(properties.keySet())) { 978 String property = (String) key; 979 if (property.startsWith(facet.getFacetId())) { 980 map.put(property.substring(facet.getFacetId().length() + 1), 981 properties.getProperty(property)); 982 } 983 } 984 facet.fromProperties(map); 985 versionMetadata.addFacet(facet); 986 } 987 } 988 } 989 990 updateProjectVersionFacets(versionMetadata, properties); 991 } 992 return versionMetadata; 993 } catch (IOException e) { 994 throw new MetadataResolutionException(e.getMessage(), e); 995 } 996 } 997 998 @Override 999 public List<String> getArtifactVersions( RepositorySession session, String repoId, String namespace, String projectId, 1000 String projectVersion) 1001 throws MetadataResolutionException { 1002 try { 1003 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + projectVersion); 1004 1005 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 1006 1007 Set<String> versions = new HashSet<>(); 1008 for (Map.Entry entry : properties.entrySet()) { 1009 String name = (String) entry.getKey(); 1010 if (name.startsWith("artifact:version:")) { 1011 versions.add((String) entry.getValue()); 1012 } 1013 } 1014 return new ArrayList<>( versions ); 1015 } catch (IOException e) { 1016 throw new MetadataResolutionException(e.getMessage(), e); 1017 } 1018 } 1019 1020 @Override 1021 public List<ProjectVersionReference> getProjectReferences( RepositorySession session, String repoId, String namespace, String projectId, 1022 String projectVersion) 1023 throws MetadataResolutionException { 1024 try { 1025 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + projectVersion); 1026 1027 Properties properties = readOrCreateProperties(directory, PROJECT_VERSION_METADATA_KEY); 1028 int numberOfRefs = Integer.parseInt(properties.getProperty("ref:lastReferenceNum", "-1")) + 1; 1029 1030 List<ProjectVersionReference> references = new ArrayList<>(); 1031 for (int i = 0; i < numberOfRefs; i++) { 1032 ProjectVersionReference reference = new ProjectVersionReference(); 1033 reference.setProjectId(properties.getProperty("ref:reference." + i + ".projectId")); 1034 reference.setNamespace(properties.getProperty("ref:reference." + i + ".namespace")); 1035 reference.setProjectVersion(properties.getProperty("ref:reference." + i + ".projectVersion")); 1036 reference.setReferenceType(ProjectVersionReference.ReferenceType.valueOf( 1037 properties.getProperty("ref:reference." + i + ".referenceType"))); 1038 references.add(reference); 1039 } 1040 return references; 1041 } catch (IOException e) { 1042 throw new MetadataResolutionException(e.getMessage(), e); 1043 } 1044 } 1045 1046 @Override 1047 public List<String> getRootNamespaces( RepositorySession session, String repoId) 1048 throws MetadataResolutionException { 1049 return this.getChildNamespaces(session, repoId, null); 1050 } 1051 1052 private Stream<String> getAllNamespacesStream(RepositorySession session, String repoId) { 1053 Path directory = null; 1054 try 1055 { 1056 directory = getDirectory(repoId); 1057 } 1058 catch ( IOException e ) 1059 { 1060 return Stream.empty( ); 1061 } 1062 if (!(Files.exists(directory) && Files.isDirectory(directory))) { 1063 return Stream.empty( ); 1064 } 1065 final String searchFile = NAMESPACE_METADATA_KEY + ".properties"; 1066 try 1067 { 1068 return Files.list(directory).filter(Files::isDirectory).filter(path -> 1069 Files.exists(path.resolve(searchFile)) 1070 ).map(path -> path.getFileName().toString()); 1071 } 1072 catch ( IOException e ) 1073 { 1074 return Stream.empty( ); 1075 } 1076 } 1077 1078 @Override 1079 public List<String> getChildNamespaces( RepositorySession session, String repoId, String baseNamespace) 1080 throws MetadataResolutionException { 1081 try { 1082 List<String> allNamespaces; 1083 Path directory = getDirectory(repoId); 1084 if (!(Files.exists(directory) && Files.isDirectory(directory))) { 1085 return Collections.emptyList(); 1086 } 1087 final String searchFile = NAMESPACE_METADATA_KEY + ".properties"; 1088 try (Stream<Path> fs = Files.list(directory)) { 1089 allNamespaces = fs.filter(Files::isDirectory).filter(path -> 1090 Files.exists(path.resolve(searchFile)) 1091 ).map(path -> path.getFileName().toString()).collect(Collectors.toList()); 1092 } 1093 1094 Set<String> namespaces = new LinkedHashSet<>(); 1095 int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0; 1096 for (String namespace : allNamespaces) { 1097 if (baseNamespace == null || namespace.startsWith(baseNamespace + ".")) { 1098 int i = namespace.indexOf('.', fromIndex); 1099 if (i >= 0) { 1100 namespaces.add(namespace.substring(fromIndex, i)); 1101 } else { 1102 namespaces.add(namespace.substring(fromIndex)); 1103 } 1104 } 1105 } 1106 return new ArrayList<>(namespaces); 1107 } catch (IOException e) { 1108 throw new MetadataResolutionException(e.getMessage(), e); 1109 } 1110 } 1111 1112 @Override 1113 public List<String> getProjects( RepositorySession session, String repoId, String namespace) 1114 throws MetadataResolutionException { 1115 try { 1116 List<String> projects; 1117 Path directory = getDirectory(repoId).resolve(namespace); 1118 if (!(Files.exists(directory) && Files.isDirectory(directory))) { 1119 return Collections.emptyList(); 1120 } 1121 final String searchFile = PROJECT_METADATA_KEY + ".properties"; 1122 try (Stream<Path> fs = Files.list(directory)) { 1123 projects = fs.filter(Files::isDirectory).filter(path -> 1124 Files.exists(path.resolve(searchFile)) 1125 ).map(path -> path.getFileName().toString()).collect(Collectors.toList()); 1126 } 1127 1128 return projects; 1129 } catch (IOException e) { 1130 throw new MetadataResolutionException(e.getMessage(), e); 1131 } 1132 } 1133 1134 @Override 1135 public List<String> getProjectVersions( RepositorySession session, String repoId, String namespace, String projectId) 1136 throws MetadataResolutionException { 1137 try { 1138 List<String> projectVersions; 1139 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId); 1140 if (!(Files.exists(directory) && Files.isDirectory(directory))) { 1141 return Collections.emptyList(); 1142 } 1143 final String searchFile = PROJECT_VERSION_METADATA_KEY + ".properties"; 1144 try (Stream<Path> fs = Files.list(directory)) { 1145 projectVersions = fs.filter(Files::isDirectory).filter(path -> 1146 Files.exists(path.resolve(searchFile)) 1147 ).map(path -> path.getFileName().toString()).collect(Collectors.toList()); 1148 } 1149 return projectVersions; 1150 } catch (IOException e) { 1151 throw new MetadataResolutionException(e.getMessage(), e); 1152 } 1153 } 1154 1155 @Override 1156 public void removeProject(RepositorySession session, String repositoryId, String namespace, String projectId) 1157 throws MetadataRepositoryException { 1158 try { 1159 Path directory = getDirectory(repositoryId).resolve(namespace + "/" + projectId); 1160 org.apache.archiva.common.utils.FileUtils.deleteDirectory(directory); 1161 } catch (IOException e) { 1162 throw new MetadataRepositoryException(e.getMessage(), e); 1163 } 1164 } 1165 1166 @Override 1167 public void removeProjectVersion(RepositorySession session, String repoId, String namespace, String projectId, String projectVersion) 1168 throws MetadataRepositoryException { 1169 try { 1170 Path directory = getDirectory(repoId).resolve(namespace + "/" + projectId + "/" + projectVersion); 1171 org.apache.archiva.common.utils.FileUtils.deleteDirectory(directory); 1172 } catch (IOException e) { 1173 throw new MetadataRepositoryException(e.getMessage(), e); 1174 } 1175 1176 } 1177 1178 private void writeProperties(Properties properties, Path directory, String propertiesKey) 1179 throws IOException { 1180 Files.createDirectories(directory); 1181 try (OutputStream os = Files.newOutputStream(directory.resolve(propertiesKey + ".properties"))) { 1182 properties.store(os, null); 1183 } 1184 } 1185 1186 private static class ArtifactComparator 1187 implements Comparator<ArtifactMetadata> { 1188 @Override 1189 public int compare(ArtifactMetadata artifact1, ArtifactMetadata artifact2) { 1190 if (artifact1.getWhenGathered() == artifact2.getWhenGathered()) { 1191 return 0; 1192 } 1193 if (artifact1.getWhenGathered() == null) { 1194 return 1; 1195 } 1196 if (artifact2.getWhenGathered() == null) { 1197 return -1; 1198 } 1199 return artifact1.getWhenGathered().compareTo(artifact2.getWhenGathered()); 1200 } 1201 } 1202 1203 @Override 1204 public List<ArtifactMetadata> getArtifacts(RepositorySession session, String repoId) 1205 throws MetadataRepositoryException { 1206 try { 1207 List<ArtifactMetadata> artifacts = new ArrayList<>(); 1208 for (String ns : getRootNamespaces(session, repoId)) { 1209 getArtifacts(session, artifacts, repoId, ns); 1210 } 1211 return artifacts; 1212 } catch (MetadataResolutionException e) { 1213 throw new MetadataRepositoryException(e.getMessage(), e); 1214 } 1215 } 1216 1217 private class ArtifactCoordinates { 1218 final String namespace; 1219 final String project; 1220 final String version; 1221 1222 public ArtifactCoordinates(String namespace, String project, String version) { 1223 this.namespace = namespace; 1224 this.project = project; 1225 this.version = version; 1226 } 1227 1228 public String getNamespace( ) 1229 { 1230 return namespace; 1231 } 1232 1233 public String getProject( ) 1234 { 1235 return project; 1236 } 1237 1238 public String getVersion( ) 1239 { 1240 return version; 1241 } 1242 } 1243 1244 @Override 1245 public Stream<ArtifactMetadata> getArtifactStream( final RepositorySession session, final String repositoryId, 1246 QueryParameter queryParameter ) throws MetadataResolutionException 1247 { 1248 1249 return getAllNamespacesStream( session, repositoryId ).filter( Objects::nonNull ).flatMap( ns -> 1250 { 1251 try 1252 { 1253 return getProjects( session, repositoryId, ns ).stream( ).map( proj -> 1254 new ArtifactCoordinates( ns, proj, null ) ); 1255 } 1256 catch ( MetadataResolutionException e ) 1257 { 1258 return null; 1259 } 1260 } 1261 ).filter( Objects::nonNull ).flatMap( artifactCoordinates -> 1262 { 1263 try 1264 { 1265 return getProjectVersions( session, repositoryId, artifactCoordinates.getNamespace( ), artifactCoordinates.getProject( ) ) 1266 .stream( ).map(version -> new ArtifactCoordinates( artifactCoordinates.getNamespace(), artifactCoordinates.getProject(), version )); 1267 } 1268 catch ( MetadataResolutionException e ) 1269 { 1270 return null; 1271 } 1272 } 1273 ).filter( Objects::nonNull ).flatMap( ac -> 1274 { 1275 try 1276 { 1277 return getArtifactStream( session, repositoryId, ac.getNamespace(), ac.getProject(), ac.getVersion() ); 1278 } 1279 catch ( MetadataResolutionException e ) 1280 { 1281 return null; 1282 } 1283 } 1284 ).filter( Objects::nonNull ); 1285 } 1286 1287 @Override 1288 public Stream<ArtifactMetadata> getArtifactStream( final RepositorySession session, final String repoId, 1289 final String namespace, final String projectId, 1290 final String projectVersion ) throws MetadataResolutionException 1291 { 1292 return getArtifacts( session, repoId, namespace, projectId, projectVersion ).stream( ); 1293 } 1294 1295 private void getArtifacts(RepositorySession session, List<ArtifactMetadata> artifacts, String repoId, String ns) 1296 throws MetadataResolutionException { 1297 for (String namespace : this.getChildNamespaces(session, repoId, ns)) { 1298 getArtifacts(session, artifacts, repoId, ns + "." + namespace); 1299 } 1300 1301 for (String project : getProjects(session, repoId, ns)) { 1302 for (String version : getProjectVersions(session, repoId, ns, project)) { 1303 artifacts.addAll(getArtifacts(session, repoId, ns, project, version)); 1304 } 1305 } 1306 } 1307 1308 @Override 1309 public List<ArtifactMetadata> searchArtifacts(RepositorySession session, String repositoryId, String text, boolean exact) { 1310 throw new UnsupportedOperationException("searchArtifacts not yet implemented in File backend"); 1311 } 1312 1313 @Override 1314 public List<ArtifactMetadata> searchArtifacts(RepositorySession session, String repositoryId, String key, String text, boolean exact) { 1315 throw new UnsupportedOperationException("searchArtifacts not yet implemented in File backend"); 1316 } 1317}