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.BufferedInputStream;
25  import java.io.File;
26  import java.io.InputStream;
27  import java.io.InputStreamReader;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Collection;
31  import java.util.zip.ZipEntry;
32  import java.util.zip.ZipFile;
33  
34  import org.apache.lucene.document.Document;
35  import org.apache.maven.index.ArtifactContext;
36  import org.apache.maven.index.ArtifactInfo;
37  import org.apache.maven.index.IndexerField;
38  import org.apache.maven.index.IndexerFieldVersion;
39  import org.apache.maven.index.MAVEN;
40  import org.codehaus.plexus.util.xml.Xpp3Dom;
41  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
42  
43  /**
44   * A Maven Plugin index creator used to provide information about Maven Plugins. It will collect the plugin prefix and
45   * the goals the plugin provides. Also, the Lucene document and the returned ArtifactInfo will be correctly filled with
46   * these information.
47   * 
48   * @author cstamas
49   */
50  @Singleton
51  @Named( MavenPluginArtifactInfoIndexCreator.ID )
52  public class MavenPluginArtifactInfoIndexCreator
53      extends AbstractIndexCreator
54  {
55      public static final String ID = "maven-plugin";
56  
57      private static final String MAVEN_PLUGIN_PACKAGING = "maven-plugin";
58  
59      public static final IndexerField FLD_PLUGIN_PREFIX = new IndexerField( MAVEN.PLUGIN_PREFIX, IndexerFieldVersion.V1,
60          "px", "MavenPlugin prefix (as keyword, stored)", IndexerField.KEYWORD_STORED );
61  
62      public static final IndexerField FLD_PLUGIN_GOALS = new IndexerField( MAVEN.PLUGIN_GOALS, IndexerFieldVersion.V1,
63          "gx", "MavenPlugin goals (as keyword, stored)", IndexerField.ANALYZED_STORED );
64  
65      public MavenPluginArtifactInfoIndexCreator()
66      {
67          super( ID, Arrays.asList( MinimalArtifactInfoIndexCreator.ID ) );
68      }
69  
70      public void populateArtifactInfo( ArtifactContext ac )
71      {
72          File artifact = ac.getArtifact();
73  
74          ArtifactInfo ai = ac.getArtifactInfo();
75  
76          // we need the file to perform these checks, and those may be only JARs
77          if ( artifact != null && MAVEN_PLUGIN_PACKAGING.equals( ai.getPackaging() )
78              && artifact.getName().endsWith( ".jar" ) )
79          {
80              // TODO: recheck, is the following true? "Maven plugins and Maven Archetypes can be only JARs?"
81  
82              // 1st, check for maven plugin
83              checkMavenPlugin( ai, artifact );
84          }
85      }
86  
87      private void checkMavenPlugin( ArtifactInfo ai, File artifact )
88      {
89          try ( ZipFile zipFile = new ZipFile( artifact ) )
90          {
91              final String pluginDescriptorPath = "META-INF/maven/plugin.xml";
92              ZipEntry zipEntry = zipFile.getEntry( pluginDescriptorPath );
93              if ( zipEntry != null )
94              {
95                  try ( InputStream is = new BufferedInputStream( zipFile.getInputStream( zipEntry ) ) )
96                  {
97                      // here the reader is closed
98                      Xpp3Dom plexusConfig =
99                          Xpp3DomBuilder.build( new InputStreamReader( is ) );
100 
101                     ai.setPrefix( plexusConfig.getChild( "goalPrefix" ).getValue() );
102 
103                     ai.setGoals( new ArrayList<>() );
104 
105                     Xpp3Dom[] mojoConfigs = plexusConfig.getChild( "mojos" ).getChildren( "mojo" );
106 
107                     for ( Xpp3Dom mojoConfig : mojoConfigs )
108                     {
109                         ai.getGoals().add( mojoConfig.getChild( "goal" ).getValue() );
110                     }
111                 }
112             }
113         }
114         catch ( Exception e )
115         {
116             if ( getLogger().isDebugEnabled() )
117             {
118                 getLogger().info(
119                     "Failed to parse Maven artifact " + artifact.getAbsolutePath() + " due to exception:", e );
120             }
121             else
122             {
123                 getLogger().info(
124                     "Failed to parse Maven artifact " + artifact.getAbsolutePath() + " due to " + e.getMessage() );
125             }
126         }
127     }
128 
129     public void updateDocument( ArtifactInfo ai, Document doc )
130     {
131         if ( ai.getPrefix() != null )
132         {
133             doc.add( FLD_PLUGIN_PREFIX.toField( ai.getPrefix() ) );
134         }
135 
136         if ( ai.getGoals() != null )
137         {
138             doc.add( FLD_PLUGIN_GOALS.toField( ArtifactInfo.lst2str( ai.getGoals() ) ) );
139         }
140     }
141 
142     public boolean updateArtifactInfo( Document doc, ArtifactInfo ai )
143     {
144         boolean res = false;
145 
146         if ( "maven-plugin".equals( ai.getPackaging() ) )
147         {
148             ai.setPrefix( doc.get( ArtifactInfo.PLUGIN_PREFIX ) );
149 
150             String goals = doc.get( ArtifactInfo.PLUGIN_GOALS );
151 
152             if ( goals != null )
153             {
154                 ai.setGoals( ArtifactInfo.str2lst( goals ) );
155             }
156 
157             res = true;
158         }
159 
160         return res;
161     }
162 
163     @Override
164     public String toString()
165     {
166         return ID;
167     }
168 
169     public Collection<IndexerField> getIndexerFields()
170     {
171         return Arrays.asList( FLD_PLUGIN_GOALS, FLD_PLUGIN_PREFIX );
172     }
173 }