]> source.dussan.org Git - archiva.git/blob
e6fb6888e40b7cd859a7dc97c23e7ac14bd83168
[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.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.repository.events.RepositoryListener;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.springframework.context.ApplicationContext;
34 import org.springframework.stereotype.Service;
35
36 import javax.annotation.PostConstruct;
37 import javax.inject.Inject;
38 import javax.inject.Named;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.List;
42
43 /**
44  * Default implementation of the metadata resolver API. At present it will handle updating the content repository
45  * from new or changed information in the model and artifacts from the repository storage.
46  * <p/>
47  * This is a singleton component to allow an alternate implementation to be provided. It is intended to be the same
48  * system-wide for the whole content repository instead of on a per-managed-repository basis. Therefore, the session is
49  * passed in as an argument to obtain any necessary resources, rather than the class being instantiated within the
50  * session in the context of a single managed repository's resolution needs.
51  * <p/>
52  * Note that the caller is responsible for the session, such as closing and saving (which is implied by the resolver
53  * being obtained from within the session). The {@link RepositorySession#markDirty()} method is used as a hint to ensure
54  * that the session knows we've made changes at close. We cannot ensure the changes will be persisted if the caller
55  * chooses to revert first. This is preferable to storing the metadata immediately - a separate session would require
56  * having a bi-directional link with the session factory, and saving the existing session might save other changes
57  * unknowingly by the caller.
58  * <p/>
59  * plexus.component role="org.apache.archiva.metadata.repository.MetadataResolver"
60  */
61 @Service( "metadataResolver#default" )
62 public class DefaultMetadataResolver
63     implements MetadataResolver
64 {
65
66     private Logger log = LoggerFactory.getLogger( DefaultMetadataResolver.class );
67
68     /**
69      * FIXME: this needs to be configurable based on storage type - and could also be instantiated per repo. Change to a
70      * factory, and perhaps retrieve from the session. We should avoid creating one per request, however.
71      * <p/>
72      * TODO: Also need to accommodate availability of proxy module
73      * ... could be a different type since we need methods to modify the storage metadata, which would also allow more
74      * appropriate methods to pass in the already determined repository configuration, for example, instead of the ID
75      *
76      * plexus.requirement role-hint="maven2"
77      */
78     @Inject
79     @Named( value = "repositoryStorage#maven2" )
80     private RepositoryStorage repositoryStorage;
81
82     /**
83      * plexus.requirement role="org.apache.archiva.repository.events.RepositoryListener"
84      */
85     @Inject
86     private List<RepositoryListener> listeners;
87
88
89     //@Inject
90     //private ApplicationContext applicationContext;
91
92     @PostConstruct
93     private void initialize()
94     {
95         //listeners =
96         //    new ArrayList<RepositoryListener>( applicationContext.getBeansOfType( RepositoryListener.class ).values() );
97     }
98
99     public ProjectVersionMetadata resolveProjectVersion( RepositorySession session, String repoId, String namespace,
100                                                          String projectId, String projectVersion )
101         throws MetadataResolutionException
102     {
103         MetadataRepository metadataRepository = session.getRepository();
104
105         ProjectVersionMetadata metadata =
106             metadataRepository.getProjectVersion( repoId, namespace, projectId, projectVersion );
107         // TODO: do we want to detect changes as well by comparing timestamps? isProjectVersionNewerThan(updated)
108         //       in such cases we might also remove/update stale metadata, including adjusting plugin-based facets
109         //       This would also be better than checking for completeness - we can then refresh only when fixed (though
110         //       sometimes this has an additional dependency - such as a parent - requesting the user to force an update
111         //       may then work here and be more efficient than always trying again)
112         if ( metadata == null || metadata.isIncomplete() )
113         {
114             try
115             {
116                 metadata = repositoryStorage.readProjectVersionMetadata( repoId, namespace, projectId, projectVersion );
117
118                 if ( log.isDebugEnabled() )
119                 {
120                     log.debug( "Resolved project version metadata from storage: " + metadata );
121                 }
122                 // FIXME: make this a more generic post-processing that plugins can take advantage of
123                 //       eg. maven projects should be able to process parent here
124                 if ( !metadata.getDependencies().isEmpty() )
125                 {
126                     ProjectVersionReference ref = new ProjectVersionReference();
127                     ref.setNamespace( namespace );
128                     ref.setProjectId( projectId );
129                     ref.setProjectVersion( projectVersion );
130                     ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
131                 }
132                 try
133                 {
134                     for ( RepositoryListener listener : listeners )
135                     {
136                         listener.addArtifact( session, repoId, namespace, projectId, metadata );
137                     }
138                     metadataRepository.updateProjectVersion( repoId, namespace, projectId, metadata );
139                 }
140                 catch ( MetadataRepositoryException e )
141                 {
142                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
143                 }
144
145                 session.markDirty();
146             }
147             catch ( RepositoryStorageMetadataInvalidException e )
148             {
149                 for ( RepositoryListener listener : listeners )
150                 {
151                     listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
152                 }
153                 throw new MetadataResolutionException( e.getMessage(), e );
154             }
155             catch ( RepositoryStorageMetadataNotFoundException e )
156             {
157                 for ( RepositoryListener listener : listeners )
158                 {
159                     listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
160                 }
161                 // no need to rethrow - return null
162             }
163         }
164         return metadata;
165     }
166
167     public Collection<ProjectVersionReference> resolveProjectReferences( RepositorySession session, String repoId,
168                                                                          String namespace, String projectId,
169                                                                          String projectVersion )
170         throws MetadataResolutionException
171     {
172         // TODO: is this assumption correct? could a storage mech. actually know all references in a non-Maven scenario?
173         // not passed to the storage mechanism as resolving references would require iterating all artifacts
174         MetadataRepository metadataRepository = session.getRepository();
175         return metadataRepository.getProjectReferences( repoId, namespace, projectId, projectVersion );
176     }
177
178     public Collection<String> resolveRootNamespaces( RepositorySession session, String repoId )
179         throws MetadataResolutionException
180     {
181         MetadataRepository metadataRepository = session.getRepository();
182         Collection<String> namespaces = metadataRepository.getRootNamespaces( repoId );
183         Collection<String> storageNamespaces =
184             repositoryStorage.listRootNamespaces( repoId, new ExcludesFilter<String>( namespaces ) );
185         if ( storageNamespaces != null && !storageNamespaces.isEmpty() )
186         {
187             if ( log.isDebugEnabled() )
188             {
189                 log.debug( "Resolved root namespaces from storage: " + storageNamespaces );
190             }
191             for ( String n : storageNamespaces )
192             {
193                 try
194                 {
195                     metadataRepository.updateNamespace( repoId, n );
196                 }
197                 catch ( MetadataRepositoryException e )
198                 {
199                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
200                 }
201             }
202             session.markDirty();
203
204             namespaces = new ArrayList<String>( namespaces );
205             namespaces.addAll( storageNamespaces );
206         }
207         return namespaces;
208     }
209
210     public Collection<String> resolveNamespaces( RepositorySession session, String repoId, String namespace )
211         throws MetadataResolutionException
212     {
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() )
220         {
221             if ( log.isDebugEnabled() )
222             {
223                 log.debug( "Resolved namespaces from storage: " + storageNamespaces );
224             }
225             for ( String n : storageNamespaces )
226             {
227                 try
228                 {
229                     metadataRepository.updateNamespace( repoId, namespace + "." + n );
230                 }
231                 catch ( MetadataRepositoryException e )
232                 {
233                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
234                 }
235             }
236             session.markDirty();
237
238             namespaces = new ArrayList<String>( namespaces );
239             namespaces.addAll( storageNamespaces );
240         }
241         return namespaces;
242     }
243
244     public Collection<String> resolveProjects( RepositorySession session, String repoId, String namespace )
245         throws MetadataResolutionException
246     {
247         MetadataRepository metadataRepository = session.getRepository();
248         Collection<String> projects = metadataRepository.getProjects( repoId, namespace );
249         Collection<String> exclusions = new ArrayList<String>( projects );
250         exclusions.addAll( metadataRepository.getNamespaces( repoId, namespace ) );
251         Collection<String> storageProjects =
252             repositoryStorage.listProjects( repoId, namespace, new ExcludesFilter<String>( exclusions ) );
253         if ( storageProjects != null && !storageProjects.isEmpty() )
254         {
255             if ( log.isDebugEnabled() )
256             {
257                 log.debug( "Resolved projects from storage: " + storageProjects );
258             }
259             for ( String projectId : storageProjects )
260             {
261                 ProjectMetadata projectMetadata = repositoryStorage.readProjectMetadata( repoId, namespace, projectId );
262                 if ( projectMetadata != null )
263                 {
264                     try
265                     {
266                         metadataRepository.updateProject( repoId, projectMetadata );
267                     }
268                     catch ( MetadataRepositoryException e )
269                     {
270                         log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
271                     }
272                 }
273             }
274             session.markDirty();
275
276             projects = new ArrayList<String>( projects );
277             projects.addAll( storageProjects );
278         }
279         return projects;
280     }
281
282     public Collection<String> resolveProjectVersions( RepositorySession session, String repoId, String namespace,
283                                                       String projectId )
284         throws MetadataResolutionException
285     {
286         MetadataRepository metadataRepository = session.getRepository();
287         Collection<String> projectVersions = metadataRepository.getProjectVersions( repoId, namespace, projectId );
288         Collection<String> storageProjectVersions = repositoryStorage.listProjectVersions( repoId, namespace, projectId,
289                                                                                            new ExcludesFilter<String>(
290                                                                                                projectVersions ) );
291         if ( storageProjectVersions != null && !storageProjectVersions.isEmpty() )
292         {
293             if ( log.isDebugEnabled() )
294             {
295                 log.debug( "Resolved project versions from storage: " + storageProjectVersions );
296             }
297             for ( String projectVersion : storageProjectVersions )
298             {
299                 try
300                 {
301                     ProjectVersionMetadata versionMetadata =
302                         repositoryStorage.readProjectVersionMetadata( repoId, namespace, projectId, projectVersion );
303                     for ( RepositoryListener listener : listeners )
304                     {
305                         listener.addArtifact( session, repoId, namespace, projectId, versionMetadata );
306                     }
307
308                     metadataRepository.updateProjectVersion( repoId, namespace, projectId, versionMetadata );
309                 }
310                 catch ( MetadataRepositoryException e )
311                 {
312                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
313                 }
314                 catch ( RepositoryStorageMetadataInvalidException e )
315                 {
316                     log.warn( "Not update project in metadata repository due to an error resolving it from storage: "
317                                   + e.getMessage() );
318
319                     for ( RepositoryListener listener : listeners )
320                     {
321                         listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
322                     }
323                 }
324                 catch ( RepositoryStorageMetadataNotFoundException e )
325                 {
326                     for ( RepositoryListener listener : listeners )
327                     {
328                         listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
329                     }
330                 }
331             }
332             session.markDirty();
333
334             projectVersions = new ArrayList<String>( projectVersions );
335             projectVersions.addAll( storageProjectVersions );
336         }
337         return projectVersions;
338     }
339
340     public Collection<ArtifactMetadata> resolveArtifacts( RepositorySession session, String repoId, String namespace,
341                                                           String projectId, String projectVersion )
342         throws MetadataResolutionException
343     {
344         MetadataRepository metadataRepository = session.getRepository();
345         Collection<ArtifactMetadata> artifacts =
346             metadataRepository.getArtifacts( repoId, namespace, projectId, projectVersion );
347         ExcludesFilter<String> filter = new ExcludesFilter<String>( createArtifactIdList( artifacts ) );
348         Collection<ArtifactMetadata> storageArtifacts =
349             repositoryStorage.readArtifactsMetadata( repoId, namespace, projectId, projectVersion, filter );
350         if ( storageArtifacts != null && !storageArtifacts.isEmpty() )
351         {
352             if ( log.isDebugEnabled() )
353             {
354                 log.debug( "Resolved artifacts from storage: " + storageArtifacts );
355             }
356             for ( ArtifactMetadata artifact : storageArtifacts )
357             {
358                 try
359                 {
360                     metadataRepository.updateArtifact( repoId, namespace, projectId, projectVersion, artifact );
361                 }
362                 catch ( MetadataRepositoryException e )
363                 {
364                     log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
365                 }
366             }
367             session.markDirty();
368
369             artifacts = new ArrayList<ArtifactMetadata>( artifacts );
370             artifacts.addAll( storageArtifacts );
371         }
372         return artifacts;
373     }
374
375     private Collection<String> createArtifactIdList( Collection<ArtifactMetadata> artifacts )
376     {
377         Collection<String> artifactIds = new ArrayList<String>();
378         for ( ArtifactMetadata artifact : artifacts )
379         {
380             artifactIds.add( artifact.getId() );
381         }
382         return artifactIds;
383     }
384 }