View Javadoc
1   package org.apache.maven.plugin.descriptor;
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 org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.ArtifactUtils;
24  import org.apache.maven.model.Plugin;
25  import org.apache.maven.plugin.lifecycle.Lifecycle;
26  import org.apache.maven.plugin.lifecycle.LifecycleConfiguration;
27  import org.apache.maven.plugin.lifecycle.io.xpp3.LifecycleMappingsXpp3Reader;
28  import org.codehaus.plexus.classworlds.realm.ClassRealm;
29  import org.codehaus.plexus.component.repository.ComponentSetDescriptor;
30  import org.codehaus.plexus.util.ReaderFactory;
31  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
32  
33  import java.io.File;
34  import java.io.FileInputStream;
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.io.Reader;
38  import java.net.MalformedURLException;
39  import java.net.URL;
40  import java.util.Collections;
41  import java.util.HashMap;
42  import java.util.List;
43  import java.util.Map;
44  import java.util.Set;
45  
46  /**
47   * @author Jason van Zyl
48   */
49  public class PluginDescriptor
50      extends ComponentSetDescriptor
51      implements Cloneable
52  {
53  
54      private static final String LIFECYCLE_DESCRIPTOR = "META-INF/maven/lifecycle.xml";
55  
56      private String groupId;
57  
58      private String artifactId;
59  
60      private String version;
61  
62      private String goalPrefix;
63  
64      private String source;
65  
66      private boolean inheritedByDefault = true;
67  
68      private List<Artifact> artifacts;
69  
70      private ClassRealm classRealm;
71  
72      // calculated on-demand.
73      private Map<String, Artifact> artifactMap;
74  
75      private Set<Artifact> introducedDependencyArtifacts;
76  
77      private String name;
78  
79      private String description;
80  
81      private String requiredMavenVersion;
82  
83      private Plugin plugin;
84  
85      private Artifact pluginArtifact;
86  
87      private Map<String, Lifecycle> lifecycleMappings;
88  
89      // ----------------------------------------------------------------------
90      //
91      // ----------------------------------------------------------------------
92  
93      @SuppressWarnings( { "unchecked", "rawtypes" } )
94      public List<MojoDescriptor> getMojos()
95      {
96          return (List) getComponents();
97      }
98  
99      public void addMojo( MojoDescriptor mojoDescriptor )
100         throws DuplicateMojoDescriptorException
101     {
102         MojoDescriptor existing = null;
103         // this relies heavily on the equals() and hashCode() for ComponentDescriptor,
104         // which uses role:roleHint for identity...and roleHint == goalPrefix:goal.
105         // role does not vary for Mojos.
106         List<MojoDescriptor> mojos = getMojos();
107 
108         if ( mojos != null && mojos.contains( mojoDescriptor ) )
109         {
110             int indexOf = mojos.indexOf( mojoDescriptor );
111 
112             existing = mojos.get( indexOf );
113         }
114 
115         if ( existing != null )
116         {
117             throw new DuplicateMojoDescriptorException( getGoalPrefix(), mojoDescriptor.getGoal(),
118                                                         existing.getImplementation(),
119                                                         mojoDescriptor.getImplementation() );
120         }
121         else
122         {
123             addComponentDescriptor( mojoDescriptor );
124         }
125     }
126 
127     public String getGroupId()
128     {
129         return groupId;
130     }
131 
132     public void setGroupId( String groupId )
133     {
134         this.groupId = groupId;
135     }
136 
137     public String getArtifactId()
138     {
139         return artifactId;
140     }
141 
142     public void setArtifactId( String artifactId )
143     {
144         this.artifactId = artifactId;
145     }
146 
147     // ----------------------------------------------------------------------
148     // Dependencies
149     // ----------------------------------------------------------------------
150 
151     public static String constructPluginKey( String groupId, String artifactId, String version )
152     {
153         return groupId + ":" + artifactId + ":" + version;
154     }
155 
156     public String getPluginLookupKey()
157     {
158         return groupId + ":" + artifactId;
159     }
160 
161     public String getId()
162     {
163         return constructPluginKey( groupId, artifactId, version );
164     }
165 
166     public static String getDefaultPluginArtifactId( String id )
167     {
168         return "maven-" + id + "-plugin";
169     }
170 
171     public static String getDefaultPluginGroupId()
172     {
173         return "org.apache.maven.plugins";
174     }
175 
176     /**
177      * Parse maven-...-plugin.
178      *
179      * TODO move to plugin-tools-api as a default only
180      */
181     public static String getGoalPrefixFromArtifactId( String artifactId )
182     {
183         if ( "maven-plugin-plugin".equals( artifactId ) )
184         {
185             return "plugin";
186         }
187         else
188         {
189             return artifactId.replaceAll( "-?maven-?", "" ).replaceAll( "-?plugin-?", "" );
190         }
191     }
192 
193     public String getGoalPrefix()
194     {
195         return goalPrefix;
196     }
197 
198     public void setGoalPrefix( String goalPrefix )
199     {
200         this.goalPrefix = goalPrefix;
201     }
202 
203     public void setVersion( String version )
204     {
205         this.version = version;
206     }
207 
208     public String getVersion()
209     {
210         return version;
211     }
212 
213     public void setSource( String source )
214     {
215         this.source = source;
216     }
217 
218     public String getSource()
219     {
220         return source;
221     }
222 
223     public boolean isInheritedByDefault()
224     {
225         return inheritedByDefault;
226     }
227 
228     public void setInheritedByDefault( boolean inheritedByDefault )
229     {
230         this.inheritedByDefault = inheritedByDefault;
231     }
232 
233     /**
234      * Gets the artifacts that make up the plugin's class realm, excluding artifacts shadowed by the Maven core realm
235      * like {@code maven-project}.
236      *
237      * @return The plugin artifacts, never {@code null}.
238      */
239     public List<Artifact> getArtifacts()
240     {
241         return artifacts;
242     }
243 
244     public void setArtifacts( List<Artifact> artifacts )
245     {
246         this.artifacts = artifacts;
247 
248         // clear the calculated artifactMap
249         artifactMap = null;
250     }
251 
252     /**
253      * The map of artifacts accessible by the versionlessKey, i.e. groupId:artifactId
254      *
255      * @return a Map of artifacts, never {@code null}
256      * @see #getArtifacts()
257      */
258     public Map<String, Artifact> getArtifactMap()
259     {
260         if ( artifactMap == null )
261         {
262             artifactMap = ArtifactUtils.artifactMapByVersionlessId( getArtifacts() );
263         }
264 
265         return artifactMap;
266     }
267 
268     public boolean equals( Object object )
269     {
270         if ( this == object )
271         {
272             return true;
273         }
274 
275         return object instanceof PluginDescriptor && getId().equals( ( (PluginDescriptor) object ).getId() );
276     }
277 
278     public int hashCode()
279     {
280         return 10 + getId().hashCode();
281     }
282 
283     public MojoDescriptor getMojo( String goal )
284     {
285         if ( getMojos() == null )
286         {
287             return null; // no mojo in this POM
288         }
289 
290         // TODO could we use a map? Maybe if the parent did that for components too, as this is too vulnerable to
291         // changes above not being propagated to the map
292         for ( MojoDescriptor desc : getMojos() )
293         {
294             if ( goal.equals( desc.getGoal() ) )
295             {
296                 return desc;
297             }
298         }
299         return null;
300     }
301 
302     public void setClassRealm( ClassRealm classRealm )
303     {
304         this.classRealm = classRealm;
305     }
306 
307     public ClassRealm getClassRealm()
308     {
309         return classRealm;
310     }
311 
312     public void setIntroducedDependencyArtifacts( Set<Artifact> introducedDependencyArtifacts )
313     {
314         this.introducedDependencyArtifacts = introducedDependencyArtifacts;
315     }
316 
317     public Set<Artifact> getIntroducedDependencyArtifacts()
318     {
319         return ( introducedDependencyArtifacts != null )
320             ? introducedDependencyArtifacts
321             : Collections.<Artifact>emptySet();
322     }
323 
324     public void setName( String name )
325     {
326         this.name = name;
327     }
328 
329     public String getName()
330     {
331         return name;
332     }
333 
334     public void setDescription( String description )
335     {
336         this.description = description;
337     }
338 
339     public String getDescription()
340     {
341         return description;
342     }
343 
344     public void setRequiredMavenVersion( String requiredMavenVersion )
345     {
346         this.requiredMavenVersion = requiredMavenVersion;
347     }
348 
349     public String getRequiredMavenVersion()
350     {
351         return requiredMavenVersion;
352     }
353 
354     public void setPlugin( Plugin plugin )
355     {
356         this.plugin = plugin;
357     }
358 
359     public Plugin getPlugin()
360     {
361         return plugin;
362     }
363 
364     public Artifact getPluginArtifact()
365     {
366         return pluginArtifact;
367     }
368 
369     public void setPluginArtifact( Artifact pluginArtifact )
370     {
371         this.pluginArtifact = pluginArtifact;
372     }
373 
374     public Lifecycle getLifecycleMapping( String lifecycleId )
375         throws IOException, XmlPullParserException
376     {
377         if ( lifecycleMappings == null )
378         {
379             LifecycleConfiguration lifecycleConfiguration;
380 
381             try ( Reader reader = ReaderFactory.newXmlReader( getDescriptorStream( LIFECYCLE_DESCRIPTOR ) ) )
382             {
383                 lifecycleConfiguration = new LifecycleMappingsXpp3Reader().read( reader );
384             }
385 
386             lifecycleMappings = new HashMap<>();
387 
388             for ( Lifecycle lifecycle : lifecycleConfiguration.getLifecycles() )
389             {
390                 lifecycleMappings.put( lifecycle.getId(), lifecycle );
391             }
392         }
393 
394         return lifecycleMappings.get( lifecycleId );
395     }
396 
397     private InputStream getDescriptorStream( String descriptor )
398         throws IOException
399     {
400         File pluginFile = ( pluginArtifact != null ) ? pluginArtifact.getFile() : null;
401         if ( pluginFile == null )
402         {
403             throw new IllegalStateException( "plugin main artifact has not been resolved for " + getId() );
404         }
405 
406         if ( pluginFile.isFile() )
407         {
408             try
409             {
410                 return new URL( "jar:" + pluginFile.toURI() + "!/" + descriptor ).openStream();
411             }
412             catch ( MalformedURLException e )
413             {
414                 throw new IllegalStateException( e );
415             }
416         }
417         else
418         {
419             return new FileInputStream( new File( pluginFile, descriptor ) );
420         }
421     }
422 
423     /**
424      * Creates a shallow copy of this plugin descriptor.
425      */
426     @Override
427     public PluginDescriptor clone()
428     {
429         try
430         {
431             return (PluginDescriptor) super.clone();
432         }
433         catch ( CloneNotSupportedException e )
434         {
435             throw new UnsupportedOperationException( e );
436         }
437     }
438 
439 }