##### Coverage Report - org.apache.commons.scxml.io.SCXMLDigester

Classes in this File | Line Coverage | Branch Coverage | Complexity
SCXMLDigester |
76% |
78% |
| 1.9183673469387754;1.918

1 |  |
     /*
2 |  |
      * Licensed to the Apache Software Foundation (ASF) under one or more
3 |  |
      * contributor license agreements.  See the NOTICE file distributed with
4 |  |
      * this work for additional information regarding copyright ownership.
5 |  |
      * The ASF licenses this file to You under the Apache License, Version 2.0
6 |  |
      * (the "License"); you may not use this file except in compliance with
7 |  |
      * the License.  You may obtain a copy of the License at
8 |  |
      *
9 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
10 |  |
      *
11 |  |
      * Unless required by applicable law or agreed to in writing, software
12 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
13 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |  |
      * See the License for the specific language governing permissions and
15 |  |
      * limitations under the License.
16 |  |
      */
17 |  |
     package org.apache.commons.scxml.io;
18 |  |
19 |  |
     import java.io.IOException;
20 |  |
     import java.net.URL;
21 |  |
     import java.text.MessageFormat;
22 |  |
     import java.util.List;
23 |  |
     import java.util.Map;
24 |  |
25 |  |
     import javax.xml.parsers.DocumentBuilder;
26 |  |
     import javax.xml.parsers.DocumentBuilderFactory;
27 |  |
     import javax.xml.parsers.ParserConfigurationException;
28 |  |
29 |  |
     import org.apache.commons.digester.Digester;
30 |  |
     import org.apache.commons.digester.ExtendedBaseRules;
31 |  |
     import org.apache.commons.digester.NodeCreateRule;
32 |  |
     import org.apache.commons.digester.ObjectCreateRule;
33 |  |
     import org.apache.commons.digester.Rule;
34 |  |
     import org.apache.commons.digester.SetNextRule;
35 |  |
     import org.apache.commons.digester.SetPropertiesRule;
36 |  |
     import org.apache.commons.logging.LogFactory;
37 |  |
38 |  |
     import org.apache.commons.scxml.PathResolver;
39 |  |
     import org.apache.commons.scxml.SCXMLHelper;
40 |  |
     import org.apache.commons.scxml.env.URLResolver;
41 |  |
     import org.apache.commons.scxml.model.Action;
42 |  |
     import org.apache.commons.scxml.model.Assign;
43 |  |
     import org.apache.commons.scxml.model.Cancel;
44 |  |
     import org.apache.commons.scxml.model.CustomAction;
45 |  |
     import org.apache.commons.scxml.model.Data;
46 |  |
     import org.apache.commons.scxml.model.Datamodel;
47 |  |
     import org.apache.commons.scxml.model.Else;
48 |  |
     import org.apache.commons.scxml.model.ElseIf;
49 |  |
     import org.apache.commons.scxml.model.Executable;
50 |  |
     import org.apache.commons.scxml.model.Exit;
51 |  |
     import org.apache.commons.scxml.model.ExternalContent;
52 |  |
     import org.apache.commons.scxml.model.Finalize;
53 |  |
     import org.apache.commons.scxml.model.History;
54 |  |
     import org.apache.commons.scxml.model.If;
55 |  |
     import org.apache.commons.scxml.model.Initial;
56 |  |
     import org.apache.commons.scxml.model.Invoke;
57 |  |
     import org.apache.commons.scxml.model.Log;
58 |  |
     import org.apache.commons.scxml.model.ModelException;
59 |  |
     import org.apache.commons.scxml.model.NamespacePrefixesHolder;
60 |  |
     import org.apache.commons.scxml.model.OnEntry;
61 |  |
     import org.apache.commons.scxml.model.OnExit;
62 |  |
     import org.apache.commons.scxml.model.Parallel;
63 |  |
     import org.apache.commons.scxml.model.Param;
64 |  |
     import org.apache.commons.scxml.model.PathResolverHolder;
65 |  |
     import org.apache.commons.scxml.model.SCXML;
66 |  |
     import org.apache.commons.scxml.model.Send;
67 |  |
     import org.apache.commons.scxml.model.State;
68 |  |
     import org.apache.commons.scxml.model.Transition;
69 |  |
     import org.apache.commons.scxml.model.TransitionTarget;
70 |  |
     import org.apache.commons.scxml.model.Var;
71 |  |
72 |  |
     import org.w3c.dom.Element;
73 |  |
     import org.w3c.dom.Node;
74 |  |
     import org.w3c.dom.NodeList;
75 |  |
76 |  |
     import org.xml.sax.Attributes;
77 |  |
     import org.xml.sax.ErrorHandler;
78 |  |
     import org.xml.sax.InputSource;
79 |  |
     import org.xml.sax.SAXException;
80 |  |
81 |  |
     /**
82 |  |
      * <p>The SCXMLDigester provides the ability to digest a SCXML document into
83 |  |
      * the Java object model provided in the model package.</p>
84 |  |
      * <p>The SCXMLDigester can be used for:</p>
85 |  |
      * <ol>
86 |  |
      *  <li>Digest a SCXML file into the Commons SCXML Java object model.</li>
87 |  |
      *  <li>Obtain a SCXML Digester for further customization of the default
88 |  |
      *      ruleset.</li>
89 |  |
      * </ol>
90 |  |
      */
