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 java.io.File;
23  import java.io.IOException;
24  import java.util.Arrays;
25  import java.util.Collection;
26  
27  import org.apache.lucene.document.Document;
28  import org.apache.lucene.document.Field;
29  import org.apache.lucene.document.Field.Index;
30  import org.apache.lucene.document.Field.Store;
31  import org.apache.maven.index.ArtifactAvailablility;
32  import org.apache.maven.index.ArtifactContext;
33  import org.apache.maven.index.ArtifactInfo;
34  import org.apache.maven.index.IndexerField;
35  import org.apache.maven.index.IndexerFieldVersion;
36  import org.apache.maven.index.MAVEN;
37  import org.apache.maven.index.NEXUS;
38  import org.apache.maven.index.artifact.Gav;
39  import org.apache.maven.index.context.IndexCreator;
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.component.annotations.Component;
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  @Component( role = IndexCreator.class, hint = 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)", Store.YES, Index.NO );
70  
71      public static final IndexerField FLD_GROUP_ID_KW = new IndexerField( MAVEN.GROUP_ID, IndexerFieldVersion.V1, "g",
72          "Artifact GroupID (as keyword)", Store.NO, Index.NOT_ANALYZED );
73  
74      public static final IndexerField FLD_GROUP_ID = new IndexerField( MAVEN.GROUP_ID, IndexerFieldVersion.V3,
75          "groupId", "Artifact GroupID (tokenized)", Store.NO, Index.ANALYZED );
76  
77      public static final IndexerField FLD_ARTIFACT_ID_KW = new IndexerField( MAVEN.ARTIFACT_ID, IndexerFieldVersion.V1,
78          "a", "Artifact ArtifactID (as keyword)", Store.NO, Index.NOT_ANALYZED );
79  
80      public static final IndexerField FLD_ARTIFACT_ID = new IndexerField( MAVEN.ARTIFACT_ID, IndexerFieldVersion.V3,
81          "artifactId", "Artifact ArtifactID (tokenized)", Store.NO, Index.ANALYZED );
82  
83      public static final IndexerField FLD_VERSION_KW = new IndexerField( MAVEN.VERSION, IndexerFieldVersion.V1, "v",
84          "Artifact Version (as keyword)", Store.NO, Index.NOT_ANALYZED );
85  
86      public static final IndexerField FLD_VERSION = new IndexerField( MAVEN.VERSION, IndexerFieldVersion.V3, "version",
87          "Artifact Version (tokenized)", Store.NO, Index.ANALYZED );
88  
89      public static final IndexerField FLD_PACKAGING = new IndexerField( MAVEN.PACKAGING, IndexerFieldVersion.V1, "p",
90          "Artifact Packaging (as keyword)", Store.NO, Index.NOT_ANALYZED );
91  
92      public static final IndexerField FLD_CLASSIFIER = new IndexerField( MAVEN.CLASSIFIER, IndexerFieldVersion.V1, "l",
93          "Artifact classifier (as keyword)", Store.NO, Index.NOT_ANALYZED );
94  
95      public static final IndexerField FLD_NAME = new IndexerField( MAVEN.NAME, IndexerFieldVersion.V1, "n",
96          "Artifact name (tokenized, stored)", Store.YES, Index.ANALYZED );
97  
98      public static final IndexerField FLD_DESCRIPTION = new IndexerField( MAVEN.DESCRIPTION, IndexerFieldVersion.V1,
99          "d", "Artifact description (tokenized, stored)", Store.YES, Index.ANALYZED );
100 
101     public static final IndexerField FLD_LAST_MODIFIED = new IndexerField( MAVEN.LAST_MODIFIED, IndexerFieldVersion.V1,
102         "m", "Artifact last modified (not indexed, stored)", Store.YES, Index.NO );
103 
104     public static final IndexerField FLD_SHA1 = new IndexerField( MAVEN.SHA1, IndexerFieldVersion.V1, "1",
105         "Artifact SHA1 checksum (as keyword, stored)", Store.YES, Index.NOT_ANALYZED );
106 
107     private Locator jl = new JavadocLocator();
108 
109     private Locator sl = new SourcesLocator();
110 
111     private Locator sigl = new SignatureLocator();
112 
113     private Locator sha1l = new Sha1Locator();
114 
115     public MinimalArtifactInfoIndexCreator()
116     {
117         super( ID );
118     }
119 
120     public void populateArtifactInfo( ArtifactContext ac )
121     {
122         File artifact = ac.getArtifact();
123 
124         File pom = ac.getPom();
125 
126         ArtifactInfo ai = ac.getArtifactInfo();
127 
128         if ( pom != null )
129         {
130             ai.lastModified = pom.lastModified();
131 
132             ai.fextension = "pom";
133         }
134 
135         // TODO handle artifacts without poms
136         if ( pom != null )
137         {
138             if ( ai.classifier != null )
139             {
140                 ai.sourcesExists = ArtifactAvailablility.NOT_AVAILABLE;
141 
142                 ai.javadocExists = ArtifactAvailablility.NOT_AVAILABLE;
143             }
144             else
145             {
146                 File sources = sl.locate( pom );
147                 if ( !sources.exists() )
148                 {
149                     ai.sourcesExists = ArtifactAvailablility.NOT_PRESENT;
150                 }
151                 else
152                 {
153                     ai.sourcesExists = ArtifactAvailablility.PRESENT;
154                 }
155 
156                 File javadoc = jl.locate( pom );
157                 if ( !javadoc.exists() )
158                 {
159                     ai.javadocExists = ArtifactAvailablility.NOT_PRESENT;
160                 }
161                 else
162                 {
163                     ai.javadocExists = ArtifactAvailablility.PRESENT;
164                 }
165             }
166         }
167 
168         Model model = ac.getPomModel();
169 
170         if ( model != null )
171         {
172             ai.name = model.getName();
173 
174             ai.description = model.getDescription();
175 
176             // for main artifacts (without classifier) only:
177             if ( ai.classifier == null )
178             {
179                 // only when this is not a classified artifact
180                 if ( model.getPackaging() != null )
181                 {
182                     // set the read value that is coming from POM
183                     ai.packaging = model.getPackaging();
184                 }
185                 else
186                 {
187                     // default it, since POM is present, is read, but does not contain explicit packaging
188                     // TODO: this change breaks junit tests, but not sure why is "null" expected value?
189                     // ai.packaging = "jar";
190                 }
191             }
192         }
193 
194         if ( "pom".equals( ai.packaging ) )
195         {
196             // special case, the POM _is_ the artifact
197             artifact = pom;
198         }
199 
200         if ( artifact != null )
201         {
202             File signature = sigl.locate( artifact );
203 
204             ai.signatureExists = signature.exists() ? ArtifactAvailablility.PRESENT : ArtifactAvailablility.NOT_PRESENT;
205 
206             File sha1 = sha1l.locate( artifact );
207 
208             if ( sha1.exists() )
209             {
210                 try
211                 {
212                     ai.sha1 = StringUtils.chomp( FileUtils.fileRead( sha1 ) ).trim().split( " " )[0];
213                 }
214                 catch ( IOException e )
215                 {
216                     ac.addError( e );
217                 }
218             }
219 
220             ai.lastModified = artifact.lastModified();
221 
222             ai.size = artifact.length();
223 
224             ai.fextension = getExtension( artifact, ac.getGav() );
225 
226             if ( ai.packaging == null )
227             {
228                 ai.packaging = ai.fextension;
229             }
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( ai.packaging ).append( ArtifactInfo.FS ).append(
261                 Long.toString( ai.lastModified ) ).append( ArtifactInfo.FS ).append( Long.toString( ai.size ) ).append(
262                 ArtifactInfo.FS ).append( ai.sourcesExists.toString() ).append( ArtifactInfo.FS ).append(
263                 ai.javadocExists.toString() ).append( ArtifactInfo.FS ).append( ai.signatureExists.toString() ).append(
264                 ArtifactInfo.FS ).append( ai.fextension ).toString();
265 
266         doc.add( FLD_INFO.toField( info ) );
267 
268         doc.add( FLD_GROUP_ID_KW.toField( ai.groupId ) );
269         doc.add( FLD_ARTIFACT_ID_KW.toField( ai.artifactId ) );
270         doc.add( FLD_VERSION_KW.toField( ai.version ) );
271 
272         // V3
273         doc.add( FLD_GROUP_ID.toField( ai.groupId ) );
274         doc.add( FLD_ARTIFACT_ID.toField( ai.artifactId ) );
275         doc.add( FLD_VERSION.toField( ai.version ) );
276 
277         if ( ai.name != null )
278         {
279             doc.add( FLD_NAME.toField( ai.name ) );
280         }
281 
282         if ( ai.description != null )
283         {
284             doc.add( FLD_DESCRIPTION.toField( ai.description ) );
285         }
286 
287         if ( ai.packaging != null )
288         {
289             doc.add( FLD_PACKAGING.toField( ai.packaging ) );
290         }
291 
292         if ( ai.classifier != null )
293         {
294             doc.add( FLD_CLASSIFIER.toField( ai.classifier ) );
295         }
296 
297         if ( ai.sha1 != null )
298         {
299             doc.add( FLD_SHA1.toField( ai.sha1 ) );
300         }
301     }
302 
303     public void updateLegacyDocument( ArtifactInfo ai, Document doc )
304     {
305         updateDocument( ai, doc );
306 
307         // legacy!
308         if ( ai.prefix != null )
309         {
310             doc.add( new Field( ArtifactInfo.PLUGIN_PREFIX, ai.prefix, Field.Store.YES, Field.Index.NOT_ANALYZED ) );
311         }
312 
313         if ( ai.goals != null )
314         {
315             doc.add( new Field( ArtifactInfo.PLUGIN_GOALS, ArtifactInfo.lst2str( ai.goals ), Field.Store.YES,
316                 Field.Index.NO ) );
317         }
318 
319         doc.removeField( ArtifactInfo.GROUP_ID );
320         doc.add( new Field( ArtifactInfo.GROUP_ID, ai.groupId, Field.Store.NO, Field.Index.NOT_ANALYZED ) );
321     }
322 
323     public boolean updateArtifactInfo( Document doc, ArtifactInfo ai )
324     {
325         boolean res = false;
326 
327         String uinfo = doc.get( ArtifactInfo.UINFO );
328 
329         if ( uinfo != null )
330         {
331             String[] r = ArtifactInfo.FS_PATTERN.split( uinfo );
332 
333             ai.groupId = r[0];
334 
335             ai.artifactId = r[1];
336 
337             ai.version = r[2];
338 
339             if ( r.length > 3 )
340             {
341                 ai.classifier = ArtifactInfo.renvl( r[3] );
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.packaging = r[0];
354 
355             ai.lastModified = Long.parseLong( r[1] );
356 
357             ai.size = Long.parseLong( r[2] );
358 
359             ai.sourcesExists = ArtifactAvailablility.fromString( r[3] );
360 
361             ai.javadocExists = ArtifactAvailablility.fromString( r[4] );
362 
363             ai.signatureExists = ArtifactAvailablility.fromString( r[5] );
364 
365             if ( r.length > 6 )
366             {
367                 ai.fextension = r[6];
368             }
369             else
370             {
371                 if ( ai.classifier != null //
372                     || "pom".equals( ai.packaging ) //
373                     || "war".equals( ai.packaging ) //
374                     || "ear".equals( ai.packaging ) )
375                 {
376                     ai.fextension = ai.packaging;
377                 }
378                 else
379                 {
380                     ai.fextension = "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.name = name;
392 
393             res = true;
394         }
395 
396         String description = doc.get( ArtifactInfo.DESCRIPTION );
397 
398         if ( description != null )
399         {
400             ai.description = 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.packaging ) )
408         {
409             ai.packaging = null;
410         }
411 
412         String sha1 = doc.get( ArtifactInfo.SHA1 );
413 
414         if ( sha1 != null )
415         {
416             ai.sha1 = 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 }