View Javadoc
1   package org.apache.maven.index.creator;
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 javax.inject.Named;
23  import javax.inject.Singleton;
24  import java.io.File;
25  import java.io.IOException;
26  import java.util.Arrays;
27  import java.util.Collection;
28  
29  import org.apache.lucene.document.Document;
30  import org.apache.lucene.document.Field;
31  import org.apache.lucene.document.Field.Index;
32  import org.apache.lucene.document.Field.Store;
33  import org.apache.maven.index.ArtifactAvailability;
34  import org.apache.maven.index.ArtifactContext;
35  import org.apache.maven.index.ArtifactInfo;
36  import org.apache.maven.index.IndexerField;
37  import org.apache.maven.index.IndexerFieldVersion;
38  import org.apache.maven.index.MAVEN;
39  import org.apache.maven.index.NEXUS;
40  import org.apache.maven.index.artifact.Gav;
41  import org.apache.maven.index.locator.JavadocLocator;
42  import org.apache.maven.index.locator.Locator;
43  import org.apache.maven.index.locator.Sha1Locator;
44  import org.apache.maven.index.locator.SignatureLocator;
45  import org.apache.maven.index.locator.SourcesLocator;
46  import org.apache.maven.model.Model;
47  import org.codehaus.plexus.util.FileUtils;
48  import org.codehaus.plexus.util.StringUtils;
49  
50  /**
51   * A minimal index creator used to provide basic information about Maven artifact. This creator will create the index
52   * fast, will not open any file to be fastest as possible but it has some drawbacks: The information gathered by this
53   * creator are sometimes based on "best-effort" only, and does not reflect the reality (ie. maven archetype packaging @see
54   * {@link MavenArchetypeArtifactInfoIndexCreator}).
55   * 
56   * @author cstamas
57   */
58  @Singleton
59  @Named( MinimalArtifactInfoIndexCreator.ID )
60  public class MinimalArtifactInfoIndexCreator
61      extends AbstractIndexCreator
62      implements LegacyDocumentUpdater
63  {
64      public static final String ID = "min";
65  
66      /**
67       * Info: packaging, lastModified, size, sourcesExists, javadocExists, signatureExists. Stored, not indexed.
68       */
69      public static final IndexerField FLD_INFO = new IndexerField( NEXUS.INFO, IndexerFieldVersion.V1, "i",
70          "Artifact INFO (not indexed, stored)", Store.YES, Index.NO );
71  
72      public static final IndexerField FLD_GROUP_ID_KW = new IndexerField( MAVEN.GROUP_ID, IndexerFieldVersion.V1, "g",
73          "Artifact GroupID (as keyword)", Store.NO, Index.NOT_ANALYZED );
74  
75      public static final IndexerField FLD_GROUP_ID = new IndexerField( MAVEN.GROUP_ID, IndexerFieldVersion.V3,
76          "groupId", "Artifact GroupID (tokenized)", Store.NO, Index.ANALYZED );
77  
78      public static final IndexerField FLD_ARTIFACT_ID_KW = new IndexerField( MAVEN.ARTIFACT_ID, IndexerFieldVersion.V1,
79          "a", "Artifact ArtifactID (as keyword)", Store.NO, Index.NOT_ANALYZED );
80  
81      public static final IndexerField FLD_ARTIFACT_ID = new IndexerField( MAVEN.ARTIFACT_ID, IndexerFieldVersion.V3,
82          "artifactId", "Artifact ArtifactID (tokenized)", Store.NO, Index.ANALYZED );
83  
84      public static final IndexerField FLD_VERSION_KW = new IndexerField( MAVEN.VERSION, IndexerFieldVersion.V1, "v",
85          "Artifact Version (as keyword)", Store.NO, Index.NOT_ANALYZED );
86  
87      public static final IndexerField FLD_VERSION = new IndexerField( MAVEN.VERSION, IndexerFieldVersion.V3, "version",
88          "Artifact Version (tokenized)", Store.NO, Index.ANALYZED );
89  
90      public static final IndexerField FLD_PACKAGING = new IndexerField( MAVEN.PACKAGING, IndexerFieldVersion.V1, "p",
91          "Artifact Packaging (as keyword)", Store.NO, Index.NOT_ANALYZED );
92  
93      public static final IndexerField FLD_EXTENSION = new IndexerField( MAVEN.EXTENSION, IndexerFieldVersion.V1, "e",
94          "Artifact extension (as keyword)", Store.NO, Index.NOT_ANALYZED );
95  
96      public static final IndexerField FLD_CLASSIFIER = new IndexerField( MAVEN.CLASSIFIER, IndexerFieldVersion.V1, "l",
97          "Artifact classifier (as keyword)", Store.NO, Index.NOT_ANALYZED );
98  
99      public static final IndexerField FLD_NAME = new IndexerField( MAVEN.NAME, IndexerFieldVersion.V1, "n",
100         "Artifact name (tokenized, stored)", Store.YES, Index.ANALYZED );
101 
102     public static final IndexerField FLD_DESCRIPTION = new IndexerField( MAVEN.DESCRIPTION, IndexerFieldVersion.V1,
103         "d", "Artifact description (tokenized, stored)", Store.YES, Index.ANALYZED );
104 
105     public static final IndexerField FLD_LAST_MODIFIED = new IndexerField( MAVEN.LAST_MODIFIED, IndexerFieldVersion.V1,
106         "m", "Artifact last modified (not indexed, stored)", Store.YES, Index.NO );
107 
108     public static final IndexerField FLD_SHA1 = new IndexerField( MAVEN.SHA1, IndexerFieldVersion.V1, "1",
109         "Artifact SHA1 checksum (as keyword, stored)", Store.YES, Index.NOT_ANALYZED );
110 
111     private Locator jl = new JavadocLocator();
112 
113     private Locator sl = new SourcesLocator();
114 
115     private Locator sigl = new SignatureLocator();
116 
117     private Locator sha1l = new Sha1Locator();
118 
119     public MinimalArtifactInfoIndexCreator()
120     {
121         super( ID );
122     }
123 
124     public void populateArtifactInfo( ArtifactContext ac )
125     {
126         File artifact = ac.getArtifact();
127 
128         File pom = ac.getPom();
129 
130         ArtifactInfo ai = ac.getArtifactInfo();
131 
132         if ( pom != null && pom.isFile() )
133         {
134             ai.setLastModified( pom.lastModified() );
135 
136             ai.setFileExtension( "pom" );
137         }
138 
139         // TODO handle artifacts without poms
140         if ( pom != null && pom.isFile() )
141         {
142             if ( ai.getClassifier() != null )
143             {
144                 ai.setSourcesExists( ArtifactAvailability.NOT_AVAILABLE );
145 
146                 ai.setJavadocExists( ArtifactAvailability.NOT_AVAILABLE );
147             }
148             else
149             {
150                 File sources = sl.locate( pom );
151                 if ( !sources.exists() )
152                 {
153                     ai.setSourcesExists( ArtifactAvailability.NOT_PRESENT );
154                 }
155                 else
156                 {
157                     ai.setSourcesExists( ArtifactAvailability.PRESENT );
158                 }
159 
160                 File javadoc = jl.locate( pom );
161                 if ( !javadoc.exists() )
162                 {
163                     ai.setJavadocExists( ArtifactAvailability.NOT_PRESENT );
164                 }
165                 else
166                 {
167                     ai.setJavadocExists( ArtifactAvailability.PRESENT );
168                 }
169             }
170         }
171 
172         Model model = ac.getPomModel();
173 
174         if ( model != null )
175         {
176             ai.setName( model.getName() );
177 
178             ai.setDescription( model.getDescription() );
179 
180             // for main artifacts (without classifier) only:
181             if ( ai.getClassifier() == null )
182             {
183                 // only when this is not a classified artifact
184                 if ( model.getPackaging() != null )
185                 {
186                     // set the read value that is coming from POM
187                     ai.setPackaging( model.getPackaging() );
188                 }
189                 else
190                 {
191                     // default it, since POM is present, is read, but does not contain explicit packaging
192                     // TODO: this change breaks junit tests, but not sure why is "null" expected value?
193                     ai.setPackaging( "jar" );
194                 }
195             }
196         }
197 
198         if ( "pom".equals( ai.getPackaging() ) )
199         {
200             // special case, the POM _is_ the artifact
201             artifact = pom;
202         }
203 
204         if ( artifact != null )
205         {
206             File signature = sigl.locate( artifact );
207 
208             ai.setSignatureExists( signature.exists() ? ArtifactAvailability.PRESENT
209                             : ArtifactAvailability.NOT_PRESENT );
210 
211             File sha1 = sha1l.locate( artifact );
212 
213             if ( sha1.exists() )
214             {
215                 try
216                 {
217                     ai.setSha1( StringUtils.chomp( FileUtils.fileRead( sha1 ) ).trim().split( " " )[0] );
218                 }
219                 catch ( IOException e )
220                 {
221                     ac.addError( e );
222                 }
223             }
224 
225             ai.setLastModified( artifact.lastModified() );
226 
227             ai.setSize( artifact.length() );
228 
229             ai.setFileExtension( getExtension( artifact, ac.getGav() ) );
230         }
231     }
232 
233     private String getExtension( File artifact, Gav gav )
234     {
235         if ( gav != null && StringUtils.isNotBlank( gav.getExtension() ) )
236         {
237             return gav.getExtension();
238         }
239 
240         // last resort, the extension of the file
241         String artifactFileName = artifact.getName().toLowerCase();
242 
243         // tar.gz? and other "special" combinations
244         if ( artifactFileName.endsWith( "tar.gz" ) )
245         {
246             return "tar.gz";
247         }
248         else if ( artifactFileName.equals( "tar.bz2" ) )
249         {
250             return "tar.bz2";
251         }
252 
253         // get the part after the last dot
254         return FileUtils.getExtension( artifactFileName );
255     }
256 
257     public void updateDocument( ArtifactInfo ai, Document doc )
258     {
259         String info =
260             new StringBuilder().append( ArtifactInfo.nvl( ai.getPackaging() ) )
261                 .append( ArtifactInfo.FS ).append( Long.toString( ai.getLastModified() ) )
262                 .append( ArtifactInfo.FS ).append( Long.toString( ai.getSize() ) )
263                 .append( ArtifactInfo.FS ).append( ai.getSourcesExists().toString() )
264                 .append( ArtifactInfo.FS ).append( ai.getJavadocExists().toString() )
265                 .append( ArtifactInfo.FS ).append( ai.getSignatureExists().toString() )
266                 .append( ArtifactInfo.FS ).append( ai.getFileExtension() ).toString();
267 
268         doc.add( FLD_INFO.toField( info ) );
269 
270         doc.add( FLD_GROUP_ID_KW.toField( ai.getGroupId() ) );
271         doc.add( FLD_ARTIFACT_ID_KW.toField( ai.getArtifactId() ) );
272         doc.add( FLD_VERSION_KW.toField( ai.getVersion() ) );
273 
274         // V3
275         doc.add( FLD_GROUP_ID.toField( ai.getGroupId() ) );
276         doc.add( FLD_ARTIFACT_ID.toField( ai.getArtifactId() ) );
277         doc.add( FLD_VERSION.toField( ai.getVersion() ) );
278         doc.add( FLD_EXTENSION.toField( ai.getFileExtension() ) );
279 
280         if ( ai.getName() != null )
281         {
282             doc.add( FLD_NAME.toField( ai.getName() ) );
283         }
284 
285         if ( ai.getDescription() != null )
286         {
287             doc.add( FLD_DESCRIPTION.toField( ai.getDescription() ) );
288         }
289 
290         if ( ai.getPackaging() != null )
291         {
292             doc.add( FLD_PACKAGING.toField( ai.getPackaging() ) );
293         }
294 
295         if ( ai.getClassifier() != null )
296         {
297             doc.add( FLD_CLASSIFIER.toField( ai.getClassifier() ) );
298         }
299 
300         if ( ai.getSha1() != null )
301         {
302             doc.add( FLD_SHA1.toField( ai.getSha1() ) );
303         }
304     }
305 
306     public void updateLegacyDocument( ArtifactInfo ai, Document doc )
307     {
308         updateDocument( ai, doc );
309 
310         // legacy!
311         if ( ai.getPrefix() != null )
312         {
313             doc.add( new Field( ArtifactInfo.PLUGIN_PREFIX, ai.getPrefix(), Field.Store.YES,
314                                 Field.Index.NOT_ANALYZED ) );
315         }
316 
317         if ( ai.getGoals() != null )
318         {
319             doc.add( new Field( ArtifactInfo.PLUGIN_GOALS, ArtifactInfo.lst2str( ai.getGoals() ), Field.Store.YES,
320                 Field.Index.NO ) );
321         }
322 
323         doc.removeField( ArtifactInfo.GROUP_ID );
324         doc.add( new Field( ArtifactInfo.GROUP_ID, ai.getGroupId(), Field.Store.NO, Field.Index.NOT_ANALYZED ) );
325     }
326 
327     public boolean updateArtifactInfo( Document doc, ArtifactInfo ai )
328     {
329         boolean res = false;
330 
331         String uinfo = doc.get( ArtifactInfo.UINFO );
332 
333         if ( uinfo != null )
334         {
335             String[] r = ArtifactInfo.FS_PATTERN.split( uinfo );
336 
337             ai.setGroupId( r[0] );
338 
339             ai.setArtifactId( r[1] );
340 
341             ai.setVersion( r[2] );
342 
343             ai.setClassifier( ArtifactInfo.renvl( r[3] ) );
344 
345             if ( r.length > 4 ) 
346             {
347               ai.setFileExtension( r[4] );
348             }
349 
350             res = true;
351         }
352 
353         String info = doc.get( ArtifactInfo.INFO );
354 
355         if ( info != null )
356         {
357             String[] r = ArtifactInfo.FS_PATTERN.split( info );
358 
359             ai.setPackaging( ArtifactInfo.renvl( r[0] ) );
360 
361             ai.setLastModified( Long.parseLong( r[1] ) );
362 
363             ai.setSize( Long.parseLong( r[2] ) );
364 
365             ai.setSourcesExists( ArtifactAvailability.fromString( r[ 3 ] ) );
366 
367             ai.setJavadocExists( ArtifactAvailability.fromString( r[ 4 ] ) );
368 
369             ai.setSignatureExists( ArtifactAvailability.fromString( r[ 5 ] ) );
370 
371             if ( r.length > 6 )
372             {
373                 ai.setFileExtension( r[6] );
374             }
375             else
376             {
377                 if ( ai.getClassifier() != null //
378                     || "pom".equals( ai.getPackaging() ) //
379                     || "war".equals( ai.getPackaging() ) //
380                     || "ear".equals( ai.getPackaging() ) )
381                 {
382                     ai.setFileExtension( ai.getPackaging() );
383                 }
384                 else
385                 {
386                     ai.setFileExtension( "jar" ); // best guess
387                 }
388             }
389 
390             res = true;
391         }
392 
393         String name = doc.get( ArtifactInfo.NAME );
394 
395         if ( name != null )
396         {
397             ai.setName( name );
398 
399             res = true;
400         }
401 
402         String description = doc.get( ArtifactInfo.DESCRIPTION );
403 
404         if ( description != null )
405         {
406             ai.setDescription( description );
407 
408             res = true;
409         }
410 
411         // sometimes there's a pom without packaging(default to jar), but no artifact, then the value will be a "null"
412         // String
413         if ( "null".equals( ai.getPackaging() ) )
414         {
415             ai.setPackaging( null );
416         }
417 
418         String sha1 = doc.get( ArtifactInfo.SHA1 );
419 
420         if ( sha1 != null )
421         {
422             ai.setSha1( sha1 );
423         }
424 
425         return res;
426 
427         // artifactInfo.fname = ???
428     }
429 
430     // ==
431 
432     @Override
433     public String toString()
434     {
435         return ID;
436     }
437 
438     public Collection<IndexerField> getIndexerFields()
439     {
440         return Arrays.asList( FLD_INFO, FLD_GROUP_ID_KW, FLD_GROUP_ID, FLD_ARTIFACT_ID_KW, FLD_ARTIFACT_ID,
441             FLD_VERSION_KW, FLD_VERSION, FLD_PACKAGING, FLD_CLASSIFIER, FLD_NAME, FLD_DESCRIPTION, FLD_LAST_MODIFIED,
442             FLD_SHA1 );
443     }
444 }