]> source.dussan.org Git - archiva.git/blob
ad7e9cbb53d75c101a6921fde706be9951c3d4eb
[archiva.git] /
1 package org.apache.maven.repository.manager.web.action;
2
3 /*
4  * Copyright 2005-2006 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 import com.opensymphony.xwork.ActionSupport;
20 import org.apache.lucene.index.Term;
21 import org.apache.lucene.search.BooleanClause;
22 import org.apache.lucene.search.BooleanQuery;
23 import org.apache.lucene.search.MatchAllDocsQuery;
24 import org.apache.lucene.search.TermQuery;
25 import org.apache.maven.repository.configuration.Configuration;
26 import org.apache.maven.repository.configuration.ConfigurationStore;
27 import org.apache.maven.repository.configuration.ConfigurationStoreException;
28 import org.apache.maven.repository.configuration.ConfiguredRepositoryFactory;
29 import org.apache.maven.repository.indexing.RepositoryArtifactIndex;
30 import org.apache.maven.repository.indexing.RepositoryArtifactIndexFactory;
31 import org.apache.maven.repository.indexing.RepositoryIndexException;
32 import org.apache.maven.repository.indexing.RepositoryIndexSearchException;
33 import org.apache.maven.repository.indexing.lucene.LuceneQuery;
34 import org.apache.maven.repository.indexing.record.StandardArtifactIndexRecord;
35 import org.apache.maven.repository.indexing.record.StandardIndexRecordFields;
36 import org.codehaus.plexus.util.StringUtils;
37
38 import java.io.File;
39 import java.io.IOException;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.HashSet;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Set;
47 import java.util.StringTokenizer;
48 import java.util.TreeMap;
49 import java.util.TreeSet;
50
51 /**
52  * Browse the repository.
53  *
54  * @todo the tree part probably belongs in a browsing component, and the indexer could optimize how it retrieves the terms rather than querying everything
55  * @plexus.component role="com.opensymphony.xwork.Action" role-hint="browseAction"
56  */
57 public class BrowseAction
58     extends ActionSupport
59 {
60     /**
61      * @plexus.requirement
62      */
63     private RepositoryArtifactIndexFactory factory;
64
65     /**
66      * @plexus.requirement
67      */
68     private ConfiguredRepositoryFactory repositoryFactory;
69
70     /**
71      * @plexus.requirement
72      */
73     private ConfigurationStore configurationStore;
74
75     private List groups;
76
77     private String groupId;
78
79     private static final String GROUP_SEPARATOR = ".";
80
81     private List artifactIds;
82
83     private String artifactId;
84
85     private List versions;
86
87     public String browse()
88         throws ConfigurationStoreException, RepositoryIndexException, IOException, RepositoryIndexSearchException
89     {
90         RepositoryArtifactIndex index = getIndex();
91
92         if ( !index.exists() )
93         {
94             addActionError( "The repository is not yet indexed. Please wait, and then try again." );
95             return ERROR;
96         }
97
98         GroupTreeNode rootNode = buildGroupTree( index );
99
100         this.groups = collateGroups( rootNode );
101
102         return SUCCESS;
103     }
104
105     public String browseGroup()
106         throws ConfigurationStoreException, RepositoryIndexException, IOException, RepositoryIndexSearchException
107     {
108         RepositoryArtifactIndex index = getIndex();
109
110         if ( !index.exists() )
111         {
112             addActionError( "The repository is not yet indexed. Please wait, and then try again." );
113             return ERROR;
114         }
115
116         GroupTreeNode rootNode = buildGroupTree( index );
117
118         if ( StringUtils.isEmpty( groupId ) )
119         {
120             // TODO: i18n
121             addActionError( "You must specify a group ID to browse" );
122             return ERROR;
123         }
124
125         StringTokenizer tok = new StringTokenizer( groupId, GROUP_SEPARATOR );
126         while ( tok.hasMoreTokens() )
127         {
128             String part = tok.nextToken();
129
130             if ( !rootNode.getChildren().containsKey( part ) )
131             {
132                 // TODO: i18n
133                 addActionError( "The group specified was not found" );
134                 return ERROR;
135             }
136             else
137             {
138                 rootNode = (GroupTreeNode) rootNode.getChildren().get( part );
139             }
140         }
141
142         this.groups = collateGroups( rootNode );
143
144         List records = index.search(
145             new LuceneQuery( new TermQuery( new Term( StandardIndexRecordFields.GROUPID_EXACT, groupId ) ) ) );
146
147         Set artifactIds = new HashSet();
148         for ( Iterator i = records.iterator(); i.hasNext(); )
149         {
150             StandardArtifactIndexRecord record = (StandardArtifactIndexRecord) i.next();
151             artifactIds.add( record.getArtifactId() );
152         }
153         this.artifactIds = new ArrayList( artifactIds );
154         Collections.sort( this.artifactIds );
155
156         return SUCCESS;
157     }
158
159     public String browseArtifact()
160         throws ConfigurationStoreException, RepositoryIndexException, IOException, RepositoryIndexSearchException
161     {
162         RepositoryArtifactIndex index = getIndex();
163
164         if ( StringUtils.isEmpty( groupId ) )
165         {
166             // TODO: i18n
167             addActionError( "You must specify a group ID to browse" );
168             return ERROR;
169         }
170
171         if ( StringUtils.isEmpty( artifactId ) )
172         {
173             // TODO: i18n
174             addActionError( "You must specify a artifact ID to browse" );
175             return ERROR;
176         }
177
178         BooleanQuery query = new BooleanQuery();
179         query.add( new TermQuery( new Term( StandardIndexRecordFields.GROUPID_EXACT, groupId ) ),
180                    BooleanClause.Occur.MUST );
181         query.add( new TermQuery( new Term( StandardIndexRecordFields.ARTIFACTID_EXACT, artifactId ) ),
182                    BooleanClause.Occur.MUST );
183
184         List records = index.search( new LuceneQuery( query ) );
185
186         if ( records.isEmpty() )
187         {
188             // TODO: i18n
189             addActionError( "Could not find any artifacts with the given group and artifact ID" );
190             return ERROR;
191         }
192
193         Set versions = new HashSet();
194         for ( Iterator i = records.iterator(); i.hasNext(); )
195         {
196             StandardArtifactIndexRecord record = (StandardArtifactIndexRecord) i.next();
197             versions.add( record.getVersion() );
198         }
199
200         this.versions = new ArrayList( versions );
201         Collections.sort( this.versions );
202
203         return SUCCESS;
204     }
205
206     private GroupTreeNode buildGroupTree( RepositoryArtifactIndex index )
207         throws IOException, RepositoryIndexSearchException
208     {
209         // TODO: give action message if indexing is in progress
210
211         // TODO: this will be inefficient over a very large number of artifacts, should be cached
212
213         List records = index.search( new LuceneQuery( new MatchAllDocsQuery() ) );
214
215         Set groups = new TreeSet();
216         for ( Iterator i = records.iterator(); i.hasNext(); )
217         {
218             StandardArtifactIndexRecord record = (StandardArtifactIndexRecord) i.next();
219             groups.add( record.getGroupId() );
220         }
221
222         GroupTreeNode rootNode = new GroupTreeNode();
223
224         // build a tree structure
225         for ( Iterator i = groups.iterator(); i.hasNext(); )
226         {
227             String groupId = (String) i.next();
228
229             StringTokenizer tok = new StringTokenizer( groupId, GROUP_SEPARATOR );
230
231             GroupTreeNode node = rootNode;
232
233             while ( tok.hasMoreTokens() )
234             {
235                 String part = tok.nextToken();
236
237                 if ( !node.getChildren().containsKey( part ) )
238                 {
239                     GroupTreeNode newNode = new GroupTreeNode( part, node );
240                     node.addChild( newNode );
241                     node = newNode;
242                 }
243                 else
244                 {
245                     node = (GroupTreeNode) node.getChildren().get( part );
246                 }
247             }
248         }
249         return rootNode;
250     }
251
252     private List collateGroups( GroupTreeNode rootNode )
253     {
254         List groups = new ArrayList();
255         for ( Iterator i = rootNode.getChildren().values().iterator(); i.hasNext(); )
256         {
257             GroupTreeNode node = (GroupTreeNode) i.next();
258
259             while ( node.getChildren().size() == 1 )
260             {
261                 node = (GroupTreeNode) node.getChildren().values().iterator().next();
262             }
263
264             groups.add( node.getFullName() );
265         }
266         return groups;
267     }
268
269     private RepositoryArtifactIndex getIndex()
270         throws ConfigurationStoreException, RepositoryIndexException
271     {
272         Configuration configuration = configurationStore.getConfigurationFromStore();
273         File indexPath = new File( configuration.getIndexPath() );
274
275         return factory.createStandardIndex( indexPath );
276     }
277
278     public List getGroups()
279     {
280         return groups;
281     }
282
283     public List getArtifactIds()
284     {
285         return artifactIds;
286     }
287
288     public String getGroupId()
289     {
290         return groupId;
291     }
292
293     public void setGroupId( String groupId )
294     {
295         this.groupId = groupId;
296     }
297
298     public String getArtifactId()
299     {
300         return artifactId;
301     }
302
303     public void setArtifactId( String artifactId )
304     {
305         this.artifactId = artifactId;
306     }
307
308     public List getVersions()
309     {
310         return versions;
311     }
312
313     private static class GroupTreeNode
314     {
315         private final String name;
316
317         private final String fullName;
318
319         private final Map children = new TreeMap();
320
321         GroupTreeNode()
322         {
323             name = null;
324             fullName = null;
325         }
326
327         GroupTreeNode( String name, GroupTreeNode parent )
328         {
329             this.name = name;
330             this.fullName = parent.fullName != null ? parent.fullName + GROUP_SEPARATOR + name : name;
331         }
332
333         public String getName()
334         {
335             return name;
336         }
337
338         public String getFullName()
339         {
340             return fullName;
341         }
342
343         public Map getChildren()
344         {
345             return children;
346         }
347
348         public void addChild( GroupTreeNode newNode )
349         {
350             children.put( newNode.name, newNode );
351         }
352     }
353 }