]> source.dussan.org Git - archiva.git/blob
bb9cc49cb46424645d47b39388a7b7e2a487bd6d
[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.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;
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 ( RepositoryStorageMetadataNotFoundException e )
139             {
140                 for ( RepositoryListener listener : listeners )
141                 {
142                     listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
143                 }
144                 // no need to rethrow - return null
145             }
146             catch ( RepositoryStorageRuntimeException 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
155         }
156         return metadata;
157     }
158
159     public Collection<ProjectVersionReference> resolveProjectReferences( RepositorySession session, String repoId,
160                                                                          String namespace, String projectId,
161                                                                          String projectVersion )
162         throws MetadataResolutionException
163     {
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 );
168     }
169
170     public Collection<String> resolveRootNamespaces( RepositorySession session, String repoId )
171         throws MetadataResolutionException
172     {
173         try
174         {
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() )
180             {
181
182                 log.debug( "Resolved root namespaces from storage: {}", storageNamespaces );
183
184                 for ( String n : storageNamespaces )
185                 {
186                     try
187                     {
188                         metadataRepository.updateNamespace( repoId, n );
189                     }
190                     catch ( MetadataRepositoryException e )
191                     {
192                         log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
193                     }
194                 }
195                 session.markDirty();
196
197                 namespaces = new ArrayList<String>( namespaces );
198                 namespaces.addAll( storageNamespaces );
199             }
200             return namespaces;
201         }
202         catch ( RepositoryStorageRuntimeException e )
203         {
204             throw new MetadataResolutionException( e.getMessage(), e );
205         }
206     }
207
208     public Collection<String> resolveNamespaces( RepositorySession session, String repoId, String namespace )
209         throws MetadataResolutionException
210     {
211         try
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
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         catch ( RepositoryStorageRuntimeException e )
243         {
244             throw new MetadataResolutionException( e.getMessage(), e );
245         }
246     }
247
248     public Collection<String> resolveProjects( RepositorySession session, String repoId, String namespace )
249         throws MetadataResolutionException
250     {
251         try
252         {
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() )
260             {
261
262                 log.debug( "Resolved projects from storage: {}", storageProjects );
263                 for ( String projectId : storageProjects )
264                 {
265                     ProjectMetadata projectMetadata =
266                         repositoryStorage.readProjectMetadata( repoId, namespace, projectId );
267                     if ( projectMetadata != null )
268                     {
269                         try
270                         {
271                             metadataRepository.updateProject( repoId, projectMetadata );
272                         }
273                         catch ( MetadataRepositoryException e )
274                         {
275                             log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
276                         }
277                     }
278                 }
279                 session.markDirty();
280
281                 projects = new ArrayList<String>( projects );
282                 projects.addAll( storageProjects );
283             }
284             return projects;
285         }
286         catch ( RepositoryStorageRuntimeException e )
287         {
288             throw new MetadataResolutionException( e.getMessage(), e );
289         }
290     }
291
292     public Collection<String> resolveProjectVersions( RepositorySession session, String repoId, String namespace,
293                                                       String projectId )
294         throws MetadataResolutionException
295     {
296         try
297         {
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() )
304             {
305                 log.debug( "Resolved project versions from storage: {}", storageProjectVersions );
306
307                 for ( String projectVersion : storageProjectVersions )
308                 {
309                     try
310                     {
311                         ProjectVersionMetadata versionMetadata =
312                             repositoryStorage.readProjectVersionMetadata( repoId, namespace, projectId,
313                                                                           projectVersion );
314                         for ( RepositoryListener listener : listeners )
315                         {
316                             listener.addArtifact( session, repoId, namespace, projectId, versionMetadata );
317                         }
318
319                         metadataRepository.updateProjectVersion( repoId, namespace, projectId, versionMetadata );
320                     }
321                     catch ( MetadataRepositoryException e )
322                     {
323                         log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
324                     }
325                     catch ( RepositoryStorageMetadataInvalidException e )
326                     {
327                         log.warn(
328                             "Not update project in metadata repository due to an error resolving it from storage: "
329                                 + e.getMessage() );
330
331                         for ( RepositoryListener listener : listeners )
332                         {
333                             listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
334                         }
335                     }
336                     catch ( RepositoryStorageMetadataNotFoundException e )
337                     {
338                         for ( RepositoryListener listener : listeners )
339                         {
340                             listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
341                         }
342                     }
343                 }
344                 session.markDirty();
345
346                 projectVersions = new ArrayList<String>( projectVersions );
347                 projectVersions.addAll( storageProjectVersions );
348             }
349             return projectVersions;
350         }
351         catch ( RepositoryStorageRuntimeException e )
352         {
353             throw new MetadataResolutionException( e.getMessage(), e );
354         }
355     }
356
357     public Collection<ArtifactMetadata> resolveArtifacts( RepositorySession session, String repoId, String namespace,
358                                                           String projectId, String projectVersion )
359         throws MetadataResolutionException
360     {
361         try
362         {
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() )
370             {
371
372                 log.debug( "Resolved artifacts from storage: {}", storageArtifacts );
373
374                 for ( ArtifactMetadata artifact : storageArtifacts )
375                 {
376                     try
377                     {
378                         metadataRepository.updateArtifact( repoId, namespace, projectId, projectVersion, artifact );
379                     }
380                     catch ( MetadataRepositoryException e )
381                     {
382                         log.warn( "Unable to persist resolved information: " + e.getMessage(), e );
383                     }
384                 }
385                 session.markDirty();
386
387                 artifacts = new ArrayList<ArtifactMetadata>( artifacts );
388                 artifacts.addAll( storageArtifacts );
389             }
390             return artifacts;
391         }
392         catch ( RepositoryStorageRuntimeException e )
393         {
394             for ( RepositoryListener listener : listeners )
395             {
396                 listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
397             }
398             throw new MetadataResolutionException( e.getMessage(), e );
399         }
400     }
401
402     private Collection<String> createArtifactIdList( Collection<ArtifactMetadata> artifacts )
403     {
404         Collection<String> artifactIds = new ArrayList<String>();
405         for ( ArtifactMetadata artifact : artifacts )
406         {
407             artifactIds.add( artifact.getId() );
408         }
409         return artifactIds;
410     }
411 }