1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.apache.maven.artifact.repository.metadata.io.xpp3;
25
26
27
28
29
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.Reader;
33 import java.text.DateFormat;
34 import org.apache.maven.artifact.repository.metadata.Metadata;
35 import org.apache.maven.artifact.repository.metadata.Plugin;
36 import org.apache.maven.artifact.repository.metadata.Snapshot;
37 import org.apache.maven.artifact.repository.metadata.SnapshotVersion;
38 import org.apache.maven.artifact.repository.metadata.Versioning;
39 import org.codehaus.plexus.util.xml.XmlStreamReader;
40 import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
41 import org.codehaus.plexus.util.xml.pull.MXParser;
42 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
43 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
44
45
46
47
48
49
50 @SuppressWarnings( "all" )
51 public class MetadataXpp3Reader
52 {
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 private boolean addDefaultEntities = true;
69
70
71
72
73 public final ContentTransformer contentTransformer;
74
75
76
77
78
79
80 public MetadataXpp3Reader()
81 {
82 this( new ContentTransformer()
83 {
84 public String transform( String source, String fieldName )
85 {
86 return source;
87 }
88 } );
89 }
90
91 public MetadataXpp3Reader(ContentTransformer contentTransformer)
92 {
93 this.contentTransformer = contentTransformer;
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 private boolean checkFieldWithDuplicate( XmlPullParser parser, String tagName, String alias, java.util.Set<String> parsed )
113 throws XmlPullParserException
114 {
115 if ( !( parser.getName().equals( tagName ) || parser.getName().equals( alias ) ) )
116 {
117 return false;
118 }
119 if ( !parsed.add( tagName ) )
120 {
121 throw new XmlPullParserException( "Duplicated tag: '" + tagName + "'", parser, null );
122 }
123 return true;
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137 private void checkUnknownAttribute( XmlPullParser parser, String attribute, String tagName, boolean strict )
138 throws XmlPullParserException, IOException
139 {
140
141 if ( strict )
142 {
143 throw new XmlPullParserException( "Unknown attribute '" + attribute + "' for tag '" + tagName + "'", parser, null );
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156 private void checkUnknownElement( XmlPullParser parser, boolean strict )
157 throws XmlPullParserException, IOException
158 {
159 if ( strict )
160 {
161 throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null );
162 }
163
164 for ( int unrecognizedTagCount = 1; unrecognizedTagCount > 0; )
165 {
166 int eventType = parser.next();
167 if ( eventType == XmlPullParser.START_TAG )
168 {
169 unrecognizedTagCount++;
170 }
171 else if ( eventType == XmlPullParser.END_TAG )
172 {
173 unrecognizedTagCount--;
174 }
175 }
176 }
177
178
179
180
181
182
183 public boolean getAddDefaultEntities()
184 {
185 return addDefaultEntities;
186 }
187
188
189
190
191
192
193
194
195
196
197
198 private boolean getBooleanValue( String s, String attribute, XmlPullParser parser )
199 throws XmlPullParserException
200 {
201 return getBooleanValue( s, attribute, parser, null );
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215 private boolean getBooleanValue( String s, String attribute, XmlPullParser parser, String defaultValue )
216 throws XmlPullParserException
217 {
218 if ( s != null && s.length() != 0 )
219 {
220 return Boolean.valueOf( s ).booleanValue();
221 }
222 if ( defaultValue != null )
223 {
224 return Boolean.valueOf( defaultValue ).booleanValue();
225 }
226 return false;
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240 private byte getByteValue( String s, String attribute, XmlPullParser parser, boolean strict )
241 throws XmlPullParserException
242 {
243 if ( s != null )
244 {
245 try
246 {
247 return Byte.valueOf( s ).byteValue();
248 }
249 catch ( NumberFormatException nfe )
250 {
251 if ( strict )
252 {
253 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a byte", parser, nfe );
254 }
255 }
256 }
257 return 0;
258 }
259
260
261
262
263
264
265
266
267
268
269
270 private char getCharacterValue( String s, String attribute, XmlPullParser parser )
271 throws XmlPullParserException
272 {
273 if ( s != null )
274 {
275 return s.charAt( 0 );
276 }
277 return 0;
278 }
279
280
281
282
283
284
285
286
287
288
289
290 private java.util.Date getDateValue( String s, String attribute, XmlPullParser parser )
291 throws XmlPullParserException
292 {
293 return getDateValue( s, attribute, null, parser );
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307 private java.util.Date getDateValue( String s, String attribute, String dateFormat, XmlPullParser parser )
308 throws XmlPullParserException
309 {
310 if ( s != null )
311 {
312 String effectiveDateFormat = dateFormat;
313 if ( dateFormat == null )
314 {
315 effectiveDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS";
316 }
317 if ( "long".equals( effectiveDateFormat ) )
318 {
319 try
320 {
321 return new java.util.Date( Long.parseLong( s ) );
322 }
323 catch ( NumberFormatException e )
324 {
325 throw new XmlPullParserException( e.getMessage(), parser, e );
326 }
327 }
328 else
329 {
330 try
331 {
332 DateFormat dateParser = new java.text.SimpleDateFormat( effectiveDateFormat, java.util.Locale.US );
333 return dateParser.parse( s );
334 }
335 catch ( java.text.ParseException e )
336 {
337 throw new XmlPullParserException( e.getMessage(), parser, e );
338 }
339 }
340 }
341 return null;
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355 private double getDoubleValue( String s, String attribute, XmlPullParser parser, boolean strict )
356 throws XmlPullParserException
357 {
358 if ( s != null )
359 {
360 try
361 {
362 return Double.valueOf( s ).doubleValue();
363 }
364 catch ( NumberFormatException nfe )
365 {
366 if ( strict )
367 {
368 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a floating point number", parser, nfe );
369 }
370 }
371 }
372 return 0;
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386 private float getFloatValue( String s, String attribute, XmlPullParser parser, boolean strict )
387 throws XmlPullParserException
388 {
389 if ( s != null )
390 {
391 try
392 {
393 return Float.valueOf( s ).floatValue();
394 }
395 catch ( NumberFormatException nfe )
396 {
397 if ( strict )
398 {
399 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a floating point number", parser, nfe );
400 }
401 }
402 }
403 return 0;
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417 private int getIntegerValue( String s, String attribute, XmlPullParser parser, boolean strict )
418 throws XmlPullParserException
419 {
420 if ( s != null )
421 {
422 try
423 {
424 return Integer.valueOf( s ).intValue();
425 }
426 catch ( NumberFormatException nfe )
427 {
428 if ( strict )
429 {
430 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be an integer", parser, nfe );
431 }
432 }
433 }
434 return 0;
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448 private long getLongValue( String s, String attribute, XmlPullParser parser, boolean strict )
449 throws XmlPullParserException
450 {
451 if ( s != null )
452 {
453 try
454 {
455 return Long.valueOf( s ).longValue();
456 }
457 catch ( NumberFormatException nfe )
458 {
459 if ( strict )
460 {
461 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a long integer", parser, nfe );
462 }
463 }
464 }
465 return 0;
466 }
467
468
469
470
471
472
473
474
475
476
477
478
479 private String getRequiredAttributeValue( String s, String attribute, XmlPullParser parser, boolean strict )
480 throws XmlPullParserException
481 {
482 if ( s == null )
483 {
484 if ( strict )
485 {
486 throw new XmlPullParserException( "Missing required value for attribute '" + attribute + "'", parser, null );
487 }
488 }
489 return s;
490 }
491
492
493
494
495
496
497
498
499
500
501
502
503 private short getShortValue( String s, String attribute, XmlPullParser parser, boolean strict )
504 throws XmlPullParserException
505 {
506 if ( s != null )
507 {
508 try
509 {
510 return Short.valueOf( s ).shortValue();
511 }
512 catch ( NumberFormatException nfe )
513 {
514 if ( strict )
515 {
516 throw new XmlPullParserException( "Unable to parse element '" + attribute + "', must be a short integer", parser, nfe );
517 }
518 }
519 }
520 return 0;
521 }
522
523
524
525
526
527
528
529 private String getTrimmedValue( String s )
530 {
531 if ( s != null )
532 {
533 s = s.trim();
534 }
535 return s;
536 }
537
538
539
540
541
542
543
544
545 private String interpolatedTrimmed( String value, String context )
546 {
547 return getTrimmedValue( contentTransformer.transform( value, context ) );
548 }
549
550
551
552
553
554
555
556
557
558
559 private int nextTag( XmlPullParser parser )
560 throws IOException, XmlPullParserException
561 {
562 int eventType = parser.next();
563 if ( eventType == XmlPullParser.TEXT )
564 {
565 eventType = parser.next();
566 }
567 if ( eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_TAG )
568 {
569 throw new XmlPullParserException( "expected START_TAG or END_TAG not " + XmlPullParser.TYPES[eventType], parser, null );
570 }
571 return eventType;
572 }
573
574
575
576
577
578
579
580
581
582
583
584 public Metadata read( XmlPullParser parser, boolean strict )
585 throws IOException, XmlPullParserException
586 {
587 Metadata metadata = null;
588 int eventType = parser.getEventType();
589 boolean parsed = false;
590 while ( eventType != XmlPullParser.END_DOCUMENT )
591 {
592 if ( eventType == XmlPullParser.START_TAG )
593 {
594 if ( strict && ! "metadata".equals( parser.getName() ) )
595 {
596 throw new XmlPullParserException( "Expected root element 'metadata' but found '" + parser.getName() + "'", parser, null );
597 }
598 else if ( parsed )
599 {
600
601 throw new XmlPullParserException( "Duplicated tag: 'metadata'", parser, null );
602 }
603 metadata = parseMetadata( parser, strict );
604 metadata.setModelEncoding( parser.getInputEncoding() );
605 parsed = true;
606 }
607 eventType = parser.next();
608 }
609 if ( parsed )
610 {
611 return metadata;
612 }
613 throw new XmlPullParserException( "Expected root element 'metadata' but found no element at all: invalid XML document", parser, null );
614 }
615
616
617
618
619
620
621
622
623
624
625
626 public Metadata read( Reader reader, boolean strict )
627 throws IOException, XmlPullParserException
628 {
629 XmlPullParser parser = addDefaultEntities ? new MXParser(EntityReplacementMap.defaultEntityReplacementMap) : new MXParser( );
630
631 parser.setInput( reader );
632
633
634 return read( parser, strict );
635 }
636
637
638
639
640
641
642
643
644
645
646 public Metadata read( Reader reader )
647 throws IOException, XmlPullParserException
648 {
649 return read( reader, true );
650 }
651
652
653
654
655
656
657
658
659
660
661
662 public Metadata read( InputStream in, boolean strict )
663 throws IOException, XmlPullParserException
664 {
665 return read( new XmlStreamReader( in ), strict );
666 }
667
668
669
670
671
672
673
674
675
676
677 public Metadata read( InputStream in )
678 throws IOException, XmlPullParserException
679 {
680 return read( new XmlStreamReader( in ) );
681 }
682
683
684
685
686
687
688
689
690
691
692
693 private Metadata parseMetadata( XmlPullParser parser, boolean strict )
694 throws IOException, XmlPullParserException
695 {
696 String tagName = parser.getName();
697 Metadata metadata = new Metadata();
698 for ( int i = parser.getAttributeCount() - 1; i >= 0; i-- )
699 {
700 String name = parser.getAttributeName( i );
701 String value = parser.getAttributeValue( i );
702
703 if ( name.indexOf( ':' ) >= 0 )
704 {
705
706 }
707 else if ( "xmlns".equals( name ) )
708 {
709
710 }
711 else if ( "modelVersion".equals( name ) )
712 {
713 metadata.setModelVersion( interpolatedTrimmed( value, "modelVersion" ) );
714 }
715 else
716 {
717 checkUnknownAttribute( parser, name, tagName, strict );
718 }
719 }
720 java.util.Set<String> parsed = new java.util.HashSet<String>();
721 while ( ( strict ? parser.nextTag() : nextTag( parser ) ) == XmlPullParser.START_TAG )
722 {
723 if ( checkFieldWithDuplicate( parser, "groupId", null, parsed ) )
724 {
725 metadata.setGroupId( interpolatedTrimmed( parser.nextText(), "groupId" ) );
726 }
727 else if ( checkFieldWithDuplicate( parser, "artifactId", null, parsed ) )
728 {
729 metadata.setArtifactId( interpolatedTrimmed( parser.nextText(), "artifactId" ) );
730 }
731 else if ( checkFieldWithDuplicate( parser, "versioning", null, parsed ) )
732 {
733 metadata.setVersioning( parseVersioning( parser, strict ) );
734 }
735 else if ( checkFieldWithDuplicate( parser, "version", null, parsed ) )
736 {
737 metadata.setVersion( interpolatedTrimmed( parser.nextText(), "version" ) );
738 }
739 else if ( checkFieldWithDuplicate( parser, "plugins", null, parsed ) )
740 {
741 java.util.List<Plugin> plugins = new java.util.ArrayList<Plugin>();
742 while ( parser.nextTag() == XmlPullParser.START_TAG )
743 {
744 if ( "plugin".equals( parser.getName() ) )
745 {
746 plugins.add( parsePlugin( parser, strict ) );
747 }
748 else
749 {
750 checkUnknownElement( parser, strict );
751 }
752 }
753 metadata.setPlugins( plugins );
754 }
755 else
756 {
757 checkUnknownElement( parser, strict );
758 }
759 }
760 return metadata;
761 }
762
763
764
765
766
767
768
769
770
771
772
773 private Plugin parsePlugin( XmlPullParser parser, boolean strict )
774 throws IOException, XmlPullParserException
775 {
776 String tagName = parser.getName();
777 Plugin plugin = new Plugin();
778 for ( int i = parser.getAttributeCount() - 1; i >= 0; i-- )
779 {
780 String name = parser.getAttributeName( i );
781 String value = parser.getAttributeValue( i );
782
783 if ( name.indexOf( ':' ) >= 0 )
784 {
785
786 }
787 else
788 {
789 checkUnknownAttribute( parser, name, tagName, strict );
790 }
791 }
792 java.util.Set<String> parsed = new java.util.HashSet<String>();
793 while ( ( strict ? parser.nextTag() : nextTag( parser ) ) == XmlPullParser.START_TAG )
794 {
795 if ( checkFieldWithDuplicate( parser, "name", null, parsed ) )
796 {
797 plugin.setName( interpolatedTrimmed( parser.nextText(), "name" ) );
798 }
799 else if ( checkFieldWithDuplicate( parser, "prefix", null, parsed ) )
800 {
801 plugin.setPrefix( interpolatedTrimmed( parser.nextText(), "prefix" ) );
802 }
803 else if ( checkFieldWithDuplicate( parser, "artifactId", null, parsed ) )
804 {
805 plugin.setArtifactId( interpolatedTrimmed( parser.nextText(), "artifactId" ) );
806 }
807 else
808 {
809 checkUnknownElement( parser, strict );
810 }
811 }
812 return plugin;
813 }
814
815
816
817
818
819
820
821
822
823
824
825 private Snapshot parseSnapshot( XmlPullParser parser, boolean strict )
826 throws IOException, XmlPullParserException
827 {
828 String tagName = parser.getName();
829 Snapshot snapshot = new Snapshot();
830 for ( int i = parser.getAttributeCount() - 1; i >= 0; i-- )
831 {
832 String name = parser.getAttributeName( i );
833 String value = parser.getAttributeValue( i );
834
835 if ( name.indexOf( ':' ) >= 0 )
836 {
837
838 }
839 else
840 {
841 checkUnknownAttribute( parser, name, tagName, strict );
842 }
843 }
844 java.util.Set<String> parsed = new java.util.HashSet<String>();
845 while ( ( strict ? parser.nextTag() : nextTag( parser ) ) == XmlPullParser.START_TAG )
846 {
847 if ( checkFieldWithDuplicate( parser, "timestamp", null, parsed ) )
848 {
849 snapshot.setTimestamp( interpolatedTrimmed( parser.nextText(), "timestamp" ) );
850 }
851 else if ( checkFieldWithDuplicate( parser, "buildNumber", null, parsed ) )
852 {
853 snapshot.setBuildNumber( getIntegerValue( interpolatedTrimmed( parser.nextText(), "buildNumber" ), "buildNumber", parser, strict ) );
854 }
855 else if ( checkFieldWithDuplicate( parser, "localCopy", null, parsed ) )
856 {
857 snapshot.setLocalCopy( getBooleanValue( interpolatedTrimmed( parser.nextText(), "localCopy" ), "localCopy", parser, "false" ) );
858 }
859 else
860 {
861 checkUnknownElement( parser, strict );
862 }
863 }
864 return snapshot;
865 }
866
867
868
869
870
871
872
873
874
875
876
877 private SnapshotVersion parseSnapshotVersion( XmlPullParser parser, boolean strict )
878 throws IOException, XmlPullParserException
879 {
880 String tagName = parser.getName();
881 SnapshotVersion snapshotVersion = new SnapshotVersion();
882 for ( int i = parser.getAttributeCount() - 1; i >= 0; i-- )
883 {
884 String name = parser.getAttributeName( i );
885 String value = parser.getAttributeValue( i );
886
887 if ( name.indexOf( ':' ) >= 0 )
888 {
889
890 }
891 else
892 {
893 checkUnknownAttribute( parser, name, tagName, strict );
894 }
895 }
896 java.util.Set<String> parsed = new java.util.HashSet<String>();
897 while ( ( strict ? parser.nextTag() : nextTag( parser ) ) == XmlPullParser.START_TAG )
898 {
899 if ( checkFieldWithDuplicate( parser, "classifier", null, parsed ) )
900 {
901 snapshotVersion.setClassifier( interpolatedTrimmed( parser.nextText(), "classifier" ) );
902 }
903 else if ( checkFieldWithDuplicate( parser, "extension", null, parsed ) )
904 {
905 snapshotVersion.setExtension( interpolatedTrimmed( parser.nextText(), "extension" ) );
906 }
907 else if ( checkFieldWithDuplicate( parser, "value", null, parsed ) )
908 {
909 snapshotVersion.setVersion( interpolatedTrimmed( parser.nextText(), "value" ) );
910 }
911 else if ( checkFieldWithDuplicate( parser, "updated", null, parsed ) )
912 {
913 snapshotVersion.setUpdated( interpolatedTrimmed( parser.nextText(), "updated" ) );
914 }
915 else
916 {
917 checkUnknownElement( parser, strict );
918 }
919 }
920 return snapshotVersion;
921 }
922
923
924
925
926
927
928
929
930
931
932
933 private Versioning parseVersioning( XmlPullParser parser, boolean strict )
934 throws IOException, XmlPullParserException
935 {
936 String tagName = parser.getName();
937 Versioning versioning = new Versioning();
938 for ( int i = parser.getAttributeCount() - 1; i >= 0; i-- )
939 {
940 String name = parser.getAttributeName( i );
941 String value = parser.getAttributeValue( i );
942
943 if ( name.indexOf( ':' ) >= 0 )
944 {
945
946 }
947 else
948 {
949 checkUnknownAttribute( parser, name, tagName, strict );
950 }
951 }
952 java.util.Set<String> parsed = new java.util.HashSet<String>();
953 while ( ( strict ? parser.nextTag() : nextTag( parser ) ) == XmlPullParser.START_TAG )
954 {
955 if ( checkFieldWithDuplicate( parser, "latest", null, parsed ) )
956 {
957 versioning.setLatest( interpolatedTrimmed( parser.nextText(), "latest" ) );
958 }
959 else if ( checkFieldWithDuplicate( parser, "release", null, parsed ) )
960 {
961 versioning.setRelease( interpolatedTrimmed( parser.nextText(), "release" ) );
962 }
963 else if ( checkFieldWithDuplicate( parser, "versions", null, parsed ) )
964 {
965 java.util.List<String> versions = new java.util.ArrayList<String>();
966 while ( parser.nextTag() == XmlPullParser.START_TAG )
967 {
968 if ( "version".equals( parser.getName() ) )
969 {
970 versions.add( interpolatedTrimmed( parser.nextText(), "versions" ) );
971 }
972 else
973 {
974 checkUnknownElement( parser, strict );
975 }
976 }
977 versioning.setVersions( versions );
978 }
979 else if ( checkFieldWithDuplicate( parser, "lastUpdated", null, parsed ) )
980 {
981 versioning.setLastUpdated( interpolatedTrimmed( parser.nextText(), "lastUpdated" ) );
982 }
983 else if ( checkFieldWithDuplicate( parser, "snapshot", null, parsed ) )
984 {
985 versioning.setSnapshot( parseSnapshot( parser, strict ) );
986 }
987 else if ( checkFieldWithDuplicate( parser, "snapshotVersions", null, parsed ) )
988 {
989 java.util.List<SnapshotVersion> snapshotVersions = new java.util.ArrayList<SnapshotVersion>();
990 while ( parser.nextTag() == XmlPullParser.START_TAG )
991 {
992 if ( "snapshotVersion".equals( parser.getName() ) )
993 {
994 snapshotVersions.add( parseSnapshotVersion( parser, strict ) );
995 }
996 else
997 {
998 checkUnknownElement( parser, strict );
999 }
1000 }
1001 versioning.setSnapshotVersions( snapshotVersions );
1002 }
1003 else
1004 {
1005 checkUnknownElement( parser, strict );
1006 }
1007 }
1008 return versioning;
1009 }
1010
1011
1012
1013
1014
1015
1016 public void setAddDefaultEntities( boolean addDefaultEntities )
1017 {
1018 this.addDefaultEntities = addDefaultEntities;
1019 }
1020
1021 public static interface ContentTransformer
1022 {
1023
1024
1025
1026
1027
1028
1029
1030 String transform( String source, String fieldName );
1031 }
1032
1033 }