1 package org.apache.archiva.metadata.repository;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.archiva.metadata.model.ArtifactMetadata;
23 import org.apache.archiva.metadata.model.ProjectMetadata;
24 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
25 import org.apache.archiva.metadata.model.ProjectVersionReference;
26 import org.apache.archiva.metadata.repository.filter.ExcludesFilter;
27 import org.apache.archiva.metadata.repository.storage.RepositoryStorage;
28 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataInvalidException;
29 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataNotFoundException;
30 import org.apache.archiva.metadata.repository.storage.RepositoryStorageRuntimeException;
31 import org.apache.archiva.repository.events.RepositoryListener;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.springframework.stereotype.Service;
36 import javax.inject.Inject;
37 import javax.inject.Named;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.List;
43 * Default implementation of the metadata resolver API. At present it will handle updating the content repository
44 * from new or changed information in the model and artifacts from the repository storage.
46 * This is a singleton component to allow an alternate implementation to be provided. It is intended to be the same
47 * system-wide for the whole content repository instead of on a per-managed-repository basis. Therefore, the session is
48 * passed in as an argument to obtain any necessary resources, rather than the class being instantiated within the
49 * session in the context of a single managed repository's resolution needs.
51 * Note that the caller is responsible for the session, such as closing and saving (which is implied by the resolver
52 * being obtained from within the session). The {@link RepositorySession#markDirty()} method is used as a hint to ensure
53 * that the session knows we've made changes at close. We cannot ensure the changes will be persisted if the caller
54 * chooses to revert first. This is preferable to storing the metadata immediately - a separate session would require
55 * having a bi-directional link with the session factory, and saving the existing session might save other changes
56 * unknowingly by the caller.
59 @Service( "metadataResolver#default" )
60 public class DefaultMetadataResolver
61 implements MetadataResolver
64 private Logger log = LoggerFactory.getLogger( DefaultMetadataResolver.class );
67 * FIXME: this needs to be configurable based on storage type - and could also be instantiated per repo. Change to a
68 * factory, and perhaps retrieve from the session. We should avoid creating one per request, however.
70 * TODO: Also need to accommodate availability of proxy module
71 * ... could be a different type since we need methods to modify the storage metadata, which would also allow more
72 * appropriate methods to pass in the already determined repository configuration, for example, instead of the ID
75 @Named( value = "repositoryStorage#maven2" )
76 private RepositoryStorage repositoryStorage;
82 private List<RepositoryListener> listeners;
84 public ProjectVersionMetadata resolveProjectVersion( RepositorySession session, String repoId, String namespace,
85 String projectId, String projectVersion )
86 throws MetadataResolutionException
88 MetadataRepository metadataRepository = session.getRepository();
90 ProjectVersionMetadata metadata =
91 metadataRepository.getProjectVersion( repoId, namespace, projectId, projectVersion );
92 // TODO: do we want to detect changes as well by comparing timestamps? isProjectVersionNewerThan(updated)
93 // in such cases we might also remove/update stale metadata, including adjusting plugin-based facets
94 // This would also be better than checking for completeness - we can then refresh only when fixed (though
95 // sometimes this has an additional dependency - such as a parent - requesting the user to force an update
96 // may then work here and be more efficient than always trying again)
97 if ( metadata == null || metadata.isIncomplete() )
101 metadata = repositoryStorage.readProjectVersionMetadata( repoId, namespace, projectId, projectVersion );
103 log.debug( "Resolved project version metadata from storage: {}", metadata );
105 // FIXME: make this a more generic post-processing that plugins can take advantage of
106 // eg. maven projects should be able to process parent here
107 if ( !metadata.getDependencies().isEmpty() )
109 ProjectVersionReference ref = new ProjectVersionReference();
110 ref.setNamespace( namespace );
111 ref.setProjectId( projectId );
112 ref.setProjectVersion( projectVersion );
113 ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
117 for ( RepositoryListener listener : listeners )
119 listener.addArtifact( session, repoId, namespace, projectId, metadata );
121 metadataRepository.updateProjectVersion( repoId, namespace, projectId, metadata );
123 catch ( MetadataRepositoryException e )
125 log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
130 catch ( RepositoryStorageMetadataInvalidException e )
132 for ( RepositoryListener listener : listeners )
134 listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
136 throw new MetadataResolutionException( e.getMessage(), e );
138 catch ( RepositoryStorageMetadataNotFoundException e )
140 for ( RepositoryListener listener : listeners )
142 listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
144 // no need to rethrow - return null
146 catch ( RepositoryStorageRuntimeException e )
148 for ( RepositoryListener listener : listeners )
150 listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
152 throw new MetadataResolutionException( e.getMessage(), e );
159 public Collection<ProjectVersionReference> resolveProjectReferences( RepositorySession session, String repoId,
160 String namespace, String projectId,
161 String projectVersion )
162 throws MetadataResolutionException
164 // TODO: is this assumption correct? could a storage mech. actually know all references in a non-Maven scenario?
165 // not passed to the storage mechanism as resolving references would require iterating all artifacts
166 MetadataRepository metadataRepository = session.getRepository();
167 return metadataRepository.getProjectReferences( repoId, namespace, projectId, projectVersion );
170 public Collection<String> resolveRootNamespaces( RepositorySession session, String repoId )
171 throws MetadataResolutionException
175 MetadataRepository metadataRepository = session.getRepository();
176 Collection<String> namespaces = metadataRepository.getRootNamespaces( repoId );
177 Collection<String> storageNamespaces =
178 repositoryStorage.listRootNamespaces( repoId, new ExcludesFilter<String>( namespaces ) );
179 if ( storageNamespaces != null && !storageNamespaces.isEmpty() )
182 log.debug( "Resolved root namespaces from storage: {}", storageNamespaces );
184 for ( String n : storageNamespaces )
188 metadataRepository.updateNamespace( repoId, n );
190 catch ( MetadataRepositoryException e )
192 log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
197 namespaces = new ArrayList<String>( namespaces );
198 namespaces.addAll( storageNamespaces );
202 catch ( RepositoryStorageRuntimeException e )
204 throw new MetadataResolutionException( e.getMessage(), e );
208 public Collection<String> resolveNamespaces( RepositorySession session, String repoId, String namespace )
209 throws MetadataResolutionException
213 MetadataRepository metadataRepository = session.getRepository();
214 Collection<String> namespaces = metadataRepository.getNamespaces( repoId, namespace );
215 Collection<String> exclusions = new ArrayList<String>( namespaces );
216 exclusions.addAll( metadataRepository.getProjects( repoId, namespace ) );
217 Collection<String> storageNamespaces =
218 repositoryStorage.listNamespaces( repoId, namespace, new ExcludesFilter<String>( exclusions ) );
219 if ( storageNamespaces != null && !storageNamespaces.isEmpty() )
222 log.debug( "Resolved namespaces from storage: {}", storageNamespaces );
224 for ( String n : storageNamespaces )
228 metadataRepository.updateNamespace( repoId, namespace + "." + n );
230 catch ( MetadataRepositoryException e )
232 log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
237 namespaces = new ArrayList<String>( namespaces );
238 namespaces.addAll( storageNamespaces );
242 catch ( RepositoryStorageRuntimeException e )
244 throw new MetadataResolutionException( e.getMessage(), e );
248 public Collection<String> resolveProjects( RepositorySession session, String repoId, String namespace )
249 throws MetadataResolutionException
253 MetadataRepository metadataRepository = session.getRepository();
254 Collection<String> projects = metadataRepository.getProjects( repoId, namespace );
255 Collection<String> exclusions = new ArrayList<String>( projects );
256 exclusions.addAll( metadataRepository.getNamespaces( repoId, namespace ) );
257 Collection<String> storageProjects =
258 repositoryStorage.listProjects( repoId, namespace, new ExcludesFilter<String>( exclusions ) );
259 if ( storageProjects != null && !storageProjects.isEmpty() )
262 log.debug( "Resolved projects from storage: {}", storageProjects );
263 for ( String projectId : storageProjects )
265 ProjectMetadata projectMetadata =
266 repositoryStorage.readProjectMetadata( repoId, namespace, projectId );
267 if ( projectMetadata != null )
271 metadataRepository.updateProject( repoId, projectMetadata );
273 catch ( MetadataRepositoryException e )
275 log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
281 projects = new ArrayList<String>( projects );
282 projects.addAll( storageProjects );
286 catch ( RepositoryStorageRuntimeException e )
288 throw new MetadataResolutionException( e.getMessage(), e );
292 public Collection<String> resolveProjectVersions( RepositorySession session, String repoId, String namespace,
294 throws MetadataResolutionException
298 MetadataRepository metadataRepository = session.getRepository();
299 Collection<String> projectVersions = metadataRepository.getProjectVersions( repoId, namespace, projectId );
300 Collection<String> storageProjectVersions =
301 repositoryStorage.listProjectVersions( repoId, namespace, projectId,
302 new ExcludesFilter<String>( projectVersions ) );
303 if ( storageProjectVersions != null && !storageProjectVersions.isEmpty() )
305 log.debug( "Resolved project versions from storage: {}", storageProjectVersions );
307 for ( String projectVersion : storageProjectVersions )
311 ProjectVersionMetadata versionMetadata =
312 repositoryStorage.readProjectVersionMetadata( repoId, namespace, projectId,
314 for ( RepositoryListener listener : listeners )
316 listener.addArtifact( session, repoId, namespace, projectId, versionMetadata );
319 metadataRepository.updateProjectVersion( repoId, namespace, projectId, versionMetadata );
321 catch ( MetadataRepositoryException e )
323 log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
325 catch ( RepositoryStorageMetadataInvalidException e )
328 "Not update project in metadata repository due to an error resolving it from storage: "
331 for ( RepositoryListener listener : listeners )
333 listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
336 catch ( RepositoryStorageMetadataNotFoundException e )
338 for ( RepositoryListener listener : listeners )
340 listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
346 projectVersions = new ArrayList<String>( projectVersions );
347 projectVersions.addAll( storageProjectVersions );
349 return projectVersions;
351 catch ( RepositoryStorageRuntimeException e )
353 throw new MetadataResolutionException( e.getMessage(), e );
357 public Collection<ArtifactMetadata> resolveArtifacts( RepositorySession session, String repoId, String namespace,
358 String projectId, String projectVersion )
359 throws MetadataResolutionException
363 MetadataRepository metadataRepository = session.getRepository();
364 Collection<ArtifactMetadata> artifacts =
365 metadataRepository.getArtifacts( repoId, namespace, projectId, projectVersion );
366 ExcludesFilter<String> filter = new ExcludesFilter<String>( createArtifactIdList( artifacts ) );
367 Collection<ArtifactMetadata> storageArtifacts =
368 repositoryStorage.readArtifactsMetadata( repoId, namespace, projectId, projectVersion, filter );
369 if ( storageArtifacts != null && !storageArtifacts.isEmpty() )
372 log.debug( "Resolved artifacts from storage: {}", storageArtifacts );
374 for ( ArtifactMetadata artifact : storageArtifacts )
378 metadataRepository.updateArtifact( repoId, namespace, projectId, projectVersion, artifact );
380 catch ( MetadataRepositoryException e )
382 log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
387 artifacts = new ArrayList<ArtifactMetadata>( artifacts );
388 artifacts.addAll( storageArtifacts );
392 catch ( RepositoryStorageRuntimeException e )
394 for ( RepositoryListener listener : listeners )
396 listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
398 throw new MetadataResolutionException( e.getMessage(), e );
402 private Collection<String> createArtifactIdList( Collection<ArtifactMetadata> artifacts )
404 Collection<String> artifactIds = new ArrayList<String>();
405 for ( ArtifactMetadata artifact : artifacts )
407 artifactIds.add( artifact.getId() );