1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.scxml2.io;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.Reader;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.net.URL;
25 import java.net.URLConnection;
26 import java.text.MessageFormat;
27 import java.util.ArrayList;
28 import java.util.EmptyStackException;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Stack;
33
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.parsers.ParserConfigurationException;
36 import javax.xml.stream.XMLInputFactory;
37 import javax.xml.stream.XMLReporter;
38 import javax.xml.stream.XMLResolver;
39 import javax.xml.stream.XMLStreamConstants;
40 import javax.xml.stream.XMLStreamException;
41 import javax.xml.stream.XMLStreamReader;
42 import javax.xml.stream.util.XMLEventAllocator;
43 import javax.xml.transform.Source;
44 import javax.xml.transform.stream.StreamSource;
45 import javax.xml.validation.Schema;
46 import javax.xml.validation.SchemaFactory;
47 import javax.xml.validation.Validator;
48
49 import org.apache.commons.logging.LogFactory;
50 import org.apache.commons.scxml2.Evaluator;
51 import org.apache.commons.scxml2.PathResolver;
52 import org.apache.commons.scxml2.env.SimpleErrorHandler;
53 import org.apache.commons.scxml2.env.URLResolver;
54 import org.apache.commons.scxml2.model.Action;
55 import org.apache.commons.scxml2.model.ActionsContainer;
56 import org.apache.commons.scxml2.model.Assign;
57 import org.apache.commons.scxml2.model.Cancel;
58 import org.apache.commons.scxml2.model.Content;
59 import org.apache.commons.scxml2.model.ContentContainer;
60 import org.apache.commons.scxml2.model.CustomAction;
61 import org.apache.commons.scxml2.model.Data;
62 import org.apache.commons.scxml2.model.Datamodel;
63 import org.apache.commons.scxml2.model.Else;
64 import org.apache.commons.scxml2.model.ElseIf;
65 import org.apache.commons.scxml2.model.EnterableState;
66 import org.apache.commons.scxml2.model.Executable;
67 import org.apache.commons.scxml2.model.ExternalContent;
68 import org.apache.commons.scxml2.model.Final;
69 import org.apache.commons.scxml2.model.Finalize;
70 import org.apache.commons.scxml2.model.Foreach;
71 import org.apache.commons.scxml2.model.History;
72 import org.apache.commons.scxml2.model.If;
73 import org.apache.commons.scxml2.model.Initial;
74 import org.apache.commons.scxml2.model.Invoke;
75 import org.apache.commons.scxml2.model.Log;
76 import org.apache.commons.scxml2.model.ModelException;
77 import org.apache.commons.scxml2.model.NamespacePrefixesHolder;
78 import org.apache.commons.scxml2.model.OnEntry;
79 import org.apache.commons.scxml2.model.OnExit;
80 import org.apache.commons.scxml2.model.Parallel;
81 import org.apache.commons.scxml2.model.Param;
82 import org.apache.commons.scxml2.model.ParamsContainer;
83 import org.apache.commons.scxml2.model.Raise;
84 import org.apache.commons.scxml2.model.SCXML;
85 import org.apache.commons.scxml2.model.Script;
86 import org.apache.commons.scxml2.model.Send;
87 import org.apache.commons.scxml2.model.SimpleTransition;
88 import org.apache.commons.scxml2.model.State;
89 import org.apache.commons.scxml2.model.Transition;
90 import org.apache.commons.scxml2.model.TransitionType;
91 import org.apache.commons.scxml2.model.TransitionalState;
92 import org.apache.commons.scxml2.model.Var;
93 import org.w3c.dom.Attr;
94 import org.w3c.dom.Document;
95 import org.w3c.dom.Element;
96 import org.w3c.dom.Node;
97 import org.w3c.dom.NodeList;
98 import org.xml.sax.SAXException;
99
100
101
102
103
104
105
106
107
108
109
110
111
112 public final class SCXMLReader {
113
114
115
116
117
118
119
120
121 private static final String XMLNS_SCXML =
122 "http://www.w3.org/2005/07/scxml";
123
124
125
126
127
128
129
130
131 private static final String XMLNS_COMMONS_SCXML =
132 "http://commons.apache.org/scxml";
133
134
135
136
137 private static final String SCXML_REQUIRED_VERSION = "1.0";
138
139
140
141 private static final String XMLNS_DEFAULT = null;
142
143
144
145
146
147 private static final String ERR_NULL_URL = "Cannot parse null URL";
148
149
150
151
152 private static final String ERR_NULL_PATH = "Cannot parse null path";
153
154
155
156
157 private static final String ERR_NULL_ISTR = "Cannot parse null InputStream";
158
159
160
161
162 private static final String ERR_NULL_READ = "Cannot parse null Reader";
163
164
165
166
167 private static final String ERR_NULL_SRC = "Cannot parse null Source";
168
169
170
171
172
173 private static final String ERR_CUSTOM_ACTION_TYPE = "Custom actions list"
174 + " contained unknown object, class not a Commons SCXML Action class subtype: ";
175
176
177
178
179 private static final String ERR_PARSER_CFG = "ParserConfigurationException while trying"
180 + " to parse stream into DOM node(s).";
181
182
183
184
185
186
187 private static final String ERR_STATE_SRC =
188 "Source attribute in <state src=\"{0}\"> cannot be parsed";
189
190
191
192
193
194 private static final String ERR_STATE_SRC_FRAGMENT = "URI Fragment in "
195 + "<state src=\"{0}\"> is an unknown state in referenced document";
196
197
198
199
200
201
202 private static final String ERR_STATE_SRC_FRAGMENT_TARGET = "URI Fragment"
203 + " in <state src=\"{0}\"> does not point to a <state> or <final>";
204
205
206
207
208
209
210 private static final String ERR_REQUIRED_ATTRIBUTE_MISSING = "<{0}> is missing"
211 +" required attribute \"{1}\" value at {2}";
212
213
214
215
216
217
218 private static final String ERR_ATTRIBUTE_NOT_BOOLEAN = "Illegal value \"{0}\""
219 + "for attribute \"{1}\" in element <{2}> at {3}."
220 +" Only the value \"true\" or \"false\" is allowed.";
221
222
223
224
225
226 private static final String ERR_RESERVED_ID_PREFIX = "Reserved id prefix \""
227 +SCXML.GENERATED_TT_ID_PREFIX+"\" used for <{0} id=\"{1}\"> at {2}";
228
229
230
231
232
233 private static final String ERR_UNSUPPORTED_TRANSITION_TYPE = "Unsupported transition type "
234 + "for <transition type=\"{0}\"> at {1}.";
235
236
237
238
239
240
241 private static final String ERR_INVALID_VERSION = "The <scxml> element defines"
242 +" an unsupported version \"{0}\", only version \"1.0\" is supported.";
243
244
245
246 private static final String ELEM_ASSIGN = "assign";
247 private static final String ELEM_CANCEL = "cancel";
248 private static final String ELEM_CONTENT = "content";
249 private static final String ELEM_DATA = "data";
250 private static final String ELEM_DATAMODEL = "datamodel";
251 private static final String ELEM_ELSE = "else";
252 private static final String ELEM_ELSEIF = "elseif";
253 private static final String ELEM_RAISE = "raise";
254 private static final String ELEM_FINAL = "final";
255 private static final String ELEM_FINALIZE = "finalize";
256 private static final String ELEM_HISTORY = "history";
257 private static final String ELEM_IF = "if";
258 private static final String ELEM_INITIAL = "initial";
259 private static final String ELEM_INVOKE = "invoke";
260 private static final String ELEM_FOREACH = "foreach";
261 private static final String ELEM_LOG = "log";
262 private static final String ELEM_ONENTRY = "onentry";
263 private static final String ELEM_ONEXIT = "onexit";
264 private static final String ELEM_PARALLEL = "parallel";
265 private static final String ELEM_PARAM = "param";
266 private static final String ELEM_SCRIPT = "script";
267 private static final String ELEM_SCXML = "scxml";
268 private static final String ELEM_SEND = "send";
269 private static final String ELEM_STATE = "state";
270 private static final String ELEM_TRANSITION = "transition";
271 private static final String ELEM_VAR = "var";
272
273
274 private static final String ATTR_ARRAY = "array";
275 private static final String ATTR_ATTR = "attr";
276 private static final String ATTR_AUTOFORWARD = "autoforward";
277 private static final String ATTR_COND = "cond";
278 private static final String ATTR_DATAMODEL = "datamodel";
279 private static final String ATTR_DELAY = "delay";
280 private static final String ATTR_DELAYEXPR = "delayexpr";
281 private static final String ATTR_EVENT = "event";
282 private static final String ATTR_EVENTEXPR = "eventexpr";
283 private static final String ATTR_EXMODE = "exmode";
284 private static final String ATTR_EXPR = "expr";
285 private static final String ATTR_HINTS = "hints";
286 private static final String ATTR_ID = "id";
287 private static final String ATTR_IDLOCATION = "idlocation";
288 private static final String ATTR_INDEX = "index";
289 private static final String ATTR_INITIAL = "initial";
290 private static final String ATTR_ITEM = "item";
291 private static final String ATTR_LABEL = "label";
292 private static final String ATTR_LOCATION = "location";
293 private static final String ATTR_NAME = "name";
294 private static final String ATTR_NAMELIST = "namelist";
295 private static final String ATTR_PROFILE = "profile";
296 private static final String ATTR_SENDID = "sendid";
297 private static final String ATTR_SENDIDEXPR = "sendidexpr";
298 private static final String ATTR_SRC = "src";
299 private static final String ATTR_SRCEXPR = "srcexpr";
300 private static final String ATTR_TARGET = "target";
301 private static final String ATTR_TARGETEXPR = "targetexpr";
302 private static final String ATTR_TYPE = "type";
303 private static final String ATTR_TYPEEXPR = "typeexpr";
304 private static final String ATTR_VERSION = "version";
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 public static SCXML read(final String scxmlPath)
323 throws IOException, ModelException, XMLStreamException {
324
325 return read(scxmlPath, new Configuration());
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 public static SCXML read(final String scxmlPath, final Configuration configuration)
342 throws IOException, ModelException, XMLStreamException {
343
344 if (scxmlPath == null) {
345 throw new IllegalArgumentException(ERR_NULL_PATH);
346 }
347 SCXML scxml = readInternal(configuration, null, scxmlPath, null, null, null);
348 if (scxml != null) {
349 ModelUpdater.updateSCXML(scxml);
350 }
351 return scxml;
352 }
353
354
355
356
357
358
359
360
361
362
363
364
365
366 public static SCXML read(final URL scxmlURL)
367 throws IOException, ModelException, XMLStreamException {
368
369 return read(scxmlURL, new Configuration());
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385 public static SCXML read(final URL scxmlURL, final Configuration configuration)
386 throws IOException, ModelException, XMLStreamException {
387
388 if (scxmlURL == null) {
389 throw new IllegalArgumentException(ERR_NULL_URL);
390 }
391 SCXML scxml = readInternal(configuration, scxmlURL, null, null, null, null);
392 if (scxml != null) {
393 ModelUpdater.updateSCXML(scxml);
394 }
395 return scxml;
396 }
397
398
399
400
401
402
403
404
405
406
407
408
409
410 public static SCXML read(final InputStream scxmlStream)
411 throws IOException, ModelException, XMLStreamException {
412
413 return read(scxmlStream, new Configuration());
414 }
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429 public static SCXML read(final InputStream scxmlStream, final Configuration configuration)
430 throws IOException, ModelException, XMLStreamException {
431
432 if (scxmlStream == null) {
433 throw new IllegalArgumentException(ERR_NULL_ISTR);
434 }
435 SCXML scxml = readInternal(configuration, null, null, scxmlStream, null, null);
436 if (scxml != null) {
437 ModelUpdater.updateSCXML(scxml);
438 }
439 return scxml;
440 }
441
442
443
444
445
446
447
448
449
450
451
452
453
454 public static SCXML read(final Reader scxmlReader)
455 throws IOException, ModelException, XMLStreamException {
456
457 return read(scxmlReader, new Configuration());
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473 public static SCXML read(final Reader scxmlReader, final Configuration configuration)
474 throws IOException, ModelException, XMLStreamException {
475
476 if (scxmlReader == null) {
477 throw new IllegalArgumentException(ERR_NULL_READ);
478 }
479 SCXML scxml = readInternal(configuration, null, null, null, scxmlReader, null);
480 if (scxml != null) {
481 ModelUpdater.updateSCXML(scxml);
482 }
483 return scxml;
484 }
485
486
487
488
489
490
491
492
493
494
495
496
497
498 public static SCXML read(final Source scxmlSource)
499 throws IOException, ModelException, XMLStreamException {
500
501 return read(scxmlSource, new Configuration());
502 }
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517 public static SCXML read(final Source scxmlSource, final Configuration configuration)
518 throws IOException, ModelException, XMLStreamException {
519
520 if (scxmlSource == null) {
521 throw new IllegalArgumentException(ERR_NULL_SRC);
522 }
523 SCXML scxml = readInternal(configuration, null, null, null, null, scxmlSource);
524 if (scxml != null) {
525 ModelUpdater.updateSCXML(scxml);
526 }
527 return scxml;
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551 private static SCXML readInternal(final Configuration configuration, final URL scxmlURL, final String scxmlPath,
552 final InputStream scxmlStream, final Reader scxmlReader, final Source scxmlSource)
553 throws IOException, ModelException, XMLStreamException {
554
555 if (configuration.pathResolver == null) {
556 if (scxmlURL != null) {
557 configuration.pathResolver = new URLResolver(scxmlURL);
558 } else if (scxmlPath != null) {
559 configuration.pathResolver = new URLResolver(new URL(scxmlPath));
560 }
561 }
562
563 XMLStreamReader reader = getReader(configuration, scxmlURL, scxmlPath, scxmlStream, scxmlReader, scxmlSource);
564
565 return readDocument(reader, configuration);
566 }
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585 private static SCXML readDocument(final XMLStreamReader reader, final Configuration configuration)
586 throws IOException, ModelException, XMLStreamException {
587
588 SCXML scxml = new SCXML();
589 while (reader.hasNext()) {
590 String name, nsURI;
591 switch (reader.next()) {
592 case XMLStreamConstants.START_ELEMENT:
593 pushNamespaces(reader, configuration);
594 nsURI = reader.getNamespaceURI();
595 name = reader.getLocalName();
596 if (XMLNS_SCXML.equals(nsURI)) {
597 if (ELEM_SCXML.equals(name)) {
598 readSCXML(reader, configuration, scxml);
599 } else {
600 reportIgnoredElement(reader, configuration, "DOCUMENT_ROOT", nsURI, name);
601 }
602 } else {
603 reportIgnoredElement(reader, configuration, "DOCUMENT_ROOT", nsURI, name);
604 }
605 break;
606 case XMLStreamConstants.NAMESPACE:
607 System.err.println(reader.getNamespaceCount());
608 break;
609 default:
610 }
611 }
612 return scxml;
613 }
614
615
616
617
618
619
620
621
622
623
624
625
626
627 private static void readSCXML(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml)
628 throws IOException, ModelException, XMLStreamException {
629
630 scxml.setDatamodelName(readAV(reader, ATTR_DATAMODEL));
631 scxml.setExmode(readAV(reader, ATTR_EXMODE));
632 scxml.setInitial(readAV(reader, ATTR_INITIAL));
633 scxml.setName(readAV(reader, ATTR_NAME));
634 scxml.setProfile(readAV(reader, ATTR_PROFILE));
635 scxml.setVersion(readRequiredAV(reader, ELEM_SCXML, ATTR_VERSION));
636 if (!SCXML_REQUIRED_VERSION.equals(scxml.getVersion())) {
637 throw new ModelException(new MessageFormat(ERR_INVALID_VERSION).format(new Object[] {scxml.getVersion()}));
638 }
639 readNamespaces(configuration, scxml);
640
641 boolean hasGlobalScript = false;
642
643 loop : while (reader.hasNext()) {
644 String name, nsURI;
645 switch (reader.next()) {
646 case XMLStreamConstants.START_ELEMENT:
647 pushNamespaces(reader, configuration);
648 nsURI = reader.getNamespaceURI();
649 name = reader.getLocalName();
650 if (XMLNS_SCXML.equals(nsURI)) {
651 if (ELEM_STATE.equals(name)) {
652 readState(reader, configuration, scxml, null);
653 } else if (ELEM_PARALLEL.equals(name)) {
654 readParallel(reader, configuration, scxml, null);
655 } else if (ELEM_FINAL.equals(name)) {
656 readFinal(reader, configuration, scxml, null);
657 } else if (ELEM_DATAMODEL.equals(name)) {
658 readDatamodel(reader, configuration, scxml, null);
659 } else if (ELEM_SCRIPT.equals(name) && !hasGlobalScript) {
660 readGlobalScript(reader, configuration, scxml);
661 hasGlobalScript = true;
662 } else {
663 reportIgnoredElement(reader, configuration, ELEM_SCXML, nsURI, name);
664 }
665 } else {
666 reportIgnoredElement(reader, configuration, ELEM_SCXML, nsURI, name);
667 }
668 break;
669 case XMLStreamConstants.END_ELEMENT:
670 popNamespaces(reader, configuration);
671 break loop;
672 default:
673 }
674 }
675 }
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690 private static void readState(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
691 final TransitionalState parent)
692 throws IOException, ModelException, XMLStreamException {
693
694 State state = new State();
695 state.setId(readOrGeneratedTransitionTargetId(reader, scxml, ELEM_STATE));
696 String initial = readAV(reader, ATTR_INITIAL);
697 if (initial != null) {
698 state.setFirst(initial);
699 }
700 String src = readAV(reader, ATTR_SRC);
701 if (src != null) {
702 String source = src;
703 Configuration copy = new Configuration(configuration);
704 if (copy.parent == null) {
705 copy.parent = scxml;
706 }
707 if (configuration.pathResolver != null) {
708 source = configuration.pathResolver.resolvePath(src);
709 copy.pathResolver = configuration.pathResolver.getResolver(src);
710 }
711 readTransitionalStateSrc(copy, source, state);
712 }
713
714 if (parent == null) {
715 scxml.addChild(state);
716 } else if (parent instanceof State) {
717 ((State)parent).addChild(state);
718 }
719 else {
720 ((Parallel)parent).addChild(state);
721 }
722 scxml.addTarget(state);
723 if (configuration.parent != null) {
724 configuration.parent.addTarget(state);
725 }
726
727 loop : while (reader.hasNext()) {
728 String name, nsURI;
729 switch (reader.next()) {
730 case XMLStreamConstants.START_ELEMENT:
731 pushNamespaces(reader, configuration);
732 nsURI = reader.getNamespaceURI();
733 name = reader.getLocalName();
734 if (XMLNS_SCXML.equals(nsURI)) {
735 if (ELEM_TRANSITION.equals(name)) {
736 state.addTransition(readTransition(reader, configuration));
737 } else if (ELEM_STATE.equals(name)) {
738 readState(reader, configuration, scxml, state);
739 } else if (ELEM_INITIAL.equals(name)) {
740 readInitial(reader, configuration, state);
741 } else if (ELEM_FINAL.equals(name)) {
742 readFinal(reader, configuration, scxml, state);
743 } else if (ELEM_ONENTRY.equals(name)) {
744 readOnEntry(reader, configuration, state);
745 } else if (ELEM_ONEXIT.equals(name)) {
746 readOnExit(reader, configuration, state);
747 } else if (ELEM_PARALLEL.equals(name)) {
748 readParallel(reader, configuration, scxml, state);
749 } else if (ELEM_DATAMODEL.equals(name)) {
750 readDatamodel(reader, configuration, null, state);
751 } else if (ELEM_INVOKE.equals(name)) {
752 readInvoke(reader, configuration, state);
753 } else if (ELEM_HISTORY.equals(name)) {
754 readHistory(reader, configuration, scxml, state);
755 } else {
756 reportIgnoredElement(reader, configuration, ELEM_STATE, nsURI, name);
757 }
758 } else {
759 reportIgnoredElement(reader, configuration, ELEM_STATE, nsURI, name);
760 }
761 break;
762 case XMLStreamConstants.END_ELEMENT:
763 popNamespaces(reader, configuration);
764 break loop;
765 default:
766 }
767 }
768 }
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783 private static void readParallel(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
784 final TransitionalState parent)
785 throws IOException, ModelException, XMLStreamException {
786
787 Parallel parallel = new Parallel();
788 parallel.setId(readOrGeneratedTransitionTargetId(reader, scxml, ELEM_PARALLEL));
789 String src = readAV(reader, ATTR_SRC);
790 if (src != null) {
791 String source = src;
792 Configuration copy = new Configuration(configuration);
793 if (copy.parent == null) {
794 copy.parent = scxml;
795 }
796 if (configuration.pathResolver != null) {
797 source = configuration.pathResolver.resolvePath(src);
798 copy.pathResolver = configuration.pathResolver.getResolver(src);
799 }
800 readTransitionalStateSrc(copy, source, parallel);
801 }
802
803 if (parent == null) {
804 scxml.addChild(parallel);
805 } else if (parent instanceof State) {
806 ((State)parent).addChild(parallel);
807 }
808 else {
809 ((Parallel)parent).addChild(parallel);
810 }
811 scxml.addTarget(parallel);
812 if (configuration.parent != null) {
813 configuration.parent.addTarget(parallel);
814 }
815
816 loop : while (reader.hasNext()) {
817 String name, nsURI;
818 switch (reader.next()) {
819 case XMLStreamConstants.START_ELEMENT:
820 pushNamespaces(reader, configuration);
821 nsURI = reader.getNamespaceURI();
822 name = reader.getLocalName();
823 if (XMLNS_SCXML.equals(nsURI)) {
824 if (ELEM_TRANSITION.equals(name)) {
825 parallel.addTransition(readTransition(reader, configuration));
826 } else if (ELEM_STATE.equals(name)) {
827 readState(reader, configuration, scxml, parallel);
828 } else if (ELEM_PARALLEL.equals(name)) {
829 readParallel(reader, configuration, scxml, parallel);
830 } else if (ELEM_ONENTRY.equals(name)) {
831 readOnEntry(reader, configuration, parallel);
832 } else if (ELEM_ONEXIT.equals(name)) {
833 readOnExit(reader, configuration, parallel);
834 } else if (ELEM_DATAMODEL.equals(name)) {
835 readDatamodel(reader, configuration, null, parallel);
836 } else if (ELEM_INVOKE.equals(name)) {
837 readInvoke(reader, configuration, parallel);
838 } else if (ELEM_HISTORY.equals(name)) {
839 readHistory(reader, configuration, scxml, parallel);
840 } else {
841 reportIgnoredElement(reader, configuration, ELEM_PARALLEL, nsURI, name);
842 }
843 } else {
844 reportIgnoredElement(reader, configuration, ELEM_PARALLEL, nsURI, name);
845 }
846 break;
847 case XMLStreamConstants.END_ELEMENT:
848 popNamespaces(reader, configuration);
849 break loop;
850 default:
851 }
852 }
853 }
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868 private static void readFinal(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
869 final State parent)
870 throws XMLStreamException, ModelException, IOException {
871
872 Final end = new Final();
873 end.setId(readOrGeneratedTransitionTargetId(reader, scxml, ELEM_FINAL));
874
875 if (parent == null) {
876 scxml.addChild(end);
877 } else {
878 parent.addChild(end);
879 }
880
881 scxml.addTarget(end);
882 if (configuration.parent != null) {
883 configuration.parent.addTarget(end);
884 }
885
886 loop : while (reader.hasNext()) {
887 String name, nsURI;
888 switch (reader.next()) {
889 case XMLStreamConstants.START_ELEMENT:
890 pushNamespaces(reader, configuration);
891 nsURI = reader.getNamespaceURI();
892 name = reader.getLocalName();
893 if (XMLNS_SCXML.equals(nsURI)) {
894 if (ELEM_ONENTRY.equals(name)) {
895 readOnEntry(reader, configuration, end);
896 } else if (ELEM_ONEXIT.equals(name)) {
897 readOnExit(reader, configuration, end);
898 } else {
899 reportIgnoredElement(reader, configuration, ELEM_FINAL, nsURI, name);
900 }
901 } else {
902 reportIgnoredElement(reader, configuration, ELEM_FINAL, nsURI, name);
903 }
904 break;
905 case XMLStreamConstants.END_ELEMENT:
906 popNamespaces(reader, configuration);
907 break loop;
908 default:
909 }
910 }
911 }
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928 private static void readTransitionalStateSrc(final Configuration configuration, final String src,
929 final TransitionalState ts)
930 throws IOException, ModelException, XMLStreamException {
931
932
933 String[] fragments = src.split("#", 2);
934 String location = fragments[0];
935 String fragment = null;
936 if (fragments.length > 1) {
937 fragment = fragments[1];
938 }
939
940
941 SCXML externalSCXML;
942 try {
943 externalSCXML = SCXMLReader.readInternal(configuration, new URL(location), null, null, null, null);
944 } catch (Exception e) {
945 MessageFormat msgFormat = new MessageFormat(ERR_STATE_SRC);
946 String errMsg = msgFormat.format(new Object[] {src});
947 throw new ModelException(errMsg + " : " + e.getMessage(), e);
948 }
949
950
951 if (fragment == null) {
952
953 if (ts instanceof State) {
954 State s = (State) ts;
955 Initial ini = new Initial();
956 SimpleTransition t = new SimpleTransition();
957 t.setNext(externalSCXML.getInitial());
958 ini.setTransition(t);
959 s.setInitial(ini);
960 for (EnterableState child : externalSCXML.getChildren()) {
961 s.addChild(child);
962 }
963 s.setDatamodel(externalSCXML.getDatamodel());
964 } else if (ts instanceof Parallel) {
965
966 }
967 } else {
968
969 Object source = externalSCXML.getTargets().get(fragment);
970 if (source == null) {
971 MessageFormat msgFormat = new MessageFormat(ERR_STATE_SRC_FRAGMENT);
972 String errMsg = msgFormat.format(new Object[] {src});
973 throw new ModelException(errMsg);
974 }
975 if (source instanceof State && ts instanceof State) {
976 State s = (State) ts;
977 State include = (State) source;
978 for (OnEntry onentry : include.getOnEntries()) {
979 s.addOnEntry(onentry);
980 }
981 for (OnExit onexit : include.getOnExits()) {
982 s.addOnExit(onexit);
983 }
984 s.setDatamodel(include.getDatamodel());
985 List<History> histories = include.getHistory();
986 for (History h : histories) {
987 s.addHistory(h);
988 configuration.parent.addTarget(h);
989 }
990 for (EnterableState child : include.getChildren()) {
991 s.addChild(child);
992 configuration.parent.addTarget(child);
993 readInExternalTargets(configuration.parent, child);
994 }
995 for (Invoke invoke : include.getInvokes()) {
996 s.addInvoke(invoke);
997 }
998 if (include.getInitial() != null) {
999 s.setInitial(include.getInitial());
1000 }
1001 List<Transition> transitions = include.getTransitionsList();
1002 for (Transition t : transitions) {
1003 s.addTransition(t);
1004 }
1005 } else if (ts instanceof Parallel && source instanceof Parallel) {
1006
1007 } else {
1008 MessageFormat msgFormat =
1009 new MessageFormat(ERR_STATE_SRC_FRAGMENT_TARGET);
1010 String errMsg = msgFormat.format(new Object[] {src});
1011 throw new ModelException(errMsg);
1012 }
1013 }
1014 }
1015
1016
1017
1018
1019
1020
1021
1022 private static void readInExternalTargets(final SCXML parent, final EnterableState es) {
1023 if (es instanceof TransitionalState) {
1024 for (History h : ((TransitionalState)es).getHistory()) {
1025 parent.addTarget(h);
1026 }
1027 for (EnterableState child : ((TransitionalState) es).getChildren()) {
1028 parent.addTarget(child);
1029 readInExternalTargets(parent, child);
1030 }
1031 }
1032 }
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 private static void readDatamodel(final XMLStreamReader reader, final Configuration configuration,
1047 final SCXML scxml, final TransitionalState parent)
1048 throws XMLStreamException, ModelException {
1049
1050 Datamodel dm = new Datamodel();
1051
1052 loop : while (reader.hasNext()) {
1053 String name, nsURI;
1054 switch (reader.next()) {
1055 case XMLStreamConstants.START_ELEMENT:
1056 pushNamespaces(reader, configuration);
1057 nsURI = reader.getNamespaceURI();
1058 name = reader.getLocalName();
1059 if (XMLNS_SCXML.equals(nsURI)) {
1060 if (ELEM_DATA.equals(name)) {
1061 readData(reader, configuration, dm);
1062 } else {
1063 reportIgnoredElement(reader, configuration, ELEM_DATAMODEL, nsURI, name);
1064 }
1065 } else {
1066 reportIgnoredElement(reader, configuration, ELEM_DATAMODEL, nsURI, name);
1067 }
1068 break;
1069 case XMLStreamConstants.END_ELEMENT:
1070 popNamespaces(reader, configuration);
1071 break loop;
1072 default:
1073 }
1074 }
1075
1076 if (parent == null) {
1077 scxml.setDatamodel(dm);
1078 } else {
1079 parent.setDatamodel(dm);
1080 }
1081 }
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092 private static void readData(final XMLStreamReader reader, final Configuration configuration, final Datamodel dm)
1093 throws XMLStreamException, ModelException {
1094
1095 Data datum = new Data();
1096 datum.setId(readRequiredAV(reader, ELEM_DATA, ATTR_ID));
1097 datum.setExpr(readAV(reader, ATTR_EXPR));
1098 readNamespaces(configuration, datum);
1099 datum.setNode(readNode(reader, configuration, XMLNS_SCXML, ELEM_DATA, new String[]{"id"}));
1100 dm.addData(datum);
1101 }
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114 private static void readInvoke(final XMLStreamReader reader, final Configuration configuration,
1115 final TransitionalState parent)
1116 throws XMLStreamException, ModelException {
1117
1118 Invoke invoke = new Invoke();
1119 invoke.setId(readAV(reader, ATTR_ID));
1120 invoke.setSrc(readAV(reader, ATTR_SRC));
1121 invoke.setSrcexpr(readAV(reader, ATTR_SRCEXPR));
1122 invoke.setType(readAV(reader, ATTR_TYPE));
1123 invoke.setAutoForward(readBooleanAV(reader, ELEM_INVOKE, ATTR_AUTOFORWARD));
1124 invoke.setPathResolver(configuration.pathResolver);
1125 readNamespaces(configuration, invoke);
1126
1127 loop : while (reader.hasNext()) {
1128 String name, nsURI;
1129 switch (reader.next()) {
1130 case XMLStreamConstants.START_ELEMENT:
1131 pushNamespaces(reader, configuration);
1132 nsURI = reader.getNamespaceURI();
1133 name = reader.getLocalName();
1134 if (XMLNS_SCXML.equals(nsURI)) {
1135 if (ELEM_PARAM.equals(name)) {
1136 readParam(reader, configuration, invoke);
1137 } else if (ELEM_FINALIZE.equals(name)) {
1138 readFinalize(reader, configuration, parent, invoke);
1139 } else if (ELEM_CONTENT.equals(name)) {
1140 readContent(reader, configuration, invoke);
1141 } else {
1142 reportIgnoredElement(reader, configuration, ELEM_INVOKE, nsURI, name);
1143 }
1144 } else {
1145 reportIgnoredElement(reader, configuration, ELEM_INVOKE, nsURI, name);
1146 }
1147 break;
1148 case XMLStreamConstants.END_ELEMENT:
1149 popNamespaces(reader, configuration);
1150 break loop;
1151 default:
1152 }
1153 }
1154
1155 parent.addInvoke(invoke);
1156 }
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167 private static void readParam(final XMLStreamReader reader, final Configuration configuration,
1168 final ParamsContainer parent)
1169 throws XMLStreamException, ModelException {
1170
1171 Param param = new Param();
1172 param.setName(readRequiredAV(reader, ELEM_PARAM, ATTR_NAME));
1173 String location = readAV(reader, ATTR_LOCATION);
1174 String expr = readAV(reader, ATTR_EXPR);
1175 if (expr != null) {
1176 if (location != null) {
1177 reportConflictingAttribute(reader, configuration, ELEM_PARAM, ATTR_LOCATION, ATTR_EXPR);
1178 }
1179 else {
1180 param.setExpr(expr);
1181 }
1182 }
1183 else if (location == null) {
1184
1185 param.setLocation(readRequiredAV(reader, ELEM_PARAM, ATTR_LOCATION));
1186 }
1187 else {
1188 param.setLocation(location);
1189 }
1190 readNamespaces(configuration, param);
1191 parent.getParams().add(param);
1192 skipToEndElement(reader);
1193 }
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 private static void readFinalize(final XMLStreamReader reader, final Configuration configuration,
1208 final TransitionalState state, final Invoke invoke)
1209 throws XMLStreamException, ModelException {
1210
1211 Finalize finalize = new Finalize();
1212 readExecutableContext(reader, configuration, finalize, null);
1213 invoke.setFinalize(finalize);
1214 finalize.setParent(state);
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 private static void readContent(final XMLStreamReader reader, final Configuration configuration,
1227 final ContentContainer contentContainer)
1228 throws XMLStreamException {
1229
1230 Content content = new Content();
1231 content.setExpr(readAV(reader, ATTR_EXPR));
1232 if (content.getExpr() != null) {
1233 skipToEndElement(reader);
1234 }
1235 else {
1236 Node body = readNode(reader, configuration, XMLNS_SCXML, ELEM_CONTENT, new String[]{});
1237 if (body.hasChildNodes()) {
1238 NodeList children = body.getChildNodes();
1239 if (children.getLength() == 1 && children.item(0).getNodeType() == Node.TEXT_NODE) {
1240 content.setBody(children.item(0).getNodeValue());
1241 }
1242 else {
1243 content.setBody(body);
1244 }
1245 }
1246 }
1247 contentContainer.setContent(content);
1248 }
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261 private static void readInitial(final XMLStreamReader reader, final Configuration configuration,
1262 final State state)
1263 throws XMLStreamException, ModelException {
1264
1265 Initial initial = new Initial();
1266
1267 loop : while (reader.hasNext()) {
1268 String name, nsURI;
1269 switch (reader.next()) {
1270 case XMLStreamConstants.START_ELEMENT:
1271 pushNamespaces(reader, configuration);
1272 nsURI = reader.getNamespaceURI();
1273 name = reader.getLocalName();
1274 if (XMLNS_SCXML.equals(nsURI)) {
1275 if (ELEM_TRANSITION.equals(name)) {
1276 initial.setTransition(readSimpleTransition(reader, configuration));
1277 } else {
1278 reportIgnoredElement(reader, configuration, ELEM_INITIAL, nsURI, name);
1279 }
1280 } else {
1281 reportIgnoredElement(reader, configuration, ELEM_INITIAL, nsURI, name);
1282 }
1283 break;
1284 case XMLStreamConstants.END_ELEMENT:
1285 popNamespaces(reader, configuration);
1286 break loop;
1287 default:
1288 }
1289 }
1290
1291 state.setInitial(initial);
1292 }
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306 private static void readHistory(final XMLStreamReader reader, final Configuration configuration,
1307 final SCXML scxml, final TransitionalState ts)
1308 throws XMLStreamException, ModelException {
1309
1310 History history = new History();
1311 history.setId(readOrGeneratedTransitionTargetId(reader, scxml, ELEM_HISTORY));
1312 history.setType(readAV(reader, ATTR_TYPE));
1313
1314 ts.addHistory(history);
1315 scxml.addTarget(history);
1316
1317 loop : while (reader.hasNext()) {
1318 String name, nsURI;
1319 switch (reader.next()) {
1320 case XMLStreamConstants.START_ELEMENT:
1321 pushNamespaces(reader, configuration);
1322 nsURI = reader.getNamespaceURI();
1323 name = reader.getLocalName();
1324 if (XMLNS_SCXML.equals(nsURI)) {
1325 if (ELEM_TRANSITION.equals(name)) {
1326 history.setTransition(readTransition(reader, configuration));
1327 } else {
1328 reportIgnoredElement(reader, configuration, ELEM_HISTORY, nsURI, name);
1329 }
1330 } else {
1331 reportIgnoredElement(reader, configuration, ELEM_HISTORY, nsURI, name);
1332 }
1333 break;
1334 case XMLStreamConstants.END_ELEMENT:
1335 popNamespaces(reader, configuration);
1336 break loop;
1337 default:
1338 }
1339 }
1340 }
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353 private static void readOnEntry(final XMLStreamReader reader, final Configuration configuration,
1354 final EnterableState es)
1355 throws XMLStreamException, ModelException {
1356
1357 OnEntry onentry = new OnEntry();
1358 onentry.setRaiseEvent(readBooleanAV(reader, ELEM_ONENTRY, ATTR_EVENT));
1359 readExecutableContext(reader, configuration, onentry, null);
1360 es.addOnEntry(onentry);
1361 }
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 private static void readOnExit(final XMLStreamReader reader, final Configuration configuration,
1375 final EnterableState es)
1376 throws XMLStreamException, ModelException {
1377
1378 OnExit onexit = new OnExit();
1379 onexit.setRaiseEvent(readBooleanAV(reader, ELEM_ONEXIT, ATTR_EVENT));
1380 readExecutableContext(reader, configuration, onexit, null);
1381 es.addOnExit(onexit);
1382 }
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394 private static SimpleTransition readSimpleTransition(final XMLStreamReader reader, final Configuration configuration)
1395 throws XMLStreamException, ModelException {
1396
1397 SimpleTransition transition = new SimpleTransition();
1398 transition.setNext(readAV(reader, ATTR_TARGET));
1399 String type = readAV(reader, ATTR_TYPE);
1400 if (type != null) {
1401 try {
1402 transition.setType(TransitionType.valueOf(type));
1403 }
1404 catch (IllegalArgumentException e) {
1405 MessageFormat msgFormat = new MessageFormat(ERR_UNSUPPORTED_TRANSITION_TYPE);
1406 String errMsg = msgFormat.format(new Object[] {type, reader.getLocation()});
1407 throw new ModelException(errMsg);
1408 }
1409 }
1410
1411 readNamespaces(configuration, transition);
1412 readExecutableContext(reader, configuration, transition, null);
1413
1414 return transition;
1415 }
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427 private static Transition readTransition(final XMLStreamReader reader, final Configuration configuration)
1428 throws XMLStreamException, ModelException {
1429
1430 Transition transition = new Transition();
1431 transition.setCond(readAV(reader, ATTR_COND));
1432 transition.setEvent(readAV(reader, ATTR_EVENT));
1433 transition.setNext(readAV(reader, ATTR_TARGET));
1434 String type = readAV(reader, ATTR_TYPE);
1435 if (type != null) {
1436 try {
1437 transition.setType(TransitionType.valueOf(type));
1438 }
1439 catch (IllegalArgumentException e) {
1440 MessageFormat msgFormat = new MessageFormat(ERR_UNSUPPORTED_TRANSITION_TYPE);
1441 String errMsg = msgFormat.format(new Object[] {type, reader.getLocation()});
1442 throw new ModelException(errMsg);
1443 }
1444 }
1445
1446 readNamespaces(configuration, transition);
1447 readExecutableContext(reader, configuration, transition, null);
1448
1449 return transition;
1450 }
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464 private static void readExecutableContext(final XMLStreamReader reader, final Configuration configuration,
1465 final Executable executable, final ActionsContainer parent)
1466 throws XMLStreamException, ModelException {
1467
1468 String end = "";
1469 if (parent != null) {
1470 end = parent.getContainerElementName();
1471 } else if (executable instanceof SimpleTransition) {
1472 end = ELEM_TRANSITION;
1473 } else if (executable instanceof OnEntry) {
1474 end = ELEM_ONENTRY;
1475 } else if (executable instanceof OnExit) {
1476 end = ELEM_ONEXIT;
1477 } else if (executable instanceof Finalize) {
1478 end = ELEM_FINALIZE;
1479 }
1480
1481 loop : while (reader.hasNext()) {
1482 String name, nsURI;
1483 switch (reader.next()) {
1484 case XMLStreamConstants.START_ELEMENT:
1485 pushNamespaces(reader, configuration);
1486 nsURI = reader.getNamespaceURI();
1487 name = reader.getLocalName();
1488 if (XMLNS_SCXML.equals(nsURI)) {
1489 if (ELEM_RAISE.equals(name)) {
1490 readRaise(reader, configuration, executable, parent);
1491 } else if (ELEM_FOREACH.equals(name)) {
1492 readForeach(reader, configuration, executable, parent);
1493 } else if (ELEM_IF.equals(name)) {
1494 readIf(reader, configuration, executable, parent);
1495 } else if (ELEM_LOG.equals(name)) {
1496 readLog(reader, configuration, executable, parent);
1497 } else if (ELEM_ASSIGN.equals(name)) {
1498 readAssign(reader, configuration, executable, parent);
1499 } else if (ELEM_SEND.equals(name)) {
1500 readSend(reader, configuration, executable, parent);
1501 } else if (ELEM_CANCEL.equals(name)) {
1502 readCancel(reader, configuration, executable, parent);
1503 } else if (ELEM_SCRIPT.equals(name)) {
1504 readScript(reader, configuration, executable, parent);
1505 } else if (ELEM_IF.equals(end) && ELEM_ELSEIF.equals(name)) {
1506 readElseIf(reader, configuration, executable, (If) parent);
1507 } else if (ELEM_IF.equals(end) && ELEM_ELSE.equals(name)) {
1508 readElse(reader, configuration, executable, (If)parent);
1509 } else {
1510 reportIgnoredElement(reader, configuration, end, nsURI, name);
1511 }
1512 } else if (XMLNS_COMMONS_SCXML.equals(nsURI)) {
1513 if (ELEM_VAR.equals(name)) {
1514 readVar(reader, configuration, executable, parent);
1515 } else {
1516 reportIgnoredElement(reader, configuration, end, nsURI, name);
1517 }
1518 } else {
1519 CustomAction customAction = null;
1520 if (!configuration.customActions.isEmpty()) {
1521 for (CustomAction ca : configuration.customActions) {
1522 if (ca.getNamespaceURI().equals(nsURI) && ca.getLocalName().equals(name)) {
1523 customAction = ca;
1524 }
1525 }
1526 }
1527 if (customAction != null) {
1528 readCustomAction(reader, configuration, customAction, executable, parent);
1529 } else {
1530 reportIgnoredElement(reader, configuration, end, nsURI, name);
1531 }
1532 }
1533 break;
1534 case XMLStreamConstants.END_ELEMENT:
1535 popNamespaces(reader, configuration);
1536 break loop;
1537 default:
1538 }
1539 }
1540 }
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554 private static void readRaise(final XMLStreamReader reader, final Configuration configuration,
1555 final Executable executable, final ActionsContainer parent)
1556 throws XMLStreamException, ModelException {
1557
1558 if (executable instanceof Finalize) {
1559
1560
1561
1562 reportIgnoredElement(reader, configuration, ELEM_FINALIZE, XMLNS_SCXML, ELEM_RAISE);
1563 }
1564 else {
1565 Raise raise = new Raise();
1566 raise.setEvent(readAV(reader, ATTR_EVENT));
1567 readNamespaces(configuration, raise);
1568 raise.setParent(executable);
1569 if (parent != null) {
1570 parent.addAction(raise);
1571 } else {
1572 executable.addAction(raise);
1573 }
1574 skipToEndElement(reader);
1575 }
1576 }
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590 private static void readIf(final XMLStreamReader reader, final Configuration configuration,
1591 final Executable executable, final ActionsContainer parent)
1592 throws XMLStreamException, ModelException {
1593
1594 If iff = new If();
1595 iff.setCond(readRequiredAV(reader, ELEM_IF, ATTR_COND));
1596 readNamespaces(configuration, iff);
1597 iff.setParent(executable);
1598 if (parent != null) {
1599 parent.addAction(iff);
1600 } else {
1601 executable.addAction(iff);
1602 }
1603 readExecutableContext(reader, configuration, executable, iff);
1604 }
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616 private static void readElseIf(final XMLStreamReader reader, final Configuration configuration,
1617 final Executable executable, final If iff)
1618 throws XMLStreamException, ModelException {
1619
1620 ElseIf elseif = new ElseIf();
1621 elseif.setCond(readRequiredAV(reader, ELEM_ELSEIF, ATTR_COND));
1622 readNamespaces(configuration, elseif);
1623 elseif.setParent(executable);
1624 iff.addAction(elseif);
1625 skipToEndElement(reader);
1626 }
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638 private static void readElse(final XMLStreamReader reader, final Configuration configuration,
1639 final Executable executable, final If iff)
1640 throws XMLStreamException {
1641
1642 Else els = new Else();
1643 readNamespaces(configuration, els);
1644 els.setParent(executable);
1645 iff.addAction(els);
1646 skipToEndElement(reader);
1647 }
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661 private static void readForeach(final XMLStreamReader reader, final Configuration configuration,
1662 final Executable executable, final ActionsContainer parent)
1663 throws XMLStreamException, ModelException {
1664
1665 Foreach fe = new Foreach();
1666 fe.setArray(readRequiredAV(reader, ELEM_FOREACH, ATTR_ARRAY));
1667 fe.setItem(readRequiredAV(reader, ELEM_FOREACH, ATTR_ITEM));
1668 fe.setIndex(readAV(reader, ATTR_INDEX));
1669 readNamespaces(configuration, fe);
1670 fe.setParent(executable);
1671 if (parent != null) {
1672 parent.addAction(fe);
1673 } else {
1674 executable.addAction(fe);
1675 }
1676 readExecutableContext(reader, configuration, executable, fe);
1677 }
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689 private static void readLog(final XMLStreamReader reader, final Configuration configuration,
1690 final Executable executable, final ActionsContainer parent)
1691 throws XMLStreamException {
1692
1693 Log log = new Log();
1694 log.setExpr(readAV(reader, ATTR_EXPR));
1695 log.setLabel(readAV(reader, ATTR_LABEL));
1696 readNamespaces(configuration, log);
1697 log.setParent(executable);
1698 if (parent != null) {
1699 parent.addAction(log);
1700 } else {
1701 executable.addAction(log);
1702 }
1703 skipToEndElement(reader);
1704 }
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716 private static void readAssign(final XMLStreamReader reader, final Configuration configuration,
1717 final Executable executable, final ActionsContainer parent)
1718 throws XMLStreamException, ModelException {
1719
1720 Assign assign = new Assign();
1721 assign.setExpr(readAV(reader, ATTR_EXPR));
1722 assign.setLocation(readRequiredAV(reader, ELEM_ASSIGN, ATTR_LOCATION));
1723 String attrValue = readAV(reader, ATTR_TYPE);
1724 if (attrValue != null) {
1725 assign.setType(Evaluator.AssignType.fromValue(attrValue));
1726 if (assign.getType() == null) {
1727 reportIgnoredAttribute(reader, configuration, ELEM_ASSIGN, ATTR_TYPE, attrValue);
1728 }
1729 }
1730 attrValue = readAV(reader, ATTR_ATTR);
1731 if (attrValue != null) {
1732 if (Evaluator.AssignType.ADD_ATTRIBUTE.equals(assign.getType())) {
1733 assign.setAttr(attrValue);
1734 }
1735 else {
1736 reportIgnoredAttribute(reader, configuration, ELEM_ASSIGN, ATTR_ATTR, attrValue);
1737 }
1738 }
1739 assign.setSrc(readAV(reader, ATTR_SRC));
1740 assign.setPathResolver(configuration.pathResolver);
1741 readNamespaces(configuration, assign);
1742 assign.setParent(executable);
1743 if (parent != null) {
1744 parent.addAction(assign);
1745 } else {
1746 executable.addAction(assign);
1747 }
1748 skipToEndElement(reader);
1749 }
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763 private static void readSend(final XMLStreamReader reader, final Configuration configuration,
1764 final Executable executable, final ActionsContainer parent)
1765 throws XMLStreamException, ModelException {
1766
1767 if (executable instanceof Finalize) {
1768
1769
1770
1771 reportIgnoredElement(reader, configuration, ELEM_FINALIZE, XMLNS_SCXML, ELEM_SEND);
1772 return;
1773 }
1774
1775 Send send = new Send();
1776 send.setId(readAV(reader, ATTR_ID));
1777 String attrValue = readAV(reader, ATTR_IDLOCATION);
1778 if (attrValue != null) {
1779 if (send.getId() != null) {
1780 reportConflictingAttribute(reader, configuration, ELEM_SEND, ATTR_ID, ATTR_IDLOCATION);
1781 }
1782 else {
1783 send.setIdlocation(attrValue);
1784 }
1785 }
1786 send.setDelay(readAV(reader, ATTR_DELAY));
1787 attrValue = readAV(reader, ATTR_DELAYEXPR);
1788 if (attrValue != null) {
1789 if (send.getDelay() != null) {
1790 reportConflictingAttribute(reader, configuration, ELEM_SEND, ATTR_DELAY, ATTR_DELAYEXPR);
1791 }
1792 else {
1793 send.setDelayexpr(attrValue);
1794 }
1795 }
1796 send.setEvent(readAV(reader, ATTR_EVENT));
1797 attrValue = readAV(reader, ATTR_EVENTEXPR);
1798 if (attrValue != null) {
1799 if (send.getEvent() != null) {
1800 reportConflictingAttribute(reader, configuration, ELEM_SEND, ATTR_EVENT, ATTR_EVENTEXPR);
1801 }
1802 else {
1803 send.setEventexpr(attrValue);
1804 }
1805 }
1806 send.setHints(readAV(reader, ATTR_HINTS));
1807 send.setNamelist(readAV(reader, ATTR_NAMELIST));
1808 send.setTarget(readAV(reader, ATTR_TARGET));
1809 attrValue = readAV(reader, ATTR_TARGETEXPR);
1810 if (attrValue != null) {
1811 if (send.getTarget() != null) {
1812 reportConflictingAttribute(reader, configuration, ELEM_SEND, ATTR_TARGET, ATTR_TARGETEXPR);
1813 }
1814 else {
1815 send.setTargetexpr(attrValue);
1816 }
1817 }
1818 send.setType(readAV(reader, ATTR_TYPE));
1819 attrValue = readAV(reader, ATTR_TYPEEXPR);
1820 if (attrValue != null) {
1821 if (send.getType() != null) {
1822 reportConflictingAttribute(reader, configuration, ELEM_SEND, ATTR_TYPE, ATTR_TYPEEXPR);
1823 }
1824 else {
1825 send.setTypeexpr(attrValue);
1826 }
1827 }
1828 readNamespaces(configuration, send);
1829
1830 loop : while (reader.hasNext()) {
1831 String name, nsURI;
1832 switch (reader.next()) {
1833 case XMLStreamConstants.START_ELEMENT:
1834 pushNamespaces(reader, configuration);
1835 nsURI = reader.getNamespaceURI();
1836 name = reader.getLocalName();
1837 if (XMLNS_SCXML.equals(nsURI)) {
1838 if (ELEM_PARAM.equals(name)) {
1839 if (send.getContent() == null) {
1840 readParam(reader, configuration, send);
1841 }
1842 else {
1843 reportIgnoredElement(reader, configuration, ELEM_SEND, nsURI, name);
1844 }
1845 } else if (ELEM_CONTENT.equals(name)) {
1846 if (send.getNamelist() == null && send.getParams().isEmpty()) {
1847 readContent(reader, configuration, send);
1848 }
1849 else {
1850 reportIgnoredElement(reader, configuration, ELEM_SEND, nsURI, name);
1851 }
1852 } else {
1853 reportIgnoredElement(reader, configuration, ELEM_SEND, nsURI, name);
1854 }
1855 } else {
1856 reportIgnoredElement(reader, configuration, ELEM_SEND, nsURI, name);
1857 }
1858 break;
1859 case XMLStreamConstants.END_ELEMENT:
1860 popNamespaces(reader, configuration);
1861 break loop;
1862 default:
1863 }
1864 }
1865
1866 send.setParent(executable);
1867 if (parent != null) {
1868 parent.addAction(send);
1869 } else {
1870 executable.addAction(send);
1871 }
1872 }
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884 private static void readCancel(final XMLStreamReader reader, final Configuration configuration,
1885 final Executable executable, final ActionsContainer parent)
1886 throws XMLStreamException, ModelException {
1887
1888 Cancel cancel = new Cancel();
1889 cancel.setSendid(readAV(reader, ATTR_SENDID));
1890 String attrValue = readAV(reader, ATTR_SENDIDEXPR);
1891 if (attrValue != null) {
1892 if (cancel.getSendid() != null) {
1893 reportConflictingAttribute(reader, configuration, ELEM_CANCEL, ATTR_SENDID, ATTR_SENDIDEXPR);
1894 }
1895 else {
1896 cancel.setSendidexpr(attrValue);
1897 }
1898 }
1899 readNamespaces(configuration, cancel);
1900 cancel.setParent(executable);
1901 if (parent != null) {
1902 parent.addAction(cancel);
1903 } else {
1904 executable.addAction(cancel);
1905 }
1906 skipToEndElement(reader);
1907 }
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919 private static void readScript(final XMLStreamReader reader, final Configuration configuration,
1920 final Executable executable, final ActionsContainer parent)
1921 throws XMLStreamException {
1922
1923 Script script = new Script();
1924 readNamespaces(configuration, script);
1925 script.setBody(readBody(reader));
1926 script.setParent(executable);
1927 if (parent != null) {
1928 parent.addAction(script);
1929 } else {
1930 executable.addAction(script);
1931 }
1932 }
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945 private static void readGlobalScript(final XMLStreamReader reader, final Configuration configuration,
1946 final SCXML scxml)
1947 throws XMLStreamException {
1948
1949 Script globalScript = new Script();
1950 globalScript.setGlobalScript(true);
1951 readNamespaces(configuration, globalScript);
1952 globalScript.setBody(readBody(reader));
1953 scxml.setGlobalScript(globalScript);
1954 }
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966 private static void readVar(final XMLStreamReader reader, final Configuration configuration,
1967 final Executable executable, final ActionsContainer parent)
1968 throws XMLStreamException {
1969
1970 Var var = new Var();
1971 var.setName(readAV(reader, ATTR_NAME));
1972 var.setExpr(readAV(reader, ATTR_EXPR));
1973 readNamespaces(configuration, var);
1974 var.setParent(executable);
1975 if (parent != null) {
1976 parent.addAction(var);
1977 } else {
1978 executable.addAction(var);
1979 }
1980 skipToEndElement(reader);
1981 }
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994 private static void readCustomAction(final XMLStreamReader reader, final Configuration configuration,
1995 final CustomAction customAction, final Executable executable,
1996 final ActionsContainer parent)
1997 throws XMLStreamException {
1998
1999
2000 Object actionObject;
2001 String className = customAction.getActionClass().getName();
2002 ClassLoader cl = configuration.customActionClassLoader;
2003 if (configuration.useContextClassLoaderForCustomActions) {
2004 cl = Thread.currentThread().getContextClassLoader();
2005 }
2006 if (cl == null) {
2007 cl = SCXMLReader.class.getClassLoader();
2008 }
2009 Class<?> clazz;
2010 try {
2011 clazz = cl.loadClass(className);
2012 actionObject = clazz.newInstance();
2013 } catch (ClassNotFoundException cnfe) {
2014 throw new XMLStreamException("Cannot find custom action class:" + className, cnfe);
2015 } catch (IllegalAccessException iae) {
2016 throw new XMLStreamException("Cannot access custom action class:" + className, iae);
2017 } catch (InstantiationException ie) {
2018 throw new XMLStreamException("Cannot instantiate custom action class:" + className, ie);
2019 }
2020 if (!(actionObject instanceof Action)) {
2021 throw new IllegalArgumentException(ERR_CUSTOM_ACTION_TYPE + className);
2022 }
2023
2024
2025 Action action = (Action) actionObject;
2026 for (int i = 0; i < reader.getAttributeCount(); i++) {
2027 String name = reader.getAttributeLocalName(i);
2028 String value = reader.getAttributeValue(i);
2029 String setter = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
2030 Method method;
2031 try {
2032 method = clazz.getMethod(setter, String.class);
2033 method.invoke(action, value);
2034 } catch (NoSuchMethodException nsme) {
2035 throw new XMLStreamException("No setter in class:" + className + ", for string property:" + name,
2036 nsme);
2037 } catch (InvocationTargetException ite) {
2038 throw new XMLStreamException("Exception calling setter for string property:" + name + " in class:"
2039 + className, ite);
2040 } catch (IllegalAccessException iae) {
2041 throw new XMLStreamException("Cannot access setter for string property:" + name + " in class:"
2042 + className, iae);
2043 }
2044 }
2045
2046
2047 if (action instanceof ExternalContent) {
2048 Node body = readNode(reader, configuration, customAction.getNamespaceURI(),
2049 customAction.getLocalName(), new String [] {});
2050 NodeList childNodes = body.getChildNodes();
2051 List<Node> externalNodes = ((ExternalContent) action).getExternalNodes();
2052 for (int i = 0; i < childNodes.getLength(); i++) {
2053 externalNodes.add(childNodes.item(i));
2054 }
2055 }
2056 else {
2057 skipToEndElement(reader);
2058 }
2059
2060
2061 readNamespaces(configuration, action);
2062 action.setParent(executable);
2063 if (parent != null) {
2064 parent.addAction(action);
2065 } else {
2066 executable.addAction(action);
2067 }
2068 }
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083 private static Node readNode(final XMLStreamReader reader, final Configuration configuration,
2084 final String namespaceURI, final String localName, final String[] attrs)
2085 throws XMLStreamException {
2086
2087
2088 Document document;
2089 try {
2090 document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
2091 } catch (ParserConfigurationException pce) {
2092 throw new XMLStreamException(ERR_PARSER_CFG);
2093 }
2094
2095
2096 Element root = document.createElementNS(namespaceURI, localName);
2097 for (final String attr1 : attrs) {
2098 Attr attr = document.createAttributeNS(XMLNS_DEFAULT, attr1);
2099 attr.setValue(readAV(reader, attr1));
2100 root.setAttributeNodeNS(attr);
2101 }
2102 document.appendChild(root);
2103
2104 boolean children = false;
2105 Node parent = root;
2106
2107
2108 loop : while (reader.hasNext()) {
2109 String name, nsURI;
2110 Node child = null;
2111 switch (reader.next()) {
2112 case XMLStreamConstants.START_ELEMENT:
2113 if (!children && root.hasChildNodes()) {
2114
2115 root.setTextContent(null);
2116 }
2117 children = true;
2118 pushNamespaces(reader, configuration);
2119 nsURI = reader.getNamespaceURI();
2120 name = reader.getLocalName();
2121 Element elem = document.createElementNS(nsURI, name);
2122 for (int i = 0; i < reader.getAttributeCount(); i++) {
2123 nsURI = reader.getAttributeNamespace(i);
2124 name = reader.getAttributeLocalName(i);
2125 String prefix = reader.getAttributePrefix(i);
2126 if (prefix != null && prefix.length() > 0) {
2127 name = prefix + ":" + name;
2128 }
2129 Attr attr = document.createAttributeNS(nsURI, name);
2130 attr.setValue(reader.getAttributeValue(i));
2131 elem.setAttributeNodeNS(attr);
2132 }
2133 parent.appendChild(elem);
2134 parent = elem;
2135 break;
2136 case XMLStreamConstants.SPACE:
2137 case XMLStreamConstants.CHARACTERS:
2138 case XMLStreamConstants.ENTITY_REFERENCE:
2139 if (!children || parent != root) {
2140 child = document.createTextNode(reader.getText());
2141 }
2142 break;
2143 case XMLStreamConstants.CDATA:
2144 children = true;
2145 child = document.createCDATASection(reader.getText());
2146 break;
2147 case XMLStreamConstants.COMMENT:
2148 children = true;
2149 child = document.createComment(reader.getText());
2150 break;
2151 case XMLStreamConstants.END_ELEMENT:
2152 popNamespaces(reader, configuration);
2153 parent = parent.getParentNode();
2154 if (parent == document) {
2155 break loop;
2156 }
2157 break;
2158 default:
2159 }
2160 if (child != null) {
2161 parent.appendChild(child);
2162 }
2163 }
2164 if (!children && root.hasChildNodes()) {
2165 root.setTextContent(root.getTextContent().trim());
2166 }
2167 return root;
2168 }
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179 private static String readBody(final XMLStreamReader reader)
2180 throws XMLStreamException {
2181
2182 StringBuilder body = new StringBuilder();
2183 org.apache.commons.logging.Log log;
2184
2185
2186 loop : while (reader.hasNext()) {
2187 switch (reader.next()) {
2188 case XMLStreamConstants.START_ELEMENT:
2189 log = LogFactory.getLog(SCXMLReader.class);
2190 log.warn("Ignoring XML content in <script> element, encountered element with local name: "
2191 + reader.getLocalName());
2192 skipToEndElement(reader);
2193 break;
2194 case XMLStreamConstants.SPACE:
2195 case XMLStreamConstants.CHARACTERS:
2196 case XMLStreamConstants.ENTITY_REFERENCE:
2197 case XMLStreamConstants.CDATA:
2198 case XMLStreamConstants.COMMENT:
2199 body.append(reader.getText());
2200 break;
2201 case XMLStreamConstants.END_ELEMENT:
2202 break loop;
2203 default:
2204 }
2205 }
2206 return body.toString();
2207 }
2208
2209
2210
2211
2212
2213 private static String nullIfEmpty(String input) {
2214 return input == null || input.trim().length()==0 ? null : input.trim();
2215 }
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225 private static String readAV(final XMLStreamReader reader, final String attrLocalName) {
2226 return nullIfEmpty(reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName));
2227 }
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239 private static Boolean readBooleanAV(final XMLStreamReader reader, final String elementName,
2240 final String attrLocalName)
2241 throws ModelException {
2242 String value = nullIfEmpty(reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName));
2243 Boolean result = "true".equals(value) ? Boolean.TRUE : "false".equals(value) ? Boolean.FALSE : null;
2244 if (result == null && value != null) {
2245 MessageFormat msgFormat = new MessageFormat(ERR_ATTRIBUTE_NOT_BOOLEAN);
2246 String errMsg = msgFormat.format(new Object[] {value, attrLocalName, elementName, reader.getLocation()});
2247 throw new ModelException(errMsg);
2248 }
2249 return result;
2250 }
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262 private static String readRequiredAV(final XMLStreamReader reader, final String elementName, final String attrLocalName)
2263 throws ModelException {
2264 String value = nullIfEmpty(reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName));
2265 if (value == null) {
2266 MessageFormat msgFormat = new MessageFormat(ERR_REQUIRED_ATTRIBUTE_MISSING);
2267 String errMsg = msgFormat.format(new Object[] {elementName, attrLocalName, reader.getLocation()});
2268 throw new ModelException(errMsg);
2269 }
2270 return value;
2271 }
2272
2273 private static String readOrGeneratedTransitionTargetId(final XMLStreamReader reader, final SCXML scxml,
2274 final String elementName)
2275 throws ModelException {
2276 String id = readAV(reader, ATTR_ID);
2277 if (id == null) {
2278 id = scxml.generateTransitionTargetId();
2279 }
2280 else if (id.startsWith(SCXML.GENERATED_TT_ID_PREFIX)) {
2281 MessageFormat msgFormat = new MessageFormat(ERR_RESERVED_ID_PREFIX);
2282 String errMsg = msgFormat.format(new Object[] {elementName, id, reader.getLocation()});
2283 throw new ModelException(errMsg);
2284 }
2285 return id;
2286 }
2287
2288
2289
2290
2291
2292
2293
2294 private static void readNamespaces(final Configuration configuration, final NamespacePrefixesHolder holder) {
2295
2296 holder.setNamespaces(configuration.getCurrentNamespaces());
2297 }
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313 private static void reportIgnoredElement(final XMLStreamReader reader, final Configuration configuration,
2314 final String parent, final String nsURI, final String name)
2315 throws XMLStreamException, ModelException {
2316
2317 org.apache.commons.logging.Log log = LogFactory.getLog(SCXMLReader.class);
2318 StringBuilder sb = new StringBuilder();
2319 sb.append("Ignoring unknown or invalid element <").append(name)
2320 .append("> in namespace \"").append(nsURI)
2321 .append("\" as child of <").append(parent)
2322 .append("> at ").append(reader.getLocation());
2323 if (!configuration.isSilent() && log.isWarnEnabled()) {
2324 log.warn(sb.toString());
2325 }
2326 if (configuration.isStrict()) {
2327 throw new ModelException(sb.toString());
2328 }
2329 XMLReporter reporter = configuration.reporter;
2330 if (reporter != null) {
2331 reporter.report(sb.toString(), "COMMONS_SCXML", null, reader.getLocation());
2332 }
2333 skipToEndElement(reader);
2334 }
2335
2336
2337
2338
2339
2340
2341 private static void skipToEndElement(final XMLStreamReader reader) throws XMLStreamException {
2342 int elementsToSkip = 1;
2343 while (elementsToSkip > 0 && reader.hasNext()) {
2344 int next = reader.next();
2345 if (next == XMLStreamConstants.START_ELEMENT) {
2346 elementsToSkip++;
2347 }
2348 else if (next == XMLStreamConstants.END_ELEMENT) {
2349 elementsToSkip--;
2350 }
2351 }
2352 }
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368 private static void reportIgnoredAttribute(final XMLStreamReader reader, final Configuration configuration,
2369 final String element, final String attr, final String value)
2370 throws XMLStreamException, ModelException {
2371
2372 org.apache.commons.logging.Log log = LogFactory.getLog(SCXMLReader.class);
2373 StringBuilder sb = new StringBuilder();
2374 sb.append("Ignoring unknown or invalid <").append(element).append("> attribute ").append(attr)
2375 .append("=\"").append(value).append("\" at ").append(reader.getLocation());
2376 if (!configuration.isSilent() && log.isWarnEnabled()) {
2377 log.warn(sb.toString());
2378 }
2379 if (configuration.isStrict()) {
2380 throw new ModelException(sb.toString());
2381 }
2382 XMLReporter reporter = configuration.reporter;
2383 if (reporter != null) {
2384 reporter.report(sb.toString(), "COMMONS_SCXML", null, reader.getLocation());
2385 }
2386 }
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402 private static void reportConflictingAttribute(final XMLStreamReader reader, final Configuration configuration,
2403 final String element, final String attr, final String conflictingAttr)
2404 throws XMLStreamException, ModelException {
2405
2406 org.apache.commons.logging.Log log = LogFactory.getLog(SCXMLReader.class);
2407 StringBuilder sb = new StringBuilder();
2408 sb.append("Ignoring <").append(element).append("> attribute \"").append(conflictingAttr)
2409 .append("\" which conflicts with already defined attribute \"").append(attr)
2410 .append("\" at ").append(reader.getLocation());
2411 if (!configuration.isSilent() && log.isWarnEnabled()) {
2412 log.warn(sb.toString());
2413 }
2414 if (configuration.isStrict()) {
2415 throw new ModelException(sb.toString());
2416 }
2417 XMLReporter reporter = configuration.reporter;
2418 if (reporter != null) {
2419 reporter.report(sb.toString(), "COMMONS_SCXML", null, reader.getLocation());
2420 }
2421 }
2422
2423
2424
2425
2426
2427
2428
2429 private static void pushNamespaces(final XMLStreamReader reader, final Configuration configuration) {
2430
2431 for (int i = 0; i < reader.getNamespaceCount(); i++) {
2432 Stack<String> stack = configuration.namespaces.get(reader.getNamespacePrefix(i));
2433 if (stack == null) {
2434 stack = new Stack<String>();
2435 configuration.namespaces.put(reader.getNamespacePrefix(i), stack);
2436 }
2437 stack.push(reader.getNamespaceURI(i));
2438 }
2439 }
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449 private static void popNamespaces(final XMLStreamReader reader, final Configuration configuration)
2450 throws XMLStreamException {
2451
2452 for (int i = 0; i < reader.getNamespaceCount(); i++) {
2453 Stack<String> stack = configuration.namespaces.get(reader.getNamespacePrefix(i));
2454 if (stack == null) {
2455 throw new XMLStreamException("Configuration namespaces stack null");
2456 }
2457 try {
2458 stack.pop();
2459 if (stack.empty()) {
2460 configuration.namespaces.remove(reader.getNamespacePrefix(i));
2461 }
2462 } catch (EmptyStackException e) {
2463 throw new XMLStreamException("Configuration namespaces stack popped too many times");
2464 }
2465 }
2466 }
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485 private static XMLStreamReader getReader(final Configuration configuration, final URL url, final String path,
2486 final InputStream stream, final Reader reader, final Source source)
2487 throws IOException, XMLStreamException {
2488
2489
2490 XMLInputFactory factory = XMLInputFactory.newInstance();
2491 if (configuration.factoryId != null && configuration.factoryClassLoader != null) {
2492 factory = XMLInputFactory.newFactory(configuration.factoryId, configuration.factoryClassLoader);
2493 }
2494 factory.setEventAllocator(configuration.allocator);
2495 for (Map.Entry<String, Object> property : configuration.properties.entrySet()) {
2496 factory.setProperty(property.getKey(), property.getValue());
2497 }
2498 factory.setXMLReporter(configuration.reporter);
2499 factory.setXMLResolver(configuration.resolver);
2500
2501
2502 InputStream urlStream = null;
2503 if (url != null || path != null) {
2504 URL scxml = (url != null ? url : new URL(path));
2505 URLConnection conn = scxml.openConnection();
2506 conn.setUseCaches(false);
2507 urlStream = conn.getInputStream();
2508 } else if (stream != null) {
2509 urlStream = stream;
2510 }
2511
2512
2513 XMLStreamReader xsr = null;
2514
2515 if (configuration.validate) {
2516
2517
2518 URL scxmlSchema = new URL("TODO");
2519 SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
2520 Schema schema;
2521 try {
2522 schema = schemaFactory.newSchema(scxmlSchema);
2523 } catch (SAXException se) {
2524 throw new XMLStreamException("Failed to create SCXML Schema for validation", se);
2525 }
2526
2527 Validator validator = schema.newValidator();
2528 validator.setErrorHandler(new SimpleErrorHandler());
2529
2530 Source src = null;
2531 if (urlStream != null) {
2532
2533 if (configuration.systemId != null) {
2534 src = new StreamSource(urlStream, configuration.systemId);
2535 } else {
2536 src = new StreamSource(urlStream);
2537 }
2538 } else if (reader != null) {
2539 if (configuration.systemId != null) {
2540 src = new StreamSource(reader, configuration.systemId);
2541 } else {
2542 src = new StreamSource(reader);
2543 }
2544 } else if (source != null) {
2545 src = source;
2546 }
2547 xsr = factory.createXMLStreamReader(src);
2548 try {
2549 validator.validate(src);
2550 } catch (SAXException se) {
2551 throw new XMLStreamException("Failed to create apply SCXML Validator", se);
2552 }
2553
2554 } else {
2555
2556
2557 if (urlStream != null) {
2558
2559 if (configuration.systemId != null) {
2560 xsr = factory.createXMLStreamReader(configuration.systemId, urlStream);
2561 } else if (configuration.encoding != null) {
2562 xsr = factory.createXMLStreamReader(urlStream, configuration.encoding);
2563 } else {
2564 xsr = factory.createXMLStreamReader(urlStream);
2565 }
2566 } else if (reader != null) {
2567 if (configuration.systemId != null) {
2568 xsr = factory.createXMLStreamReader(configuration.systemId, reader);
2569 } else {
2570 xsr = factory.createXMLStreamReader(reader);
2571 }
2572 } else if (source != null) {
2573 xsr = factory.createXMLStreamReader(source);
2574 }
2575
2576 }
2577
2578 return xsr;
2579 }
2580
2581
2582
2583
2584 private SCXMLReader() {
2585 super();
2586 }
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604 public static class Configuration {
2605
2606
2607
2608
2609
2610
2611
2612
2613 final String factoryId;
2614
2615
2616
2617
2618 final ClassLoader factoryClassLoader;
2619
2620
2621
2622
2623 final XMLEventAllocator allocator;
2624
2625
2626
2627
2628
2629 final Map<String, Object> properties;
2630
2631
2632
2633
2634 final XMLResolver resolver;
2635
2636
2637
2638
2639 final XMLReporter reporter;
2640
2641
2642
2643
2644
2645 final String encoding;
2646
2647
2648
2649
2650 final String systemId;
2651
2652
2653
2654
2655 final boolean validate;
2656
2657
2658
2659
2660
2661 final List<CustomAction> customActions;
2662
2663
2664
2665
2666 final ClassLoader customActionClassLoader;
2667
2668
2669
2670
2671 final boolean useContextClassLoaderForCustomActions;
2672
2673
2674
2675
2676
2677 final Map<String, Stack<String>> namespaces;
2678
2679
2680
2681
2682
2683
2684 SCXML parent;
2685
2686
2687
2688
2689 PathResolver pathResolver;
2690
2691
2692
2693
2694
2695 boolean silent;
2696
2697
2698
2699
2700
2701 boolean strict;
2702
2703
2704
2705
2706
2707
2708
2709 public Configuration() {
2710 this(null, null);
2711 }
2712
2713
2714
2715
2716
2717
2718
2719 public Configuration(final XMLReporter reporter, final PathResolver pathResolver) {
2720 this(null, null, null, null, null, reporter, null, null, false, pathResolver, null, null, null, false);
2721 }
2722
2723
2724
2725
2726
2727
2728
2729
2730 public Configuration(final XMLReporter reporter, final PathResolver pathResolver,
2731 final List<CustomAction> customActions) {
2732 this(null, null, null, null, null, reporter, null, null, false, pathResolver, null, customActions, null,
2733 false);
2734 }
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757 public Configuration(final String factoryId, final ClassLoader classLoader, final XMLEventAllocator allocator,
2758 final Map<String, Object> properties, final XMLResolver resolver, final XMLReporter reporter,
2759 final String encoding, final String systemId, final boolean validate, final PathResolver pathResolver,
2760 final List<CustomAction> customActions, final ClassLoader customActionClassLoader,
2761 final boolean useContextClassLoaderForCustomActions) {
2762 this(factoryId, classLoader, allocator, properties, resolver, reporter, encoding, systemId, validate,
2763 pathResolver, null, customActions, customActionClassLoader,
2764 useContextClassLoaderForCustomActions);
2765 }
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778 Configuration(final XMLReporter reporter, final PathResolver pathResolver, final SCXML parent) {
2779 this(null, null, null, null, null, reporter, null, null, false, pathResolver, parent, null, null, false);
2780 }
2781
2782
2783
2784
2785
2786
2787 Configuration(final Configuration source) {
2788 this(source.factoryId, source.factoryClassLoader, source.allocator, source.properties, source.resolver,
2789 source.reporter, source.encoding, source.systemId, source.validate, source.pathResolver,
2790 source.parent, source.customActions, source.customActionClassLoader,
2791 source.useContextClassLoaderForCustomActions, source.silent, source.strict);
2792 }
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817 Configuration(final String factoryId, final ClassLoader factoryClassLoader, final XMLEventAllocator allocator,
2818 final Map<String, Object> properties, final XMLResolver resolver, final XMLReporter reporter,
2819 final String encoding, final String systemId, final boolean validate, final PathResolver pathResolver,
2820 final SCXML parent, final List<CustomAction> customActions, final ClassLoader customActionClassLoader,
2821 final boolean useContextClassLoaderForCustomActions) {
2822 this(factoryId, factoryClassLoader, allocator, properties, resolver, reporter, encoding, systemId,
2823 validate, pathResolver, parent, customActions, customActionClassLoader,
2824 useContextClassLoaderForCustomActions, false, false);
2825 }
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853 Configuration(final String factoryId, final ClassLoader factoryClassLoader, final XMLEventAllocator allocator,
2854 final Map<String, Object> properties, final XMLResolver resolver, final XMLReporter reporter,
2855 final String encoding, final String systemId, final boolean validate, final PathResolver pathResolver,
2856 final SCXML parent, final List<CustomAction> customActions, final ClassLoader customActionClassLoader,
2857 final boolean useContextClassLoaderForCustomActions, final boolean silent, final boolean strict) {
2858 this.factoryId = factoryId;
2859 this.factoryClassLoader = factoryClassLoader;
2860 this.allocator = allocator;
2861 this.properties = (properties == null ? new HashMap<String, Object>() : properties);
2862 this.resolver = resolver;
2863 this.reporter = reporter;
2864 this.encoding = encoding;
2865 this.systemId = systemId;
2866 this.validate = validate;
2867 this.pathResolver = pathResolver;
2868 this.parent = parent;
2869 this.customActions = (customActions == null ? new ArrayList<CustomAction>() : customActions);
2870 this.customActionClassLoader = customActionClassLoader;
2871 this.useContextClassLoaderForCustomActions = useContextClassLoaderForCustomActions;
2872 this.namespaces = new HashMap<String, Stack<String>>();
2873 this.silent = silent;
2874 this.strict = strict;
2875 }
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886 Map<String, String> getCurrentNamespaces() {
2887 Map<String, String> currentNamespaces = new HashMap<String, String>();
2888 for (Map.Entry<String, Stack<String>> nsEntry : namespaces.entrySet()) {
2889 currentNamespaces.put(nsEntry.getKey(), nsEntry.getValue().peek());
2890 }
2891 return currentNamespaces;
2892 }
2893
2894
2895
2896
2897
2898
2899 public boolean isSilent() {
2900 return silent;
2901 }
2902
2903
2904
2905
2906
2907
2908 public void setSilent(boolean silent) {
2909 this.silent = silent;
2910 }
2911
2912
2913
2914
2915
2916
2917 public boolean isStrict() {
2918 return strict;
2919 }
2920
2921
2922
2923
2924
2925
2926 public void setStrict(boolean strict) {
2927 this.strict = strict;
2928 }
2929 }
2930 }