]> source.dussan.org Git - archiva.git/blob
f56d72c1627ccfb7a03f9905cbc84f677c061b5d
[archiva.git] /
1 package org.apache.archiva.metadata.repository;
2
3 /*
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
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
22 import org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.metadata.model.ArtifactMetadata;
24 import org.apache.archiva.metadata.model.ProjectMetadata;
25 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
26 import org.apache.archiva.metadata.model.ProjectVersionReference;
27 import org.apache.archiva.metadata.repository.filter.ExcludesFilter;
28 import org.apache.archiva.metadata.repository.storage.RepositoryStorage;
29 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataInvalidException;
30 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataNotFoundException;
31 import org.apache.archiva.repository.events.RepositoryListener;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.springframework.stereotype.Service;
35
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;
41
42 /**
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.
45  * <p/>
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.
50  * <p/>
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.
57  * <p/>
58  */
59 @Service( "metadataResolver#default" )
60 public class DefaultMetadataResolver
61     implements MetadataResolver
62 {
63
64     private Logger log = LoggerFactory.getLogger( DefaultMetadataResolver.class );
65
66     /**
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.
69      * <p/>
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
73      */
74     @Inject
75     @Named( value = "repositoryStorage#maven2" )
76     private RepositoryStorage repositoryStorage;
77
78     /**
79      *
80      */
81     @Inject
82     private List<RepositoryListener> listeners;
83
84     public ProjectVersionMetadata resolveProjectVersion( RepositorySession session, String repoId, String namespace,
85                                                          String projectId, String projectVersion )
86         throws MetadataResolutionException
87     {
88         MetadataRepository metadataRepository = session.getRepository();
89
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() )
98         {
99             try
100             {
101                 metadata = repositoryStorage.readProjectVersionMetadata( repoId, namespace, projectId, projectVersion );
102
103                 log.debug( "Resolved project version metadata from storage: {}", metadata );
104
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() )
108                 {
109                     ProjectVersionReference ref = new ProjectVersionReference();
110                     ref.setNamespace( namespace );
111                     ref.setProjectId( projectId );
112                     ref.setProjectVersion( projectVersion );
113                     ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
114                 }
115                 try
116                 {
117                     for ( RepositoryListener listener : listeners )
118                     {
119                         listener.addArtifact( session, repoId, namespace, projectId, metadata );
120                     }
121                     metadataRepository.updateProjectVersion( repoId, namespace, projectId, metadata );
122                 }
123                 catch ( MetadataRepositoryException e )
124                 {
125                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
126                 }
127
128                 session.markDirty();
129             }
130             catch ( RepositoryStorageMetadataInvalidException e )
131             {
132                 for ( RepositoryListener listener : listeners )
133                 {
134                     listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
135                 }
136                 throw new MetadataResolutionException( e.getMessage(), e );
137             }
138             catch ( RepositoryAdminException e )
139             {
140                 for ( RepositoryListener listener : listeners )
141                 {
142                     listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
143                 }
144                 throw new MetadataResolutionException( e.getMessage(), e );
145             }
146             catch ( RepositoryStorageMetadataNotFoundException e )
147             {
148                 for ( RepositoryListener listener : listeners )
149                 {
150                     listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
151                 }
152                 // no need to rethrow - return null
153             }
154         }
155         return metadata;
156     }
157
158     public Collection<ProjectVersionReference> resolveProjectReferences( RepositorySession session, String repoId,
159                                                                          String namespace, String projectId,
160                                                                          String projectVersion )
161         throws MetadataResolutionException
162     {
163         // TODO: is this assumption correct? could a storage mech. actually know all references in a non-Maven scenario?
164         // not passed to the storage mechanism as resolving references would require iterating all artifacts
165         MetadataRepository metadataRepository = session.getRepository();
166         return metadataRepository.getProjectReferences( repoId, namespace, projectId, projectVersion );
167     }
168
169     public Collection<String> resolveRootNamespaces( RepositorySession session, String repoId )
170         throws MetadataResolutionException
171     {
172         MetadataRepository metadataRepository = session.getRepository();
173         Collection<String> namespaces = metadataRepository.getRootNamespaces( repoId );
174         Collection<String> storageNamespaces =
175             repositoryStorage.listRootNamespaces( repoId, new ExcludesFilter<String>( namespaces ) );
176         if ( storageNamespaces != null && !storageNamespaces.isEmpty() )
177         {
178             if ( log.isDebugEnabled() )
179             {
180                 log.debug( "Resolved root namespaces from storage: " + storageNamespaces );
181             }
182             for ( String n : storageNamespaces )
183             {
184                 try
185                 {
186                     metadataRepository.updateNamespace( repoId, n );
187                 }
188                 catch ( MetadataRepositoryException e )
189                 {
190                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
191                 }
192             }
193             session.markDirty();
194
195             namespaces = new ArrayList<String>( namespaces );
196             namespaces.addAll( storageNamespaces );
197         }
198         return namespaces;
199     }
200
201     public Collection<String> resolveNamespaces( RepositorySession session, String repoId, String namespace )
202         throws MetadataResolutionException
203     {
204         MetadataRepository metadataRepository = session.getRepository();
205         Collection<String> namespaces = metadataRepository.getNamespaces( repoId, namespace );
206         Collection<String> exclusions = new ArrayList<String>( namespaces );
207         exclusions.addAll( metadataRepository.getProjects( repoId, namespace ) );
208         Collection<String> storageNamespaces =
209             repositoryStorage.listNamespaces( repoId, namespace, new ExcludesFilter<String>( exclusions ) );
210         if ( storageNamespaces != null && !storageNamespaces.isEmpty() )
211         {
212             if ( log.isDebugEnabled() )
213             {
214                 log.debug( "Resolved namespaces from storage: " + storageNamespaces );
215             }
216             for ( String n : storageNamespaces )
217             {
218                 try
219                 {
220                     metadataRepository.updateNamespace( repoId, namespace + "." + n );
221                 }
222                 catch ( MetadataRepositoryException e )
223                 {
224                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
225                 }
226             }
227             session.markDirty();
228
229             namespaces = new ArrayList<String>( namespaces );
230             namespaces.addAll( storageNamespaces );
231         }
232         return namespaces;
233     }
234
235     public Collection<String> resolveProjects( RepositorySession session, String repoId, String namespace )
236         throws MetadataResolutionException
237     {
238         MetadataRepository metadataRepository = session.getRepository();
239         Collection<String> projects = metadataRepository.getProjects( repoId, namespace );
240         Collection<String> exclusions = new ArrayList<String>( projects );
241         exclusions.addAll( metadataRepository.getNamespaces( repoId, namespace ) );
242         Collection<String> storageProjects =
243             repositoryStorage.listProjects( repoId, namespace, new ExcludesFilter<String>( exclusions ) );
244         if ( storageProjects != null && !storageProjects.isEmpty() )
245         {
246             if ( log.isDebugEnabled() )
247             {
248                 log.debug( "Resolved projects from storage: " + storageProjects );
249             }
250             for ( String projectId : storageProjects )
251             {
252                 ProjectMetadata projectMetadata = repositoryStorage.readProjectMetadata( repoId, namespace, projectId );
253                 if ( projectMetadata != null )
254                 {
255                     try
256                     {
257                         metadataRepository.updateProject( repoId, projectMetadata );
258                     }
259                     catch ( MetadataRepositoryException e )
260                     {
261                         log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
262                     }
263                 }
264             }
265             session.markDirty();
266
267             projects = new ArrayList<String>( projects );
268             projects.addAll( storageProjects );
269         }
270         return projects;
271     }
272
273     public Collection<String> resolveProjectVersions( RepositorySession session, String repoId, String namespace,
274                                                       String projectId )
275         throws MetadataResolutionException
276     {
277         MetadataRepository metadataRepository = session.getRepository();
278         Collection<String> projectVersions = metadataRepository.getProjectVersions( repoId, namespace, projectId );
279         Collection<String> storageProjectVersions = repositoryStorage.listProjectVersions( repoId, namespace, projectId,
280                                                                                            new ExcludesFilter<String>(
281                                                                                                projectVersions ) );
282         if ( storageProjectVersions != null && !storageProjectVersions.isEmpty() )
283         {
284             if ( log.isDebugEnabled() )
285             {
286                 log.debug( "Resolved project versions from storage: " + storageProjectVersions );
287             }
288             for ( String projectVersion : storageProjectVersions )
289             {
290                 try
291                 {
292                     ProjectVersionMetadata versionMetadata =
293                         repositoryStorage.readProjectVersionMetadata( repoId, namespace, projectId, projectVersion );
294                     for ( RepositoryListener listener : listeners )
295                     {
296                         listener.addArtifact( session, repoId, namespace, projectId, versionMetadata );
297                     }
298
299                     metadataRepository.updateProjectVersion( repoId, namespace, projectId, versionMetadata );
300                 }
301                 catch ( MetadataRepositoryException e )
302                 {
303                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
304                 }
305                 catch ( RepositoryStorageMetadataInvalidException e )
306                 {
307                     log.warn( "Not update project in metadata repository due to an error resolving it from storage: "
308                                   + e.getMessage() );
309
310                     for ( RepositoryListener listener : listeners )
311                     {
312                         listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
313                     }
314                 }
315                 catch ( RepositoryStorageMetadataNotFoundException e )
316                 {
317                     for ( RepositoryListener listener : listeners )
318                     {
319                         listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
320                     }
321                 }
322             }
323             session.markDirty();
324
325             projectVersions = new ArrayList<String>( projectVersions );
326             projectVersions.addAll( storageProjectVersions );
327         }
328         return projectVersions;
329     }
330
331     public Collection<ArtifactMetadata> resolveArtifacts( RepositorySession session, String repoId, String namespace,
332                                                           String projectId, String projectVersion )
333         throws MetadataResolutionException
334     {
335         MetadataRepository metadataRepository = session.getRepository();
336         Collection<ArtifactMetadata> artifacts =
337             metadataRepository.getArtifacts( repoId, namespace, projectId, projectVersion );
338         ExcludesFilter<String> filter = new ExcludesFilter<String>( createArtifactIdList( artifacts ) );
339         Collection<ArtifactMetadata> storageArtifacts =
340             repositoryStorage.readArtifactsMetadata( repoId, namespace, projectId, projectVersion, filter );
341         if ( storageArtifacts != null && !storageArtifacts.isEmpty() )
342         {
343             if ( log.isDebugEnabled() )
344             {
345                 log.debug( "Resolved artifacts from storage: " + storageArtifacts );
346             }
347             for ( ArtifactMetadata artifact : storageArtifacts )
348             {
349                 try
350                 {
351                     metadataRepository.updateArtifact( repoId, namespace, projectId, projectVersion, artifact );
352                 }
353                 catch ( MetadataRepositoryException e )
354                 {
355                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
356                 }
357             }
358             session.markDirty();
359
360             artifacts = new ArrayList<ArtifactMetadata>( artifacts );
361             artifacts.addAll( storageArtifacts );
362         }
363         return artifacts;
364     }
365
366     private Collection<String> createArtifactIdList( Collection<ArtifactMetadata> artifacts )
367     {
368         Collection<String> artifactIds = new ArrayList<String>();
369         for ( ArtifactMetadata artifact : artifacts )
370         {
371             artifactIds.add( artifact.getId() );
372         }
373         return artifactIds;
374     }
375 }