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