91 |  |
     public final class SCXMLDigester {
92 |  |
93 |  |
         /**
94 |  |
          * The SCXML namespace that this Digester is built for. Any document
95 |  |
          * that is intended to be parsed by this digester <b>must</b>
96 |  |
          * bind the SCXML elements to this namespace.
97 |  |
          */
98 |  |
         private static final String NAMESPACE_SCXML =
99 |  |
             "http://www.w3.org/2005/07/scxml";
100 |  |
101 |  |
         //---------------------- PUBLIC METHODS ----------------------//
102 |  |
         /**
103 |  |
          * <p>API for standalone usage where the SCXML document is a URL.</p>
104 |  |
          *
105 |  |
          * @param scxmlURL
106 |  |
          *            a canonical absolute URL to parse (relative URLs within the
107 |  |
          *            top level document are to be resovled against this URL).
108 |  |
          * @param errHandler
109 |  |
          *            The SAX ErrorHandler
110 |  |
          *
111 |  |
          * @return SCXML The SCXML object corresponding to the file argument
112 |  |
          *
113 |  |
          * @throws IOException Underlying Digester parsing threw an IOException
114 |  |
          * @throws SAXException Underlying Digester parsing threw a SAXException
115 |  |
          * @throws ModelException If the resulting document model has flaws
116 |  |
          *
117 |  |
          * @see ErrorHandler
118 |  |
          * @see PathResolver
119 |  |
          */
120 |  |
         public static SCXML digest(final URL scxmlURL,
121 |  |
                 final ErrorHandler errHandler)
122 |  |
         throws IOException, SAXException, ModelException {
123 |  |
124 | 2 |
             if (scxmlURL == null) {
125 | 0 |
                 throw new IllegalArgumentException(ERR_NULL_URL);
126 |  |
             }
127 |  |
128 | 2 |
             return digest(scxmlURL, errHandler, null);
129 |  |
130 |  |
         }
131 |  |
132 |  |
         /**
133 |  |
          * <p>API for standalone usage where the SCXML document is a URI.
134 |  |
          * A PathResolver must be provided.</p>
135 |  |
          *
136 |  |
          * @param pathResolver
137 |  |
          *            The PathResolver for this context
138 |  |
          * @param documentRealPath
139 |  |
          *            The String pointing to the absolute (real) path of the
140 |  |
          *            SCXML document
141 |  |
          * @param errHandler
142 |  |
          *            The SAX ErrorHandler
143 |  |
          *
144 |  |
          * @return SCXML The SCXML object corresponding to the file argument
145 |  |
          *
146 |  |
          * @throws IOException Underlying Digester parsing threw an IOException
147 |  |
          * @throws SAXException Underlying Digester parsing threw a SAXException
148 |  |
          * @throws ModelException If the resulting document model has flaws
149 |  |
          *
150 |  |
          * @see ErrorHandler
151 |  |
          * @see PathResolver
152 |  |
          */
153 |  |
         public static SCXML digest(final String documentRealPath,
154 |  |
                 final ErrorHandler errHandler, final PathResolver pathResolver)
155 |  |
         throws IOException, SAXException, ModelException {
156 |  |
157 | 1 |
             return digest(documentRealPath, errHandler, pathResolver, null);
158 |  |
159 |  |
         }
160 |  |
161 |  |
         /**
162 |  |
          * <p>API for standalone usage where the SCXML document is an
163 |  |
          * InputSource. This method may be used when the SCXML document is
164 |  |
          * packaged in a Java archive, or part of a compound document
165 |  |
          * where the SCXML root is available as a
166 |  |
          * <code>org.w3c.dom.Element</code> or via a <code>java.io.Reader</code>.
167 |  |
          * </p>
168 |  |
          *
169 |  |
          * <p><em>Note:</em> Since there is no path resolution, the SCXML document
170 |  |
          * must not have external state sources.</p>
171 |  |
          *
172 |  |
          * @param documentInputSource
173 |  |
          *            The InputSource for the SCXML document
174 |  |
          * @param errHandler
175 |  |
          *            The SAX ErrorHandler
176 |  |
          *
177 |  |
          * @return SCXML The SCXML object corresponding to the file argument
178 |  |
          *
179 |  |
          * @throws IOException Underlying Digester parsing threw an IOException
180 |  |
          * @throws SAXException Underlying Digester parsing threw a SAXException
181 |  |
          * @throws ModelException If the resulting document model has flaws
182 |  |
          *
183 |  |
          * @see ErrorHandler
184 |  |
          */
185 |  |
         public static SCXML digest(final InputSource documentInputSource,
186 |  |
                 final ErrorHandler errHandler)
187 |  |
         throws IOException, SAXException, ModelException {
188 |  |
189 | 0 |
             if (documentInputSource == null) {
190 | 0 |
                 throw new IllegalArgumentException(ERR_NULL_ISRC);
191 |  |
             }
192 |  |
193 | 0 |
             return digest(documentInputSource, errHandler, null);
194 |  |
195 |  |
         }
196 |  |
197 |  |
         /**
198 |  |
          * <p>API for standalone usage where the SCXML document is a URL, and
199 |  |
          * the document uses custom actions.</p>
200 |  |
          *
201 |  |
          * @param scxmlURL
202 |  |
          *            a canonical absolute URL to parse (relative URLs within the
203 |  |
          *            top level document are to be resovled against this URL).
204 |  |
          * @param errHandler
205 |  |
          *            The SAX ErrorHandler
206 |  |
          * @param customActions
207 |  |
          *            The list of {@link CustomAction}s this digester
208 |  |
          *            instance will process, can be null or empty
209 |  |
          *
210 |  |
          * @return SCXML The SCXML object corresponding to the file argument
211 |  |
          *
212 |  |
          * @throws IOException Underlying Digester parsing threw an IOException
213 |  |
          * @throws SAXException Underlying Digester parsing threw a SAXException
214 |  |
          * @throws ModelException If the resulting document model has flaws
215 |  |
          *
216 |  |
          * @see ErrorHandler
217 |  |
          * @see PathResolver
218 |  |
          */
219 |  |
         public static SCXML digest(final URL scxmlURL,
220 |  |
                 final ErrorHandler errHandler, final List customActions)
221 |  |
         throws IOException, SAXException, ModelException {
222 |  |
223 | 50 |
             SCXML scxml = null;
224 | 50 |
             Digester scxmlDigester = SCXMLDigester
225 |  |
                     .newInstance(null, new URLResolver(scxmlURL), customActions);
226 | 50 |
             scxmlDigester.setErrorHandler(errHandler);
227 |  |
228 |  |
             try {
229 | 50 |
                 scxml = (SCXML) scxmlDigester.parse(scxmlURL.toString());
230 | 0 |
             } catch (RuntimeException rte) {
231 |  |
                 // Intercept runtime exceptions, only to log them with a
232 |  |
                 // sensible error message about failure in document parsing
233 | 0 |
                 MessageFormat msgFormat = new MessageFormat(ERR_DOC_PARSE_FAIL);
234 | 0 |
                 String errMsg = msgFormat.format(new Object[] {
235 |  |
                     String.valueOf(scxmlURL), rte.getMessage()
236 |  |
                 });
237 | 0 |
                 org.apache.commons.logging.Log log = LogFactory.
238 | 133 |
                     getLog(SCXMLDigester.class);
239 | 0 |
                 log.error(errMsg, rte);
240 | 0 |
                 throw rte;
241 | 50 |
             }
242 |  |
243 | 50 |
             if (scxml != null) {
244 | 50 |
                 ModelUpdater.updateSCXML(scxml);
245 |  |
             }
246 |  |
247 | 50 |
             return scxml;
248 |  |
249 |  |
         }
250 |  |
251 |  |
         /**
252 |  |
          * <p>API for standalone usage where the SCXML document is a URI.
253 |  |
          * A PathResolver must be provided.</p>
254 |  |
          *
255 |  |
          * @param pathResolver
256 |  |
          *            The PathResolver for this context
257 |  |
          * @param documentRealPath
258 |  |
          *            The String pointing to the absolute (real) path of the
259 |  |
          *            SCXML document
260 |  |
          * @param errHandler
261 |  |
          *            The SAX ErrorHandler
262 |  |
          * @param customActions
263 |  |
          *            The list of {@link CustomAction}s this digester
264 |  |
          *            instance will process, can be null or empty
265 |  |
          *
266 |  |
          * @return SCXML The SCXML object corresponding to the file argument
267 |  |
          *
268 |  |
          * @throws IOException Underlying Digester parsing threw an IOException
269 |  |
          * @throws SAXException Underlying Digester parsing threw a SAXException
270 |  |
          * @throws ModelException If the resulting document model has flaws
271 |  |
          *
272 |  |
          * @see ErrorHandler
273 |  |
          * @see PathResolver
274 |  |
          */
275 |  |
         public static SCXML digest(final String documentRealPath,
276 |  |
                 final ErrorHandler errHandler, final PathResolver pathResolver,
277 |  |
                 final List customActions)
278 |  |
         throws IOException, SAXException, ModelException {
279 |  |
280 | 1 |
             if (documentRealPath == null) {
281 | 0 |
                 throw new IllegalArgumentException(ERR_NULL_PATH);
282 |  |
             }
283 |  |
284 | 1 |
             SCXML scxml = null;
285 | 1 |
             Digester scxmlDigester = SCXMLDigester.newInstance(null, pathResolver,
286 |  |
                 customActions);
287 | 1 |
             scxmlDigester.setErrorHandler(errHandler);
288 |  |
289 |  |
             try {
290 | 1 |
                 scxml = (SCXML) scxmlDigester.parse(documentRealPath);
291 | 0 |
             } catch (RuntimeException rte) {
292 |  |
                 // Intercept runtime exceptions, only to log them with a
293 |  |
                 // sensible error message about failure in document parsing
294 | 0 |
                 MessageFormat msgFormat = new MessageFormat(ERR_DOC_PARSE_FAIL);
295 | 0 |
                 String errMsg = msgFormat.format(new Object[] {
296 |  |
                     documentRealPath, rte.getMessage()
297 |  |
                 });
298 | 0 |
                 org.apache.commons.logging.Log log = LogFactory.
299 |  |
                     getLog(SCXMLDigester.class);
300 | 0 |
                 log.error(errMsg, rte);
301 | 0 |
                 throw rte;
302 | 1 |
             }
303 |  |
304 | 1 |
             if (scxml != null) {
305 | 1 |
                 ModelUpdater.updateSCXML(scxml);
306 |  |
             }
307 |  |
308 | 1 |
             return scxml;
309 |  |
310 |  |
         }
311 |  |
312 |  |
         /**
313 |  |
          * <p>API for standalone usage where the SCXML document is an
314 |  |
          * InputSource. This method may be used when the SCXML document is
315 |  |
          * packaged in a Java archive, or part of a compound document
316 |  |
          * where the SCXML root is available as a
317 |  |
          * <code>org.w3c.dom.Element</code> or via a <code>java.io.Reader</code>.
318 |  |
          * </p>
319 |  |
          *
320 |  |
          * <p><em>Note:</em> Since there is no path resolution, the SCXML document
321 |  |
          * must not have external state sources.</p>
322 |  |
          *
323 |  |
          * @param documentInputSource
324 |  |
          *            The InputSource for the SCXML document
325 |  |
          * @param errHandler
326 |  |
          *            The SAX ErrorHandler
327 |  |
          * @param customActions
328 |  |
          *            The list of {@link CustomAction}s this digester
329 |  |
          *            instance will process, can be null or empty
330 |  |
          *
331 |  |
          * @return SCXML The SCXML object corresponding to the file argument
332 |  |
          *
333 |  |
          * @throws IOException Underlying Digester parsing threw an IOException
334 |  |
          * @throws SAXException Underlying Digester parsing threw a SAXException
335 |  |
          * @throws ModelException If the resulting document model has flaws
336 |  |
          *
337 |  |
          * @see ErrorHandler
338 |  |
          */
339 |  |
         public static SCXML digest(final InputSource documentInputSource,
340 |  |
                 final ErrorHandler errHandler, final List customActions)
341 |  |
         throws IOException, SAXException, ModelException {
342 |  |
343 | 0 |
             Digester scxmlDigester = SCXMLDigester.newInstance(null, null,
344 |  |
                 customActions);
345 | 0 |
             scxmlDigester.setErrorHandler(errHandler);
346 |  |
347 | 0 |
             SCXML scxml = null;
348 |  |
             try {
349 | 0 |
                 scxml = (SCXML) scxmlDigester.parse(documentInputSource);
350 | 0 |
             }  catch (RuntimeException rte) {
351 |  |
                 // Intercept runtime exceptions, only to log them with a
352 |  |
                 // sensible error message about failure in document parsing
353 | 0 |
                 org.apache.commons.logging.Log log = LogFactory.
354 |  |
                     getLog(SCXMLDigester.class);
355 | 0 |
                 log.error(ERR_ISRC_PARSE_FAIL, rte);
356 | 0 |
                 throw rte;
357 | 0 |
             }
358 |  |
359 | 0 |
             if (scxml != null) {
360 | 0 |
                 ModelUpdater.updateSCXML(scxml);
361 |  |
             }
362 |  |
363 | 0 |
             return scxml;
364 |  |
365 |  |
         }
366 |  |
367 |  |
         /**
368 |  |
          * <p>Obtain a SCXML digester instance for further customization.</p>
369 |  |
          * <b>API Notes:</b>
370 |  |
          * <ul>
371 |  |
          *   <li>Use the digest() convenience methods if you do not
372 |  |
          *       need a custom digester.</li>
373 |  |
          *   <li>After the SCXML document is parsed by the customized digester,
374 |  |
          *       the object model <b>must</b> be made executor-ready by calling
375 |  |
          *       <code>updateSCXML(SCXML)</code> method in this class.</li>
376 |  |
          * </ul>
377 |  |
          *
378 |  |
          * @return Digester A newly configured SCXML digester instance
379 |  |
          *
380 |  |
          * @see SCXMLDigester#updateSCXML(SCXML)
381 |  |
          */
382 |  |
         public static Digester newInstance() {
383 |  |
384 | 0 |
             return newInstance(null, null, null);
385 |  |
386 |  |
         }
387 |  |
388 |  |
         /**
389 |  |
          * <p>Obtain a SCXML digester instance for further customization.</p>
390 |  |
          * <b>API Notes:</b>
391 |  |
          * <ul>
392 |  |
          *   <li>Use the digest() convenience methods if you do not
393 |  |
          *       need a custom digester.</li>
394 |  |
          *   <li>After the SCXML document is parsed by the customized digester,
395 |  |
          *       the object model <b>must</b> be made executor-ready by calling
396 |  |
          *       <code>updateSCXML(SCXML)</code> method in this class.</li>
397 |  |
          * </ul>
398 |  |
          *
399 |  |
          * @param pr The PathResolver, may be null for standalone documents
400 |  |
          * @return Digester A newly configured SCXML digester instance
401 |  |
          *
402 |  |
          * @see SCXMLDigester#updateSCXML(SCXML)
403 |  |
          */
404 |  |
         public static Digester newInstance(final PathResolver pr) {
405 |  |
406 | 0 |
             return newInstance(null, pr, null);
407 |  |
408 |  |
         }
409 |  |
410 |  |
         /**
411 |  |
          * <p>Obtain a SCXML digester instance for further customization.</p>
412 |  |
          * <b>API Notes:</b>
413 |  |
          * <ul>
414 |  |
          *   <li>Use the digest() convenience methods if you do not
415 |  |
          *       need a custom digester.</li>
416 |  |
          *   <li>After the SCXML document is parsed by the customized digester,
417 |  |
          *       the object model <b>must</b> be made executor-ready by calling
418 |  |
          *       <code>updateSCXML(SCXML)</code> method in this class.</li>
419 |  |
          * </ul>
420 |  |
          *
421 |  |
          * @param scxml The parent SCXML document if there is one (in case of
422 |  |
          *              state templates for example), null otherwise
423 |  |
          * @param pr The PathResolver, may be null for standalone documents
424 |  |
          * @return Digester A newly configured SCXML digester instance
425 |  |
          *
426 |  |
          * @see SCXMLDigester#updateSCXML(SCXML)
427 |  |
          */
428 |  |
         public static Digester newInstance(final SCXML scxml,
429 |  |
                 final PathResolver pr) {
430 |  |
431 | 0 |
             return newInstance(scxml, pr, null);
432 |  |
433 |  |
         }
434 |  |
435 |  |
         /**
436 |  |
          * <p>Obtain a SCXML digester instance for further customization.</p>
437 |  |
          * <b>API Notes:</b>
438 |  |
          * <ul>
439 |  |
          *   <li>Use the digest() convenience methods if you do not
440 |  |
          *       need a custom digester.</li>
441 |  |
          *   <li>After the SCXML document is parsed by the customized digester,
442 |  |
          *       the object model <b>must</b> be made executor-ready by calling
443 |  |
          *       <code>updateSCXML(SCXML)</code> method in this class.</li>
444 |  |
          * </ul>
445 |  |
          *
446 |  |
          * @param scxml The parent SCXML document if there is one (in case of
447 |  |
          *              state templates for example), null otherwise
448 |  |
          * @param pr The PathResolver, may be null for standalone documents
449 |  |
          * @param customActions The list of {@link CustomAction}s this digester
450 |  |
          *              instance will process, can be null or empty
451 |  |
          * @return Digester A newly configured SCXML digester instance
452 |  |
          *
453 |  |
          * @see SCXMLDigester#updateSCXML(SCXML)
454 |  |
          */
455 |  |
         public static Digester newInstance(final SCXML scxml,
456 |  |
                 final PathResolver pr, final List customActions) {
457 |  |
458 | 54 |
             Digester digester = new Digester();
459 | 54 |
             digester.setNamespaceAware(true);
460 |  |
             //Uncomment next line after SCXML DTD is available
461 |  |
             //digester.setValidating(true);
462 | 54 |
             digester.setRules(initRules(scxml, pr, customActions));
463 | 54 |
             return digester;
464 |  |
         }
465 |  |
466 |  |
         /**
467 |  |
          * <p>Update the SCXML object model and make it SCXMLExecutor ready.
468 |  |
          * This is part of post-digester processing, and sets up the necessary
469 |  |
          * object references throughtout the SCXML object model for the parsed
470 |  |
          * document. Should be used only if a customized digester obtained
471 |  |
          * using the <code>newInstance()</code> methods is needed.</p>
472 |  |
          *
473 |  |
          * @param scxml The SCXML object (output from Digester)
474 |  |
          * @throws ModelException If the document model has flaws
475 |  |
          */
476 |  |
        public static void updateSCXML(final SCXML scxml)
477 |  |
        throws ModelException {
478 | 0 |
            ModelUpdater.updateSCXML(scxml);
479 | 0 |
        }
480 |  |
481 |  |
         //---------------------- PRIVATE CONSTANTS ----------------------//
482 |  |
         //// Patterns to get the digestion going, prefixed by XP_
483 |  |
         /** Root &lt;scxml&gt; element. */
484 |  |
         private static final String XP_SM = "scxml";
485 |  |
486 |  |
         /** &lt;state&gt; children of root &lt;scxml&gt; element. */
487 |  |
         private static final String XP_SM_ST = "scxml/state";
488 |  |
489 |  |
         //// Universal matches, prefixed by XPU_
490 |  |
         // State
491 |  |
         /** &lt;state&gt; children of &lt;state&gt; elements. */
492 |  |
         private static final String XPU_ST_ST = "!*/state/state";
493 |  |
494 |  |
         /** &lt;state&gt; children of &lt;parallel&gt; elements. */
495 |  |
         private static final String XPU_PAR_ST = "!*/parallel/state";
496 |  |
497 |  |
         /** &lt;state&gt; children of transition &lt;target&gt; elements. */
498 |  |
         private static final String XPU_TR_TAR_ST = "!*/transition/target/state";
499 |  |
500 |  |
         //private static final String XPU_ST_TAR_ST = "!*/state/target/state";
501 |  |
502 |  |
         // Parallel
503 |  |
         /** &lt;parallel&gt; child of &lt;state&gt; elements. */
504 |  |
         private static final String XPU_ST_PAR = "!*/state/parallel";
505 |  |
506 |  |
         // If
507 |  |
         /** &lt;if&gt; element. */
508 |  |
         private static final String XPU_IF = "!*/if";
509 |  |
510 |  |
         // Executables, next three patterns useful when adding custom actions
511 |  |
         /** &lt;onentry&gt; element. */
512 |  |
         private static final String XPU_ONEN = "!*/onentry";
513 |  |
514 |  |
         /** &lt;onexit&gt; element. */
515 |  |
         private static final String XPU_ONEX = "!*/onexit";
516 |  |
517 |  |
         /** &lt;transition&gt; element. */
518 |  |
         private static final String XPU_TR = "!*/transition";
519 |  |
520 |  |
         /** &lt;finalize&gt; element. */
521 |  |
         private static final String XPU_FIN = "!*/finalize";
522 |  |
523 |  |
         //// Path Fragments, constants prefixed by XPF_
524 |  |
         // Onentries and Onexits
525 |  |
         /** &lt;onentry&gt; child element. */
526 |  |
         private static final String XPF_ONEN = "/onentry";
527 |  |
528 |  |
         /** &lt;onexit&gt; child element. */
529 |  |
         private static final String XPF_ONEX = "/onexit";
530 |  |
531 |  |
         // Datamodel section
532 |  |
         /** &lt;datamodel&gt; child element. */
533 |  |
         private static final String XPF_DM = "/datamodel";
534 |  |
535 |  |
         /** Individual &lt;data&gt; elements. */
536 |  |
         private static final String XPF_DATA = "/data";
537 |  |
538 |  |
         // Initial
539 |  |
         /** &lt;initial&gt; child element. */
540 |  |
         private static final String XPF_INI = "/initial";
541 |  |
542 |  |
         // Invoke, param and finalize
543 |  |
         /** &lt;invoke&gt; child element of &lt;state&gt;. */
544 |  |
         private static final String XPF_INV = "/invoke";
545 |  |
546 |  |
         /** &lt;param&gt; child element of &lt;invoke&gt;. */
547 |  |
         private static final String XPF_PRM = "/param";
548 |  |
549 |  |
         /** &lt;finalize&gt; child element of &lt;invoke&gt;. */
550 |  |
         private static final String XPF_FIN = "/finalize";
551 |  |
552 |  |
         // History
553 |  |
         /** &lt;history&gt; child element. */
554 |  |
         private static final String XPF_HIST = "/history";
555 |  |
556 |  |
         // Transition, target and exit
557 |  |
         /** &lt;transition&gt; child element. */
558 |  |
         private static final String XPF_TR = "/transition";
559 |  |
560 |  |
         /** &lt;target&gt; child element. */
561 |  |
         private static final String XPF_TAR = "/target";
562 |  |
563 |  |
         /** &lt;exit&gt; child element. */
564 |  |
         private static final String XPF_EXT = "/exit";
565 |  |
566 |  |
         // Actions
567 |  |
         /** &lt;var&gt; child element. */
568 |  |
         private static final String XPF_VAR = "/var";
569 |  |
570 |  |
         /** &lt;assign&gt; child element. */
571 |  |
         private static final String XPF_ASN = "/assign";
572 |  |
573 |  |
         /** &lt;log&gt; child element. */
574 |  |
         private static final String XPF_LOG = "/log";
575 |  |
576 |  |
         /** &lt;send&gt; child element. */
577 |  |
         private static final String XPF_SND = "/send";
578 |  |
579 |  |
         /** &lt;cancel&gt; child element. */
580 |  |
         private static final String XPF_CAN = "/cancel";
581 |  |
582 |  |
         /** &lt;elseif&gt; child element. */
583 |  |
         private static final String XPF_EIF = "/elseif";
584 |  |
585 |  |
         /** &lt;else&gt; child element. */
586 |  |
         private static final String XPF_ELS = "/else";
587 |  |
588 |  |
         //// Other constants
589 |  |
         // Error messages
590 |  |
         /**
591 |  |
          * Null URL passed as argument.
592 |  |
          */
593 |  |
         private static final String ERR_NULL_URL = "Cannot parse null URL";
594 |  |
595 |  |
         /**
596 |  |
          * Null path passed as argument.
597 |  |
          */
598 |  |
         private static final String ERR_NULL_PATH = "Cannot parse null URL";
599 |  |
600 |  |
         /**
601 |  |
          * Null InputSource passed as argument.
602 |  |
          */
603 |  |
         private static final String ERR_NULL_ISRC = "Cannot parse null URL";
604 |  |
605 |  |
         /**
606 |  |
          * Parsing SCXML document has failed.
607 |  |
          */
608 |  |
         private static final String ERR_DOC_PARSE_FAIL = "Error parsing "
609 |  |
             + "SCXML document: \"{0}\", with message: \"{1}\"\n";
610 |  |
611 |  |
         /**
612 |  |
          * Parsing SCXML document InputSource has failed.
613 |  |
          */
614 |  |
         private static final String ERR_ISRC_PARSE_FAIL =
615 |  |
             "Could not parse SCXML InputSource";
616 |  |
617 |  |
         /**
618 |  |
          * Parser configuration error while registering data rule.
619 |  |
          */
620 |  |
         private static final String ERR_PARSER_CFG_DATA = "XML Parser "
621 |  |
             + "misconfiguration, error registering <data> element rule";
622 |  |
623 |  |
         /**
624 |  |
          * Parser configuration error while registering send rule.
625 |  |
          */
626 |  |
         private static final String ERR_PARSER_CFG_SEND = "XML Parser "
627 |  |
             + "misconfiguration, error registering <send> element rule";
628 |  |
629 |  |
         /**
630 |  |
          * Parser configuration error while registering body content rule for
631 |  |
          * custom action.
632 |  |
          */
633 |  |
         private static final String ERR_PARSER_CFG_CUSTOM = "XML Parser "
634 |  |
             + "misconfiguration, error registering custom action rules";
635 |  |
636 |  |
         /**
637 |  |
          * Error message while attempting to define a custom action which does
638 |  |
          * not extend the Commons SCXML Action base class.
639 |  |
          */
640 |  |
         private static final String ERR_CUSTOM_ACTION_TYPE = "Custom actions list"
641 |  |
             + " contained unknown object (not a Commons SCXML Action subtype)";
642 |  |
643 |  |
         // String constants
644 |  |
         /** Slash. */
645 |  |
         private static final String STR_SLASH = "/";
646 |  |
647 |  |
         //---------------------- PRIVATE UTILITY METHODS ----------------------//
648 |  |
         /*
649 |  |
          * Private utility functions for configuring digester rule base for SCXML.
650 |  |
          */
651 |  |
         /**
652 |  |
          * Initialize the Digester rules for the current document.
653 |  |
          *
654 |  |
          * @param scxml The parent SCXML document (or null)
655 |  |
          * @param pr The PathResolver
656 |  |
          * @param customActions The list of custom actions this digester needs
657 |  |
          *                      to be able to process
658 |  |
          *
659 |  |
          * @return scxmlRules The rule set to be used for digestion
660 |  |
          */
661 |  |
         private static ExtendedBaseRules initRules(final SCXML scxml,
662 |  |
                 final PathResolver pr, final List customActions) {
663 |  |
664 | 54 |
             ExtendedBaseRules scxmlRules = new ExtendedBaseRules();
665 | 54 |
             scxmlRules.setNamespaceURI(NAMESPACE_SCXML);
666 |  |
667 |  |
             //// SCXML
668 | 54 |
             scxmlRules.add(XP_SM, new ObjectCreateRule(SCXML.class));
669 | 54 |
             scxmlRules.add(XP_SM, new SetPropertiesRule());
670 |  |
671 |  |
             //// Datamodel at document root i.e. <scxml> datamodel
672 | 54 |
             addDatamodelRules(XP_SM + XPF_DM, scxmlRules, scxml, pr);
673 |  |
674 |  |
             //// States
675 |  |
             // Level one states
676 | 54 |
             addStateRules(XP_SM_ST, scxmlRules, customActions, scxml, pr, 0);
677 | 54 |
             scxmlRules.add(XP_SM_ST, new SetNextRule("addState"));
678 |  |
             // Nested states
679 | 54 |
             addStateRules(XPU_ST_ST, scxmlRules, customActions, scxml, pr, 1);
680 | 54 |
             scxmlRules.add(XPU_ST_ST, new SetNextRule("addChild"));
681 |  |
682 |  |
             // Parallel states
683 | 54 |
             addStateRules(XPU_PAR_ST, scxmlRules, customActions, scxml, pr, 1);
684 | 54 |
             scxmlRules.add(XPU_PAR_ST, new SetNextRule("addState"));
685 |  |
             // Target states
686 | 54 |
             addStateRules(XPU_TR_TAR_ST, scxmlRules, customActions, scxml, pr, 2);
687 | 54 |
             scxmlRules.add(XPU_TR_TAR_ST, new SetNextRule("setTarget"));
688 |  |
689 |  |
             //// Parallels
690 | 54 |
             addParallelRules(XPU_ST_PAR, scxmlRules, pr, customActions, scxml);
691 |  |
692 |  |
             //// Ifs
693 | 54 |
             addIfRules(XPU_IF, scxmlRules, pr, customActions);
694 |  |
695 |  |
             //// Custom actions
696 | 54 |
             addCustomActionRules(XPU_ONEN, scxmlRules, customActions);
697 | 54 |
             addCustomActionRules(XPU_ONEX, scxmlRules, customActions);
698 | 54 |
             addCustomActionRules(XPU_TR, scxmlRules, customActions);
699 | 54 |
             addCustomActionRules(XPU_IF, scxmlRules, customActions);
700 | 54 |
             addCustomActionRules(XPU_FIN, scxmlRules, customActions);
701 |  |
702 | 54 |
             return scxmlRules;
703 |  |
704 |  |
         }
705 |  |
706 |  |
         /**
707 |  |
          * Add Digester rules for all &lt;state&gt; elements.
708 |  |
          *
709 |  |
          * @param xp The Digester style XPath expression of the parent
710 |  |
          *           XML element
711 |  |
          * @param scxmlRules The rule set to be used for digestion
712 |  |
          * @param customActions The list of custom actions this digester needs
713 |  |
          *                      to be able to process
714 |  |
          * @param scxml The parent SCXML document (or null)
715 |  |
          * @param pr The PathResolver
716 |  |
          * @param parent The distance between this state and its parent
717 |  |
          *               state on the Digester stack
718 |  |
          */
719 |  |
         private static void addStateRules(final String xp,
720 |  |
                 final ExtendedBaseRules scxmlRules, final List customActions,
721 |  |
                 final SCXML scxml, final PathResolver pr, final int parent) {
722 | 216 |
             scxmlRules.add(xp, new ObjectCreateRule(State.class));
723 | 216 |
             addStatePropertiesRules(xp, scxmlRules, customActions, pr, scxml);
724 | 216 |
             addDatamodelRules(xp + XPF_DM, scxmlRules, scxml, pr);
725 | 216 |
             addInvokeRules(xp + XPF_INV, scxmlRules, customActions, pr, scxml);
726 | 216 |
             addInitialRules(xp + XPF_INI, scxmlRules, customActions, pr, scxml);
727 | 216 |
             addHistoryRules(xp + XPF_HIST, scxmlRules, customActions, pr, scxml);
728 | 216 |
             addParentRule(xp, scxmlRules, parent);
729 | 216 |
             addTransitionRules(xp + XPF_TR, scxmlRules, "addTransition",
730 |  |
                 pr, customActions);
731 | 216 |
             addHandlerRules(xp, scxmlRules, pr, customActions);
732 | 216 |
             scxmlRules.add(xp, new UpdateModelRule(scxml));
733 | 216 |
         }
734 |  |
735 |  |
         /**
736 |  |
          * Add Digester rules for all &lt;parallel&gt; elements.
737 |  |
          *
738 |  |
          * @param xp The Digester style XPath expression of the parent
739 |  |
          *           XML element
740 |  |
          * @param scxmlRules The rule set to be used for digestion
741 |  |
          * @param customActions The list of custom actions this digester needs
742 |  |
          *                      to be able to process
743 |  |
          * @param pr The {@link PathResolver} for this document
744 |  |
          * @param scxml The parent SCXML document (or null)
745 |  |
          */
746 |  |
         private static void addParallelRules(final String xp,
747 |  |
                 final ExtendedBaseRules scxmlRules, final PathResolver pr,
748 |  |
                 final List customActions, final SCXML scxml) {
749 | 54 |
             addSimpleRulesTuple(xp, scxmlRules, Parallel.class, null, null,
750 |  |
                     "setParallel");
751 | 54 |
             addHandlerRules(xp, scxmlRules, pr, customActions);
752 | 54 |
             addParentRule(xp, scxmlRules, 1);
753 | 54 |
             scxmlRules.add(xp, new UpdateModelRule(scxml));
754 | 54 |
         }
755 |  |
756 |  |
         /**
757 |  |
          * Add Digester rules for all &lt;state&gt; element attributes.
758 |  |
          *
759 |  |
          * @param xp The Digester style XPath expression of the parent
760 |  |
          *           XML element
761 |  |
          * @param scxmlRules The rule set to be used for digestion
762 |  |
          * @param customActions The list of custom actions this digester needs
763 |  |
          *                      to be able to process
764 |  |
          * @param pr The PathResolver
765 |  |
          * @param scxml The root document, if this one is src'ed in
766 |  |
          */
767 |  |
         private static void addStatePropertiesRules(final String xp,
768 |  |
                 final ExtendedBaseRules scxmlRules, final List customActions,
769 |  |
                 final PathResolver pr, final SCXML scxml) {
770 | 216 |
             scxmlRules.add(xp, new SetPropertiesRule(new String[] {"id", "final"},
771 |  |
                 new String[] {"id", "isFinal"}));
772 | 216 |
             scxmlRules.add(xp, new DigestSrcAttributeRule(scxml,
773 |  |
                 customActions, pr));
774 | 216 |
         }
775 |  |
776 |  |
         /**
777 |  |
          * Add Digester rules for all &lt;datamodel&gt; elements.
778 |  |
          *
779 |  |
          * @param xp The Digester style XPath expression of the parent
780 |  |
          *           XML element
781 |  |
          * @param scxmlRules The rule set to be used for digestion
782 |  |
          * @param pr The PathResolver
783 |  |
          * @param scxml The parent SCXML document (or null)
784 |  |
          */
785 |  |
         private static void addDatamodelRules(final String xp,
786 |  |
                 final ExtendedBaseRules scxmlRules, final SCXML scxml,
787 |  |
                 final PathResolver pr) {
788 | 270 |
             scxmlRules.add(xp, new ObjectCreateRule(Datamodel.class));
789 | 270 |
             scxmlRules.add(xp + XPF_DATA, new ObjectCreateRule(Data.class));
790 | 270 |
             scxmlRules.add(xp + XPF_DATA, new SetPropertiesRule());
791 | 270 |
             scxmlRules.add(xp + XPF_DATA, new SetCurrentNamespacesRule());
792 | 270 |
             scxmlRules.add(xp + XPF_DATA, new SetNextRule("addData"));
793 |  |
             try {
794 | 270 |
                 scxmlRules.add(xp + XPF_DATA, new ParseDataRule(pr));
795 | 0 |
             } catch (ParserConfigurationException pce) {
796 | 0 |
                 org.apache.commons.logging.Log log = LogFactory.
797 |  |
                     getLog(SCXMLDigester.class);
798 | 0 |
                 log.error(ERR_PARSER_CFG_DATA, pce);
799 | 270 |
             }
800 | 270 |
             scxmlRules.add(xp, new SetNextRule("setDatamodel"));
801 | 270 |
         }
802 |  |
803 |  |
         /**
804 |  |
          * Add Digester rules for all &lt;invoke&gt; elements.
805 |  |
          *
806 |  |
          * @param xp The Digester style XPath expression of the parent
807 |  |
          *           XML element
808 |  |
          * @param scxmlRules The rule set to be used for digestion
809 |  |
          * @param customActions The list of {@link CustomAction}s this digester
810 |  |
          *              instance will process, can be null or empty
811 |  |
          * @param pr The PathResolver
812 |  |
          * @param scxml The parent SCXML document (or null)
813 |  |
          */
814 |  |
         private static void addInvokeRules(final String xp,
815 |  |
                 final ExtendedBaseRules scxmlRules, final List customActions,
816 |  |
                 final PathResolver pr, final SCXML scxml) {
817 | 216 |
             scxmlRules.add(xp, new ObjectCreateRule(Invoke.class));
818 | 216 |
             scxmlRules.add(xp, new SetPropertiesRule());
819 | 216 |
             scxmlRules.add(xp, new SetCurrentNamespacesRule());
820 | 216 |
             scxmlRules.add(xp, new SetPathResolverRule(pr));
821 | 216 |
             scxmlRules.add(xp + XPF_PRM, new ObjectCreateRule(Param.class));
822 | 216 |
             scxmlRules.add(xp + XPF_PRM, new SetPropertiesRule());
823 | 216 |
             scxmlRules.add(xp + XPF_PRM, new SetCurrentNamespacesRule());
824 | 216 |
             scxmlRules.add(xp + XPF_PRM, new SetNextRule("addParam"));
825 | 216 |
             scxmlRules.add(xp + XPF_FIN, new ObjectCreateRule(Finalize.class));
826 | 216 |
             scxmlRules.add(xp + XPF_FIN, new UpdateFinalizeRule());
827 | 216 |
             addActionRules(xp + XPF_FIN, scxmlRules, pr, customActions);
828 | 216 |
             scxmlRules.add(xp + XPF_FIN, new SetNextRule("setFinalize"));
829 | 216 |
             scxmlRules.add(xp, new SetNextRule("setInvoke"));
830 | 216 |
         }
831 |  |
832 |  |
         /**
833 |  |
          * Add Digester rules for all &lt;initial&gt; elements.
834 |  |
          *
835 |  |
          * @param xp The Digester style XPath expression of the parent
836 |  |
          *           XML element
837 |  |
          * @param scxmlRules The rule set to be used for digestion
838 |  |
          * @param customActions The list of custom actions this digester needs
839 |  |
          *                      to be able to process
840 |  |
          * @param pr The PathResolver
841 |  |
          * @param scxml The parent SCXML document (or null)
842 |  |
          */
843 |  |
         private static void addInitialRules(final String xp,
844 |  |
                 final ExtendedBaseRules scxmlRules, final List customActions,
845 |  |
                 final PathResolver pr, final SCXML scxml) {
846 | 216 |
             scxmlRules.add(xp, new ObjectCreateRule(Initial.class));
847 | 216 |
             addPseudoStatePropertiesRules(xp, scxmlRules, customActions, pr,
848 |  |
                 scxml);
849 | 216 |
             scxmlRules.add(xp, new UpdateModelRule(scxml));
850 | 216 |
             addTransitionRules(xp + XPF_TR, scxmlRules, "setTransition",
851 |  |
                 pr, customActions);
852 | 216 |
             scxmlRules.add(xp, new SetNextRule("setInitial"));
853 | 216 |
         }
854 |  |
855 |  |
         /**
856 |  |
          * Add Digester rules for all &lt;history&gt; elements.
857 |  |
          *
858 |  |
          * @param xp The Digester style XPath expression of the parent
859 |  |
          *           XML element
860 |  |
          * @param scxmlRules The rule set to be used for digestion
861 |  |
          * @param customActions The list of custom actions this digester needs
862 |  |
          *                      to be able to process
863 |  |
          * @param pr The PathResolver
864 |  |
          * @param scxml The parent SCXML document (or null)
865 |  |
          */
866 |  |
         private static void addHistoryRules(final String xp,
867 |  |
                 final ExtendedBaseRules scxmlRules, final List customActions,
868 |  |
                 final PathResolver pr, final SCXML scxml) {
869 | 216 |
             scxmlRules.add(xp, new ObjectCreateRule(History.class));
870 | 216 |
             addPseudoStatePropertiesRules(xp, scxmlRules, customActions, pr,
871 |  |
                 scxml);
872 | 216 |
             scxmlRules.add(xp, new UpdateModelRule(scxml));
873 | 216 |
             scxmlRules.add(xp, new SetPropertiesRule(new String[] {"type"},
874 |  |
                 new String[] {"type"}));
875 | 216 |
             addTransitionRules(xp + XPF_TR, scxmlRules, "setTransition",
876 |  |
                 pr, customActions);
877 | 216 |
             scxmlRules.add(xp, new SetNextRule("addHistory"));
878 | 216 |
         }
879 |  |
880 |  |
         /**
881 |  |
          * Add Digester rules for all pseudo state (initial, history) element
882 |  |
          * attributes.
883 |  |
          *
884 |  |
          * @param xp The Digester style XPath expression of the parent
885 |  |
          *           XML element
886 |  |
          * @param scxmlRules The rule set to be used for digestion
887 |  |
          * @param customActions The list of custom actions this digester needs
888 |  |
          *                      to be able to process
889 |  |
          * @param pr The PathResolver
890 |  |
          * @param scxml The root document, if this one is src'ed in
891 |  |
          */
892 |  |
         private static void addPseudoStatePropertiesRules(final String xp,
893 |  |
                 final ExtendedBaseRules scxmlRules, final List customActions,
894 |  |
                 final PathResolver pr, final SCXML scxml) {
895 | 432 |
             scxmlRules.add(xp, new SetPropertiesRule(new String[] {"id"},
896 |  |
                 new String[] {"id"}));
897 | 432 |
             scxmlRules.add(xp, new DigestSrcAttributeRule(scxml, customActions,
898 |  |
                 pr));
899 | 432 |
             addParentRule(xp, scxmlRules, 1);
900 | 432 |
         }
901 |  |
902 |  |
         /**
903 |  |
          * Add Digester rule for all setting parent state.
904 |  |
          *
905 |  |
          * @param xp The Digester style XPath expression of the parent
906 |  |
          *           XML element
907 |  |
          * @param scxmlRules The rule set to be used for digestion
908 |  |
          * @param parent The distance between this state and its parent
909 |  |
          *               state on the Digester stack
910 |  |
          */
911 |  |
         private static void addParentRule(final String xp,
912 |  |
                 final ExtendedBaseRules scxmlRules, final int parent) {
913 | 702 |
             if (parent < 1) {
914 | 54 |
                 return;
915 |  |
             }
916 | 648 |
             scxmlRules.add(xp, new Rule() {
917 |  |
                 // A generic version of setTopRule
918 | 648 |
                 public void body(final String namespace, final String name,
919 |  |
                         final String text) throws Exception {
920 | 153 |
                     TransitionTarget t = (TransitionTarget) getDigester().peek();
921 | 153 |
                     TransitionTarget p = (TransitionTarget) getDigester().peek(
922 |  |
                             parent);
923 |  |
                     // CHANGE - Moved parent property to TransitionTarget
924 | 153 |
                     t.setParent(p);
925 | 153 |
                 }
926 |  |
             });
927 | 648 |
         }
928 |  |
929 |  |
         /**
930 |  |
          * Add Digester rules for all &lt;transition&gt; elements.
931 |  |
          *
932 |  |
          * @param xp The Digester style XPath expression of the parent
933 |  |
          *           XML element
934 |  |
          * @param scxmlRules The rule set to be used for digestion
935 |  |
          * @param setNextMethod The method name for adding this transition
936 |  |
          *             to its parent (defined by the SCXML Java object model).
937 |  |
          * @param pr The {@link PathResolver} for this document
938 |  |
          * @param customActions The list of custom actions this digester needs
939 |  |
          *                      to be able to process
940 |  |
          */
941 |  |
         private static void addTransitionRules(final String xp,
942 |  |
                 final ExtendedBaseRules scxmlRules, final String setNextMethod,
943 |  |
                 final PathResolver pr, final List customActions) {
944 | 648 |
             scxmlRules.add(xp, new ObjectCreateRule(Transition.class));
945 | 648 |
             scxmlRules.add(xp, new SetPropertiesRule(
946 |  |
                 new String[] {"event", "cond", "target"},
947 |  |
                 new String[] {"event", "cond", "next"}));
948 | 648 |
             scxmlRules.add(xp, new SetCurrentNamespacesRule());
949 | 648 |
             scxmlRules.add(xp + XPF_TAR, new SetPropertiesRule());
950 | 648 |
             addActionRules(xp, scxmlRules, pr, customActions);
951 | 648 |
             scxmlRules.add(xp + XPF_EXT, new Rule() {
952 | 648 |
                 public void end(final String namespace, final String name) {
953 | 0 |
                     Transition t = (Transition) getDigester().peek(1);
954 | 0 |
                     State exitState = new State();
955 | 0 |
                     exitState.setIsFinal(true);
956 | 0 |
                     t.setTarget(exitState);
957 | 0 |
                 }
958 |  |
             });
959 | 648 |
             scxmlRules.add(xp, new SetNextRule(setNextMethod));
960 | 648 |
         }
961 |  |
962 |  |
         /**
963 |  |
          * Add Digester rules for all &lt;onentry&gt; and &lt;onexit&gt;
964 |  |
          * elements.
965 |  |
          *
966 |  |
          * @param xp The Digester style XPath expression of the parent
967 |  |
          *           XML element
968 |  |
          * @param scxmlRules The rule set to be used for digestion
969 |  |
          * @param pr The {@link PathResolver} for this document
970 |  |
          * @param customActions The list of custom actions this digester needs
971 |  |
          *                      to be able to process
972 |  |
          */
973 |  |
         private static void addHandlerRules(final String xp,
974 |  |
                 final ExtendedBaseRules scxmlRules, final PathResolver pr,
975 |  |
                 final List customActions) {
976 | 270 |
             scxmlRules.add(xp + XPF_ONEN, new ObjectCreateRule(OnEntry.class));
977 | 270 |
             addActionRules(xp + XPF_ONEN, scxmlRules, pr, customActions);
978 | 270 |
             scxmlRules.add(xp + XPF_ONEN, new SetNextRule("setOnEntry"));
979 | 270 |
             scxmlRules.add(xp + XPF_ONEX, new ObjectCreateRule(OnExit.class));
980 | 270 |
             addActionRules(xp + XPF_ONEX, scxmlRules, pr, customActions);
981 | 270 |
             scxmlRules.add(xp + XPF_ONEX, new SetNextRule("setOnExit"));
982 | 270 |
         }
983 |  |
984 |  |
         /**
985 |  |
          * Add Digester rules for all actions (&quot;executable&quot; elements).
986 |  |
          *
987 |  |
          * @param xp The Digester style XPath expression of the parent
988 |  |
          *           XML element
989 |  |
          * @param scxmlRules The rule set to be used for digestion
990 |  |
          * @param pr The {@link PathResolver} for this document
991 |  |
          * @param customActions The list of custom actions this digester needs
992 |  |
          *                      to be able to process
993 |  |
          */
994 |  |
         private static void addActionRules(final String xp,
995 |  |
                 final ExtendedBaseRules scxmlRules, final PathResolver pr,
996 |  |
                 final List customActions) {
997 | 1458 |
             addActionRulesTuple(xp + XPF_ASN, scxmlRules, Assign.class);
998 | 1458 |
             scxmlRules.add(xp + XPF_ASN, new SetPathResolverRule(pr));
999 | 1458 |
             addActionRulesTuple(xp + XPF_VAR, scxmlRules, Var.class);
1000 | 1458 |
             addActionRulesTuple(xp + XPF_LOG, scxmlRules, Log.class);
1001 | 1458 |
             addSendRulesTuple(xp + XPF_SND, scxmlRules);
1002 | 1458 |
             addActionRulesTuple(xp + XPF_CAN, scxmlRules, Cancel.class);
1003 | 1458 |
             addActionRulesTuple(xp + XPF_EXT, scxmlRules, Exit.class);
1004 |  |
             //addCustomActionRules(xp, scxmlRules, customActions);
1005 | 1458 |
         }
1006 |  |
1007 |  |
         /**
1008 |  |
          * Add custom action rules, if any custom actions are provided.
1009 |  |
          *
1010 |  |
          * @param xp The Digester style XPath expression of the parent
1011 |  |
          *           XML element
1012 |  |
          * @param scxmlRules The rule set to be used for digestion
1013 |  |
          * @param customActions The list of custom actions this digester needs
1014 |  |
          *                      to be able to process
1015 |  |
          */
1016 |  |
         private static void addCustomActionRules(final String xp,
1017 |  |
                 final ExtendedBaseRules scxmlRules, final List customActions) {
1018 | 270 |
             if (customActions == null || customActions.size() == 0) {
1019 | 250 |
                 return;
1020 |  |
             }
1021 | 45 |
             for (int i = 0; i < customActions.size(); i++) {
1022 | 25 |
                 Object item = customActions.get(i);
1023 | 25 |
                 if (item == null || !(item instanceof CustomAction)) {
1024 | 0 |
                     org.apache.commons.logging.Log log = LogFactory.
1025 |  |
                         getLog(SCXMLDigester.class);
1026 | 0 |
                     log.warn(ERR_CUSTOM_ACTION_TYPE);
1027 |  |
                 } else {
1028 | 25 |
                     CustomAction ca = (CustomAction) item;
1029 | 25 |
                     scxmlRules.setNamespaceURI(ca.getNamespaceURI());
1030 | 25 |
                     String xpfLocalName = STR_SLASH + ca.getLocalName();
1031 | 25 |
                     Class klass = ca.getActionClass();
1032 | 25 |
                     if (SCXMLHelper.implementationOf(klass,
1033 |  |
                             ExternalContent.class)) {
1034 | 0 |
                         addCustomActionRulesTuple(xp + xpfLocalName, scxmlRules,
1035 |  |
                             klass, true);
1036 |  |
                     } else {
1037 | 25 |
                         addCustomActionRulesTuple(xp + xpfLocalName, scxmlRules,
1038 |  |
                             klass, false);
1039 |  |
                     }
1040 |  |
                 }
1041 |  |
             }
1042 | 20 |
             scxmlRules.setNamespaceURI(NAMESPACE_SCXML);
1043 | 20 |
         }
1044 |  |
1045 |  |
         /**
1046 |  |
          * Add Digester rules that are specific to the &lt;send&gt; action
1047 |  |
          * element.
1048 |  |
          *
1049 |  |
          * @param xp The Digester style XPath expression of &lt;send&gt; element
1050 |  |
          * @param scxmlRules The rule set to be used for digestion
1051 |  |
          */
1052 |  |
         private static void addSendRulesTuple(final String xp,
1053 |  |
                 final ExtendedBaseRules scxmlRules) {
1054 | 1458 |
             addActionRulesTuple(xp, scxmlRules, Send.class);
1055 |  |
             try {
1056 | 1458 |
                 scxmlRules.add(xp, new ParseExternalContentRule());
1057 | 0 |
             } catch (ParserConfigurationException pce) {
1058 | 0 |
                 org.apache.commons.logging.Log log = LogFactory.
1059 |  |
                     getLog(SCXMLDigester.class);
1060 | 0 |
                 log.error(ERR_PARSER_CFG_SEND, pce);
1061 | 1458 |
             }
1062 | 1458 |
         }
1063 |  |
1064 |  |
         /**
1065 |  |
          * Add Digester rules for a simple custom action (no body content).
1066 |  |
          *
1067 |  |
          * @param xp The path to the custom action element
1068 |  |
          * @param scxmlRules The rule set to be used for digestion
1069 |  |
          * @param klass The <code>Action</code> class implementing the custom
1070 |  |
          *              action.
1071 |  |
          * @param bodyContent Whether the custom rule has body content
1072 |  |
          *              that should be parsed using
1073 |  |
          *              <code>NodeCreateRule</code>
1074 |  |
          */
1075 |  |
         private static void addCustomActionRulesTuple(final String xp,
1076 |  |
                 final ExtendedBaseRules scxmlRules, final Class klass,
1077 |  |
                 final boolean bodyContent) {
1078 | 25 |
             addActionRulesTuple(xp, scxmlRules, klass);
1079 | 25 |
             if (bodyContent) {
1080 |  |
                 try {
1081 | 0 |
                     scxmlRules.add(xp, new ParseExternalContentRule());
1082 | 0 |
                 } catch (ParserConfigurationException pce) {
1083 | 0 |
                     org.apache.commons.logging.Log log = LogFactory.
1084 |  |
                         getLog(SCXMLDigester.class);
1085 | 0 |
                     log.error(ERR_PARSER_CFG_CUSTOM, pce);
1086 | 0 |
                 }
1087 |  |
             }
1088 | 25 |
         }
1089 |  |
1090 |  |
         /**
1091 |  |
          * Add Digester rules for all &lt;if&gt; elements.
1092 |  |
          *
1093 |  |
          * @param xp The Digester style XPath expression of the parent
1094 |  |
          *           XML element
1095 |  |
          * @param scxmlRules The rule set to be used for digestion
1096 |  |
          * @param pr The {@link PathResolver} for this document
1097 |  |
          * @param customActions The list of custom actions this digester needs
1098 |  |
          *                      to be able to process
1099 |  |
          */
1100 |  |
         private static void addIfRules(final String xp,
1101 |  |
                 final ExtendedBaseRules scxmlRules, final PathResolver pr,
1102 |  |
                 final List customActions) {
1103 | 54 |
             addActionRulesTuple(xp, scxmlRules, If.class);
1104 | 54 |
             addActionRules(xp, scxmlRules, pr, customActions);
1105 | 54 |
             addActionRulesTuple(xp + XPF_EIF, scxmlRules, ElseIf.class);
1106 | 54 |
             addActionRulesTuple(xp + XPF_ELS, scxmlRules, Else.class);
1107 | 54 |
         }
1108 |  |
1109 |  |
         /**
1110 |  |
          * Add Digester rules that are common across all actions elements.
1111 |  |
          *
1112 |  |
          * @param xp The Digester style XPath expression of the parent
1113 |  |
          *           XML element
1114 |  |
          * @param scxmlRules The rule set to be used for digestion
1115 |  |
          * @param klass The class in the Java object model to be instantiated
1116 |  |
          *              in the ObjectCreateRule for this action
1117 |  |
          */
1118 |  |
         private static void addActionRulesTuple(final String xp,
1119 |  |
                 final ExtendedBaseRules scxmlRules, final Class klass) {
1120 | 8935 |
             addSimpleRulesTuple(xp, scxmlRules, klass, null, null, "addAction");
1121 | 8935 |
             scxmlRules.add(xp, new SetExecutableParentRule());
1122 | 8935 |
             scxmlRules.add(xp, new SetCurrentNamespacesRule());
1123 | 8935 |
         }
1124 |  |
1125 |  |
         /**
1126 |  |
          * Add the run of the mill Digester rules for any element.
1127 |  |
          *
1128 |  |
          * @param xp The Digester style XPath expression of the parent
1129 |  |
          *           XML element
1130 |  |
          * @param scxmlRules The rule set to be used for digestion
1131 |  |
          * @param klass The class in the Java object model to be instantiated
1132 |  |
          *              in the ObjectCreateRule for this action
1133 |  |
          * @param args The attributes to be mapped into the object model
1134 |  |
          * @param props The properties that args get mapped to
1135 |  |
          * @param addMethod The method that the SetNextRule should call
1136 |  |
          */
1137 |  |
         private static void addSimpleRulesTuple(final String xp,
1138 |  |
                 final ExtendedBaseRules scxmlRules, final Class klass,
1139 |  |
                 final String[] args, final String[] props,
1140 |  |
                 final String addMethod) {
1141 | 8989 |
             scxmlRules.add(xp, new ObjectCreateRule(klass));
1142 | 8989 |
             if (args == null) {
1143 | 8989 |
                 scxmlRules.add(xp, new SetPropertiesRule());
1144 |  |
             } else {
1145 | 0 |
                 scxmlRules.add(xp, new SetPropertiesRule(args, props));
1146 |  |
             }
1147 | 8989 |
             scxmlRules.add(xp, new SetNextRule(addMethod));
1148 | 8989 |
         }
1149 |  |
1150 |  |
         /**
1151 |  |
          * Discourage instantiation since this is a utility class.
1152 |  |
          */
1153 |  |
         private SCXMLDigester() {
1154 | 0 |
             super();
1155 | 0 |
         }
1156 |  |
1157 |  |
         /**
1158 |  |
          * Custom digestion rule for establishing necessary associations of this
1159 |  |
          * TransitionTarget with the root SCXML object.
1160 |  |
          * These include: <br>
1161 |  |
          * 1) Updation of the SCXML object's global targets Map <br>
1162 |  |
          * 2) Obtaining a handle to the SCXML object's NotificationRegistry <br>
1163 |  |
          *
1164 |  |
          * @deprecated Will be removed in version 1.0
1165 |  |
          */
1166 |  |
         public static class UpdateModelRule extends Rule {
1167 |  |
1168 |  |
             /**
1169 |  |
              * The root SCXML object.
1170 |  |
              */
1171 |  |
             private SCXML scxml;
1172 |  |
1173 |  |
             /**
1174 |  |
              * Constructor.
1175 |  |
              * @param scxml The root SCXML object
1176 |  |
              */
1177 |  |
             public UpdateModelRule(final SCXML scxml) {
1178 | 702 |
                 super();
1179 | 702 |
                 this.scxml = scxml;
1180 | 702 |
             }
1181 |  |
1182 |  |
             /**
1183 |  |
              * @see Rule#end(String, String)
1184 |  |
              */
1185 |  |
             public final void end(final String namespace, final String name) {
1186 | 294 |
                 if (scxml == null) {
1187 | 117 |
                     scxml = (SCXML) getDigester()
1188 |  |
                             .peek(getDigester().getCount() - 1);
1189 |  |
                 }
1190 | 294 |
                 TransitionTarget tt = (TransitionTarget) getDigester().peek();
1191 | 294 |
                 scxml.addTarget(tt);
1192 | 294 |
             }
1193 |  |
         }
1194 |  |
1195 |  |
         /**
1196 |  |
          * Custom digestion rule for setting Executable parent of Action elements.
1197 |  |
          *
1198 |  |
          * @deprecated Will be removed in version 1.0
1199 |  |
          */
1200 |  |
         public static class SetExecutableParentRule extends Rule {
1201 |  |
1202 |  |
             /**
1203 |  |
              * Constructor.
1204 |  |
              */
1205 |  |
             public SetExecutableParentRule() {
1206 | 8935 |
                 super();
1207 | 8935 |
             }
1208 |  |
1209 |  |
             /**
1210 |  |
              * @see Rule#end(String, String)
1211 |  |
              */
1212 |  |
             public final void end(final String namespace, final String name) {
1213 | 181 |
                 Action child = (Action) getDigester().peek();
1214 | 215 |
                 for (int i = 1; i < getDigester().getCount() - 1; i++) {
1215 | 215 |
                     Object ancestor = getDigester().peek(i);
1216 | 215 |
                     if (ancestor instanceof Executable) {
1217 | 181 |
                         child.setParent((Executable) ancestor);
1218 | 181 |
                         return;
1219 |  |
                     }
1220 |  |
                 }
1221 | 0 |
             }
1222 |  |
         }
1223 |  |
1224 |  |
         /**
1225 |  |
          * Custom digestion rule for parsing bodies of
1226 |  |
          * <code>ExternalContent</code> elements.
1227 |  |
          *
1228 |  |
          * @see ExternalContent
1229 |  |
          *
1230 |  |
          * @deprecated Will be removed in version 1.0
1231 |  |
          */
1232 |  |
         public static class ParseExternalContentRule extends NodeCreateRule {
1233 |  |
             /**
1234 |  |
              * Constructor.
1235 |  |
              * @throws ParserConfigurationException A JAXP configuration error
1236 |  |
              */
1237 |  |
             public ParseExternalContentRule()
1238 |  |
             throws ParserConfigurationException {
1239 | 1458 |
                 super();
1240 | 1458 |
             }
1241 |  |
             /**
1242 |  |
              * @see Rule#end(String, String)
1243 |  |
              */
1244 |  |
             public final void end(final String namespace, final String name) {
1245 | 14 |
                 Element bodyElement = (Element) getDigester().pop();
1246 | 14 |
                 NodeList childNodes = bodyElement.getChildNodes();
1247 | 14 |
                 List externalNodes = ((ExternalContent) getDigester().
1248 |  |
                     peek()).getExternalNodes();
1249 | 20 |
                 for (int i = 0; i < childNodes.getLength(); i++) {
1250 | 6 |
                     externalNodes.add(childNodes.item(i));
1251 |  |
                 }
1252 | 14 |
             }
1253 |  |
         }
1254 |  |
1255 |  |
         /**
1256 |  |
          * Custom digestion rule for parsing bodies of &lt;data&gt; elements.
1257 |  |
          *
1258 |  |
          * @deprecated Will be removed in version 1.0
1259 |  |
          */
1260 |  |
         public static class ParseDataRule extends NodeCreateRule {
1261 |  |
1262 |  |
             /**
1263 |  |
              * The PathResolver used to resolve the src attribute to the
1264 |  |
              * SCXML document it points to.
1265 |  |
              * @see PathResolver
1266 |  |
              */
1267 |  |
             private PathResolver pr;
1268 |  |
1269 |  |
             /**
1270 |  |
              * The "src" attribute, retained to check if body content is legal.
1271 |  |
              */
1272 |  |
             private String src;
1273 |  |
1274 |  |
             /**
1275 |  |
              * The "expr" attribute, retained to check if body content is legal.
1276 |  |
              */
1277 |  |
             private String expr;
1278 |  |
1279 |  |
             /**
1280 |  |
              * The XML tree for this data, parse as a Node, obtained from
1281 |  |
              * either the "src" or the "expr" attributes.
1282 |  |
              */
1283 |  |
             private Node attrNode;
1284 |  |
1285 |  |
             /**
1286 |  |
              * Constructor.
1287 |  |
              *
1288 |  |
              * @param pr The <code>PathResolver</code>
1289 |  |
              * @throws ParserConfigurationException A JAXP configuration error
1290 |  |
              */
1291 |  |
             public ParseDataRule(final PathResolver pr)
1292 |  |
             throws ParserConfigurationException {
1293 | 270 |
                 super();
1294 | 270 |
                 this.pr = pr;
1295 | 270 |
             }
1296 |  |
1297 |  |
             /**
1298 |  |
              * @see Rule#begin(String, String, Attributes)
1299 |  |
              */
1300 |  |
             public final void begin(final String namespace, final String name,
1301 |  |
                     final Attributes attributes) throws Exception {
1302 | 64 |
                 super.begin(namespace, name, attributes);
1303 | 64 |
                 src = attributes.getValue("src");
1304 | 64 |
                 expr = attributes.getValue("expr");
1305 | 64 |
                 if (!SCXMLHelper.isStringEmpty(src)) {
1306 | 0 |
                     String path = null;
1307 | 0 |
                     if (pr == null) {
1308 | 0 |
                         path = src;
1309 |  |
                     } else {
1310 | 0 |
                         path = pr.resolvePath(src);
1311 |  |
                     }
1312 |  |
                     try {
1313 | 0 |
                         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.
1314 |  |
                             newInstance();
1315 | 0 |
                         DocumentBuilder db = dbFactory.newDocumentBuilder();
1316 | 0 |
                         attrNode = db.parse(path);
1317 | 0 |
                     } catch (Throwable t) { // you read that correctly
1318 | 0 |
                         org.apache.commons.logging.Log log = LogFactory.
1319 |  |
                             getLog(SCXMLDigester.class);
1320 | 0 |
                         log.error(t.getMessage(), t);
1321 | 0 |
                     }
1322 | 0 |
                     return;
1323 |  |
                 }
1324 | 64 |
             }
1325 |  |
1326 |  |
             /**
1327 |  |
              * @see Rule#end(String, String)
1328 |  |
              */
1329 |  |
             public final void end(final String namespace, final String name) {
1330 | 64 |
                 Node bodyNode = (Node) getDigester().pop();
1331 | 64 |
                 Data data = ((Data) getDigester().peek());
1332 |  |
                 // Prefer "src" over "expr", "expr" over child nodes
1333 |  |
                 // "expr" can only be evaluated at execution time
1334 | 64 |
                 if (!SCXMLHelper.isStringEmpty(src)) {
1335 | 0 |
                     data.setNode(attrNode);
1336 | 64 |
                 } else  if (SCXMLHelper.isStringEmpty(expr)) {
1337 |  |
                     // both "src" and "expr" are empty
1338 | 60 |
                     data.setNode(bodyNode);
1339 |  |
                 }
1340 | 64 |
             }
1341 |  |
         }
1342 |  |
1343 |  |
         /**
1344 |  |
          * Custom digestion rule for external sources, that is, the src attribute of
1345 |  |
          * the &lt;state&gt; element.
1346 |  |
          *
1347 |  |
          * @deprecated Will be removed in version 1.0
1348 |  |
          */
1349 |  |
         public static class DigestSrcAttributeRule extends Rule {
1350 |  |
1351 |  |
             /**
1352 |  |
              * The PathResolver used to resolve the src attribute to the
1353 |  |
              * SCXML document it points to.
1354 |  |
              * @see PathResolver
1355 |  |
              */
1356 |  |
             private PathResolver pr;
1357 |  |
1358 |  |
             /**
1359 |  |
              * The root document.
1360 |  |
              */
1361 |  |
             private SCXML root;
1362 |  |
1363 |  |
             /**
1364 |  |
              * The list of custom actions the parent document is capable of
1365 |  |
              * processing (and hence, the child should be, by transitivity).
1366 |  |
              * @see CustomAction
1367 |  |
              */
1368 |  |
             private List customActions;
1369 |  |
1370 |  |
             /**
1371 |  |
              * Constructor.
1372 |  |
              * @param pr The PathResolver
1373 |  |
              * @param customActions The list of custom actions this digester needs
1374 |  |
              *                      to be able to process
1375 |  |
              *
1376 |  |
              * @see PathResolver
1377 |  |
              * @see CustomAction
1378 |  |
              *
1379 |  |
              * TODO: Remove in v1.0
1380 |  |
              */
1381 |  |
             public DigestSrcAttributeRule(final List customActions,
1382 |  |
                     final PathResolver pr) {
1383 | 0 |
                 super();
1384 | 0 |
                 this.customActions = customActions;
1385 | 0 |
                 this.pr = pr;
1386 | 0 |
             }
1387 |  |
1388 |  |
             /**
1389 |  |
              * Constructor.
1390 |  |
              * @param root The root document, if this one is src'ed in
1391 |  |
              * @param pr The PathResolver
1392 |  |
              * @param customActions The list of custom actions this digester needs
1393 |  |
              *                      to be able to process
1394 |  |
              *
1395 |  |
              * @see PathResolver
1396 |  |
              * @see CustomAction
1397 |  |
              */
1398 |  |
             public DigestSrcAttributeRule(final SCXML root,
1399 |  |
                     final List customActions, final PathResolver pr) {
1400 | 648 |
                 super();
1401 | 648 |
                 this.root = root;
1402 | 648 |
                 this.customActions = customActions;
1403 | 648 |
                 this.pr = pr;
1404 | 648 |
             }
1405 |  |
1406 |  |
             /**
1407 |  |
              * @see Rule#begin(String, String, Attributes)
1408 |  |
              */
1409 |  |
             public final void begin(final String namespace, final String name,
1410 |  |
                     final Attributes attributes) {
1411 | 289 |
                 String src = attributes.getValue("src");
1412 | 289 |
                 if (SCXMLHelper.isStringEmpty(src)) {
1413 | 286 |
                     return;
1414 |  |
                 }
1415 | 3 |
                 Digester digester = getDigester();
1416 | 3 |
                 SCXML scxml = (SCXML) digester.peek(digester.getCount() - 1);
1417 |  |
                 // 1) Digest the external SCXML file
1418 | 3 |
                 SCXML externalSCXML = null;
1419 |  |
                 String path;
1420 |  |
                 Digester externalSrcDigester;
1421 | 3 |
                 if (pr == null) {
1422 | 0 |
                     path = src;
1423 | 0 |
                     if (root != null) {
1424 | 0 |
                         externalSrcDigester = newInstance(root, null,
1425 |  |
                             customActions);
1426 |  |
                     } else {
1427 | 0 |
                         externalSrcDigester = newInstance(scxml, null,
1428 |  |
                             customActions);
1429 |  |
                     }
1430 |  |
                 } else {
1431 | 3 |
                     path = pr.resolvePath(src);
1432 | 3 |
                     if (root != null) {
1433 | 1 |
                         externalSrcDigester = newInstance(root,
1434 |  |
                             pr.getResolver(src), customActions);
1435 |  |
                     } else {
1436 | 2 |
                         externalSrcDigester = newInstance(scxml,
1437 |  |
                             pr.getResolver(src), customActions);
1438 |  |
                     }
1439 |  |
                 }
1440 |  |
1441 |  |
                 try {
1442 | 3 |
                     externalSCXML = (SCXML) externalSrcDigester.parse(path);
1443 | 0 |
                 } catch (Exception e) {
1444 | 0 |
                     org.apache.commons.logging.Log log = LogFactory.
1445 |  |
                         getLog(SCXMLDigester.class);
1446 | 0 |
                     log.error(e.getMessage(), e);
1447 | 3 |
                 }
1448 |  |
                 // 2) Adopt the children and datamodel
1449 | 3 |
                 if (externalSCXML == null) {
1450 | 0 |
                     return;
1451 |  |
                 }
1452 | 3 |
                 State s = (State) digester.peek();
1453 | 3 |
                 Transition t = new Transition();
1454 | 3 |
                 t.setNext(externalSCXML.getInitialstate());
1455 | 3 |
                 Initial ini = new Initial();
1456 | 3 |
                 ini.setTransition(t);
1457 | 3 |
                 s.setInitial(ini);
1458 | 3 |
                 Map children = externalSCXML.getStates();
1459 | 3 |
                 Object[] ids = children.keySet().toArray();
1460 | 8 |
                 for (int i = 0; i < ids.length; i++) {
1461 | 5 |
                     s.addChild((State) children.get(ids[i]));
1462 |  |
                 }
1463 | 3 |
                 s.setDatamodel(externalSCXML.getDatamodel());
1464 | 3 |
             }
1465 |  |
         }
1466 |  |
1467 |  |
         /**
1468 |  |
          * Custom digestion rule for setting PathResolver for runtime retrieval.
1469 |  |
          *
1470 |  |
          * @deprecated Will be removed in version 1.0
1471 |  |
          */
1472 |  |
         public static class SetPathResolverRule extends Rule {
1473 |  |
1474 |  |
             /**
1475 |  |
              * The PathResolver to set.
1476 |  |
              * @see PathResolver
1477 |  |
              */
1478 |  |
             private PathResolver pr;
1479 |  |
1480 |  |
             /**
1481 |  |
              * Constructor.
1482 |  |
              * @param pr The PathResolver
1483 |  |
              *
1484 |  |
              * @see PathResolver
1485 |  |
              */
1486 |  |
             public SetPathResolverRule(final PathResolver pr) {
1487 | 1674 |
                 super();
1488 | 1674 |
                 this.pr = pr;
1489 | 1674 |
             }
1490 |  |
1491 |  |
             /**
1492 |  |
              * @see Rule#begin(String, String, Attributes)
1493 |  |
              */
1494 |  |
             public final void begin(final String namespace, final String name,
1495 |  |
                     final Attributes attributes) {
1496 | 67 |
                 PathResolverHolder prHolder = (PathResolverHolder) getDigester().
1497 |  |
                     peek();
1498 | 67 |
                 prHolder.setPathResolver(pr);
1499 | 67 |
             }
1500 |  |
         }
1501 |  |
1502 |  |
         /**
1503 |  |
          * Custom digestion rule for setting state parent of finalize.
1504 |  |
          *
1505 |  |
          * @deprecated Will be removed in version 1.0
1506 |  |
          */
1507 | 216 |
         public static class UpdateFinalizeRule extends Rule {
1508 |  |
1509 |  |
             /**
1510 |  |
              * @see Rule#begin(String, String, Attributes)
1511 |  |
              */
1512 |  |
             public final void begin(final String namespace, final String name,
1513 |  |
                     final Attributes attributes) {
1514 | 1 |
                 Finalize finalize = (Finalize) getDigester().peek();
1515 |  |
                 // state/invoke/finalize --> peek(2)
1516 | 1 |
                 TransitionTarget tt = (TransitionTarget) getDigester().peek(2);
1517 | 1 |
                 finalize.setParent(tt);
1518 | 1 |
             }
1519 |  |
         }
1520 |  |
1521 |  |
1522 |  |
         /**
1523 |  |
          * Custom digestion rule for attaching a snapshot of current namespaces
1524 |  |
          * to SCXML actions for deferred XPath evaluation.
1525 |  |
          *
1526 |  |
          */
1527 | 20570 |
         private static class SetCurrentNamespacesRule extends Rule {
1528 |  |
1529 |  |
             /**
1530 |  |
              * @see Rule#begin(String, String, Attributes)
1531 |  |
              */
1532 |  |
             public final void begin(final String namespace, final String name,
1533 |  |
                     final Attributes attributes) {
1534 | 488 |
                 NamespacePrefixesHolder nsHolder =
1535 |  |
                     (NamespacePrefixesHolder) getDigester().peek();
1536 | 488 |
                 nsHolder.setNamespaces(getDigester().getCurrentNamespaces());
1537 | 488 |
             }
1538 |  |
         }
1539 |  |
1540 |  |
     }
1541 |  |