View Javadoc

1   /*
2    * $Id$
3    */
4   
5   package org.apache.maven.plugin.tools.model.io.xpp3;
6   
7     //---------------------------------/
8    //- Imported classes and packages -/
9   //---------------------------------/
10  
11  import java.io.ByteArrayInputStream;
12  import java.io.IOException;
13  import java.io.InputStreamReader;
14  import java.io.Reader;
15  import java.io.StringReader;
16  import java.io.StringWriter;
17  import java.text.DateFormat;
18  import java.text.ParsePosition;
19  import java.util.Locale;
20  import java.util.regex.Matcher;
21  import java.util.regex.Pattern;
22  import org.apache.maven.plugin.tools.model.Component;
23  import org.apache.maven.plugin.tools.model.LifecycleExecution;
24  import org.apache.maven.plugin.tools.model.Mojo;
25  import org.apache.maven.plugin.tools.model.Parameter;
26  import org.apache.maven.plugin.tools.model.PluginMetadata;
27  import org.codehaus.plexus.util.IOUtil;
28  import org.codehaus.plexus.util.xml.pull.MXParser;
29  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
30  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
31  
32  /**
33   * Class PluginMetadataXpp3Reader.
34   * 
35   * @version $Revision$ $Date$
36   */
37  public class PluginMetadataXpp3Reader {
38  
39  
40        //--------------------------/
41       //- Class/Member Variables -/
42      //--------------------------/
43  
44      /**
45       * If set the parser till be loaded with all single characters
46       * from the XHTML specification.
47       * The entities used:
48       * <ul>
49       * <li>http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent</li>
50       * <li>http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent</li>
51       * <li>http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent</li>
52       * </ul>
53       */
54      private boolean addDefaultEntities = true;
55  
56  
57        //-----------/
58       //- Methods -/
59      //-----------/
60  
61      /**
62       * Method getAddDefaultEntities
63       */
64      public boolean getAddDefaultEntities()
65      {
66          return addDefaultEntities;
67      } //-- boolean getAddDefaultEntities() 
68  
69      /**
70       * Method getBooleanValue
71       * 
72       * @param s
73       * @param parser
74       * @param attribute
75       */
76      public boolean getBooleanValue(String s, String attribute, XmlPullParser parser)
77          throws XmlPullParserException
78      {
79          if ( s != null )
80          {
81              return Boolean.valueOf( s ).booleanValue();
82          }
83          return false;
84      } //-- boolean getBooleanValue(String, String, XmlPullParser) 
85  
86      /**
87       * Method getCharacterValue
88       * 
89       * @param s
90       * @param parser
91       * @param attribute
92       */
93      public char getCharacterValue(String s, String attribute, XmlPullParser parser)
94          throws XmlPullParserException
95      {
96          if ( s != null )
97          {
98              return s.charAt( 0 );
99          }
100         return 0;
101     } //-- char getCharacterValue(String, String, XmlPullParser) 
102 
103     /**
104      * Method getDateValue
105      * 
106      * @param s
107      * @param parser
108      * @param dateFormat
109      * @param attribute
110      */
111     public java.util.Date getDateValue(String s, String attribute, String dateFormat, XmlPullParser parser)
112         throws XmlPullParserException
113     {
114         if ( s != null )
115         {
116             if ( dateFormat == null )
117             {
118                 return new java.util.Date( Long.valueOf( s ).longValue() );
119             }
120             else
121             {
122                 DateFormat dateParser = new java.text.SimpleDateFormat( dateFormat, Locale.US );
123                 try
124                 {
125                     return dateParser.parse( s );
126                 }
127                 catch ( java.text.ParseException e )
128                 {
129                     throw new XmlPullParserException( e.getMessage() );
130                 }
131             }
132         }
133         return null;
134     } //-- java.util.Date getDateValue(String, String, String, XmlPullParser) 
135 
136     /**
137      * Method getDoubleValue
138      * 
139      * @param s
140      * @param strict
141      * @param parser
142      * @param attribute
143      */
144     public double getDoubleValue(String s, String attribute, XmlPullParser parser, boolean strict)
145         throws XmlPullParserException
146     {
147         if ( s != null )
148         {
149             try
150             {
151                 return Double.valueOf( s ).doubleValue();
152             }
153             catch ( NumberFormatException e )
154             {
155                 if ( strict )
156                 {
157                     throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a floating point number", parser, null );
158                 }
159             }
160         }
161         return 0;
162     } //-- double getDoubleValue(String, String, XmlPullParser, boolean) 
163 
164     /**
165      * Method getFloatValue
166      * 
167      * @param s
168      * @param strict
169      * @param parser
170      * @param attribute
171      */
172     public float getFloatValue(String s, String attribute, XmlPullParser parser, boolean strict)
173         throws XmlPullParserException
174     {
175         if ( s != null )
176         {
177             try
178             {
179                 return Float.valueOf( s ).floatValue();
180             }
181             catch ( NumberFormatException e )
182             {
183                 if ( strict )
184                 {
185                     throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a floating point number", parser, null );
186                 }
187             }
188         }
189         return 0;
190     } //-- float getFloatValue(String, String, XmlPullParser, boolean) 
191 
192     /**
193      * Method getIntegerValue
194      * 
195      * @param s
196      * @param strict
197      * @param parser
198      * @param attribute
199      */
200     public int getIntegerValue(String s, String attribute, XmlPullParser parser, boolean strict)
201         throws XmlPullParserException
202     {
203         if ( s != null )
204         {
205             try
206             {
207                 return Integer.valueOf( s ).intValue();
208             }
209             catch ( NumberFormatException e )
210             {
211                 if ( strict )
212                 {
213                     throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be an integer", parser, null );
214                 }
215             }
216         }
217         return 0;
218     } //-- int getIntegerValue(String, String, XmlPullParser, boolean) 
219 
220     /**
221      * Method getLongValue
222      * 
223      * @param s
224      * @param strict
225      * @param parser
226      * @param attribute
227      */
228     public long getLongValue(String s, String attribute, XmlPullParser parser, boolean strict)
229         throws XmlPullParserException
230     {
231         if ( s != null )
232         {
233             try
234             {
235                 return Long.valueOf( s ).longValue();
236             }
237             catch ( NumberFormatException e )
238             {
239                 if ( strict )
240                 {
241                     throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a long integer", parser, null );
242                 }
243             }
244         }
245         return 0;
246     } //-- long getLongValue(String, String, XmlPullParser, boolean) 
247 
248     /**
249      * Method getRequiredAttributeValue
250      * 
251      * @param s
252      * @param strict
253      * @param parser
254      * @param attribute
255      */
256     public String getRequiredAttributeValue(String s, String attribute, XmlPullParser parser, boolean strict)
257         throws XmlPullParserException
258     {
259         if ( s == null )
260         {
261             if ( strict )
262             {
263                 throw new XmlPullParserException( "Missing required value for attribute '" + attribute + "'", parser, null );
264             }
265         }
266         return s;
267     } //-- String getRequiredAttributeValue(String, String, XmlPullParser, boolean) 
268 
269     /**
270      * Method getShortValue
271      * 
272      * @param s
273      * @param strict
274      * @param parser
275      * @param attribute
276      */
277     public short getShortValue(String s, String attribute, XmlPullParser parser, boolean strict)
278         throws XmlPullParserException
279     {
280         if ( s != null )
281         {
282             try
283             {
284                 return Short.valueOf( s ).shortValue();
285             }
286             catch ( NumberFormatException e )
287             {
288                 if ( strict )
289                 {
290                     throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a short integer", parser, null );
291                 }
292             }
293         }
294         return 0;
295     } //-- short getShortValue(String, String, XmlPullParser, boolean) 
296 
297     /**
298      * Method getTrimmedValue
299      * 
300      * @param s
301      */
302     public String getTrimmedValue(String s)
303     {
304         if ( s != null )
305         {
306             s = s.trim();
307         }
308         return s;
309     } //-- String getTrimmedValue(String) 
310 
311     /**
312      * Method parseComponent
313      * 
314      * @param tagName
315      * @param encoding
316      * @param strict
317      * @param parser
318      */
319     private Component parseComponent(String tagName, XmlPullParser parser, boolean strict, String encoding)
320         throws IOException, XmlPullParserException
321     {
322         Component component = new Component();
323         component.setModelEncoding( encoding );
324         java.util.Set parsed = new java.util.HashSet();
325         while ( parser.nextTag() == XmlPullParser.START_TAG )
326         {
327             if ( parser.getName().equals( "role" )  )
328             {
329                 if ( parsed.contains( "role" ) )
330                 {
331                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
332                 }
333                 parsed.add( "role" );
334                 component.setRole( getTrimmedValue( parser.nextText()) );
335             }
336             else if ( parser.getName().equals( "hint" )  )
337             {
338                 if ( parsed.contains( "hint" ) )
339                 {
340                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
341                 }
342                 parsed.add( "hint" );
343                 component.setHint( getTrimmedValue( parser.nextText()) );
344             }
345             else
346             {
347                 if ( strict )
348                 {
349                     throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null);
350                 }
351             }
352         }
353         return component;
354     } //-- Component parseComponent(String, XmlPullParser, boolean, String) 
355 
356     /**
357      * Method parseLifecycleExecution
358      * 
359      * @param tagName
360      * @param encoding
361      * @param strict
362      * @param parser
363      */
364     private LifecycleExecution parseLifecycleExecution(String tagName, XmlPullParser parser, boolean strict, String encoding)
365         throws IOException, XmlPullParserException
366     {
367         LifecycleExecution lifecycleExecution = new LifecycleExecution();
368         lifecycleExecution.setModelEncoding( encoding );
369         java.util.Set parsed = new java.util.HashSet();
370         while ( parser.nextTag() == XmlPullParser.START_TAG )
371         {
372             if ( parser.getName().equals( "lifecycle" )  )
373             {
374                 if ( parsed.contains( "lifecycle" ) )
375                 {
376                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
377                 }
378                 parsed.add( "lifecycle" );
379                 lifecycleExecution.setLifecycle( getTrimmedValue( parser.nextText()) );
380             }
381             else if ( parser.getName().equals( "phase" )  )
382             {
383                 if ( parsed.contains( "phase" ) )
384                 {
385                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
386                 }
387                 parsed.add( "phase" );
388                 lifecycleExecution.setPhase( getTrimmedValue( parser.nextText()) );
389             }
390             else if ( parser.getName().equals( "goal" )  )
391             {
392                 if ( parsed.contains( "goal" ) )
393                 {
394                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
395                 }
396                 parsed.add( "goal" );
397                 lifecycleExecution.setGoal( getTrimmedValue( parser.nextText()) );
398             }
399             else
400             {
401                 if ( strict )
402                 {
403                     throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null);
404                 }
405             }
406         }
407         return lifecycleExecution;
408     } //-- LifecycleExecution parseLifecycleExecution(String, XmlPullParser, boolean, String) 
409 
410     /**
411      * Method parseMojo
412      * 
413      * @param tagName
414      * @param encoding
415      * @param strict
416      * @param parser
417      */
418     private Mojo parseMojo(String tagName, XmlPullParser parser, boolean strict, String encoding)
419         throws IOException, XmlPullParserException
420     {
421         Mojo mojo = new Mojo();
422         mojo.setModelEncoding( encoding );
423         java.util.Set parsed = new java.util.HashSet();
424         while ( parser.nextTag() == XmlPullParser.START_TAG )
425         {
426             if ( parser.getName().equals( "goal" )  )
427             {
428                 if ( parsed.contains( "goal" ) )
429                 {
430                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
431                 }
432                 parsed.add( "goal" );
433                 mojo.setGoal( getTrimmedValue( parser.nextText()) );
434             }
435             else if ( parser.getName().equals( "phase" )  )
436             {
437                 if ( parsed.contains( "phase" ) )
438                 {
439                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
440                 }
441                 parsed.add( "phase" );
442                 mojo.setPhase( getTrimmedValue( parser.nextText()) );
443             }
444             else if ( parser.getName().equals( "aggregator" )  )
445             {
446                 if ( parsed.contains( "aggregator" ) )
447                 {
448                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
449                 }
450                 parsed.add( "aggregator" );
451                 mojo.setAggregator( getBooleanValue( getTrimmedValue( parser.nextText()), "aggregator", parser ) );
452             }
453             else if ( parser.getName().equals( "requiresDependencyResolution" )  )
454             {
455                 if ( parsed.contains( "requiresDependencyResolution" ) )
456                 {
457                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
458                 }
459                 parsed.add( "requiresDependencyResolution" );
460                 mojo.setRequiresDependencyResolution( getTrimmedValue( parser.nextText()) );
461             }
462             else if ( parser.getName().equals( "requiresProject" )  )
463             {
464                 if ( parsed.contains( "requiresProject" ) )
465                 {
466                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
467                 }
468                 parsed.add( "requiresProject" );
469                 mojo.setRequiresProject( getBooleanValue( getTrimmedValue( parser.nextText()), "requiresProject", parser ) );
470             }
471             else if ( parser.getName().equals( "requiresReports" )  )
472             {
473                 if ( parsed.contains( "requiresReports" ) )
474                 {
475                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
476                 }
477                 parsed.add( "requiresReports" );
478                 mojo.setRequiresReports( getBooleanValue( getTrimmedValue( parser.nextText()), "requiresReports", parser ) );
479             }
480             else if ( parser.getName().equals( "requiresOnline" )  )
481             {
482                 if ( parsed.contains( "requiresOnline" ) )
483                 {
484                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
485                 }
486                 parsed.add( "requiresOnline" );
487                 mojo.setRequiresOnline( getBooleanValue( getTrimmedValue( parser.nextText()), "requiresOnline", parser ) );
488             }
489             else if ( parser.getName().equals( "inheritByDefault" )  )
490             {
491                 if ( parsed.contains( "inheritByDefault" ) )
492                 {
493                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
494                 }
495                 parsed.add( "inheritByDefault" );
496                 mojo.setInheritByDefault( getBooleanValue( getTrimmedValue( parser.nextText()), "inheritByDefault", parser ) );
497             }
498             else if ( parser.getName().equals( "requiresDirectInvocation" )  )
499             {
500                 if ( parsed.contains( "requiresDirectInvocation" ) )
501                 {
502                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
503                 }
504                 parsed.add( "requiresDirectInvocation" );
505                 mojo.setRequiresDirectInvocation( getBooleanValue( getTrimmedValue( parser.nextText()), "requiresDirectInvocation", parser ) );
506             }
507             else if ( parser.getName().equals( "execution" )  )
508             {
509                 if ( parsed.contains( "execution" ) )
510                 {
511                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
512                 }
513                 parsed.add( "execution" );
514                 mojo.setExecution( parseLifecycleExecution( "execution", parser, strict, encoding ) );
515             }
516             else if ( parser.getName().equals( "components" )  )
517             {
518                 if ( parsed.contains( "components" ) )
519                 {
520                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
521                 }
522                 parsed.add( "components" );
523                 java.util.List components = new java.util.ArrayList();
524                 mojo.setComponents( components );
525                 while ( parser.nextTag() == XmlPullParser.START_TAG )
526                 {
527                     if ( parser.getName().equals( "component" ) )
528                     {
529                         components.add( parseComponent( "component", parser, strict, encoding ) );
530                     }
531                     else
532                     {
533                         parser.nextText();
534                     }
535                 }
536             }
537             else if ( parser.getName().equals( "parameters" )  )
538             {
539                 if ( parsed.contains( "parameters" ) )
540                 {
541                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
542                 }
543                 parsed.add( "parameters" );
544                 java.util.List parameters = new java.util.ArrayList();
545                 mojo.setParameters( parameters );
546                 while ( parser.nextTag() == XmlPullParser.START_TAG )
547                 {
548                     if ( parser.getName().equals( "parameter" ) )
549                     {
550                         parameters.add( parseParameter( "parameter", parser, strict, encoding ) );
551                     }
552                     else
553                     {
554                         parser.nextText();
555                     }
556                 }
557             }
558             else if ( parser.getName().equals( "description" )  )
559             {
560                 if ( parsed.contains( "description" ) )
561                 {
562                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
563                 }
564                 parsed.add( "description" );
565                 mojo.setDescription( getTrimmedValue( parser.nextText()) );
566             }
567             else if ( parser.getName().equals( "deprecated" )  )
568             {
569                 if ( parsed.contains( "deprecated" ) )
570                 {
571                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
572                 }
573                 parsed.add( "deprecated" );
574                 mojo.setDeprecation( getTrimmedValue( parser.nextText()) );
575             }
576             else if ( parser.getName().equals( "call" )  )
577             {
578                 if ( parsed.contains( "call" ) )
579                 {
580                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
581                 }
582                 parsed.add( "call" );
583                 mojo.setCall( getTrimmedValue( parser.nextText()) );
584             }
585             else
586             {
587                 if ( strict )
588                 {
589                     throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null);
590                 }
591             }
592         }
593         return mojo;
594     } //-- Mojo parseMojo(String, XmlPullParser, boolean, String) 
595 
596     /**
597      * Method parseParameter
598      * 
599      * @param tagName
600      * @param encoding
601      * @param strict
602      * @param parser
603      */
604     private Parameter parseParameter(String tagName, XmlPullParser parser, boolean strict, String encoding)
605         throws IOException, XmlPullParserException
606     {
607         Parameter parameter = new Parameter();
608         parameter.setModelEncoding( encoding );
609         java.util.Set parsed = new java.util.HashSet();
610         while ( parser.nextTag() == XmlPullParser.START_TAG )
611         {
612             if ( parser.getName().equals( "name" )  )
613             {
614                 if ( parsed.contains( "name" ) )
615                 {
616                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
617                 }
618                 parsed.add( "name" );
619                 parameter.setName( getTrimmedValue( parser.nextText()) );
620             }
621             else if ( parser.getName().equals( "alias" )  )
622             {
623                 if ( parsed.contains( "alias" ) )
624                 {
625                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
626                 }
627                 parsed.add( "alias" );
628                 parameter.setAlias( getTrimmedValue( parser.nextText()) );
629             }
630             else if ( parser.getName().equals( "property" )  )
631             {
632                 if ( parsed.contains( "property" ) )
633                 {
634                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
635                 }
636                 parsed.add( "property" );
637                 parameter.setProperty( getTrimmedValue( parser.nextText()) );
638             }
639             else if ( parser.getName().equals( "required" )  )
640             {
641                 if ( parsed.contains( "required" ) )
642                 {
643                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
644                 }
645                 parsed.add( "required" );
646                 parameter.setRequired( getBooleanValue( getTrimmedValue( parser.nextText()), "required", parser ) );
647             }
648             else if ( parser.getName().equals( "readonly" )  )
649             {
650                 if ( parsed.contains( "readonly" ) )
651                 {
652                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
653                 }
654                 parsed.add( "readonly" );
655                 parameter.setReadonly( getBooleanValue( getTrimmedValue( parser.nextText()), "readonly", parser ) );
656             }
657             else if ( parser.getName().equals( "expression" )  )
658             {
659                 if ( parsed.contains( "expression" ) )
660                 {
661                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
662                 }
663                 parsed.add( "expression" );
664                 parameter.setExpression( getTrimmedValue( parser.nextText()) );
665             }
666             else if ( parser.getName().equals( "defaultValue" )  )
667             {
668                 if ( parsed.contains( "defaultValue" ) )
669                 {
670                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
671                 }
672                 parsed.add( "defaultValue" );
673                 parameter.setDefaultValue( getTrimmedValue( parser.nextText()) );
674             }
675             else if ( parser.getName().equals( "type" )  )
676             {
677                 if ( parsed.contains( "type" ) )
678                 {
679                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
680                 }
681                 parsed.add( "type" );
682                 parameter.setType( getTrimmedValue( parser.nextText()) );
683             }
684             else if ( parser.getName().equals( "description" )  )
685             {
686                 if ( parsed.contains( "description" ) )
687                 {
688                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
689                 }
690                 parsed.add( "description" );
691                 parameter.setDescription( getTrimmedValue( parser.nextText()) );
692             }
693             else if ( parser.getName().equals( "deprecated" )  )
694             {
695                 if ( parsed.contains( "deprecated" ) )
696                 {
697                     throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
698                 }
699                 parsed.add( "deprecated" );
700                 parameter.setDeprecation( getTrimmedValue( parser.nextText()) );
701             }
702             else
703             {
704                 if ( strict )
705                 {
706                     throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null);
707                 }
708             }
709         }
710         return parameter;
711     } //-- Parameter parseParameter(String, XmlPullParser, boolean, String) 
712 
713     /**
714      * Method parsePluginMetadata
715      * 
716      * @param tagName
717      * @param encoding
718      * @param strict
719      * @param parser
720      */
721     private PluginMetadata parsePluginMetadata(String tagName, XmlPullParser parser, boolean strict, String encoding)
722         throws IOException, XmlPullParserException
723     {
724         PluginMetadata pluginMetadata = new PluginMetadata();
725         pluginMetadata.setModelEncoding( encoding );
726         java.util.Set parsed = new java.util.HashSet();
727         int eventType = parser.getEventType();
728         boolean foundRoot = false;
729         while ( eventType != XmlPullParser.END_DOCUMENT )
730         {
731             if ( eventType == XmlPullParser.START_TAG )
732             {
733                 if ( parser.getName().equals( tagName ) )
734                 {
735                     foundRoot = true;
736                 }
737                 else if ( parser.getName().equals( "mojos" )  )
738                 {
739                     if ( parsed.contains( "mojos" ) )
740                     {
741                         throw new XmlPullParserException( "Duplicated tag: '" + parser.getName() + "'", parser, null);
742                     }
743                     parsed.add( "mojos" );
744                     java.util.List mojos = new java.util.ArrayList();
745                     pluginMetadata.setMojos( mojos );
746                     while ( parser.nextTag() == XmlPullParser.START_TAG )
747                     {
748                         if ( parser.getName().equals( "mojo" ) )
749                         {
750                             mojos.add( parseMojo( "mojo", parser, strict, encoding ) );
751                         }
752                         else
753                         {
754                             parser.nextText();
755                         }
756                     }
757                 }
758                 else
759                 {
760                     if ( foundRoot )
761                     {
762                         if ( strict )
763                         {
764                             throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null);
765                         }
766                     }
767                 }
768             }
769             eventType = parser.next();
770         }
771         return pluginMetadata;
772     } //-- PluginMetadata parsePluginMetadata(String, XmlPullParser, boolean, String) 
773 
774     /**
775      * Method read
776      * 
777      * @param reader
778      * @param strict
779      */
780     public PluginMetadata read(Reader reader, boolean strict)
781         throws IOException, XmlPullParserException
782     {
783         XmlPullParser parser = new MXParser();
784         
785         parser.setInput( reader );
786         
787         if ( addDefaultEntities ) 
788         {
789             // ----------------------------------------------------------------------
790             // Latin 1 entities
791             // ----------------------------------------------------------------------
792             
793             parser.defineEntityReplacementText( "nbsp", "\u00a0" ); 
794             parser.defineEntityReplacementText( "iexcl", "\u00a1" ); 
795             parser.defineEntityReplacementText( "cent", "\u00a2" ); 
796             parser.defineEntityReplacementText( "pound", "\u00a3" ); 
797             parser.defineEntityReplacementText( "curren", "\u00a4" ); 
798             parser.defineEntityReplacementText( "yen", "\u00a5" ); 
799             parser.defineEntityReplacementText( "brvbar", "\u00a6" ); 
800             parser.defineEntityReplacementText( "sect", "\u00a7" ); 
801             parser.defineEntityReplacementText( "uml", "\u00a8" ); 
802             parser.defineEntityReplacementText( "copy", "\u00a9" ); 
803             parser.defineEntityReplacementText( "ordf", "\u00aa" ); 
804             parser.defineEntityReplacementText( "laquo", "\u00ab" ); 
805             parser.defineEntityReplacementText( "not", "\u00ac" ); 
806             parser.defineEntityReplacementText( "shy", "\u00ad" ); 
807             parser.defineEntityReplacementText( "reg", "\u00ae" ); 
808             parser.defineEntityReplacementText( "macr", "\u00af" ); 
809             parser.defineEntityReplacementText( "deg", "\u00b0" ); 
810             parser.defineEntityReplacementText( "plusmn", "\u00b1" ); 
811             parser.defineEntityReplacementText( "sup2", "\u00b2" ); 
812             parser.defineEntityReplacementText( "sup3", "\u00b3" ); 
813             parser.defineEntityReplacementText( "acute", "\u00b4" ); 
814             parser.defineEntityReplacementText( "micro", "\u00b5" ); 
815             parser.defineEntityReplacementText( "para", "\u00b6" ); 
816             parser.defineEntityReplacementText( "middot", "\u00b7" ); 
817             parser.defineEntityReplacementText( "cedil", "\u00b8" ); 
818             parser.defineEntityReplacementText( "sup1", "\u00b9" ); 
819             parser.defineEntityReplacementText( "ordm", "\u00ba" ); 
820             parser.defineEntityReplacementText( "raquo", "\u00bb" ); 
821             parser.defineEntityReplacementText( "frac14", "\u00bc" ); 
822             parser.defineEntityReplacementText( "frac12", "\u00bd" ); 
823             parser.defineEntityReplacementText( "frac34", "\u00be" ); 
824             parser.defineEntityReplacementText( "iquest", "\u00bf" ); 
825             parser.defineEntityReplacementText( "Agrave", "\u00c0" ); 
826             parser.defineEntityReplacementText( "Aacute", "\u00c1" ); 
827             parser.defineEntityReplacementText( "Acirc", "\u00c2" ); 
828             parser.defineEntityReplacementText( "Atilde", "\u00c3" ); 
829             parser.defineEntityReplacementText( "Auml", "\u00c4" ); 
830             parser.defineEntityReplacementText( "Aring", "\u00c5" ); 
831             parser.defineEntityReplacementText( "AElig", "\u00c6" ); 
832             parser.defineEntityReplacementText( "Ccedil", "\u00c7" ); 
833             parser.defineEntityReplacementText( "Egrave", "\u00c8" ); 
834             parser.defineEntityReplacementText( "Eacute", "\u00c9" ); 
835             parser.defineEntityReplacementText( "Ecirc", "\u00ca" ); 
836             parser.defineEntityReplacementText( "Euml", "\u00cb" ); 
837             parser.defineEntityReplacementText( "Igrave", "\u00cc" ); 
838             parser.defineEntityReplacementText( "Iacute", "\u00cd" ); 
839             parser.defineEntityReplacementText( "Icirc", "\u00ce" ); 
840             parser.defineEntityReplacementText( "Iuml", "\u00cf" ); 
841             parser.defineEntityReplacementText( "ETH", "\u00d0" ); 
842             parser.defineEntityReplacementText( "Ntilde", "\u00d1" ); 
843             parser.defineEntityReplacementText( "Ograve", "\u00d2" ); 
844             parser.defineEntityReplacementText( "Oacute", "\u00d3" ); 
845             parser.defineEntityReplacementText( "Ocirc", "\u00d4" ); 
846             parser.defineEntityReplacementText( "Otilde", "\u00d5" ); 
847             parser.defineEntityReplacementText( "Ouml", "\u00d6" ); 
848             parser.defineEntityReplacementText( "times", "\u00d7" ); 
849             parser.defineEntityReplacementText( "Oslash", "\u00d8" ); 
850             parser.defineEntityReplacementText( "Ugrave", "\u00d9" ); 
851             parser.defineEntityReplacementText( "Uacute", "\u00da" ); 
852             parser.defineEntityReplacementText( "Ucirc", "\u00db" ); 
853             parser.defineEntityReplacementText( "Uuml", "\u00dc" ); 
854             parser.defineEntityReplacementText( "Yacute", "\u00dd" ); 
855             parser.defineEntityReplacementText( "THORN", "\u00de" ); 
856             parser.defineEntityReplacementText( "szlig", "\u00df" ); 
857             parser.defineEntityReplacementText( "agrave", "\u00e0" ); 
858             parser.defineEntityReplacementText( "aacute", "\u00e1" ); 
859             parser.defineEntityReplacementText( "acirc", "\u00e2" ); 
860             parser.defineEntityReplacementText( "atilde", "\u00e3" ); 
861             parser.defineEntityReplacementText( "auml", "\u00e4" ); 
862             parser.defineEntityReplacementText( "aring", "\u00e5" ); 
863             parser.defineEntityReplacementText( "aelig", "\u00e6" ); 
864             parser.defineEntityReplacementText( "ccedil", "\u00e7" ); 
865             parser.defineEntityReplacementText( "egrave", "\u00e8" ); 
866             parser.defineEntityReplacementText( "eacute", "\u00e9" ); 
867             parser.defineEntityReplacementText( "ecirc", "\u00ea" ); 
868             parser.defineEntityReplacementText( "euml", "\u00eb" ); 
869             parser.defineEntityReplacementText( "igrave", "\u00ec" ); 
870             parser.defineEntityReplacementText( "iacute", "\u00ed" ); 
871             parser.defineEntityReplacementText( "icirc", "\u00ee" ); 
872             parser.defineEntityReplacementText( "iuml", "\u00ef" ); 
873             parser.defineEntityReplacementText( "eth", "\u00f0" ); 
874             parser.defineEntityReplacementText( "ntilde", "\u00f1" ); 
875             parser.defineEntityReplacementText( "ograve", "\u00f2" ); 
876             parser.defineEntityReplacementText( "oacute", "\u00f3" ); 
877             parser.defineEntityReplacementText( "ocirc", "\u00f4" ); 
878             parser.defineEntityReplacementText( "otilde", "\u00f5" ); 
879             parser.defineEntityReplacementText( "ouml", "\u00f6" ); 
880             parser.defineEntityReplacementText( "divide", "\u00f7" ); 
881             parser.defineEntityReplacementText( "oslash", "\u00f8" ); 
882             parser.defineEntityReplacementText( "ugrave", "\u00f9" ); 
883             parser.defineEntityReplacementText( "uacute", "\u00fa" ); 
884             parser.defineEntityReplacementText( "ucirc", "\u00fb" ); 
885             parser.defineEntityReplacementText( "uuml", "\u00fc" ); 
886             parser.defineEntityReplacementText( "yacute", "\u00fd" ); 
887             parser.defineEntityReplacementText( "thorn", "\u00fe" ); 
888             parser.defineEntityReplacementText( "yuml", "\u00ff" ); 
889             
890             // ----------------------------------------------------------------------
891             // Special entities
892             // ----------------------------------------------------------------------
893             
894             parser.defineEntityReplacementText( "OElig", "\u0152" ); 
895             parser.defineEntityReplacementText( "oelig", "\u0153" ); 
896             parser.defineEntityReplacementText( "Scaron", "\u0160" ); 
897             parser.defineEntityReplacementText( "scaron", "\u0161" ); 
898             parser.defineEntityReplacementText( "Yuml", "\u0178" ); 
899             parser.defineEntityReplacementText( "circ", "\u02c6" ); 
900             parser.defineEntityReplacementText( "tilde", "\u02dc" ); 
901             parser.defineEntityReplacementText( "ensp", "\u2002" ); 
902             parser.defineEntityReplacementText( "emsp", "\u2003" ); 
903             parser.defineEntityReplacementText( "thinsp", "\u2009" ); 
904             parser.defineEntityReplacementText( "zwnj", "\u200c" ); 
905             parser.defineEntityReplacementText( "zwj", "\u200d" ); 
906             parser.defineEntityReplacementText( "lrm", "\u200e" ); 
907             parser.defineEntityReplacementText( "rlm", "\u200f" ); 
908             parser.defineEntityReplacementText( "ndash", "\u2013" ); 
909             parser.defineEntityReplacementText( "mdash", "\u2014" ); 
910             parser.defineEntityReplacementText( "lsquo", "\u2018" ); 
911             parser.defineEntityReplacementText( "rsquo", "\u2019" ); 
912             parser.defineEntityReplacementText( "sbquo", "\u201a" ); 
913             parser.defineEntityReplacementText( "ldquo", "\u201c" ); 
914             parser.defineEntityReplacementText( "rdquo", "\u201d" ); 
915             parser.defineEntityReplacementText( "bdquo", "\u201e" ); 
916             parser.defineEntityReplacementText( "dagger", "\u2020" ); 
917             parser.defineEntityReplacementText( "Dagger", "\u2021" ); 
918             parser.defineEntityReplacementText( "permil", "\u2030" ); 
919             parser.defineEntityReplacementText( "lsaquo", "\u2039" ); 
920             parser.defineEntityReplacementText( "rsaquo", "\u203a" ); 
921             parser.defineEntityReplacementText( "euro", "\u20ac" ); 
922             
923             // ----------------------------------------------------------------------
924             // Symbol entities
925             // ----------------------------------------------------------------------
926             
927             parser.defineEntityReplacementText( "fnof", "\u0192" ); 
928             parser.defineEntityReplacementText( "Alpha", "\u0391" ); 
929             parser.defineEntityReplacementText( "Beta", "\u0392" ); 
930             parser.defineEntityReplacementText( "Gamma", "\u0393" ); 
931             parser.defineEntityReplacementText( "Delta", "\u0394" ); 
932             parser.defineEntityReplacementText( "Epsilon", "\u0395" ); 
933             parser.defineEntityReplacementText( "Zeta", "\u0396" ); 
934             parser.defineEntityReplacementText( "Eta", "\u0397" ); 
935             parser.defineEntityReplacementText( "Theta", "\u0398" ); 
936             parser.defineEntityReplacementText( "Iota", "\u0399" ); 
937             parser.defineEntityReplacementText( "Kappa", "\u039a" ); 
938             parser.defineEntityReplacementText( "Lambda", "\u039b" ); 
939             parser.defineEntityReplacementText( "Mu", "\u039c" ); 
940             parser.defineEntityReplacementText( "Nu", "\u039d" ); 
941             parser.defineEntityReplacementText( "Xi", "\u039e" ); 
942             parser.defineEntityReplacementText( "Omicron", "\u039f" ); 
943             parser.defineEntityReplacementText( "Pi", "\u03a0" ); 
944             parser.defineEntityReplacementText( "Rho", "\u03a1" ); 
945             parser.defineEntityReplacementText( "Sigma", "\u03a3" ); 
946             parser.defineEntityReplacementText( "Tau", "\u03a4" ); 
947             parser.defineEntityReplacementText( "Upsilon", "\u03a5" ); 
948             parser.defineEntityReplacementText( "Phi", "\u03a6" ); 
949             parser.defineEntityReplacementText( "Chi", "\u03a7" ); 
950             parser.defineEntityReplacementText( "Psi", "\u03a8" ); 
951             parser.defineEntityReplacementText( "Omega", "\u03a9" ); 
952             parser.defineEntityReplacementText( "alpha", "\u03b1" ); 
953             parser.defineEntityReplacementText( "beta", "\u03b2" ); 
954             parser.defineEntityReplacementText( "gamma", "\u03b3" ); 
955             parser.defineEntityReplacementText( "delta", "\u03b4" ); 
956             parser.defineEntityReplacementText( "epsilon", "\u03b5" ); 
957             parser.defineEntityReplacementText( "zeta", "\u03b6" ); 
958             parser.defineEntityReplacementText( "eta", "\u03b7" ); 
959             parser.defineEntityReplacementText( "theta", "\u03b8" ); 
960             parser.defineEntityReplacementText( "iota", "\u03b9" ); 
961             parser.defineEntityReplacementText( "kappa", "\u03ba" ); 
962             parser.defineEntityReplacementText( "lambda", "\u03bb" ); 
963             parser.defineEntityReplacementText( "mu", "\u03bc" ); 
964             parser.defineEntityReplacementText( "nu", "\u03bd" ); 
965             parser.defineEntityReplacementText( "xi", "\u03be" ); 
966             parser.defineEntityReplacementText( "omicron", "\u03bf" ); 
967             parser.defineEntityReplacementText( "pi", "\u03c0" ); 
968             parser.defineEntityReplacementText( "rho", "\u03c1" ); 
969             parser.defineEntityReplacementText( "sigmaf", "\u03c2" ); 
970             parser.defineEntityReplacementText( "sigma", "\u03c3" ); 
971             parser.defineEntityReplacementText( "tau", "\u03c4" ); 
972             parser.defineEntityReplacementText( "upsilon", "\u03c5" ); 
973             parser.defineEntityReplacementText( "phi", "\u03c6" ); 
974             parser.defineEntityReplacementText( "chi", "\u03c7" ); 
975             parser.defineEntityReplacementText( "psi", "\u03c8" ); 
976             parser.defineEntityReplacementText( "omega", "\u03c9" ); 
977             parser.defineEntityReplacementText( "thetasym", "\u03d1" ); 
978             parser.defineEntityReplacementText( "upsih", "\u03d2" ); 
979             parser.defineEntityReplacementText( "piv", "\u03d6" ); 
980             parser.defineEntityReplacementText( "bull", "\u2022" ); 
981             parser.defineEntityReplacementText( "hellip", "\u2026" ); 
982             parser.defineEntityReplacementText( "prime", "\u2032" ); 
983             parser.defineEntityReplacementText( "Prime", "\u2033" ); 
984             parser.defineEntityReplacementText( "oline", "\u203e" ); 
985             parser.defineEntityReplacementText( "frasl", "\u2044" ); 
986             parser.defineEntityReplacementText( "weierp", "\u2118" ); 
987             parser.defineEntityReplacementText( "image", "\u2111" ); 
988             parser.defineEntityReplacementText( "real", "\u211c" ); 
989             parser.defineEntityReplacementText( "trade", "\u2122" ); 
990             parser.defineEntityReplacementText( "alefsym", "\u2135" ); 
991             parser.defineEntityReplacementText( "larr", "\u2190" ); 
992             parser.defineEntityReplacementText( "uarr", "\u2191" ); 
993             parser.defineEntityReplacementText( "rarr", "\u2192" ); 
994             parser.defineEntityReplacementText( "darr", "\u2193" ); 
995             parser.defineEntityReplacementText( "harr", "\u2194" ); 
996             parser.defineEntityReplacementText( "crarr", "\u21b5" ); 
997             parser.defineEntityReplacementText( "lArr", "\u21d0" ); 
998             parser.defineEntityReplacementText( "uArr", "\u21d1" ); 
999             parser.defineEntityReplacementText( "rArr", "\u21d2" ); 
1000             parser.defineEntityReplacementText( "dArr", "\u21d3" ); 
1001             parser.defineEntityReplacementText( "hArr", "\u21d4" ); 
1002             parser.defineEntityReplacementText( "forall", "\u2200" ); 
1003             parser.defineEntityReplacementText( "part", "\u2202" ); 
1004             parser.defineEntityReplacementText( "exist", "\u2203" ); 
1005             parser.defineEntityReplacementText( "empty", "\u2205" ); 
1006             parser.defineEntityReplacementText( "nabla", "\u2207" ); 
1007             parser.defineEntityReplacementText( "isin", "\u2208" ); 
1008             parser.defineEntityReplacementText( "notin", "\u2209" ); 
1009             parser.defineEntityReplacementText( "ni", "\u220b" ); 
1010             parser.defineEntityReplacementText( "prod", "\u220f" ); 
1011             parser.defineEntityReplacementText( "sum", "\u2211" ); 
1012             parser.defineEntityReplacementText( "minus", "\u2212" ); 
1013             parser.defineEntityReplacementText( "lowast", "\u2217" ); 
1014             parser.defineEntityReplacementText( "radic", "\u221a" ); 
1015             parser.defineEntityReplacementText( "prop", "\u221d" ); 
1016             parser.defineEntityReplacementText( "infin", "\u221e" ); 
1017             parser.defineEntityReplacementText( "ang", "\u2220" ); 
1018             parser.defineEntityReplacementText( "and", "\u2227" ); 
1019             parser.defineEntityReplacementText( "or", "\u2228" ); 
1020             parser.defineEntityReplacementText( "cap", "\u2229" ); 
1021             parser.defineEntityReplacementText( "cup", "\u222a" ); 
1022             parser.defineEntityReplacementText( "int", "\u222b" ); 
1023             parser.defineEntityReplacementText( "there4", "\u2234" ); 
1024             parser.defineEntityReplacementText( "sim", "\u223c" ); 
1025             parser.defineEntityReplacementText( "cong", "\u2245" ); 
1026             parser.defineEntityReplacementText( "asymp", "\u2248" ); 
1027             parser.defineEntityReplacementText( "ne", "\u2260" ); 
1028             parser.defineEntityReplacementText( "equiv", "\u2261" ); 
1029             parser.defineEntityReplacementText( "le", "\u2264" ); 
1030             parser.defineEntityReplacementText( "ge", "\u2265" ); 
1031             parser.defineEntityReplacementText( "sub", "\u2282" ); 
1032             parser.defineEntityReplacementText( "sup", "\u2283" ); 
1033             parser.defineEntityReplacementText( "nsub", "\u2284" ); 
1034             parser.defineEntityReplacementText( "sube", "\u2286" ); 
1035             parser.defineEntityReplacementText( "supe", "\u2287" ); 
1036             parser.defineEntityReplacementText( "oplus", "\u2295" ); 
1037             parser.defineEntityReplacementText( "otimes", "\u2297" ); 
1038             parser.defineEntityReplacementText( "perp", "\u22a5" ); 
1039             parser.defineEntityReplacementText( "sdot", "\u22c5" ); 
1040             parser.defineEntityReplacementText( "lceil", "\u2308" ); 
1041             parser.defineEntityReplacementText( "rceil", "\u2309" ); 
1042             parser.defineEntityReplacementText( "lfloor", "\u230a" ); 
1043             parser.defineEntityReplacementText( "rfloor", "\u230b" ); 
1044             parser.defineEntityReplacementText( "lang", "\u2329" ); 
1045             parser.defineEntityReplacementText( "rang", "\u232a" ); 
1046             parser.defineEntityReplacementText( "loz", "\u25ca" ); 
1047             parser.defineEntityReplacementText( "spades", "\u2660" ); 
1048             parser.defineEntityReplacementText( "clubs", "\u2663" ); 
1049             parser.defineEntityReplacementText( "hearts", "\u2665" ); 
1050             parser.defineEntityReplacementText( "diams", "\u2666" ); 
1051             
1052         }
1053         
1054         parser.next();
1055         String encoding = parser.getInputEncoding();
1056         
1057         return parsePluginMetadata( "pluginMetadata", parser, strict, encoding );
1058     } //-- PluginMetadata read(Reader, boolean) 
1059 
1060     /**
1061      * Method read
1062      * 
1063      * @param reader
1064      */
1065     public PluginMetadata read(Reader reader)
1066         throws IOException, XmlPullParserException
1067     {
1068         return read( reader, true );
1069     } //-- PluginMetadata read(Reader) 
1070 
1071     /**
1072      * Returns the state of the "add default entities" flag.
1073      * 
1074      * @param addDefaultEntities
1075      */
1076     public void setAddDefaultEntities(boolean addDefaultEntities)
1077     {
1078         this.addDefaultEntities = addDefaultEntities;
1079     } //-- void setAddDefaultEntities(boolean) 
1080 
1081 }