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