1
2
3
4
5
6 package org.apache.maven.archetype.catalog.io.xpp3;
7
8
9
10
11
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.Reader;
15 import java.text.DateFormat;
16 import org.apache.maven.archetype.catalog.Archetype;
17 import org.apache.maven.archetype.catalog.ArchetypeCatalog;
18 import org.codehaus.plexus.util.ReaderFactory;
19 import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
20 import org.codehaus.plexus.util.xml.pull.MXParser;
21 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
22 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
23
24
25
26
27
28
29 @SuppressWarnings( "all" )
30 public class ArchetypeCatalogXpp3Reader
31 {
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 private boolean addDefaultEntities = true;
48
49
50
51
52 public final ContentTransformer contentTransformer;
53
54
55
56
57
58
59 public ArchetypeCatalogXpp3Reader()
60 {
61 this( new ContentTransformer()
62 {
63 public String transform( String source, String fieldName )
64 {
65 return source;
66 }
67 } );
68 }
69
70 public ArchetypeCatalogXpp3Reader(ContentTransformer contentTransformer)
71 {
72 this.contentTransformer = contentTransformer;
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 private boolean checkFieldWithDuplicate( XmlPullParser parser, String tagName, String alias, java.util.Set parsed )
91 throws XmlPullParserException
92 {
93 if ( !( parser.getName().equals( tagName ) || parser.getName().equals( alias ) ) )
94 {
95 return false;
96 }
97 if ( !parsed.add( tagName ) )
98 {
99 throw new XmlPullParserException( "Duplicated tag: '" + tagName + "'", parser, null );
100 }
101 return true;
102 }
103
104
105
106
107
108
109
110
111
112
113
114 private void checkUnknownAttribute( XmlPullParser parser, String attribute, String tagName, boolean strict )
115 throws XmlPullParserException, IOException
116 {
117
118 if ( strict )
119 {
120 throw new XmlPullParserException( "Unknown attribute '" + attribute + "' for tag '" + tagName + "'", parser, null );
121 }
122 }
123
124
125
126
127
128
129
130
131
132 private void checkUnknownElement( XmlPullParser parser, boolean strict )
133 throws XmlPullParserException, IOException
134 {
135 if ( strict )
136 {
137 throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null );
138 }
139
140 for ( int unrecognizedTagCount = 1; unrecognizedTagCount > 0; )
141 {
142 int eventType = parser.next();
143 if ( eventType == XmlPullParser.START_TAG )
144 {
145 unrecognizedTagCount++;
146 }
147 else if ( eventType == XmlPullParser.END_TAG )
148 {
149 unrecognizedTagCount--;
150 }
151 }
152 }
153
154
155
156
157
158
159 public boolean getAddDefaultEntities()
160 {
161 return addDefaultEntities;
162 }
163
164
165
166
167
168
169
170
171
172
173 private boolean getBooleanValue( String s, String attribute, XmlPullParser parser )
174 throws XmlPullParserException
175 {
176 return getBooleanValue( s, attribute, parser, null );
177 }
178
179
180
181
182
183
184
185
186
187
188
189 private boolean getBooleanValue( String s, String attribute, XmlPullParser parser, String defaultValue )
190 throws XmlPullParserException
191 {
192 if ( s != null && s.length() != 0 )
193 {
194 return Boolean.valueOf( s ).booleanValue();
195 }
196 if ( defaultValue != null )
197 {
198 return Boolean.valueOf( defaultValue ).booleanValue();
199 }
200 return false;
201 }
202
203
204
205
206
207
208
209
210
211
212
213 private byte getByteValue( String s, String attribute, XmlPullParser parser, boolean strict )
214 throws XmlPullParserException
215 {
216 if ( s != null )
217 {
218 try
219 {
220 return Byte.valueOf( s ).byteValue();
221 }
222 catch ( NumberFormatException nfe )
223 {
224 if ( strict )
225 {
226 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a byte", parser, nfe );
227 }
228 }
229 }
230 return 0;
231 }
232
233
234
235
236
237
238
239
240
241
242 private char getCharacterValue( String s, String attribute, XmlPullParser parser )
243 throws XmlPullParserException
244 {
245 if ( s != null )
246 {
247 return s.charAt( 0 );
248 }
249 return 0;
250 }
251
252
253
254
255
256
257
258
259
260
261 private java.util.Date getDateValue( String s, String attribute, XmlPullParser parser )
262 throws XmlPullParserException
263 {
264 return getDateValue( s, attribute, null, parser );
265 }
266
267
268
269
270
271
272
273
274
275
276
277 private java.util.Date getDateValue( String s, String attribute, String dateFormat, XmlPullParser parser )
278 throws XmlPullParserException
279 {
280 if ( s != null )
281 {
282 String effectiveDateFormat = dateFormat;
283 if ( dateFormat == null )
284 {
285 effectiveDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS";
286 }
287 if ( "long".equals( effectiveDateFormat ) )
288 {
289 try
290 {
291 return new java.util.Date( Long.parseLong( s ) );
292 }
293 catch ( NumberFormatException e )
294 {
295 throw new XmlPullParserException( e.getMessage(), parser, e );
296 }
297 }
298 else
299 {
300 try
301 {
302 DateFormat dateParser = new java.text.SimpleDateFormat( effectiveDateFormat, java.util.Locale.US );
303 return dateParser.parse( s );
304 }
305 catch ( java.text.ParseException e )
306 {
307 throw new XmlPullParserException( e.getMessage(), parser, e );
308 }
309 }
310 }
311 return null;
312 }
313
314
315
316
317
318
319
320
321
322
323
324 private double getDoubleValue( String s, String attribute, XmlPullParser parser, boolean strict )
325 throws XmlPullParserException
326 {
327 if ( s != null )
328 {
329 try
330 {
331 return Double.valueOf( s ).doubleValue();
332 }
333 catch ( NumberFormatException nfe )
334 {
335 if ( strict )
336 {
337 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a floating point number", parser, nfe );
338 }
339 }
340 }
341 return 0;
342 }
343
344
345
346
347
348
349
350
351
352
353
354 private float getFloatValue( String s, String attribute, XmlPullParser parser, boolean strict )
355 throws XmlPullParserException
356 {
357 if ( s != null )
358 {
359 try
360 {
361 return Float.valueOf( s ).floatValue();
362 }
363 catch ( NumberFormatException nfe )
364 {
365 if ( strict )
366 {
367 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a floating point number", parser, nfe );
368 }
369 }
370 }
371 return 0;
372 }
373
374
375
376
377
378
379
380
381
382
383
384 private int getIntegerValue( String s, String attribute, XmlPullParser parser, boolean strict )
385 throws XmlPullParserException
386 {
387 if ( s != null )
388 {
389 try
390 {
391 return Integer.valueOf( s ).intValue();
392 }
393 catch ( NumberFormatException nfe )
394 {
395 if ( strict )
396 {
397 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be an integer", parser, nfe );
398 }
399 }
400 }
401 return 0;
402 }
403
404
405
406
407
408
409
410
411
412
413
414 private long getLongValue( String s, String attribute, XmlPullParser parser, boolean strict )
415 throws XmlPullParserException
416 {
417 if ( s != null )
418 {
419 try
420 {
421 return Long.valueOf( s ).longValue();
422 }
423 catch ( NumberFormatException nfe )
424 {
425 if ( strict )
426 {
427 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a long integer", parser, nfe );
428 }
429 }
430 }
431 return 0;
432 }
433
434
435
436
437
438
439
440
441
442
443
444 private String getRequiredAttributeValue( String s, String attribute, XmlPullParser parser, boolean strict )
445 throws XmlPullParserException
446 {
447 if ( s == null )
448 {
449 if ( strict )
450 {
451 throw new XmlPullParserException( "Missing required value for attribute '" + attribute + "'", parser, null );
452 }
453 }
454 return s;
455 }
456
457
458
459
460
461
462
463
464
465
466
467 private short getShortValue( String s, String attribute, XmlPullParser parser, boolean strict )
468 throws XmlPullParserException
469 {
470 if ( s != null )
471 {
472 try
473 {
474 return Short.valueOf( s ).shortValue();
475 }
476 catch ( NumberFormatException nfe )
477 {
478 if ( strict )
479 {
480 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a short integer", parser, nfe );
481 }
482 }
483 }
484 return 0;
485 }
486
487
488
489
490
491
492
493 private String getTrimmedValue( String s )
494 {
495 if ( s != null )
496 {
497 s = s.trim();
498 }
499 return s;
500 }
501
502
503
504
505
506
507
508
509 private String interpolatedTrimmed( String value, String context )
510 {
511 return getTrimmedValue( contentTransformer.transform( value, context ) );
512 }
513
514
515
516
517
518
519
520
521
522 private int nextTag( XmlPullParser parser )
523 throws IOException, XmlPullParserException
524 {
525 int eventType = parser.next();
526 if ( eventType == XmlPullParser.TEXT )
527 {
528 eventType = parser.next();
529 }
530 if ( eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_TAG )
531 {
532 throw new XmlPullParserException( "expected START_TAG or END_TAG not " + XmlPullParser.TYPES[eventType], parser, null );
533 }
534 return eventType;
535 }
536
537
538
539
540
541
542
543
544
545
546 public ArchetypeCatalog read( Reader reader, boolean strict )
547 throws IOException, XmlPullParserException
548 {
549 XmlPullParser parser = addDefaultEntities ? new MXParser(EntityReplacementMap.defaultEntityReplacementMap) : new MXParser( );
550
551 parser.setInput( reader );
552
553
554 return read( parser, strict );
555 }
556
557
558
559
560
561
562
563
564
565 public ArchetypeCatalog read( Reader reader )
566 throws IOException, XmlPullParserException
567 {
568 return read( reader, true );
569 }
570
571
572
573
574
575
576
577
578
579
580 public ArchetypeCatalog read( InputStream in, boolean strict )
581 throws IOException, XmlPullParserException
582 {
583 return read( ReaderFactory.newXmlReader( in ), strict );
584 }
585
586
587
588
589
590
591
592
593
594 public ArchetypeCatalog read( InputStream in )
595 throws IOException, XmlPullParserException
596 {
597 return read( ReaderFactory.newXmlReader( in ) );
598 }
599
600
601
602
603
604
605
606
607
608
609 private Archetype parseArchetype( XmlPullParser parser, boolean strict )
610 throws IOException, XmlPullParserException
611 {
612 String tagName = parser.getName();
613 Archetype archetype = new Archetype();
614 for ( int i = parser.getAttributeCount() - 1; i >= 0; i-- )
615 {
616 String name = parser.getAttributeName( i );
617 String value = parser.getAttributeValue( i );
618
619 if ( name.indexOf( ':' ) >= 0 )
620 {
621
622 }
623 else
624 {
625 checkUnknownAttribute( parser, name, tagName, strict );
626 }
627 }
628 java.util.Set parsed = new java.util.HashSet();
629 while ( ( strict ? parser.nextTag() : nextTag( parser ) ) == XmlPullParser.START_TAG )
630 {
631 if ( checkFieldWithDuplicate( parser, "groupId", null, parsed ) )
632 {
633 archetype.setGroupId( interpolatedTrimmed( parser.nextText(), "groupId" ) );
634 }
635 else if ( checkFieldWithDuplicate( parser, "artifactId", null, parsed ) )
636 {
637 archetype.setArtifactId( interpolatedTrimmed( parser.nextText(), "artifactId" ) );
638 }
639 else if ( checkFieldWithDuplicate( parser, "version", null, parsed ) )
640 {
641 archetype.setVersion( interpolatedTrimmed( parser.nextText(), "version" ) );
642 }
643 else if ( checkFieldWithDuplicate( parser, "repository", null, parsed ) )
644 {
645 archetype.setRepository( interpolatedTrimmed( parser.nextText(), "repository" ) );
646 }
647 else if ( checkFieldWithDuplicate( parser, "description", null, parsed ) )
648 {
649 archetype.setDescription( interpolatedTrimmed( parser.nextText(), "description" ) );
650 }
651 else
652 {
653 checkUnknownElement( parser, strict );
654 }
655 }
656 return archetype;
657 }
658
659
660
661
662
663
664
665
666
667
668 private ArchetypeCatalog parseArchetypeCatalog( XmlPullParser parser, boolean strict )
669 throws IOException, XmlPullParserException
670 {
671 String tagName = parser.getName();
672 ArchetypeCatalog archetypeCatalog = new ArchetypeCatalog();
673 for ( int i = parser.getAttributeCount() - 1; i >= 0; i-- )
674 {
675 String name = parser.getAttributeName( i );
676 String value = parser.getAttributeValue( i );
677
678 if ( name.indexOf( ':' ) >= 0 )
679 {
680
681 }
682 else if ( "xmlns".equals( name ) )
683 {
684
685 }
686 else
687 {
688 checkUnknownAttribute( parser, name, tagName, strict );
689 }
690 }
691 java.util.Set parsed = new java.util.HashSet();
692 while ( ( strict ? parser.nextTag() : nextTag( parser ) ) == XmlPullParser.START_TAG )
693 {
694 if ( checkFieldWithDuplicate( parser, "archetypes", null, parsed ) )
695 {
696 java.util.List<Archetype> archetypes = new java.util.ArrayList<Archetype>();
697 archetypeCatalog.setArchetypes( archetypes );
698 while ( parser.nextTag() == XmlPullParser.START_TAG )
699 {
700 if ( "archetype".equals( parser.getName() ) )
701 {
702 archetypes.add( parseArchetype( parser, strict ) );
703 }
704 else
705 {
706 checkUnknownElement( parser, strict );
707 }
708 }
709 }
710 else
711 {
712 checkUnknownElement( parser, strict );
713 }
714 }
715 return archetypeCatalog;
716 }
717
718
719
720
721
722
723
724
725
726
727 private ArchetypeCatalog read( XmlPullParser parser, boolean strict )
728 throws IOException, XmlPullParserException
729 {
730 ArchetypeCatalog archetypeCatalog = null;
731 int eventType = parser.getEventType();
732 boolean parsed = false;
733 while ( eventType != XmlPullParser.END_DOCUMENT )
734 {
735 if ( eventType == XmlPullParser.START_TAG )
736 {
737 if ( strict && ! "archetype-catalog".equals( parser.getName() ) )
738 {
739 throw new XmlPullParserException( "Expected root element 'archetype-catalog' but found '" + parser.getName() + "'", parser, null );
740 }
741 else if ( parsed )
742 {
743
744 throw new XmlPullParserException( "Duplicated tag: 'archetype-catalog'", parser, null );
745 }
746 archetypeCatalog = parseArchetypeCatalog( parser, strict );
747 archetypeCatalog.setModelEncoding( parser.getInputEncoding() );
748 parsed = true;
749 }
750 eventType = parser.next();
751 }
752 if ( parsed )
753 {
754 return archetypeCatalog;
755 }
756 throw new XmlPullParserException( "Expected root element 'archetype-catalog' but found no element at all: invalid XML document", parser, null );
757 }
758
759
760
761
762
763
764 public void setAddDefaultEntities( boolean addDefaultEntities )
765 {
766 this.addDefaultEntities = addDefaultEntities;
767 }
768
769 public static interface ContentTransformer
770 {
771
772
773
774
775
776
777
778 String transform( String source, String fieldName );
779 }
780
781 }