]> source.dussan.org Git - archiva.git/blob
4ca2ca4a65de2cef07dc8b9fcfe06c1f35d26a82
[archiva.git] /
1 package org.apache.maven.repository.indexing;\r
2 \r
3 /*\r
4  * Copyright 2005-2006 The Apache Software Foundation.\r
5  *\r
6  * Licensed under the Apache License, Version 2.0 (the "License");\r
7  * you may not use this file except in compliance with the License.\r
8  * You may obtain a copy of the License at\r
9  *\r
10  *      http://www.apache.org/licenses/LICENSE-2.0\r
11  *\r
12  * Unless required by applicable law or agreed to in writing, software\r
13  * distributed under the License is distributed on an "AS IS" BASIS,\r
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
15  * See the License for the specific language governing permissions and\r
16  * limitations under the License.\r
17  */\r
18 \r
19 import org.apache.lucene.document.Document;\r
20 import org.apache.lucene.index.Term;\r
21 import org.apache.lucene.queryParser.ParseException;\r
22 import org.apache.lucene.queryParser.QueryParser;\r
23 import org.apache.lucene.search.BooleanQuery;\r
24 import org.apache.lucene.search.Hits;\r
25 import org.apache.lucene.search.IndexSearcher;\r
26 import org.apache.lucene.search.TermQuery;\r
27 import org.apache.maven.repository.indexing.query.CompoundQuery;\r
28 import org.apache.maven.repository.indexing.query.CompoundQueryTerm;\r
29 import org.apache.maven.repository.indexing.query.Query;\r
30 import org.apache.maven.repository.indexing.query.RangeQuery;\r
31 import org.apache.maven.repository.indexing.query.SinglePhraseQuery;\r
32 import org.apache.maven.artifact.Artifact;\r
33 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;\r
34 import org.apache.maven.artifact.repository.metadata.GroupRepositoryMetadata;\r
35 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;\r
36 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;\r
37 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;\r
38 import org.apache.maven.artifact.factory.ArtifactFactory;\r
39 import org.codehaus.plexus.logging.AbstractLogEnabled;\r
40 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;\r
41 \r
42 import java.io.IOException;\r
43 import java.io.File;\r
44 import java.io.InputStream;\r
45 import java.io.InputStreamReader;\r
46 import java.util.ArrayList;\r
47 import java.util.Iterator;\r
48 import java.util.List;\r
49 import java.util.StringTokenizer;\r
50 import java.util.Collections;\r
51 import java.net.MalformedURLException;\r
52 import java.net.URL;\r
53 \r
54 /**\r
55  * Abstract Class to hold common codes for the different RepositoryIndexSearcher\r
56  */\r
57 public class DefaultRepositoryIndexSearcher\r
58     extends AbstractLogEnabled\r
59     implements RepositoryIndexSearcher\r
60 {\r
61     protected RepositoryIndex index;\r
62 \r
63     private ArtifactFactory factory;\r
64 \r
65     /**\r
66      * Constructor\r
67      *\r
68      * @param index the index object\r
69      */\r
70     protected DefaultRepositoryIndexSearcher( RepositoryIndex index, ArtifactFactory factory )\r
71     {\r
72         this.index = index;\r
73         this.factory = factory;\r
74     }\r
75 \r
76     /**\r
77      * @see RepositoryIndexSearcher#search(org.apache.maven.repository.indexing.query.Query)\r
78      */\r
79     public List search( Query query )\r
80         throws RepositoryIndexSearchException\r
81     {\r
82 \r
83         org.apache.lucene.search.Query luceneQuery;\r
84         try\r
85         {\r
86             luceneQuery = createLuceneQuery( query );\r
87         }\r
88         catch ( ParseException e )\r
89         {\r
90             throw new RepositoryIndexSearchException( "Unable to construct query: " + e.getMessage(), e );\r
91         }\r
92 \r
93         IndexSearcher searcher;\r
94         try\r
95         {\r
96             searcher = new IndexSearcher( index.getIndexPath() );\r
97         }\r
98         catch ( IOException e )\r
99         {\r
100             throw new RepositoryIndexSearchException( "Unable to open index: " + e.getMessage(), e );\r
101         }\r
102 \r
103         List docs;\r
104         try\r
105         {\r
106             Hits hits = searcher.search( luceneQuery );\r
107             docs = buildList( hits );\r
108         }\r
109         catch ( IOException e )\r
110         {\r
111             throw new RepositoryIndexSearchException( "Unable to search index: " + e.getMessage(), e );\r
112         }\r
113         catch ( XmlPullParserException xe )\r
114         {\r
115             throw new RepositoryIndexSearchException( "Unable to parse metadata file: " + xe.getMessage(), xe );\r
116         }\r
117 \r
118         finally\r
119         {\r
120             try\r
121             {\r
122                 searcher.close();\r
123             }\r
124             catch ( IOException e )\r
125             {\r
126                 getLogger().error( "Unable to close index searcher", e );\r
127             }\r
128         }\r
129 \r
130         return docs;\r
131     }\r
132 \r
133     /**\r
134      * Method to create a lucene Query object from a single query phrase\r
135      *\r
136      * @param field the index field name to search into\r
137      * @param value the index field value to match the field with\r
138      * @return a lucene Query object representing the query phrase field = value\r
139      * @throws ParseException\r
140      */\r
141     private org.apache.lucene.search.Query createLuceneQuery( String field, String value )\r
142         throws ParseException\r
143     {\r
144         org.apache.lucene.search.Query qry;\r
145         if ( index.isKeywordField( field ) )\r
146         {\r
147             Term term = new Term( field, value );\r
148             qry = new TermQuery( term );\r
149         }\r
150         else\r
151         {\r
152             QueryParser parser = new QueryParser( field, index.getAnalyzer() );\r
153             qry = parser.parse( value );\r
154         }\r
155         return qry;\r
156     }\r
157 \r
158     /**\r
159      * Method to create a lucene Query object by converting a prepared Query object\r
160      *\r
161      * @param query the prepared Query object to be converted into a lucene Query object\r
162      * @return a lucene Query object to represent the passed Query object\r
163      * @throws ParseException\r
164      */\r
165     private org.apache.lucene.search.Query createLuceneQuery( Query query )\r
166         throws ParseException\r
167     {\r
168         org.apache.lucene.search.Query retVal;\r
169 \r
170         if ( query instanceof CompoundQuery )\r
171         {\r
172             BooleanQuery booleanQuery = new BooleanQuery();\r
173             CompoundQuery compoundQuery = (CompoundQuery) query;\r
174             List queries = compoundQuery.getQueries();\r
175             for ( Iterator i = queries.iterator(); i.hasNext(); )\r
176             {\r
177                 CompoundQueryTerm subquery = (CompoundQueryTerm) i.next();\r
178 \r
179                 org.apache.lucene.search.Query luceneQuery = createLuceneQuery( subquery.getQuery() );\r
180 \r
181                 booleanQuery.add( luceneQuery, subquery.isRequired(), subquery.isProhibited() );\r
182             }\r
183             retVal = booleanQuery;\r
184         }\r
185         else if ( query instanceof RangeQuery )\r
186         {\r
187             RangeQuery rq = (RangeQuery) query;\r
188             List queries = rq.getQueries();\r
189             Iterator iter = queries.iterator();\r
190             Term begin = null, end = null;\r
191             if ( queries.size() == 2 )\r
192             {\r
193                 SinglePhraseQuery qry = (SinglePhraseQuery) iter.next();\r
194                 begin = new Term( qry.getField(), qry.getValue() );\r
195                 qry = (SinglePhraseQuery) iter.next();\r
196                 end = new Term( qry.getField(), qry.getValue() );\r
197             }\r
198             retVal = new org.apache.lucene.search.RangeQuery( begin, end, rq.isInclusive() );\r
199         }\r
200         else\r
201         {\r
202             SinglePhraseQuery singlePhraseQuery = (SinglePhraseQuery) query;\r
203             retVal = createLuceneQuery( singlePhraseQuery.getField(), singlePhraseQuery.getValue() );\r
204         }\r
205         return retVal;\r
206     }\r
207 \r
208     /**\r
209      * Create a list of artifact objects from the result set.\r
210      *\r
211      * @param hits the search result set\r
212      * @return List\r
213      * @throws IOException\r
214      */\r
215     private List buildList( Hits hits )\r
216         throws MalformedURLException, IOException, XmlPullParserException\r
217     {\r
218         List artifactList = new ArrayList();\r
219 \r
220         for ( int i = 0; i < hits.length(); i++ )\r
221         {\r
222             Document doc = hits.doc( i );\r
223 \r
224             artifactList.add( createSearchedObjectFromIndexDocument( doc ) );\r
225         }\r
226 \r
227         return artifactList;\r
228     }\r
229 \r
230     /**\r
231      * Method for creating the object to be returned for the search\r
232      *\r
233      * @param doc the index document where the object field values will be retrieved from\r
234      * @return Object\r
235      */\r
236     protected Object createSearchedObjectFromIndexDocument( Document doc )\r
237         throws MalformedURLException, IOException, XmlPullParserException\r
238     {\r
239         String groupId, artifactId, version, name, packaging;\r
240 \r
241         if ( doc.get( index.FLD_DOCTYPE ).equals( index.ARTIFACT ) )\r
242         {\r
243             groupId = doc.get( ArtifactRepositoryIndex.FLD_GROUPID );\r
244             artifactId = doc.get( ArtifactRepositoryIndex.FLD_ARTIFACTID );\r
245             version = doc.get( ArtifactRepositoryIndex.FLD_VERSION );\r
246             name = doc.get( ArtifactRepositoryIndex.FLD_NAME );\r
247             packaging = name.substring( name.lastIndexOf( '.' ) + 1 );\r
248             Artifact artifact = factory.createBuildArtifact( groupId, artifactId, version, packaging );\r
249             String groupIdTemp = groupId.replace( '.', '/' );\r
250             artifact.setFile( new File(\r
251                 index.getRepository().getBasedir() + groupIdTemp + "/" + artifactId + "/" + version + "/" + name ) );\r
252 \r
253             return artifact;\r
254         }\r
255         else if ( doc.get( index.FLD_DOCTYPE ).equals( index.POM ) )\r
256         {\r
257             groupId = doc.get( PomRepositoryIndex.FLD_GROUPID );\r
258             artifactId = doc.get( PomRepositoryIndex.FLD_ARTIFACTID );\r
259             version = doc.get( PomRepositoryIndex.FLD_VERSION );\r
260             packaging = doc.get( PomRepositoryIndex.FLD_PACKAGING );\r
261 \r
262             return factory.createBuildArtifact( groupId, artifactId, version, packaging );\r
263         }\r
264         else if ( doc.get( index.FLD_DOCTYPE ).equals( index.METADATA ) )\r
265         {\r
266             List pathParts = new ArrayList();\r
267             StringTokenizer st = new StringTokenizer( doc.get( MetadataRepositoryIndex.FLD_NAME ), "/\\" );\r
268             while ( st.hasMoreTokens() )\r
269             {\r
270                 pathParts.add( st.nextToken() );\r
271             }\r
272 \r
273             Collections.reverse( pathParts );\r
274             Iterator it = pathParts.iterator();\r
275             String metadataFile = (String) it.next();\r
276             String tmpDir = (String) it.next();\r
277 \r
278             String metadataType = "";\r
279             if ( tmpDir.equals( doc.get( MetadataRepositoryIndex.FLD_GROUPID ) ) )\r
280             {\r
281                 metadataType = MetadataRepositoryIndex.GROUP_METADATA;\r
282             }\r
283             else if ( tmpDir.equals( doc.get( MetadataRepositoryIndex.FLD_ARTIFACTID ) ) )\r
284             {\r
285                 metadataType = MetadataRepositoryIndex.ARTIFACT_METADATA;\r
286             }\r
287             else\r
288             {\r
289                 metadataType = MetadataRepositoryIndex.SNAPSHOT_METADATA;\r
290             }\r
291 \r
292             RepositoryMetadata repoMetadata = null;\r
293             repoMetadata = getMetadata( doc.get( MetadataRepositoryIndex.FLD_GROUPID ),\r
294                                         doc.get( MetadataRepositoryIndex.FLD_ARTIFACTID ),\r
295                                         doc.get( MetadataRepositoryIndex.FLD_VERSION ), metadataFile, metadataType );\r
296 \r
297             return repoMetadata;\r
298         }\r
299 \r
300         return null;\r
301     }\r
302 \r
303     /**\r
304      * Create RepositoryMetadata object.\r
305      *\r
306      * @param groupId      the groupId to be set\r
307      * @param artifactId   the artifactId to be set\r
308      * @param version      the version to be set\r
309      * @param filename     the name of the metadata file\r
310      * @param metadataType the type of RepositoryMetadata object to be created (GROUP, ARTIFACT or SNAPSHOT)\r
311      * @return RepositoryMetadata\r
312      * @throws MalformedURLException\r
313      * @throws IOException\r
314      * @throws XmlPullParserException\r
315      */\r
316     private RepositoryMetadata getMetadata( String groupId, String artifactId, String version, String filename,\r
317                                             String metadataType )\r
318         throws MalformedURLException, IOException, XmlPullParserException\r
319     {\r
320         RepositoryMetadata repoMetadata = null;\r
321         URL url;\r
322         InputStream is = null;\r
323         MetadataXpp3Reader metadataReader = new MetadataXpp3Reader();\r
324 \r
325         //group metadata\r
326         if ( metadataType.equals( MetadataRepositoryIndex.GROUP_METADATA ) )\r
327         {\r
328             url = new File( index.getRepository().getBasedir() + groupId.replace( '.', '/' ) + "/" + filename ).toURL();\r
329             is = url.openStream();\r
330             repoMetadata = new GroupRepositoryMetadata( groupId );\r
331             repoMetadata.setMetadata( metadataReader.read( new InputStreamReader( is ) ) );\r
332         }\r
333         //artifact metadata\r
334         else if ( metadataType.equals( MetadataRepositoryIndex.ARTIFACT_METADATA ) )\r
335         {\r
336             url = new File( index.getRepository().getBasedir() + groupId.replace( '.', '/' ) + "/" + artifactId + "/" +\r
337                 filename ).toURL();\r
338             is = url.openStream();\r
339             repoMetadata =\r
340                 new ArtifactRepositoryMetadata( factory.createBuildArtifact( groupId, artifactId, version, "jar" ) );\r
341             repoMetadata.setMetadata( metadataReader.read( new InputStreamReader( is ) ) );\r
342         }\r
343         //snapshot/version metadata\r
344         else if ( metadataType.equals( MetadataRepositoryIndex.SNAPSHOT_METADATA ) )\r
345         {\r
346             url = new File( index.getRepository().getBasedir() + groupId.replace( '.', '/' ) + "/" + artifactId + "/" +\r
347                 version + "/" + filename ).toURL();\r
348             is = url.openStream();\r
349             repoMetadata = new SnapshotArtifactRepositoryMetadata(\r
350                 factory.createBuildArtifact( groupId, artifactId, version, "jar" ) );\r
351             repoMetadata.setMetadata( metadataReader.read( new InputStreamReader( is ) ) );\r
352         }\r
353 \r
354         return repoMetadata;\r
355     }\r
356 \r
357 }\r