View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.descriptor;
20  
21  import javax.xml.stream.XMLStreamException;
22  import javax.xml.stream.XMLStreamReader;
23  
24  import java.io.BufferedInputStream;
25  import java.io.BufferedReader;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.Reader;
29  import java.util.ArrayList;
30  import java.util.List;
31  import java.util.Optional;
32  
33  import com.ctc.wstx.stax.WstxInputFactory;
34  import org.apache.maven.api.xml.XmlNode;
35  import org.apache.maven.internal.xml.XmlNodeStaxBuilder;
36  import org.apache.maven.internal.xml.XmlPlexusConfiguration;
37  import org.apache.maven.plugin.descriptor.io.PluginDescriptorStaxReader;
38  import org.codehaus.plexus.component.repository.ComponentDependency;
39  import org.codehaus.plexus.component.repository.ComponentRequirement;
40  import org.codehaus.plexus.configuration.PlexusConfiguration;
41  import org.codehaus.plexus.configuration.PlexusConfigurationException;
42  
43  /**
44   * Build plugin descriptor object from {@code plugin.xml}.
45   *
46   * @author Jason van Zyl
47   */
48  public class PluginDescriptorBuilder {
49  
50      public static final String PLUGIN_2_0_0 = "http://maven.apache.org/PLUGIN/2.0.0";
51      private static final int BUFFER_SIZE = 8192;
52  
53      public interface StreamSupplier {
54          InputStream open() throws IOException;
55      }
56  
57      public interface ReaderSupplier {
58          Reader open() throws IOException;
59      }
60  
61      /**
62       * @deprecated use {@link #build(ReaderSupplier)}
63       */
64      @Deprecated
65      public PluginDescriptor build(Reader reader) throws PlexusConfigurationException {
66          return build(reader, null);
67      }
68  
69      /**
70       * @deprecated use {@link #build(ReaderSupplier, String)}
71       */
72      @Deprecated
73      public PluginDescriptor build(Reader reader, String source) throws PlexusConfigurationException {
74          return build(() -> reader, source);
75      }
76  
77      public PluginDescriptor build(ReaderSupplier readerSupplier) throws PlexusConfigurationException {
78          return build(readerSupplier, null);
79      }
80  
81      public PluginDescriptor build(ReaderSupplier readerSupplier, String source) throws PlexusConfigurationException {
82          try (BufferedReader br = new BufferedReader(readerSupplier.open(), BUFFER_SIZE)) {
83              br.mark(BUFFER_SIZE);
84              XMLStreamReader xsr = WstxInputFactory.newFactory().createXMLStreamReader(br);
85              xsr.nextTag();
86              String nsUri = xsr.getNamespaceURI();
87              try (BufferedReader br2 = reset(readerSupplier, br)) {
88                  xsr = WstxInputFactory.newFactory().createXMLStreamReader(br2);
89                  return build(source, nsUri, xsr);
90              }
91          } catch (XMLStreamException | IOException e) {
92              throw new PlexusConfigurationException(e.getMessage(), e);
93          }
94      }
95  
96      /**
97       * @deprecated use {@link #build(StreamSupplier, String)}
98       */
99      @Deprecated
100     public PluginDescriptor build(InputStream input, String source) throws PlexusConfigurationException {
101         return build(() -> input, source);
102     }
103 
104     public PluginDescriptor build(StreamSupplier inputSupplier) throws PlexusConfigurationException {
105         return build(inputSupplier, null);
106     }
107 
108     public PluginDescriptor build(StreamSupplier inputSupplier, String source) throws PlexusConfigurationException {
109         try (BufferedInputStream bis = new BufferedInputStream(inputSupplier.open(), BUFFER_SIZE)) {
110             bis.mark(BUFFER_SIZE);
111             XMLStreamReader xsr = WstxInputFactory.newFactory().createXMLStreamReader(bis);
112             xsr.nextTag();
113             String nsUri = xsr.getNamespaceURI();
114             try (BufferedInputStream bis2 = reset(inputSupplier, bis)) {
115                 xsr = WstxInputFactory.newFactory().createXMLStreamReader(bis2);
116                 return build(source, nsUri, xsr);
117             }
118         } catch (XMLStreamException | IOException e) {
119             throw new PlexusConfigurationException(e.getMessage(), e);
120         }
121     }
122 
123     private static BufferedInputStream reset(StreamSupplier inputSupplier, BufferedInputStream bis) throws IOException {
124         try {
125             bis.reset();
126             return bis;
127         } catch (IOException e) {
128             return new BufferedInputStream(inputSupplier.open(), BUFFER_SIZE);
129         }
130     }
131 
132     private static BufferedReader reset(ReaderSupplier readerSupplier, BufferedReader br) throws IOException {
133         try {
134             br.reset();
135             return br;
136         } catch (IOException e) {
137             return new BufferedReader(readerSupplier.open(), BUFFER_SIZE);
138         }
139     }
140 
141     private PluginDescriptor build(String source, String nsUri, XMLStreamReader xsr)
142             throws XMLStreamException, PlexusConfigurationException {
143         if (PLUGIN_2_0_0.equals(nsUri)) {
144             org.apache.maven.api.plugin.descriptor.PluginDescriptor pd =
145                     new PluginDescriptorStaxReader().read(xsr, true);
146             return new PluginDescriptor(pd);
147         } else {
148             XmlNode node = XmlNodeStaxBuilder.build(xsr, true, null);
149             PlexusConfiguration cfg = XmlPlexusConfiguration.toPlexusConfiguration(node);
150             return build(source, cfg);
151         }
152     }
153 
154     private PluginDescriptor build(String source, PlexusConfiguration c) throws PlexusConfigurationException {
155         PluginDescriptor pluginDescriptor = new PluginDescriptor();
156 
157         pluginDescriptor.setSource(source);
158         pluginDescriptor.setGroupId(extractGroupId(c));
159         pluginDescriptor.setArtifactId(extractArtifactId(c));
160         pluginDescriptor.setVersion(extractVersion(c));
161         pluginDescriptor.setGoalPrefix(extractGoalPrefix(c));
162 
163         pluginDescriptor.setName(extractName(c));
164         pluginDescriptor.setDescription(extractDescription(c));
165 
166         pluginDescriptor.setIsolatedRealm(extractIsolatedRealm(c));
167         pluginDescriptor.setInheritedByDefault(extractInheritedByDefault(c));
168         pluginDescriptor.setRequiredJavaVersion(extractRequiredJavaVersion(c).orElse(null));
169         pluginDescriptor.setRequiredMavenVersion(extractRequiredMavenVersion(c).orElse(null));
170 
171         pluginDescriptor.addMojos(extractMojos(c, pluginDescriptor));
172 
173         pluginDescriptor.setDependencies(extractComponentDependencies(c));
174 
175         return pluginDescriptor;
176     }
177 
178     private String extractGroupId(PlexusConfiguration c) {
179         return c.getChild("groupId").getValue();
180     }
181 
182     private String extractArtifactId(PlexusConfiguration c) {
183         return c.getChild("artifactId").getValue();
184     }
185 
186     private String extractVersion(PlexusConfiguration c) {
187         return c.getChild("version").getValue();
188     }
189 
190     private String extractGoalPrefix(PlexusConfiguration c) {
191         return c.getChild("goalPrefix").getValue();
192     }
193 
194     private String extractName(PlexusConfiguration c) {
195         return c.getChild("name").getValue();
196     }
197 
198     private String extractDescription(PlexusConfiguration c) {
199         return c.getChild("description").getValue();
200     }
201 
202     private List<MojoDescriptor> extractMojos(PlexusConfiguration c, PluginDescriptor pluginDescriptor)
203             throws PlexusConfigurationException {
204         List<MojoDescriptor> mojos = new ArrayList<>();
205 
206         PlexusConfiguration[] mojoConfigurations = c.getChild("mojos").getChildren("mojo");
207 
208         for (PlexusConfiguration component : mojoConfigurations) {
209             mojos.add(buildComponentDescriptor(component, pluginDescriptor));
210         }
211         return mojos;
212     }
213 
214     private boolean extractInheritedByDefault(PlexusConfiguration c) {
215         String inheritedByDefault = c.getChild("inheritedByDefault").getValue();
216 
217         if (inheritedByDefault != null) {
218             return Boolean.parseBoolean(inheritedByDefault);
219         }
220         return false;
221     }
222 
223     private boolean extractIsolatedRealm(PlexusConfiguration c) {
224         String isolatedRealm = c.getChild("isolatedRealm").getValue();
225 
226         if (isolatedRealm != null) {
227             return Boolean.parseBoolean(isolatedRealm);
228         }
229         return false;
230     }
231 
232     private Optional<String> extractRequiredJavaVersion(PlexusConfiguration c) {
233         return Optional.ofNullable(c.getChild("requiredJavaVersion")).map(PlexusConfiguration::getValue);
234     }
235 
236     private Optional<String> extractRequiredMavenVersion(PlexusConfiguration c) {
237         return Optional.ofNullable(c.getChild("requiredMavenVersion")).map(PlexusConfiguration::getValue);
238     }
239 
240     private List<ComponentDependency> extractComponentDependencies(PlexusConfiguration c) {
241 
242         PlexusConfiguration[] dependencyConfigurations =
243                 c.getChild("dependencies").getChildren("dependency");
244 
245         List<ComponentDependency> dependencies = new ArrayList<>();
246 
247         for (PlexusConfiguration d : dependencyConfigurations) {
248             dependencies.add(extractComponentDependency(d));
249         }
250         return dependencies;
251     }
252 
253     private ComponentDependency extractComponentDependency(PlexusConfiguration d) {
254         ComponentDependency cd = new ComponentDependency();
255 
256         cd.setArtifactId(extractArtifactId(d));
257 
258         cd.setGroupId(extractGroupId(d));
259 
260         cd.setType(d.getChild("type").getValue());
261 
262         cd.setVersion(extractVersion(d));
263         return cd;
264     }
265 
266     @SuppressWarnings("checkstyle:methodlength")
267     public MojoDescriptor buildComponentDescriptor(PlexusConfiguration c, PluginDescriptor pluginDescriptor)
268             throws PlexusConfigurationException {
269         MojoDescriptor mojo = new MojoDescriptor();
270         mojo.setPluginDescriptor(pluginDescriptor);
271 
272         mojo.setGoal(c.getChild("goal").getValue());
273 
274         mojo.setImplementation(c.getChild("implementation").getValue());
275 
276         PlexusConfiguration langConfig = c.getChild("language");
277 
278         if (langConfig != null) {
279             mojo.setLanguage(langConfig.getValue());
280         }
281 
282         PlexusConfiguration configuratorConfig = c.getChild("configurator");
283 
284         if (configuratorConfig != null) {
285             mojo.setComponentConfigurator(configuratorConfig.getValue());
286         }
287 
288         PlexusConfiguration composerConfig = c.getChild("composer");
289 
290         if (composerConfig != null) {
291             mojo.setComponentComposer(composerConfig.getValue());
292         }
293 
294         String since = c.getChild("since").getValue();
295 
296         if (since != null) {
297             mojo.setSince(since);
298         }
299 
300         PlexusConfiguration deprecated = c.getChild("deprecated", false);
301 
302         if (deprecated != null) {
303             mojo.setDeprecated(deprecated.getValue());
304         }
305 
306         String phase = c.getChild("phase").getValue();
307 
308         if (phase != null) {
309             mojo.setPhase(phase);
310         }
311 
312         String executePhase = c.getChild("executePhase").getValue();
313 
314         if (executePhase != null) {
315             mojo.setExecutePhase(executePhase);
316         }
317 
318         String executeMojo = c.getChild("executeGoal").getValue();
319 
320         if (executeMojo != null) {
321             mojo.setExecuteGoal(executeMojo);
322         }
323 
324         String executeLifecycle = c.getChild("executeLifecycle").getValue();
325 
326         if (executeLifecycle != null) {
327             mojo.setExecuteLifecycle(executeLifecycle);
328         }
329 
330         mojo.setInstantiationStrategy(c.getChild("instantiationStrategy").getValue());
331 
332         mojo.setDescription(extractDescription(c));
333 
334         PlexusConfiguration dependencyResolution = c.getChild("requiresDependencyResolution", false);
335 
336         if (dependencyResolution != null) {
337             mojo.setDependencyResolutionRequired(dependencyResolution.getValue());
338         }
339 
340         PlexusConfiguration dependencyCollection = c.getChild("requiresDependencyCollection", false);
341 
342         if (dependencyCollection != null) {
343             mojo.setDependencyCollectionRequired(dependencyCollection.getValue());
344         }
345 
346         String directInvocationOnly = c.getChild("requiresDirectInvocation").getValue();
347 
348         if (directInvocationOnly != null) {
349             mojo.setDirectInvocationOnly(Boolean.parseBoolean(directInvocationOnly));
350         }
351 
352         String requiresProject = c.getChild("requiresProject").getValue();
353 
354         if (requiresProject != null) {
355             mojo.setProjectRequired(Boolean.parseBoolean(requiresProject));
356         }
357 
358         String requiresReports = c.getChild("requiresReports").getValue();
359 
360         if (requiresReports != null) {
361             mojo.setRequiresReports(Boolean.parseBoolean(requiresReports));
362         }
363 
364         String aggregator = c.getChild("aggregator").getValue();
365 
366         if (aggregator != null) {
367             mojo.setAggregator(Boolean.parseBoolean(aggregator));
368         }
369 
370         String requiresOnline = c.getChild("requiresOnline").getValue();
371 
372         if (requiresOnline != null) {
373             mojo.setOnlineRequired(Boolean.parseBoolean(requiresOnline));
374         }
375 
376         String inheritedByDefault = c.getChild("inheritedByDefault").getValue();
377 
378         if (inheritedByDefault != null) {
379             mojo.setInheritedByDefault(Boolean.parseBoolean(inheritedByDefault));
380         }
381 
382         String threadSafe = c.getChild("threadSafe").getValue();
383 
384         if (threadSafe != null) {
385             mojo.setThreadSafe(Boolean.parseBoolean(threadSafe));
386         }
387 
388         String v4Api = c.getChild("v4Api").getValue();
389 
390         if (v4Api != null) {
391             mojo.setV4Api(Boolean.parseBoolean(v4Api));
392         }
393 
394         // ----------------------------------------------------------------------
395         // Configuration
396         // ----------------------------------------------------------------------
397 
398         PlexusConfiguration mojoConfig = c.getChild("configuration");
399         mojo.setMojoConfiguration(mojoConfig);
400 
401         // ----------------------------------------------------------------------
402         // Parameters
403         // ----------------------------------------------------------------------
404 
405         PlexusConfiguration[] parameterConfigurations = c.getChild("parameters").getChildren("parameter");
406 
407         List<Parameter> parameters = new ArrayList<>();
408 
409         for (PlexusConfiguration d : parameterConfigurations) {
410             Parameter parameter = new Parameter();
411 
412             parameter.setName(extractName(d));
413 
414             parameter.setAlias(d.getChild("alias").getValue());
415 
416             parameter.setType(d.getChild("type").getValue());
417 
418             String required = d.getChild("required").getValue();
419 
420             parameter.setRequired(Boolean.parseBoolean(required));
421 
422             PlexusConfiguration editableConfig = d.getChild("editable");
423 
424             // we need the null check for pre-build legacy plugins...
425             if (editableConfig != null) {
426                 String editable = d.getChild("editable").getValue();
427 
428                 parameter.setEditable(editable == null || Boolean.parseBoolean(editable));
429             }
430 
431             parameter.setDescription(extractDescription(d));
432 
433             parameter.setDeprecated(d.getChild("deprecated").getValue());
434 
435             parameter.setImplementation(d.getChild("implementation").getValue());
436 
437             parameter.setSince(d.getChild("since").getValue());
438 
439             PlexusConfiguration paramConfig = mojoConfig.getChild(parameter.getName(), false);
440             if (paramConfig != null) {
441                 parameter.setExpression(paramConfig.getValue(null));
442                 parameter.setDefaultValue(paramConfig.getAttribute("default-value"));
443             }
444 
445             parameters.add(parameter);
446         }
447 
448         mojo.setParameters(parameters);
449 
450         // TODO this should not need to be handed off...
451 
452         // ----------------------------------------------------------------------
453         // Requirements
454         // ----------------------------------------------------------------------
455 
456         PlexusConfiguration[] requirements = c.getChild("requirements").getChildren("requirement");
457 
458         for (PlexusConfiguration requirement : requirements) {
459             ComponentRequirement cr = new ComponentRequirement();
460 
461             cr.setRole(requirement.getChild("role").getValue());
462 
463             cr.setRoleHint(requirement.getChild("role-hint").getValue());
464 
465             cr.setFieldName(requirement.getChild("field-name").getValue());
466 
467             mojo.addRequirement(cr);
468         }
469 
470         return mojo;
471     }
472 
473     // ----------------------------------------------------------------------
474     //
475     // ----------------------------------------------------------------------
476 
477     public PlexusConfiguration buildConfiguration(Reader configuration) throws PlexusConfigurationException {
478         try {
479             XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(configuration);
480             return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeStaxBuilder.build(reader, true, null));
481         } catch (XMLStreamException e) {
482             throw new PlexusConfigurationException(e.getMessage(), e);
483         }
484     }
485 
486     public PlexusConfiguration buildConfiguration(InputStream configuration) throws PlexusConfigurationException {
487         try {
488             XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(configuration);
489             return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeStaxBuilder.build(reader, true, null));
490         } catch (XMLStreamException e) {
491             throw new PlexusConfigurationException(e.getMessage(), e);
492         }
493     }
494 }