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