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