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