1 package org.apache.maven.repository.indexing;
\r
4 * Copyright 2005-2006 The Apache Software Foundation.
\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
10 * http://www.apache.org/licenses/LICENSE-2.0
\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
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
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
55 * Abstract Class to hold common codes for the different RepositoryIndexSearcher
\r
57 public class DefaultRepositoryIndexSearcher
\r
58 extends AbstractLogEnabled
\r
59 implements RepositoryIndexSearcher
\r
61 protected RepositoryIndex index;
\r
63 private ArtifactFactory factory;
\r
68 * @param index the index object
\r
70 protected DefaultRepositoryIndexSearcher( RepositoryIndex index, ArtifactFactory factory )
\r
73 this.factory = factory;
\r
77 * @see RepositoryIndexSearcher#search(org.apache.maven.repository.indexing.query.Query)
\r
79 public List search( Query query )
\r
80 throws RepositoryIndexSearchException
\r
83 org.apache.lucene.search.Query luceneQuery;
\r
86 luceneQuery = createLuceneQuery( query );
\r
88 catch ( ParseException e )
\r
90 throw new RepositoryIndexSearchException( "Unable to construct query: " + e.getMessage(), e );
\r
93 IndexSearcher searcher;
\r
96 searcher = new IndexSearcher( index.getIndexPath() );
\r
98 catch ( IOException e )
\r
100 throw new RepositoryIndexSearchException( "Unable to open index: " + e.getMessage(), e );
\r
106 Hits hits = searcher.search( luceneQuery );
\r
107 docs = buildList( hits );
\r
109 catch ( IOException e )
\r
111 throw new RepositoryIndexSearchException( "Unable to search index: " + e.getMessage(), e );
\r
113 catch ( XmlPullParserException xe )
\r
115 throw new RepositoryIndexSearchException( "Unable to parse metadata file: " + xe.getMessage(), xe );
\r
124 catch ( IOException e )
\r
126 getLogger().error( "Unable to close index searcher", e );
\r
134 * Method to create a lucene Query object from a single query phrase
\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
141 private org.apache.lucene.search.Query createLuceneQuery( String field, String value )
\r
142 throws ParseException
\r
144 org.apache.lucene.search.Query qry;
\r
145 if ( index.isKeywordField( field ) )
\r
147 Term term = new Term( field, value );
\r
148 qry = new TermQuery( term );
\r
152 QueryParser parser = new QueryParser( field, index.getAnalyzer() );
\r
153 qry = parser.parse( value );
\r
159 * Method to create a lucene Query object by converting a prepared Query object
\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
165 private org.apache.lucene.search.Query createLuceneQuery( Query query )
\r
166 throws ParseException
\r
168 org.apache.lucene.search.Query retVal;
\r
170 if ( query instanceof CompoundQuery )
\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
177 CompoundQueryTerm subquery = (CompoundQueryTerm) i.next();
\r
179 org.apache.lucene.search.Query luceneQuery = createLuceneQuery( subquery.getQuery() );
\r
181 booleanQuery.add( luceneQuery, subquery.isRequired(), subquery.isProhibited() );
\r
183 retVal = booleanQuery;
\r
185 else if ( query instanceof RangeQuery )
\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
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
198 retVal = new org.apache.lucene.search.RangeQuery( begin, end, rq.isInclusive() );
\r
202 SinglePhraseQuery singlePhraseQuery = (SinglePhraseQuery) query;
\r
203 retVal = createLuceneQuery( singlePhraseQuery.getField(), singlePhraseQuery.getValue() );
\r
209 * Create a list of artifact objects from the result set.
\r
211 * @param hits the search result set
\r
213 * @throws IOException
\r
215 private List buildList( Hits hits )
\r
216 throws MalformedURLException, IOException, XmlPullParserException
\r
218 List artifactList = new ArrayList();
\r
220 for ( int i = 0; i < hits.length(); i++ )
\r
222 Document doc = hits.doc( i );
\r
224 artifactList.add( createSearchedObjectFromIndexDocument( doc ) );
\r
227 return artifactList;
\r
231 * Method for creating the object to be returned for the search
\r
233 * @param doc the index document where the object field values will be retrieved from
\r
236 protected Object createSearchedObjectFromIndexDocument( Document doc )
\r
237 throws MalformedURLException, IOException, XmlPullParserException
\r
239 String groupId, artifactId, version, name, packaging;
\r
241 if ( doc.get( index.FLD_DOCTYPE ).equals( index.ARTIFACT ) )
\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
255 else if ( doc.get( index.FLD_DOCTYPE ).equals( index.POM ) )
\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
262 return factory.createBuildArtifact( groupId, artifactId, version, packaging );
\r
264 else if ( doc.get( index.FLD_DOCTYPE ).equals( index.METADATA ) )
\r
266 List pathParts = new ArrayList();
\r
267 StringTokenizer st = new StringTokenizer( doc.get( MetadataRepositoryIndex.FLD_NAME ), "/\\" );
\r
268 while ( st.hasMoreTokens() )
\r
270 pathParts.add( st.nextToken() );
\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
278 String metadataType = "";
\r
279 if ( tmpDir.equals( doc.get( MetadataRepositoryIndex.FLD_GROUPID ) ) )
\r
281 metadataType = MetadataRepositoryIndex.GROUP_METADATA;
\r
283 else if ( tmpDir.equals( doc.get( MetadataRepositoryIndex.FLD_ARTIFACTID ) ) )
\r
285 metadataType = MetadataRepositoryIndex.ARTIFACT_METADATA;
\r
289 metadataType = MetadataRepositoryIndex.SNAPSHOT_METADATA;
\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
297 return repoMetadata;
\r
304 * Create RepositoryMetadata object.
\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
316 private RepositoryMetadata getMetadata( String groupId, String artifactId, String version, String filename,
\r
317 String metadataType )
\r
318 throws MalformedURLException, IOException, XmlPullParserException
\r
320 RepositoryMetadata repoMetadata = null;
\r
322 InputStream is = null;
\r
323 MetadataXpp3Reader metadataReader = new MetadataXpp3Reader();
\r
326 if ( metadataType.equals( MetadataRepositoryIndex.GROUP_METADATA ) )
\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
333 //artifact metadata
\r
334 else if ( metadataType.equals( MetadataRepositoryIndex.ARTIFACT_METADATA ) )
\r
336 url = new File( index.getRepository().getBasedir() + groupId.replace( '.', '/' ) + "/" + artifactId + "/" +
\r
337 filename ).toURL();
\r
338 is = url.openStream();
\r
340 new ArtifactRepositoryMetadata( factory.createBuildArtifact( groupId, artifactId, version, "jar" ) );
\r
341 repoMetadata.setMetadata( metadataReader.read( new InputStreamReader( is ) ) );
\r
343 //snapshot/version metadata
\r
344 else if ( metadataType.equals( MetadataRepositoryIndex.SNAPSHOT_METADATA ) )
\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
354 return repoMetadata;
\r