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