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