View Javadoc
1   // =================== DO NOT EDIT THIS FILE ====================
2   //  Generated by Modello Velocity from reader-stax.vm
3   //  template, any modifications will be overwritten.
4   // ==============================================================
5   package org.apache.maven.plugin.descriptor.io;
6   
7   import java.io.IOException;
8   import java.io.InputStream;
9   import java.io.Reader;
10  import java.text.DateFormat;
11  import java.util.ArrayDeque;
12  import java.util.ArrayList;
13  import java.util.Collections;
14  import java.util.Date;
15  import java.util.Deque;
16  import java.util.HashMap;
17  import java.util.HashSet;
18  import java.util.LinkedHashMap;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Set;
22  import org.apache.maven.api.annotations.Generated;
23  import org.apache.maven.api.plugin.descriptor.PluginDescriptor;
24  import org.apache.maven.api.plugin.descriptor.MojoDescriptor;
25  import org.apache.maven.api.plugin.descriptor.Parameter;
26  import org.apache.maven.api.plugin.descriptor.Requirement;
27  import org.apache.maven.api.plugin.descriptor.Dependency;
28  import org.apache.maven.api.plugin.descriptor.Resolution;
29  import org.apache.maven.internal.xml.XmlNodeStaxBuilder;
30  import org.apache.maven.api.xml.XmlNode;
31  import javax.xml.stream.XMLInputFactory;
32  import javax.xml.stream.XMLStreamException;
33  import javax.xml.stream.XMLStreamReader;
34  import javax.xml.transform.stream.StreamSource;
35  
36  import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
37  import static javax.xml.XMLConstants.XML_NS_URI;
38  
39  @Generated
40  public class PluginDescriptorStaxReader {
41  
42      private static final Map<String, String> DEFAULT_ENTITIES;
43      static {
44          Map<String, String> entities = new HashMap<>();
45          entities.put("nbsp", "\u00a0");
46          entities.put("iexcl", "\u00a1");
47          entities.put("cent", "\u00a2");
48          entities.put("pound", "\u00a3");
49          entities.put("curren", "\u00a4");
50          entities.put("yen", "\u00a5");
51          entities.put("brvbar", "\u00a6");
52          entities.put("sect", "\u00a7");
53          entities.put("uml", "\u00a8");
54          entities.put("copy", "\u00a9");
55          entities.put("ordf", "\u00aa");
56          entities.put("laquo", "\u00ab");
57          entities.put("not", "\u00ac");
58          entities.put("shy", "\u00ad");
59          entities.put("reg", "\u00ae");
60          entities.put("macr", "\u00af");
61          entities.put("deg", "\u00b0");
62          entities.put("plusmn", "\u00b1");
63          entities.put("sup2", "\u00b2");
64          entities.put("sup3", "\u00b3");
65          entities.put("acute", "\u00b4");
66          entities.put("micro", "\u00b5");
67          entities.put("para", "\u00b6");
68          entities.put("middot", "\u00b7");
69          entities.put("cedil", "\u00b8");
70          entities.put("sup1", "\u00b9");
71          entities.put("ordm", "\u00ba");
72          entities.put("raquo", "\u00bb");
73          entities.put("frac14", "\u00bc");
74          entities.put("frac12", "\u00bd");
75          entities.put("frac34", "\u00be");
76          entities.put("iquest", "\u00bf");
77          entities.put("Agrave", "\u00c0");
78          entities.put("Aacute", "\u00c1");
79          entities.put("Acirc", "\u00c2");
80          entities.put("Atilde", "\u00c3");
81          entities.put("Auml", "\u00c4");
82          entities.put("Aring", "\u00c5");
83          entities.put("AElig", "\u00c6");
84          entities.put("Ccedil", "\u00c7");
85          entities.put("Egrave", "\u00c8");
86          entities.put("Eacute", "\u00c9");
87          entities.put("Ecirc", "\u00ca");
88          entities.put("Euml", "\u00cb");
89          entities.put("Igrave", "\u00cc");
90          entities.put("Iacute", "\u00cd");
91          entities.put("Icirc", "\u00ce");
92          entities.put("Iuml", "\u00cf");
93          entities.put("ETH", "\u00d0");
94          entities.put("Ntilde", "\u00d1");
95          entities.put("Ograve", "\u00d2");
96          entities.put("Oacute", "\u00d3");
97          entities.put("Ocirc", "\u00d4");
98          entities.put("Otilde", "\u00d5");
99          entities.put("Ouml", "\u00d6");
100         entities.put("times", "\u00d7");
101         entities.put("Oslash", "\u00d8");
102         entities.put("Ugrave", "\u00d9");
103         entities.put("Uacute", "\u00da");
104         entities.put("Ucirc", "\u00db");
105         entities.put("Uuml", "\u00dc");
106         entities.put("Yacute", "\u00dd");
107         entities.put("THORN", "\u00de");
108         entities.put("szlig", "\u00df");
109         entities.put("agrave", "\u00e0");
110         entities.put("aacute", "\u00e1");
111         entities.put("acirc", "\u00e2");
112         entities.put("atilde", "\u00e3");
113         entities.put("auml", "\u00e4");
114         entities.put("aring", "\u00e5");
115         entities.put("aelig", "\u00e6");
116         entities.put("ccedil", "\u00e7");
117         entities.put("egrave", "\u00e8");
118         entities.put("eacute", "\u00e9");
119         entities.put("ecirc", "\u00ea");
120         entities.put("euml", "\u00eb");
121         entities.put("igrave", "\u00ec");
122         entities.put("iacute", "\u00ed");
123         entities.put("icirc", "\u00ee");
124         entities.put("iuml", "\u00ef");
125         entities.put("eth", "\u00f0");
126         entities.put("ntilde", "\u00f1");
127         entities.put("ograve", "\u00f2");
128         entities.put("oacute", "\u00f3");
129         entities.put("ocirc", "\u00f4");
130         entities.put("otilde", "\u00f5");
131         entities.put("ouml", "\u00f6");
132         entities.put("divide", "\u00f7");
133         entities.put("oslash", "\u00f8");
134         entities.put("ugrave", "\u00f9");
135         entities.put("uacute", "\u00fa");
136         entities.put("ucirc", "\u00fb");
137         entities.put("uuml", "\u00fc");
138         entities.put("yacute", "\u00fd");
139         entities.put("thorn", "\u00fe");
140         entities.put("yuml", "\u00ff");
141 
142         // ----------------------------------------------------------------------
143         // Special entities
144         // ----------------------------------------------------------------------
145 
146         entities.put("OElig", "\u0152");
147         entities.put("oelig", "\u0153");
148         entities.put("Scaron", "\u0160");
149         entities.put("scaron", "\u0161");
150         entities.put("Yuml", "\u0178");
151         entities.put("circ", "\u02c6");
152         entities.put("tilde", "\u02dc");
153         entities.put("ensp", "\u2002");
154         entities.put("emsp", "\u2003");
155         entities.put("thinsp", "\u2009");
156         entities.put("zwnj", "\u200c");
157         entities.put("zwj", "\u200d");
158         entities.put("lrm", "\u200e");
159         entities.put("rlm", "\u200f");
160         entities.put("ndash", "\u2013");
161         entities.put("mdash", "\u2014");
162         entities.put("lsquo", "\u2018");
163         entities.put("rsquo", "\u2019");
164         entities.put("sbquo", "\u201a");
165         entities.put("ldquo", "\u201c");
166         entities.put("rdquo", "\u201d");
167         entities.put("bdquo", "\u201e");
168         entities.put("dagger", "\u2020");
169         entities.put("Dagger", "\u2021");
170         entities.put("permil", "\u2030");
171         entities.put("lsaquo", "\u2039");
172         entities.put("rsaquo", "\u203a");
173         entities.put("euro", "\u20ac");
174 
175         // ----------------------------------------------------------------------
176         // Symbol entities
177         // ----------------------------------------------------------------------
178 
179         entities.put("fnof", "\u0192");
180         entities.put("Alpha", "\u0391");
181         entities.put("Beta", "\u0392");
182         entities.put("Gamma", "\u0393");
183         entities.put("Delta", "\u0394");
184         entities.put("Epsilon", "\u0395");
185         entities.put("Zeta", "\u0396");
186         entities.put("Eta", "\u0397");
187         entities.put("Theta", "\u0398");
188         entities.put("Iota", "\u0399");
189         entities.put("Kappa", "\u039a");
190         entities.put("Lambda", "\u039b");
191         entities.put("Mu", "\u039c");
192         entities.put("Nu", "\u039d");
193         entities.put("Xi", "\u039e");
194         entities.put("Omicron", "\u039f");
195         entities.put("Pi", "\u03a0");
196         entities.put("Rho", "\u03a1");
197         entities.put("Sigma", "\u03a3");
198         entities.put("Tau", "\u03a4");
199         entities.put("Upsilon", "\u03a5");
200         entities.put("Phi", "\u03a6");
201         entities.put("Chi", "\u03a7");
202         entities.put("Psi", "\u03a8");
203         entities.put("Omega", "\u03a9");
204         entities.put("alpha", "\u03b1");
205         entities.put("beta", "\u03b2");
206         entities.put("gamma", "\u03b3");
207         entities.put("delta", "\u03b4");
208         entities.put("epsilon", "\u03b5");
209         entities.put("zeta", "\u03b6");
210         entities.put("eta", "\u03b7");
211         entities.put("theta", "\u03b8");
212         entities.put("iota", "\u03b9");
213         entities.put("kappa", "\u03ba");
214         entities.put("lambda", "\u03bb");
215         entities.put("mu", "\u03bc");
216         entities.put("nu", "\u03bd");
217         entities.put("xi", "\u03be");
218         entities.put("omicron", "\u03bf");
219         entities.put("pi", "\u03c0");
220         entities.put("rho", "\u03c1");
221         entities.put("sigmaf", "\u03c2");
222         entities.put("sigma", "\u03c3");
223         entities.put("tau", "\u03c4");
224         entities.put("upsilon", "\u03c5");
225         entities.put("phi", "\u03c6");
226         entities.put("chi", "\u03c7");
227         entities.put("psi", "\u03c8");
228         entities.put("omega", "\u03c9");
229         entities.put("thetasym", "\u03d1");
230         entities.put("upsih", "\u03d2");
231         entities.put("piv", "\u03d6");
232         entities.put("bull", "\u2022");
233         entities.put("hellip", "\u2026");
234         entities.put("prime", "\u2032");
235         entities.put("Prime", "\u2033");
236         entities.put("oline", "\u203e");
237         entities.put("frasl", "\u2044");
238         entities.put("weierp", "\u2118");
239         entities.put("image", "\u2111");
240         entities.put("real", "\u211c");
241         entities.put("trade", "\u2122");
242         entities.put("alefsym", "\u2135");
243         entities.put("larr", "\u2190");
244         entities.put("uarr", "\u2191");
245         entities.put("rarr", "\u2192");
246         entities.put("darr", "\u2193");
247         entities.put("harr", "\u2194");
248         entities.put("crarr", "\u21b5");
249         entities.put("lArr", "\u21d0");
250         entities.put("uArr", "\u21d1");
251         entities.put("rArr", "\u21d2");
252         entities.put("dArr", "\u21d3");
253         entities.put("hArr", "\u21d4");
254         entities.put("forall", "\u2200");
255         entities.put("part", "\u2202");
256         entities.put("exist", "\u2203");
257         entities.put("empty", "\u2205");
258         entities.put("nabla", "\u2207");
259         entities.put("isin", "\u2208");
260         entities.put("notin", "\u2209");
261         entities.put("ni", "\u220b");
262         entities.put("prod", "\u220f");
263         entities.put("sum", "\u2211");
264         entities.put("minus", "\u2212");
265         entities.put("lowast", "\u2217");
266         entities.put("radic", "\u221a");
267         entities.put("prop", "\u221d");
268         entities.put("infin", "\u221e");
269         entities.put("ang", "\u2220");
270         entities.put("and", "\u2227");
271         entities.put("or", "\u2228");
272         entities.put("cap", "\u2229");
273         entities.put("cup", "\u222a");
274         entities.put("int", "\u222b");
275         entities.put("there4", "\u2234");
276         entities.put("sim", "\u223c");
277         entities.put("cong", "\u2245");
278         entities.put("asymp", "\u2248");
279         entities.put("ne", "\u2260");
280         entities.put("equiv", "\u2261");
281         entities.put("le", "\u2264");
282         entities.put("ge", "\u2265");
283         entities.put("sub", "\u2282");
284         entities.put("sup", "\u2283");
285         entities.put("nsub", "\u2284");
286         entities.put("sube", "\u2286");
287         entities.put("supe", "\u2287");
288         entities.put("oplus", "\u2295");
289         entities.put("otimes", "\u2297");
290         entities.put("perp", "\u22a5");
291         entities.put("sdot", "\u22c5");
292         entities.put("lceil", "\u2308");
293         entities.put("rceil", "\u2309");
294         entities.put("lfloor", "\u230a");
295         entities.put("rfloor", "\u230b");
296         entities.put("lang", "\u2329");
297         entities.put("rang", "\u232a");
298         entities.put("loz", "\u25ca");
299         entities.put("spades", "\u2660");
300         entities.put("clubs", "\u2663");
301         entities.put("hearts", "\u2665");
302         entities.put("diams", "\u2666");
303         DEFAULT_ENTITIES = Collections.unmodifiableMap(entities);
304     }
305 
306     static class InputFactoryHolder {
307         static XMLInputFactory XML_INPUT_FACTORY;
308         static {
309             XMLInputFactory factory = XMLInputFactory.newFactory();
310             factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
311             XML_INPUT_FACTORY = factory;
312         }
313     }
314 
315     private boolean addDefaultEntities = true;
316 
317     private final ContentTransformer contentTransformer;
318 
319     public PluginDescriptorStaxReader() {
320         this((s, f) -> s);
321     }
322 
323     public PluginDescriptorStaxReader(ContentTransformer contentTransformer) {
324         this.contentTransformer = contentTransformer;
325     }
326 
327     /**
328      * Returns the {@link XMLInputFactory} used by this reader.
329      *
330      * @return the {@link XMLInputFactory} used by this reader.
331      */
332     public XMLInputFactory getXMLInputFactory() {
333         return InputFactoryHolder.XML_INPUT_FACTORY;
334     }
335 
336     /**
337      * Returns the state of the "add default entities" flag.
338      *
339      * @return boolean
340      */
341     public boolean getAddDefaultEntities() {
342         return addDefaultEntities;
343     } //-- boolean getAddDefaultEntities()
344 
345     /**
346      * Sets the state of the "add default entities" flag.
347      *
348      * @param addDefaultEntities a addDefaultEntities object.
349      */
350     public void setAddDefaultEntities(boolean addDefaultEntities) {
351         this.addDefaultEntities = addDefaultEntities;
352     } //-- void setAddDefaultEntities(boolean)
353 
354 
355     public PluginDescriptor read(Reader reader) throws XMLStreamException {
356         return read(reader, true);
357     }
358 
359     /**
360      * @param reader a reader object.
361      * @param strict a strict object.
362      * @throws XMLStreamException XMLStreamException if
363      * any.
364      * @return PluginDescriptor
365      */
366     public PluginDescriptor read(Reader reader, boolean strict) throws XMLStreamException {
367         StreamSource streamSource = new StreamSource(reader);
368         XMLInputFactory factory = getXMLInputFactory();
369         XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
370     return read(parser, strict);
371     } //-- PluginDescriptor read(Reader, boolean)
372 
373     public PluginDescriptor read(InputStream in) throws XMLStreamException {
374         return read(in, true);
375     }
376 
377     /**
378      * Method read.
379      *
380      * @param in a in object.
381      * @param strict a strict object.
382      * @throws XMLStreamException XMLStreamException if
383      * any.
384      * @return PluginDescriptor
385      */
386     public PluginDescriptor read(InputStream in, boolean strict) throws XMLStreamException {
387         StreamSource streamSource = new StreamSource(in);
388         XMLInputFactory factory = getXMLInputFactory();
389         XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
390         return read(parser, strict);
391     } //-- PluginDescriptor read(InputStream, boolean)
392 
393     /**
394      * Method read.
395      *
396      * @param parser a parser object.
397      * @param strict a strict object.
398      * @throws XMLStreamException XMLStreamException if
399      * any.
400      * @return PluginDescriptor
401      */
402     public PluginDescriptor read(XMLStreamReader parser, boolean strict) throws XMLStreamException {
403         Deque<Object> context = new ArrayDeque<>();
404         PluginDescriptor pluginDescriptor = null;
405         int eventType = parser.getEventType();
406         boolean parsed = false;
407         while (eventType != XMLStreamReader.END_DOCUMENT) {
408             if (eventType == XMLStreamReader.START_ELEMENT) {
409                 if (strict && ! "plugin".equals(parser.getLocalName())) {
410                     throw new XMLStreamException("Expected root element 'plugin' but found '" + parser.getName() + "'", parser.getLocation(), null);
411                 } else if (parsed) {
412                     // fallback, already expected a XMLStreamException due to invalid XML
413                     throw new XMLStreamException("Duplicated tag: 'plugin'", parser.getLocation(), null);
414                 }
415                 pluginDescriptor = parsePluginDescriptor(parser, strict, context);
416                 parsed = true;
417             }
418             eventType = parser.next();
419         }
420         if (parsed) {
421             return pluginDescriptor;
422         }
423         throw new XMLStreamException("Expected root element 'plugin' but found no element at all: invalid XML document", parser.getLocation(), null);
424     } //-- PluginDescriptor read(XMLStreamReader, boolean)
425 
426     private PluginDescriptor parsePluginDescriptor(XMLStreamReader parser, boolean strict, Deque<Object> context) throws XMLStreamException {
427         String tagName = parser.getLocalName();
428         PluginDescriptor.Builder pluginDescriptor = PluginDescriptor.newBuilder(true);
429         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
430             String name = parser.getAttributeLocalName(i);
431             String ns = parser.getAttributeNamespace(i);
432             String value = parser.getAttributeValue(i);
433             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
434                 // just ignore attributes with non-default namespace (for example: xsi and xml)
435             } else if ("xmlns".equals(name)) {
436                 // ignore xmlns attribute in root class, which is a reserved attribute name
437             } else {
438                 checkUnknownAttribute(parser, name, tagName, strict);
439             }
440         }
441         Set<String> parsed = new HashSet<>();
442         context.addLast( pluginDescriptor );
443         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
444             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
445             switch (childName) {
446                 case "name": {
447                     pluginDescriptor.name(interpolatedTrimmed(nextText(parser, strict), "name"));
448                     break;
449                 }
450                 case "description": {
451                     pluginDescriptor.description(interpolatedTrimmed(nextText(parser, strict), "description"));
452                     break;
453                 }
454                 case "groupId": {
455                     pluginDescriptor.groupId(interpolatedTrimmed(nextText(parser, strict), "groupId"));
456                     break;
457                 }
458                 case "artifactId": {
459                     pluginDescriptor.artifactId(interpolatedTrimmed(nextText(parser, strict), "artifactId"));
460                     break;
461                 }
462                 case "version": {
463                     pluginDescriptor.version(interpolatedTrimmed(nextText(parser, strict), "version"));
464                     break;
465                 }
466                 case "goalPrefix": {
467                     pluginDescriptor.goalPrefix(interpolatedTrimmed(nextText(parser, strict), "goalPrefix"));
468                     break;
469                 }
470                 case "isolatedRealm": {
471                     pluginDescriptor.isolatedRealm(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "isolatedRealm"), "isolatedRealm", parser, false));
472                     break;
473                 }
474                 case "inheritedByDefault": {
475                     pluginDescriptor.inheritedByDefault(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "inheritedByDefault"), "inheritedByDefault", parser, true));
476                     break;
477                 }
478                 case "requiredJavaVersion": {
479                     pluginDescriptor.requiredJavaVersion(interpolatedTrimmed(nextText(parser, strict), "requiredJavaVersion"));
480                     break;
481                 }
482                 case "requiredMavenVersion": {
483                     pluginDescriptor.requiredMavenVersion(interpolatedTrimmed(nextText(parser, strict), "requiredMavenVersion"));
484                     break;
485                 }
486                 case "mojos": {
487                     List<MojoDescriptor> mojos = new ArrayList<>();
488                     while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
489                         if ("mojo".equals(parser.getLocalName())) {
490                             mojos.add(parseMojoDescriptor(parser, strict, context));
491                         } else {
492                             checkUnknownElement(parser, strict);
493                         }
494                     }
495                     pluginDescriptor.mojos(mojos);
496                     break;
497                 }
498                 default: {
499                     checkUnknownElement(parser, strict);
500                     break;
501                 }
502             }
503         }
504         context.removeLast();
505         pluginDescriptor.namespaceUri(parser.getNamespaceURI());
506         pluginDescriptor.modelEncoding(parser.getEncoding());
507         return pluginDescriptor.build();
508     }
509 
510     private MojoDescriptor parseMojoDescriptor(XMLStreamReader parser, boolean strict, Deque<Object> context) throws XMLStreamException {
511         String tagName = parser.getLocalName();
512         MojoDescriptor.Builder mojoDescriptor = MojoDescriptor.newBuilder(true);
513         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
514             String name = parser.getAttributeLocalName(i);
515             String ns = parser.getAttributeNamespace(i);
516             String value = parser.getAttributeValue(i);
517             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
518                 // just ignore attributes with non-default namespace (for example: xsi and xml)
519             } else {
520                 checkUnknownAttribute(parser, name, tagName, strict);
521             }
522         }
523         Set<String> parsed = new HashSet<>();
524         context.addLast( mojoDescriptor );
525         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
526             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
527             switch (childName) {
528                 case "goal": {
529                     mojoDescriptor.goal(interpolatedTrimmed(nextText(parser, strict), "goal"));
530                     break;
531                 }
532                 case "description": {
533                     mojoDescriptor.description(interpolatedTrimmed(nextText(parser, strict), "description"));
534                     break;
535                 }
536                 case "implementation": {
537                     mojoDescriptor.implementation(interpolatedTrimmed(nextText(parser, strict), "implementation"));
538                     break;
539                 }
540                 case "language": {
541                     mojoDescriptor.language(interpolatedTrimmed(nextText(parser, strict), "language"));
542                     break;
543                 }
544                 case "phase": {
545                     mojoDescriptor.phase(interpolatedTrimmed(nextText(parser, strict), "phase"));
546                     break;
547                 }
548                 case "executePhase": {
549                     mojoDescriptor.executePhase(interpolatedTrimmed(nextText(parser, strict), "executePhase"));
550                     break;
551                 }
552                 case "executeGoal": {
553                     mojoDescriptor.executeGoal(interpolatedTrimmed(nextText(parser, strict), "executeGoal"));
554                     break;
555                 }
556                 case "executeLifecycle": {
557                     mojoDescriptor.executeLifecycle(interpolatedTrimmed(nextText(parser, strict), "executeLifecycle"));
558                     break;
559                 }
560                 case "dependencyResolution": {
561                     mojoDescriptor.dependencyResolution(interpolatedTrimmed(nextText(parser, strict), "dependencyResolution"));
562                     break;
563                 }
564                 case "dependencyCollection": {
565                     mojoDescriptor.dependencyCollection(interpolatedTrimmed(nextText(parser, strict), "dependencyCollection"));
566                     break;
567                 }
568                 case "directInvocationOnly": {
569                     mojoDescriptor.directInvocationOnly(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "directInvocationOnly"), "directInvocationOnly", parser, false));
570                     break;
571                 }
572                 case "projectRequired": {
573                     mojoDescriptor.projectRequired(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "projectRequired"), "projectRequired", parser, true));
574                     break;
575                 }
576                 case "onlineRequired": {
577                     mojoDescriptor.onlineRequired(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "onlineRequired"), "onlineRequired", parser, false));
578                     break;
579                 }
580                 case "aggregator": {
581                     mojoDescriptor.aggregator(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "aggregator"), "aggregator", parser, false));
582                     break;
583                 }
584                 case "inheritedByDefault": {
585                     mojoDescriptor.inheritedByDefault(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "inheritedByDefault"), "inheritedByDefault", parser, true));
586                     break;
587                 }
588                 case "since": {
589                     mojoDescriptor.since(interpolatedTrimmed(nextText(parser, strict), "since"));
590                     break;
591                 }
592                 case "deprecated": {
593                     mojoDescriptor.deprecated(interpolatedTrimmed(nextText(parser, strict), "deprecated"));
594                     break;
595                 }
596                 case "configurator": {
597                     mojoDescriptor.configurator(interpolatedTrimmed(nextText(parser, strict), "configurator"));
598                     break;
599                 }
600                 case "parameters": {
601                     List<Parameter> parameters = new ArrayList<>();
602                     while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
603                         if ("parameter".equals(parser.getLocalName())) {
604                             parameters.add(parseParameter(parser, strict, context));
605                         } else {
606                             checkUnknownElement(parser, strict);
607                         }
608                     }
609                     mojoDescriptor.parameters(parameters);
610                     break;
611                 }
612                 case "resolutions": {
613                     List<Resolution> resolutions = new ArrayList<>();
614                     while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
615                         if ("resolution".equals(parser.getLocalName())) {
616                             resolutions.add(parseResolution(parser, strict, context));
617                         } else {
618                             checkUnknownElement(parser, strict);
619                         }
620                     }
621                     mojoDescriptor.resolutions(resolutions);
622                     break;
623                 }
624                 default: {
625                     checkUnknownElement(parser, strict);
626                     break;
627                 }
628             }
629         }
630         context.removeLast();
631         mojoDescriptor.id(((PluginDescriptor.Builder) context.peekLast()).build().getId() + ":" + mojoDescriptor.build().getGoal());
632         mojoDescriptor.fullGoalName(((PluginDescriptor.Builder) context.peekLast()).build().getGoalPrefix() + ":" + mojoDescriptor.build().getGoal());
633         return mojoDescriptor.build();
634     }
635 
636     private Parameter parseParameter(XMLStreamReader parser, boolean strict, Deque<Object> context) throws XMLStreamException {
637         String tagName = parser.getLocalName();
638         Parameter.Builder parameter = Parameter.newBuilder(true);
639         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
640             String name = parser.getAttributeLocalName(i);
641             String ns = parser.getAttributeNamespace(i);
642             String value = parser.getAttributeValue(i);
643             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
644                 // just ignore attributes with non-default namespace (for example: xsi and xml)
645             } else {
646                 checkUnknownAttribute(parser, name, tagName, strict);
647             }
648         }
649         Set<String> parsed = new HashSet<>();
650         context.addLast( parameter );
651         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
652             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
653             switch (childName) {
654                 case "name": {
655                     parameter.name(interpolatedTrimmed(nextText(parser, strict), "name"));
656                     break;
657                 }
658                 case "alias": {
659                     parameter.alias(interpolatedTrimmed(nextText(parser, strict), "alias"));
660                     break;
661                 }
662                 case "type": {
663                     parameter.type(interpolatedTrimmed(nextText(parser, strict), "type"));
664                     break;
665                 }
666                 case "required": {
667                     parameter.required(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "required"), "required", parser, false));
668                     break;
669                 }
670                 case "editable": {
671                     parameter.editable(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "editable"), "editable", parser, true));
672                     break;
673                 }
674                 case "description": {
675                     parameter.description(interpolatedTrimmed(nextText(parser, strict), "description"));
676                     break;
677                 }
678                 case "since": {
679                     parameter.since(interpolatedTrimmed(nextText(parser, strict), "since"));
680                     break;
681                 }
682                 case "deprecated": {
683                     parameter.deprecated(interpolatedTrimmed(nextText(parser, strict), "deprecated"));
684                     break;
685                 }
686                 case "expression": {
687                     parameter.expression(interpolatedTrimmed(nextText(parser, strict), "expression"));
688                     break;
689                 }
690                 case "defaultValue": {
691                     parameter.defaultValue(interpolatedTrimmed(nextText(parser, strict), "defaultValue"));
692                     break;
693                 }
694                 default: {
695                     checkUnknownElement(parser, strict);
696                     break;
697                 }
698             }
699         }
700         context.removeLast();
701         return parameter.build();
702     }
703 
704     private Requirement parseRequirement(XMLStreamReader parser, boolean strict, Deque<Object> context) throws XMLStreamException {
705         String tagName = parser.getLocalName();
706         Requirement.Builder requirement = Requirement.newBuilder(true);
707         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
708             String name = parser.getAttributeLocalName(i);
709             String ns = parser.getAttributeNamespace(i);
710             String value = parser.getAttributeValue(i);
711             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
712                 // just ignore attributes with non-default namespace (for example: xsi and xml)
713             } else {
714                 checkUnknownAttribute(parser, name, tagName, strict);
715             }
716         }
717         Set<String> parsed = new HashSet<>();
718         context.addLast( requirement );
719         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
720             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
721             switch (childName) {
722                 case "role": {
723                     requirement.role(interpolatedTrimmed(nextText(parser, strict), "role"));
724                     break;
725                 }
726                 case "role-hint": {
727                     requirement.roleHint(interpolatedTrimmed(nextText(parser, strict), "role-hint"));
728                     break;
729                 }
730                 case "field-name": {
731                     requirement.fieldName(interpolatedTrimmed(nextText(parser, strict), "field-name"));
732                     break;
733                 }
734                 default: {
735                     checkUnknownElement(parser, strict);
736                     break;
737                 }
738             }
739         }
740         context.removeLast();
741         return requirement.build();
742     }
743 
744     private Dependency parseDependency(XMLStreamReader parser, boolean strict, Deque<Object> context) throws XMLStreamException {
745         String tagName = parser.getLocalName();
746         Dependency.Builder dependency = Dependency.newBuilder(true);
747         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
748             String name = parser.getAttributeLocalName(i);
749             String ns = parser.getAttributeNamespace(i);
750             String value = parser.getAttributeValue(i);
751             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
752                 // just ignore attributes with non-default namespace (for example: xsi and xml)
753             } else {
754                 checkUnknownAttribute(parser, name, tagName, strict);
755             }
756         }
757         Set<String> parsed = new HashSet<>();
758         context.addLast( dependency );
759         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
760             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
761             switch (childName) {
762                 case "groupId": {
763                     dependency.groupId(interpolatedTrimmed(nextText(parser, strict), "groupId"));
764                     break;
765                 }
766                 case "artifactId": {
767                     dependency.artifactId(interpolatedTrimmed(nextText(parser, strict), "artifactId"));
768                     break;
769                 }
770                 case "version": {
771                     dependency.version(interpolatedTrimmed(nextText(parser, strict), "version"));
772                     break;
773                 }
774                 case "type": {
775                     dependency.type(interpolatedTrimmed(nextText(parser, strict), "type"));
776                     break;
777                 }
778                 default: {
779                     checkUnknownElement(parser, strict);
780                     break;
781                 }
782             }
783         }
784         context.removeLast();
785         return dependency.build();
786     }
787 
788     private Resolution parseResolution(XMLStreamReader parser, boolean strict, Deque<Object> context) throws XMLStreamException {
789         String tagName = parser.getLocalName();
790         Resolution.Builder resolution = Resolution.newBuilder(true);
791         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
792             String name = parser.getAttributeLocalName(i);
793             String ns = parser.getAttributeNamespace(i);
794             String value = parser.getAttributeValue(i);
795             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
796                 // just ignore attributes with non-default namespace (for example: xsi and xml)
797             } else {
798                 checkUnknownAttribute(parser, name, tagName, strict);
799             }
800         }
801         Set<String> parsed = new HashSet<>();
802         context.addLast( resolution );
803         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
804             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
805             switch (childName) {
806                 case "field": {
807                     resolution.field(interpolatedTrimmed(nextText(parser, strict), "field"));
808                     break;
809                 }
810                 case "pathScope": {
811                     resolution.pathScope(interpolatedTrimmed(nextText(parser, strict), "pathScope"));
812                     break;
813                 }
814                 case "requestType": {
815                     resolution.requestType(interpolatedTrimmed(nextText(parser, strict), "requestType"));
816                     break;
817                 }
818                 default: {
819                     checkUnknownElement(parser, strict);
820                     break;
821                 }
822             }
823         }
824         context.removeLast();
825         return resolution.build();
826     }
827 
828 
829     private String checkDuplicate(String tagName, XMLStreamReader parser, Set<String> parsed) throws XMLStreamException {
830         if (!parsed.add(tagName)) {
831             throw new XMLStreamException("Duplicated tag: '" + tagName + "'", parser.getLocation(), null);
832         }
833         return tagName;
834     }
835 
836     /**
837      * Method checkUnknownAttribute.
838      *
839      * @param parser a parser object.
840      * @param strict a strict object.
841      * @param tagName a tagName object.
842      * @param attribute a attribute object.
843      * @throws XMLStreamException XMLStreamException if
844      * any.
845      * @throws IOException IOException if any.
846      */
847     private void checkUnknownAttribute(XMLStreamReader parser, String attribute, String tagName, boolean strict) throws XMLStreamException {
848         // strictXmlAttributes = true for model: if strict == true, not only elements are checked but attributes too
849         if (strict) {
850             throw new XMLStreamException("Unknown attribute '" + attribute + "' for tag '" + tagName + "'", parser.getLocation(), null);
851         }
852     } //-- void checkUnknownAttribute(XMLStreamReader, String, String, boolean)
853 
854     /**
855      * Method checkUnknownElement.
856      *
857      * @param parser a parser object.
858      * @param strict a strict object.
859      * @throws XMLStreamException XMLStreamException if
860      * any.
861      * @throws IOException IOException if any.
862      */
863     private void checkUnknownElement(XMLStreamReader parser, boolean strict) throws XMLStreamException {
864         if (strict) {
865             throw new XMLStreamException("Unrecognised tag: '" + parser.getName() + "'", parser.getLocation(), null);
866         }
867 
868         for (int unrecognizedTagCount = 1; unrecognizedTagCount > 0;) {
869             int eventType = nextTag(parser);
870             if (eventType == XMLStreamReader.START_ELEMENT) {
871                 unrecognizedTagCount++;
872             } else if (eventType == XMLStreamReader.END_ELEMENT) {
873                 unrecognizedTagCount--;
874             }
875         }
876     } //-- void checkUnknownElement(XMLStreamReader, boolean)
877 
878     /**
879      * Method getTrimmedValue.
880      *
881      * @param s a s object.
882      * @return String
883      */
884     private String getTrimmedValue(String s) {
885         if (s != null) {
886             s = s.trim();
887         }
888         return s;
889     } //-- String getTrimmedValue(String)
890 
891     /**
892      * Method interpolatedTrimmed.
893      *
894      * @param value a value object.
895      * @param context a context object.
896      * @return String
897      */
898     private String interpolatedTrimmed(String value, String context) {
899         return getTrimmedValue(contentTransformer.transform(value, context));
900     } //-- String interpolatedTrimmed(String, String)
901 
902     /**
903      * Method nextTag.
904      *
905      * @param parser a parser object.
906      * @throws IOException IOException if any.
907      * @throws XMLStreamException XMLStreamException if
908      * any.
909      * @return int
910      */
911     private int nextTag(XMLStreamReader parser) throws XMLStreamException {
912         while (true) {
913             int next = parser.next();
914             switch (next) {
915                 case XMLStreamReader.SPACE:
916                 case XMLStreamReader.COMMENT:
917                 case XMLStreamReader.PROCESSING_INSTRUCTION:
918                 case XMLStreamReader.CDATA:
919                 case XMLStreamReader.CHARACTERS:
920                     continue;
921                 case XMLStreamReader.START_ELEMENT:
922                 case XMLStreamReader.END_ELEMENT:
923                     return next;
924             }
925         }
926     } //-- int nextTag(XMLStreamReader)
927 
928     private String nextText(XMLStreamReader parser, boolean strict) throws XMLStreamException {
929         int eventType = parser.getEventType();
930         if (eventType != XMLStreamReader.START_ELEMENT) {
931             throw new XMLStreamException("parser must be on START_ELEMENT to read next text", parser.getLocation(), null);
932         }
933         eventType = parser.next();
934         StringBuilder result = new StringBuilder();
935         while (true) {
936             if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
937                 result.append(parser.getText());
938             } else if (eventType == XMLStreamReader.ENTITY_REFERENCE) {
939                 String val = null;
940                 if (strict) {
941                     throw new XMLStreamException("Entities are not supported in strict mode", parser.getLocation(), null);
942                 } else if (addDefaultEntities) {
943                     val = DEFAULT_ENTITIES.get(parser.getLocalName());
944                 }
945                 if (val != null) {
946                     result.append(val);
947                 } else {
948                     result.append("&").append(parser.getLocalName()).append(";");
949                 }
950             } else if (eventType != XMLStreamReader.COMMENT) {
951                 break;
952             }
953             eventType = parser.next();
954         }
955         if (eventType != XMLStreamReader.END_ELEMENT) {
956             throw new XMLStreamException(
957                 "TEXT must be immediately followed by END_ELEMENT and not " + eventType /*TODO: TYPES[eventType]*/, parser.getLocation(), null);
958         }
959         return result.toString();
960     }
961 
962     private XmlNode buildXmlNode(XMLStreamReader parser) throws XMLStreamException {
963         return XmlNodeStaxBuilder.build(parser);
964     }
965 
966     /**
967      * Method getBooleanValue.
968      *
969      * @param s a s object.
970      * @param defaultValue a defaultValue object.
971      * @param parser a parser object.
972      * @param attribute a attribute object.
973      * @throws XMLStreamException XMLStreamException if
974      * any.
975      * @return boolean
976      */
977     private boolean getBooleanValue(String s, String attribute, XMLStreamReader parser, boolean defaultValue) throws XMLStreamException {
978         if (s != null && s.length() != 0) {
979             return Boolean.valueOf(s).booleanValue();
980         }
981         return defaultValue;
982     } //-- boolean getBooleanValue(String, String, XMLStreamReader, String)
983 
984     public static interface ContentTransformer {
985         /**
986          * Interpolate the value read from the xpp3 document
987          * @param source The source value
988          * @param fieldName A description of the field being interpolated. The implementation may use this to
989          *                           log stuff.
990          * @return The interpolated value.
991          */
992         String transform(String source, String fieldName);
993     }
994 
995 }