001 package org.apache.maven.plugin.descriptor;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.File;
023 import java.io.FileInputStream;
024 import java.io.IOException;
025 import java.io.InputStream;
026 import java.io.Reader;
027 import java.net.MalformedURLException;
028 import java.net.URL;
029 import java.util.Collections;
030 import java.util.HashMap;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.Set;
034
035 import org.apache.maven.artifact.Artifact;
036 import org.apache.maven.artifact.ArtifactUtils;
037 import org.apache.maven.model.Plugin;
038 import org.apache.maven.plugin.lifecycle.Lifecycle;
039 import org.apache.maven.plugin.lifecycle.LifecycleConfiguration;
040 import org.apache.maven.plugin.lifecycle.io.xpp3.LifecycleMappingsXpp3Reader;
041 import org.codehaus.plexus.classworlds.realm.ClassRealm;
042 import org.codehaus.plexus.component.repository.ComponentSetDescriptor;
043 import org.codehaus.plexus.util.IOUtil;
044 import org.codehaus.plexus.util.ReaderFactory;
045 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
046
047 /**
048 * @author Jason van Zyl
049 */
050 public class PluginDescriptor
051 extends ComponentSetDescriptor
052 implements Cloneable
053 {
054
055 private static final String LIFECYCLE_DESCRIPTOR = "META-INF/maven/lifecycle.xml";
056
057 private String groupId;
058
059 private String artifactId;
060
061 private String version;
062
063 private String goalPrefix;
064
065 private String source;
066
067 private boolean inheritedByDefault = true;
068
069 private List<Artifact> artifacts;
070
071 private ClassRealm classRealm;
072
073 // calculated on-demand.
074 private Map<String, Artifact> artifactMap;
075
076 private Set<Artifact> introducedDependencyArtifacts;
077
078 private String name;
079
080 private String description;
081
082 private String requiredMavenVersion;
083
084 private Plugin plugin;
085
086 private Artifact pluginArtifact;
087
088 private Map<String, Lifecycle> lifecycleMappings;
089
090 // ----------------------------------------------------------------------
091 //
092 // ----------------------------------------------------------------------
093
094 @SuppressWarnings( { "unchecked", "rawtypes" } )
095 public List<MojoDescriptor> getMojos()
096 {
097 return (List) getComponents();
098 }
099
100 public void addMojo( MojoDescriptor mojoDescriptor )
101 throws DuplicateMojoDescriptorException
102 {
103 MojoDescriptor existing = null;
104 // this relies heavily on the equals() and hashCode() for ComponentDescriptor,
105 // which uses role:roleHint for identity...and roleHint == goalPrefix:goal.
106 // role does not vary for Mojos.
107 List<MojoDescriptor> mojos = getMojos();
108
109 if ( mojos != null && mojos.contains( mojoDescriptor ) )
110 {
111 int indexOf = mojos.indexOf( mojoDescriptor );
112
113 existing = mojos.get( indexOf );
114 }
115
116 if ( existing != null )
117 {
118 throw new DuplicateMojoDescriptorException( getGoalPrefix(), mojoDescriptor.getGoal(), existing
119 .getImplementation(), 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 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 ) ? introducedDependencyArtifacts
320 : Collections.<Artifact> emptySet();
321 }
322
323 public void setName( String name )
324 {
325 this.name = name;
326 }
327
328 public String getName()
329 {
330 return name;
331 }
332
333 public void setDescription( String description )
334 {
335 this.description = description;
336 }
337
338 public String getDescription()
339 {
340 return description;
341 }
342
343 public void setRequiredMavenVersion( String requiredMavenVersion )
344 {
345 this.requiredMavenVersion = requiredMavenVersion;
346 }
347
348 public String getRequiredMavenVersion()
349 {
350 return requiredMavenVersion;
351 }
352
353 public void setPlugin( Plugin plugin )
354 {
355 this.plugin = plugin;
356 }
357
358 public Plugin getPlugin()
359 {
360 return plugin;
361 }
362
363 public Artifact getPluginArtifact()
364 {
365 return pluginArtifact;
366 }
367
368 public void setPluginArtifact( Artifact pluginArtifact )
369 {
370 this.pluginArtifact = pluginArtifact;
371 }
372
373 public Lifecycle getLifecycleMapping( String lifecycleId )
374 throws IOException, XmlPullParserException
375 {
376 if ( lifecycleMappings == null )
377 {
378 LifecycleConfiguration lifecycleConfiguration;
379
380 Reader reader = null;
381 try
382 {
383 reader = ReaderFactory.newXmlReader( getDescriptorStream( LIFECYCLE_DESCRIPTOR ) );
384
385 lifecycleConfiguration = new LifecycleMappingsXpp3Reader().read( reader );
386 }
387 finally
388 {
389 IOUtil.close( reader );
390 }
391
392 lifecycleMappings = new HashMap<String, Lifecycle>();
393
394 for ( Lifecycle lifecycle : lifecycleConfiguration.getLifecycles() )
395 {
396 lifecycleMappings.put( lifecycle.getId(), lifecycle );
397 }
398 }
399
400 return lifecycleMappings.get( lifecycleId );
401 }
402
403 private InputStream getDescriptorStream( String descriptor )
404 throws IOException
405 {
406 File pluginFile = ( pluginArtifact != null ) ? pluginArtifact.getFile() : null;
407 if ( pluginFile == null )
408 {
409 throw new IllegalStateException( "plugin main artifact has not been resolved for " + getId() );
410 }
411
412 if ( pluginFile.isFile() )
413 {
414 try
415 {
416 return new URL( "jar:" + pluginFile.toURI() + "!/" + descriptor ).openStream();
417 }
418 catch ( MalformedURLException e )
419 {
420 throw new IllegalStateException( e );
421 }
422 }
423 else
424 {
425 return new FileInputStream( new File( pluginFile, descriptor ) );
426 }
427 }
428
429 /**
430 * Creates a shallow copy of this plugin descriptor.
431 */
432 @Override
433 public PluginDescriptor clone()
434 {
435 try
436 {
437 return (PluginDescriptor) super.clone();
438 }
439 catch ( CloneNotSupportedException e )
440 {
441 throw new UnsupportedOperationException( e );
442 }
443 }
444
445 }