]> source.dussan.org Git - archiva.git/blob
144f8c44f43ffbd6e5acb2e0dfd6379031838f04
[archiva.git] /
1 package org.apache.maven.archiva.database.browsing;
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 java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26 import org.apache.commons.collections.CollectionUtils;
27 import org.apache.commons.collections.PredicateUtils;
28 import org.apache.commons.collections.functors.NotPredicate;
29 import org.apache.commons.lang.StringUtils;
30 import org.apache.maven.archiva.common.utils.VersionUtil;
31 import org.apache.maven.archiva.database.ArchivaDAO;
32 import org.apache.maven.archiva.database.ArchivaDatabaseException;
33 import org.apache.maven.archiva.database.Constraint;
34 import org.apache.maven.archiva.database.ObjectNotFoundException;
35 import org.apache.maven.archiva.database.constraints.ArtifactsRelatedConstraint;
36 import org.apache.maven.archiva.database.constraints.ProjectsByArtifactUsageConstraint;
37 import org.apache.maven.archiva.database.constraints.UniqueArtifactIdConstraint;
38 import org.apache.maven.archiva.database.constraints.UniqueGroupIdConstraint;
39 import org.apache.maven.archiva.database.constraints.UniqueVersionConstraint;
40 import org.apache.maven.archiva.database.updater.DatabaseUpdater;
41 import org.apache.maven.archiva.model.ArchivaArtifact;
42 import org.apache.maven.archiva.model.ArchivaProjectModel;
43 import org.apache.maven.archiva.model.Keys;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * DefaultRepositoryBrowsing
49  *
50  * @version $Id$
51  * @plexus.component role="org.apache.maven.archiva.database.browsing.RepositoryBrowsing"
52  */
53 public class DefaultRepositoryBrowsing
54     implements RepositoryBrowsing
55 {
56     private Logger log = LoggerFactory.getLogger( DefaultRepositoryBrowsing.class );
57
58     /**
59      * @plexus.requirement role-hint="jdo"
60      */
61     private ArchivaDAO dao;
62
63     /**
64      * @plexus.requirement role-hint="jdo"
65      */
66     private DatabaseUpdater dbUpdater;
67
68     /**
69      * @see RepositoryBrowsing#getRoot(String, List)
70      */
71     @SuppressWarnings("unchecked")
72     public BrowsingResults getRoot( final String principal, final List<String> observableRepositoryIds )
73     {
74         final BrowsingResults results = new BrowsingResults();
75
76         if ( !observableRepositoryIds.isEmpty() )
77         {
78             final List<String> groups = (List<String>) dao.query( new UniqueGroupIdConstraint( observableRepositoryIds ) );
79             results.setSelectedRepositoryIds( observableRepositoryIds );
80             results.setGroupIds( GroupIdFilter.filterGroups( groups ) );
81         }
82         return results;
83     }
84
85     /**
86      * @see RepositoryBrowsing#selectArtifactId(String, List, String, String)
87      */
88     @SuppressWarnings("unchecked")
89     public BrowsingResults selectArtifactId( final String principal, final List<String> observableRepositoryIds,
90                                              final String groupId, final String artifactId )
91     {
92         final BrowsingResults results = new BrowsingResults( groupId, artifactId );
93
94         if ( !observableRepositoryIds.isEmpty() )
95         {
96             // NOTE: No group Id or artifact Id's should be returned here.
97             List<String> versions =
98                 (List<String>) dao.query( new UniqueVersionConstraint( observableRepositoryIds, groupId, artifactId ) );
99             results.setSelectedRepositoryIds( observableRepositoryIds );
100
101             results.setVersions( processSnapshots( versions ) );
102         }
103         return results;
104     }
105
106     /**
107      * @see RepositoryBrowsing#selectGroupId(String, List, String)
108      */
109     @SuppressWarnings("unchecked")
110     public BrowsingResults selectGroupId( final String principal, final List<String> observableRepositoryIds,
111                                           final String groupId )
112     {
113         final BrowsingResults results = new BrowsingResults( groupId );
114
115         if ( !observableRepositoryIds.isEmpty() )
116         {
117             final List<String> groups = (List<String>) dao.query( new UniqueGroupIdConstraint( observableRepositoryIds, groupId ) );
118             final List<String> artifacts =
119                 (List<String>) dao.query( new UniqueArtifactIdConstraint( observableRepositoryIds, groupId ) );
120
121             // Remove searched for groupId from groups list.
122             // Easier to do this here, vs doing it in the SQL query.
123             CollectionUtils.filter( groups, NotPredicate.getInstance( PredicateUtils.equalPredicate( groupId ) ) );
124
125             results.setSelectedRepositoryIds( observableRepositoryIds );
126             results.setGroupIds( groups );
127             results.setArtifacts( artifacts );
128         }
129
130         return results;
131     }
132
133     /**
134      * @see RepositoryBrowsing#selectVersion(String, List, String, String, String)
135      */
136     public ArchivaProjectModel selectVersion( final String principal, final List<String> observableRepositoryIds,
137                                               final String groupId, final String artifactId, final String version )
138         throws ObjectNotFoundException, ArchivaDatabaseException
139     {
140         if ( observableRepositoryIds.isEmpty() )
141         {
142             throw new ArchivaDatabaseException( "There are no observable repositories for the user " + principal );
143         }
144
145         ArchivaArtifact pomArtifact = getArtifact( principal, observableRepositoryIds, groupId, artifactId, version );
146         ArchivaProjectModel model;
147
148         if ( !pomArtifact.getModel().isProcessed() )
149         {
150             // Process it.
151             dbUpdater.updateUnprocessed( pomArtifact );
152         }
153
154         model = getProjectModel( groupId, artifactId, pomArtifact.getVersion() );
155
156         if ( model.getPackaging() == null || "".equals( model.getPackaging() ) )
157         {
158             model.setPackaging( pomArtifact.getType() );
159         }
160
161         return model;
162     }
163
164     public String getRepositoryId( final String principal, final List<String> observableRepositoryIds,
165                                    final String groupId, final String artifactId, final String version )
166         throws ObjectNotFoundException, ArchivaDatabaseException
167     {
168         if ( observableRepositoryIds.isEmpty() )
169         {
170             throw new ArchivaDatabaseException( "There are no observable repositories for the user " + principal );
171         }
172
173         try
174         {
175             ArchivaArtifact pomArchivaArtifact =
176                 getArtifact( principal, observableRepositoryIds, groupId, artifactId, version );
177
178             return pomArchivaArtifact.getModel().getRepositoryId();
179         }
180         catch ( ObjectNotFoundException e )
181         {
182             return getNoPomArtifactRepoId( principal, observableRepositoryIds, groupId, artifactId, version,
183                                            observableRepositoryIds.get( 0 ) );
184         }
185     }
186
187     /**
188      * @see RepositoryBrowsing#getOtherSnapshotVersions(List, String, String, String)
189      */
190     @SuppressWarnings("unchecked")
191     public List<String> getOtherSnapshotVersions( List<String> observableRepositoryIds, String groupId,
192                                                  String artifactId, String version )
193         throws ObjectNotFoundException, ArchivaDatabaseException
194     {
195         List<String> timestampedVersions = new ArrayList<String>();
196
197         if ( VersionUtil.isSnapshot( version ) )
198         {
199             List<String> versions =
200                 (List<String>) dao.query( new UniqueVersionConstraint( observableRepositoryIds, groupId, artifactId ) );
201
202             for ( String uniqueVersion : versions )
203             {   
204                 if ( VersionUtil.getBaseVersion( uniqueVersion ).equals( version ) || 
205                         VersionUtil.getBaseVersion( uniqueVersion ).equals( VersionUtil.getBaseVersion( version ) ) )
206                 {
207                     if ( !timestampedVersions.contains( uniqueVersion ) )
208                     {
209                         timestampedVersions.add( uniqueVersion );
210                     }
211                 }      
212             }
213         }
214
215         return timestampedVersions;
216     }
217
218     private ArchivaArtifact getArtifact( final String principal, final List<String> observableRepositoryIds,
219                                          final String groupId, final String artifactId, final String version )
220         throws ObjectNotFoundException, ArchivaDatabaseException
221     {
222         ArchivaArtifact pomArtifact = null;
223         Constraint constraint = new ArtifactsRelatedConstraint( groupId, artifactId, version );
224
225         try
226         {
227             List<ArchivaArtifact> artifacts = dao.getArtifactDAO().queryArtifacts( constraint );
228
229             // it's possible that similar artifacts reside in different repos
230             if ( !artifacts.isEmpty() )
231             {
232                 for ( ArchivaArtifact artifact : artifacts )
233                 {
234                     if ( observableRepositoryIds.contains( artifact.getRepositoryId() ) )
235                     {
236                         pomArtifact = artifact;
237                         break;
238                     }
239                 }
240             }
241         }
242         catch ( ArchivaDatabaseException e )
243         {
244             log.warn( "ArchivaDatabaseException occurred while querying for artifact '" + groupId + ":" + artifactId +
245                 ":" + version + "'." );
246         }
247
248         if ( pomArtifact == null )
249         {
250             for ( final String repositoryId : observableRepositoryIds )
251             {
252                 pomArtifact = handleGenericSnapshots( groupId, artifactId, version, repositoryId );
253
254                 if ( pomArtifact != null )
255                 {
256                     break;
257                 }
258             }
259         }
260
261         // throw exception if pom artifact is still null!
262         if ( pomArtifact == null )
263         {
264             throw new ObjectNotFoundException( "Unable to find artifact " + Keys.toKey( groupId, artifactId, version ) +
265                 " in observable repository [" + StringUtils.join( observableRepositoryIds.iterator(), ", " ) +
266                 "] for user " + principal );
267         }
268
269         return pomArtifact;
270     }
271
272     public List<ArchivaProjectModel> getUsedBy( final String principal, final List<String> observableRepositoryIds,
273                                                 final String groupId, final String artifactId, final String version )
274         throws ArchivaDatabaseException
275     {
276         ProjectsByArtifactUsageConstraint constraint =
277             new ProjectsByArtifactUsageConstraint( groupId, artifactId, version );
278         List<ArchivaProjectModel> results = dao.getProjectModelDAO().queryProjectModels( constraint );
279         if ( results == null )
280         {
281             // defensive. to honor contract as specified. never null.
282             return Collections.emptyList();
283         }
284
285         return results;
286     }
287
288     /**
289      * Removes SNAPSHOT versions with build numbers. Retains only the generic SNAPSHOT version. 
290      * Example, if the list of versions are: 
291      * - 2.0 
292      * - 2.0.1 
293      * - 2.1-20070522.143249-1 
294      * - 2.1-20070522.157829-2 
295      * 
296      * the returned version list would contain 2.0, 2.0.1 and 2.1-SNAPSHOT.
297      * 
298      * @param versions
299      */
300     private List<String> processSnapshots( List<String> versions )
301     {
302         List<String> cleansedVersions = new ArrayList<String>();
303
304         for ( String version : versions )
305         {
306             if ( VersionUtil.isSnapshot( version ) )
307             {   
308                 String baseVersion = VersionUtil.getBaseVersion( version );
309                 if ( !cleansedVersions.contains( baseVersion ) )
310                 {
311                     cleansedVersions.add( baseVersion );
312                 }
313             }
314             else
315             {
316                 cleansedVersions.add( version );
317             }
318         }
319
320         return cleansedVersions;
321     }
322
323     /**
324      * Handles querying of generic (*-SNAPSHOT) snapshot version. Process: - Get all the timestamped/unique versions of
325      * the artifact from the db - Sort the queried project models - Reverse the list of queried project models to get
326      * the latest timestamp version - Loop through the list and get the first one to match the generic (*-SNAPHOT)
327      * version
328      * 
329      * @param groupId
330      * @param artifactId
331      * @param version
332      * @param pomArtifact
333      * @throws ArchivaDatabaseException
334      */
335     @SuppressWarnings("unchecked")
336     private ArchivaArtifact handleGenericSnapshots( final String groupId, final String artifactId,
337                                                     final String version, final String repositoryId )
338         throws ArchivaDatabaseException
339     {
340         ArchivaArtifact result = null;
341
342         if ( VersionUtil.isGenericSnapshot( version ) )
343         {
344             final List<String> versions = (List<String>) dao.query( new UniqueVersionConstraint( groupId, artifactId ) );
345             Collections.sort( versions );
346             Collections.reverse( versions );
347
348             for ( String uniqueVersion : versions )
349             {
350                 if ( VersionUtil.getBaseVersion( uniqueVersion ).equals( version ) )
351                 {
352                     try
353                     {
354                         log.debug( "Retrieving artifact with version " + uniqueVersion );
355                         Constraint constraint = new ArtifactsRelatedConstraint( groupId, artifactId, uniqueVersion );
356                         List<ArchivaArtifact> artifacts = dao.getArtifactDAO().queryArtifacts( constraint );
357
358                         for ( ArchivaArtifact artifact : artifacts )
359                         {
360                             if ( artifact.getRepositoryId().equals( repositoryId ) )
361                             {
362                                 result = artifact;
363                                 break;
364                             }
365                         }
366                     }
367                     catch ( ObjectNotFoundException e )
368                     {
369                         log.debug( "Artifact '" + groupId + ":" + artifactId + ":" + uniqueVersion +
370                             "' in repository '" + repositoryId + "' not found in the database." );
371                         continue;
372                     }
373                 }
374             }
375         }
376         return result;
377     }
378
379     /**
380      * Get the project model from the database.
381      * 
382      * @param groupId
383      * @param artifactId
384      * @param version
385      * @return
386      * @throws ArchivaDatabaseException
387      */
388     private ArchivaProjectModel getProjectModel( String groupId, String artifactId, String version )
389         throws ArchivaDatabaseException
390     {
391         ArchivaProjectModel model = null;
392
393         try
394         {
395             model = dao.getProjectModelDAO().getProjectModel( groupId, artifactId, version );
396         }
397         catch ( ObjectNotFoundException e )
398         {
399             log.debug( "Unable to find project model for [" + Keys.toKey( groupId, artifactId, version ) + "]", e );
400         }
401
402         if ( model == null )
403         {
404             model = new ArchivaProjectModel();
405             model.setGroupId( groupId );
406             model.setArtifactId( artifactId );
407             model.setVersion( version );
408         }
409
410         return model;
411     }
412
413     private String getNoPomArtifactRepoId( String principal, List<String> observableRepos, String groupId,
414                                            String artifactId, String version, String repositoryId )
415         throws ObjectNotFoundException, ArchivaDatabaseException
416     {
417         ArchivaArtifact artifact = null;
418
419         String type = getArtifactType( groupId, artifactId, version );
420
421         artifact = dao.getArtifactDAO().createArtifact( groupId, artifactId, version, null, type, repositoryId );
422
423         if ( artifact == null )
424         {
425             // Lets not persist these
426             artifact = new ArchivaArtifact( groupId, artifactId, version, null, type, repositoryId );
427         }
428
429         // Allowed to see this?
430         if ( !observableRepos.contains( artifact.getModel().getRepositoryId() ) )
431         {
432             throw new ObjectNotFoundException( "Unable to find artifact " + Keys.toKey( groupId, artifactId, version ) +
433                 " in observable repository [" + StringUtils.join( observableRepos.iterator(), ", " ) + "] for user " +
434                 principal );
435         }
436
437         return artifact.getModel().getRepositoryId();
438     }
439
440     private String getArtifactType( String groupId, String artifactId, String version )
441         throws ObjectNotFoundException, ArchivaDatabaseException
442     {
443         String type = "jar";
444
445         try
446         {
447             List<ArchivaArtifact> artifacts =
448                 dao.getArtifactDAO().queryArtifacts( new ArtifactsRelatedConstraint( groupId, artifactId, version ) );
449
450             if ( artifacts.size() > 0 )
451             {
452                 type = artifacts.get( 0 ).getType();
453             }
454         }
455         catch ( ObjectNotFoundException e )
456         {
457             // swallow exception?
458         }
459
460         return type;
461     }
462
463 }