Source Code Cross Referenced for SCXMLDigester.java in  » Library » Apache-commons-scxml-0.6-src » org » apache » commons » scxml » io » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache commons scxml 0.6 src » org.apache.commons.scxml.io 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:        package org.apache.commons.scxml.io;
0018:
0019:        import java.io.IOException;
0020:        import java.net.URL;
0021:        import java.text.MessageFormat;
0022:        import java.util.List;
0023:        import java.util.Map;
0024:
0025:        import javax.xml.parsers.DocumentBuilder;
0026:        import javax.xml.parsers.DocumentBuilderFactory;
0027:        import javax.xml.parsers.ParserConfigurationException;
0028:
0029:        import org.apache.commons.digester.Digester;
0030:        import org.apache.commons.digester.ExtendedBaseRules;
0031:        import org.apache.commons.digester.NodeCreateRule;
0032:        import org.apache.commons.digester.ObjectCreateRule;
0033:        import org.apache.commons.digester.Rule;
0034:        import org.apache.commons.digester.SetNextRule;
0035:        import org.apache.commons.digester.SetPropertiesRule;
0036:        import org.apache.commons.logging.LogFactory;
0037:
0038:        import org.apache.commons.scxml.PathResolver;
0039:        import org.apache.commons.scxml.SCXMLHelper;
0040:        import org.apache.commons.scxml.env.URLResolver;
0041:        import org.apache.commons.scxml.model.Action;
0042:        import org.apache.commons.scxml.model.Assign;
0043:        import org.apache.commons.scxml.model.Cancel;
0044:        import org.apache.commons.scxml.model.CustomAction;
0045:        import org.apache.commons.scxml.model.Data;
0046:        import org.apache.commons.scxml.model.Datamodel;
0047:        import org.apache.commons.scxml.model.Else;
0048:        import org.apache.commons.scxml.model.ElseIf;
0049:        import org.apache.commons.scxml.model.Executable;
0050:        import org.apache.commons.scxml.model.Exit;
0051:        import org.apache.commons.scxml.model.ExternalContent;
0052:        import org.apache.commons.scxml.model.Finalize;
0053:        import org.apache.commons.scxml.model.History;
0054:        import org.apache.commons.scxml.model.If;
0055:        import org.apache.commons.scxml.model.Initial;
0056:        import org.apache.commons.scxml.model.Invoke;
0057:        import org.apache.commons.scxml.model.Log;
0058:        import org.apache.commons.scxml.model.ModelException;
0059:        import org.apache.commons.scxml.model.NamespacePrefixesHolder;
0060:        import org.apache.commons.scxml.model.OnEntry;
0061:        import org.apache.commons.scxml.model.OnExit;
0062:        import org.apache.commons.scxml.model.Parallel;
0063:        import org.apache.commons.scxml.model.Param;
0064:        import org.apache.commons.scxml.model.PathResolverHolder;
0065:        import org.apache.commons.scxml.model.SCXML;
0066:        import org.apache.commons.scxml.model.Send;
0067:        import org.apache.commons.scxml.model.State;
0068:        import org.apache.commons.scxml.model.Transition;
0069:        import org.apache.commons.scxml.model.TransitionTarget;
0070:        import org.apache.commons.scxml.model.Var;
0071:
0072:        import org.w3c.dom.Element;
0073:        import org.w3c.dom.Node;
0074:        import org.w3c.dom.NodeList;
0075:
0076:        import org.xml.sax.Attributes;
0077:        import org.xml.sax.ErrorHandler;
0078:        import org.xml.sax.InputSource;
0079:        import org.xml.sax.SAXException;
0080:
0081:        /**
0082:         * <p>The SCXMLDigester provides the ability to digest a SCXML document into
0083:         * the Java object model provided in the model package.</p>
0084:         * <p>The SCXMLDigester can be used for:</p>
0085:         * <ol>
0086:         *  <li>Digest a SCXML file into the Commons SCXML Java object model.</li>
0087:         *  <li>Obtain a SCXML Digester for further customization of the default
0088:         *      ruleset.</li>
0089:         * </ol>
0090:         */
0091:        public final class SCXMLDigester {
0092:
0093:            /**
0094:             * The SCXML namespace that this Digester is built for. Any document
0095:             * that is intended to be parsed by this digester <b>must</b>
0096:             * bind the SCXML elements to this namespace.
0097:             */
0098:            private static final String NAMESPACE_SCXML = "http://www.w3.org/2005/07/scxml";
0099:
0100:            //---------------------- PUBLIC METHODS ----------------------//
0101:            /**
0102:             * <p>API for standalone usage where the SCXML document is a URL.</p>
0103:             *
0104:             * @param scxmlURL
0105:             *            a canonical absolute URL to parse (relative URLs within the
0106:             *            top level document are to be resovled against this URL).
0107:             * @param errHandler
0108:             *            The SAX ErrorHandler
0109:             *
0110:             * @return SCXML The SCXML object corresponding to the file argument
0111:             *
0112:             * @throws IOException Underlying Digester parsing threw an IOException
0113:             * @throws SAXException Underlying Digester parsing threw a SAXException
0114:             * @throws ModelException If the resulting document model has flaws
0115:             *
0116:             * @see ErrorHandler
0117:             * @see PathResolver
0118:             */
0119:            public static SCXML digest(final URL scxmlURL,
0120:                    final ErrorHandler errHandler) throws IOException,
0121:                    SAXException, ModelException {
0122:
0123:                if (scxmlURL == null) {
0124:                    throw new IllegalArgumentException(ERR_NULL_URL);
0125:                }
0126:
0127:                return digest(scxmlURL, errHandler, null);
0128:
0129:            }
0130:
0131:            /**
0132:             * <p>API for standalone usage where the SCXML document is a URI.
0133:             * A PathResolver must be provided.</p>
0134:             *
0135:             * @param pathResolver
0136:             *            The PathResolver for this context
0137:             * @param documentRealPath
0138:             *            The String pointing to the absolute (real) path of the
0139:             *            SCXML document
0140:             * @param errHandler
0141:             *            The SAX ErrorHandler
0142:             *
0143:             * @return SCXML The SCXML object corresponding to the file argument
0144:             *
0145:             * @throws IOException Underlying Digester parsing threw an IOException
0146:             * @throws SAXException Underlying Digester parsing threw a SAXException
0147:             * @throws ModelException If the resulting document model has flaws
0148:             *
0149:             * @see ErrorHandler
0150:             * @see PathResolver
0151:             */
0152:            public static SCXML digest(final String documentRealPath,
0153:                    final ErrorHandler errHandler,
0154:                    final PathResolver pathResolver) throws IOException,
0155:                    SAXException, ModelException {
0156:
0157:                return digest(documentRealPath, errHandler, pathResolver, null);
0158:
0159:            }
0160:
0161:            /**
0162:             * <p>API for standalone usage where the SCXML document is an
0163:             * InputSource. This method may be used when the SCXML document is
0164:             * packaged in a Java archive, or part of a compound document
0165:             * where the SCXML root is available as a
0166:             * <code>org.w3c.dom.Element</code> or via a <code>java.io.Reader</code>.
0167:             * </p>
0168:             *
0169:             * <p><em>Note:</em> Since there is no path resolution, the SCXML document
0170:             * must not have external state sources.</p>
0171:             *
0172:             * @param documentInputSource
0173:             *            The InputSource for the SCXML document
0174:             * @param errHandler
0175:             *            The SAX ErrorHandler
0176:             *
0177:             * @return SCXML The SCXML object corresponding to the file argument
0178:             *
0179:             * @throws IOException Underlying Digester parsing threw an IOException
0180:             * @throws SAXException Underlying Digester parsing threw a SAXException
0181:             * @throws ModelException If the resulting document model has flaws
0182:             *
0183:             * @see ErrorHandler
0184:             */
0185:            public static SCXML digest(final InputSource documentInputSource,
0186:                    final ErrorHandler errHandler) throws IOException,
0187:                    SAXException, ModelException {
0188:
0189:                if (documentInputSource == null) {
0190:                    throw new IllegalArgumentException(ERR_NULL_ISRC);
0191:                }
0192:
0193:                return digest(documentInputSource, errHandler, null);
0194:
0195:            }
0196:
0197:            /**
0198:             * <p>API for standalone usage where the SCXML document is a URL, and
0199:             * the document uses custom actions.</p>
0200:             *
0201:             * @param scxmlURL
0202:             *            a canonical absolute URL to parse (relative URLs within the
0203:             *            top level document are to be resovled against this URL).
0204:             * @param errHandler
0205:             *            The SAX ErrorHandler
0206:             * @param customActions
0207:             *            The list of {@link CustomAction}s this digester
0208:             *            instance will process, can be null or empty
0209:             *
0210:             * @return SCXML The SCXML object corresponding to the file argument
0211:             *
0212:             * @throws IOException Underlying Digester parsing threw an IOException
0213:             * @throws SAXException Underlying Digester parsing threw a SAXException
0214:             * @throws ModelException If the resulting document model has flaws
0215:             *
0216:             * @see ErrorHandler
0217:             * @see PathResolver
0218:             */
0219:            public static SCXML digest(final URL scxmlURL,
0220:                    final ErrorHandler errHandler, final List customActions)
0221:                    throws IOException, SAXException, ModelException {
0222:
0223:                SCXML scxml = null;
0224:                Digester scxmlDigester = SCXMLDigester.newInstance(null,
0225:                        new URLResolver(scxmlURL), customActions);
0226:                scxmlDigester.setErrorHandler(errHandler);
0227:
0228:                try {
0229:                    scxml = (SCXML) scxmlDigester.parse(scxmlURL.toString());
0230:                } catch (RuntimeException rte) {
0231:                    // Intercept runtime exceptions, only to log them with a
0232:                    // sensible error message about failure in document parsing
0233:                    MessageFormat msgFormat = new MessageFormat(
0234:                            ERR_DOC_PARSE_FAIL);
0235:                    String errMsg = msgFormat.format(new Object[] {
0236:                            String.valueOf(scxmlURL), rte.getMessage() });
0237:                    org.apache.commons.logging.Log log = LogFactory
0238:                            .getLog(SCXMLDigester.class);
0239:                    log.error(errMsg, rte);
0240:                    throw rte;
0241:                }
0242:
0243:                if (scxml != null) {
0244:                    ModelUpdater.updateSCXML(scxml);
0245:                }
0246:
0247:                return scxml;
0248:
0249:            }
0250:
0251:            /**
0252:             * <p>API for standalone usage where the SCXML document is a URI.
0253:             * A PathResolver must be provided.</p>
0254:             *
0255:             * @param pathResolver
0256:             *            The PathResolver for this context
0257:             * @param documentRealPath
0258:             *            The String pointing to the absolute (real) path of the
0259:             *            SCXML document
0260:             * @param errHandler
0261:             *            The SAX ErrorHandler
0262:             * @param customActions
0263:             *            The list of {@link CustomAction}s this digester
0264:             *            instance will process, can be null or empty
0265:             *
0266:             * @return SCXML The SCXML object corresponding to the file argument
0267:             *
0268:             * @throws IOException Underlying Digester parsing threw an IOException
0269:             * @throws SAXException Underlying Digester parsing threw a SAXException
0270:             * @throws ModelException If the resulting document model has flaws
0271:             *
0272:             * @see ErrorHandler
0273:             * @see PathResolver
0274:             */
0275:            public static SCXML digest(final String documentRealPath,
0276:                    final ErrorHandler errHandler,
0277:                    final PathResolver pathResolver, final List customActions)
0278:                    throws IOException, SAXException, ModelException {
0279:
0280:                if (documentRealPath == null) {
0281:                    throw new IllegalArgumentException(ERR_NULL_PATH);
0282:                }
0283:
0284:                SCXML scxml = null;
0285:                Digester scxmlDigester = SCXMLDigester.newInstance(null,
0286:                        pathResolver, customActions);
0287:                scxmlDigester.setErrorHandler(errHandler);
0288:
0289:                try {
0290:                    scxml = (SCXML) scxmlDigester.parse(documentRealPath);
0291:                } catch (RuntimeException rte) {
0292:                    // Intercept runtime exceptions, only to log them with a
0293:                    // sensible error message about failure in document parsing
0294:                    MessageFormat msgFormat = new MessageFormat(
0295:                            ERR_DOC_PARSE_FAIL);
0296:                    String errMsg = msgFormat.format(new Object[] {
0297:                            documentRealPath, rte.getMessage() });
0298:                    org.apache.commons.logging.Log log = LogFactory
0299:                            .getLog(SCXMLDigester.class);
0300:                    log.error(errMsg, rte);
0301:                    throw rte;
0302:                }
0303:
0304:                if (scxml != null) {
0305:                    ModelUpdater.updateSCXML(scxml);
0306:                }
0307:
0308:                return scxml;
0309:
0310:            }
0311:
0312:            /**
0313:             * <p>API for standalone usage where the SCXML document is an
0314:             * InputSource. This method may be used when the SCXML document is
0315:             * packaged in a Java archive, or part of a compound document
0316:             * where the SCXML root is available as a
0317:             * <code>org.w3c.dom.Element</code> or via a <code>java.io.Reader</code>.
0318:             * </p>
0319:             *
0320:             * <p><em>Note:</em> Since there is no path resolution, the SCXML document
0321:             * must not have external state sources.</p>
0322:             *
0323:             * @param documentInputSource
0324:             *            The InputSource for the SCXML document
0325:             * @param errHandler
0326:             *            The SAX ErrorHandler
0327:             * @param customActions
0328:             *            The list of {@link CustomAction}s this digester
0329:             *            instance will process, can be null or empty
0330:             *
0331:             * @return SCXML The SCXML object corresponding to the file argument
0332:             *
0333:             * @throws IOException Underlying Digester parsing threw an IOException
0334:             * @throws SAXException Underlying Digester parsing threw a SAXException
0335:             * @throws ModelException If the resulting document model has flaws
0336:             *
0337:             * @see ErrorHandler
0338:             */
0339:            public static SCXML digest(final InputSource documentInputSource,
0340:                    final ErrorHandler errHandler, final List customActions)
0341:                    throws IOException, SAXException, ModelException {
0342:
0343:                Digester scxmlDigester = SCXMLDigester.newInstance(null, null,
0344:                        customActions);
0345:                scxmlDigester.setErrorHandler(errHandler);
0346:
0347:                SCXML scxml = null;
0348:                try {
0349:                    scxml = (SCXML) scxmlDigester.parse(documentInputSource);
0350:                } catch (RuntimeException rte) {
0351:                    // Intercept runtime exceptions, only to log them with a
0352:                    // sensible error message about failure in document parsing
0353:                    org.apache.commons.logging.Log log = LogFactory
0354:                            .getLog(SCXMLDigester.class);
0355:                    log.error(ERR_ISRC_PARSE_FAIL, rte);
0356:                    throw rte;
0357:                }
0358:
0359:                if (scxml != null) {
0360:                    ModelUpdater.updateSCXML(scxml);
0361:                }
0362:
0363:                return scxml;
0364:
0365:            }
0366:
0367:            /**
0368:             * <p>Obtain a SCXML digester instance for further customization.</p>
0369:             * <b>API Notes:</b>
0370:             * <ul>
0371:             *   <li>Use the digest() convenience methods if you do not
0372:             *       need a custom digester.</li>
0373:             *   <li>After the SCXML document is parsed by the customized digester,
0374:             *       the object model <b>must</b> be made executor-ready by calling
0375:             *       <code>updateSCXML(SCXML)</code> method in this class.</li>
0376:             * </ul>
0377:             *
0378:             * @return Digester A newly configured SCXML digester instance
0379:             *
0380:             * @see SCXMLDigester#updateSCXML(SCXML)
0381:             */
0382:            public static Digester newInstance() {
0383:
0384:                return newInstance(null, null, null);
0385:
0386:            }
0387:
0388:            /**
0389:             * <p>Obtain a SCXML digester instance for further customization.</p>
0390:             * <b>API Notes:</b>
0391:             * <ul>
0392:             *   <li>Use the digest() convenience methods if you do not
0393:             *       need a custom digester.</li>
0394:             *   <li>After the SCXML document is parsed by the customized digester,
0395:             *       the object model <b>must</b> be made executor-ready by calling
0396:             *       <code>updateSCXML(SCXML)</code> method in this class.</li>
0397:             * </ul>
0398:             *
0399:             * @param pr The PathResolver, may be null for standalone documents
0400:             * @return Digester A newly configured SCXML digester instance
0401:             *
0402:             * @see SCXMLDigester#updateSCXML(SCXML)
0403:             */
0404:            public static Digester newInstance(final PathResolver pr) {
0405:
0406:                return newInstance(null, pr, null);
0407:
0408:            }
0409:
0410:            /**
0411:             * <p>Obtain a SCXML digester instance for further customization.</p>
0412:             * <b>API Notes:</b>
0413:             * <ul>
0414:             *   <li>Use the digest() convenience methods if you do not
0415:             *       need a custom digester.</li>
0416:             *   <li>After the SCXML document is parsed by the customized digester,
0417:             *       the object model <b>must</b> be made executor-ready by calling
0418:             *       <code>updateSCXML(SCXML)</code> method in this class.</li>
0419:             * </ul>
0420:             *
0421:             * @param scxml The parent SCXML document if there is one (in case of
0422:             *              state templates for example), null otherwise
0423:             * @param pr The PathResolver, may be null for standalone documents
0424:             * @return Digester A newly configured SCXML digester instance
0425:             *
0426:             * @see SCXMLDigester#updateSCXML(SCXML)
0427:             */
0428:            public static Digester newInstance(final SCXML scxml,
0429:                    final PathResolver pr) {
0430:
0431:                return newInstance(scxml, pr, null);
0432:
0433:            }
0434:
0435:            /**
0436:             * <p>Obtain a SCXML digester instance for further customization.</p>
0437:             * <b>API Notes:</b>
0438:             * <ul>
0439:             *   <li>Use the digest() convenience methods if you do not
0440:             *       need a custom digester.</li>
0441:             *   <li>After the SCXML document is parsed by the customized digester,
0442:             *       the object model <b>must</b> be made executor-ready by calling
0443:             *       <code>updateSCXML(SCXML)</code> method in this class.</li>
0444:             * </ul>
0445:             *
0446:             * @param scxml The parent SCXML document if there is one (in case of
0447:             *              state templates for example), null otherwise
0448:             * @param pr The PathResolver, may be null for standalone documents
0449:             * @param customActions The list of {@link CustomAction}s this digester
0450:             *              instance will process, can be null or empty
0451:             * @return Digester A newly configured SCXML digester instance
0452:             *
0453:             * @see SCXMLDigester#updateSCXML(SCXML)
0454:             */
0455:            public static Digester newInstance(final SCXML scxml,
0456:                    final PathResolver pr, final List customActions) {
0457:
0458:                Digester digester = new Digester();
0459:                digester.setNamespaceAware(true);
0460:                //Uncomment next line after SCXML DTD is available
0461:                //digester.setValidating(true);
0462:                digester.setRules(initRules(scxml, pr, customActions));
0463:                return digester;
0464:            }
0465:
0466:            /**
0467:             * <p>Update the SCXML object model and make it SCXMLExecutor ready.
0468:             * This is part of post-digester processing, and sets up the necessary
0469:             * object references throughtout the SCXML object model for the parsed
0470:             * document. Should be used only if a customized digester obtained
0471:             * using the <code>newInstance()</code> methods is needed.</p>
0472:             *
0473:             * @param scxml The SCXML object (output from Digester)
0474:             * @throws ModelException If the document model has flaws
0475:             */
0476:            public static void updateSCXML(final SCXML scxml)
0477:                    throws ModelException {
0478:                ModelUpdater.updateSCXML(scxml);
0479:            }
0480:
0481:            //---------------------- PRIVATE CONSTANTS ----------------------//
0482:            //// Patterns to get the digestion going, prefixed by XP_
0483:            /** Root &lt;scxml&gt; element. */
0484:            private static final String XP_SM = "scxml";
0485:
0486:            /** &lt;state&gt; children of root &lt;scxml&gt; element. */
0487:            private static final String XP_SM_ST = "scxml/state";
0488:
0489:            //// Universal matches, prefixed by XPU_
0490:            // State
0491:            /** &lt;state&gt; children of &lt;state&gt; elements. */
0492:            private static final String XPU_ST_ST = "!*/state/state";
0493:
0494:            /** &lt;state&gt; children of &lt;parallel&gt; elements. */
0495:            private static final String XPU_PAR_ST = "!*/parallel/state";
0496:
0497:            /** &lt;state&gt; children of transition &lt;target&gt; elements. */
0498:            private static final String XPU_TR_TAR_ST = "!*/transition/target/state";
0499:
0500:            //private static final String XPU_ST_TAR_ST = "!*/state/target/state";
0501:
0502:            // Parallel
0503:            /** &lt;parallel&gt; child of &lt;state&gt; elements. */
0504:            private static final String XPU_ST_PAR = "!*/state/parallel";
0505:
0506:            // If
0507:            /** &lt;if&gt; element. */
0508:            private static final String XPU_IF = "!*/if";
0509:
0510:            // Executables, next three patterns useful when adding custom actions
0511:            /** &lt;onentry&gt; element. */
0512:            private static final String XPU_ONEN = "!*/onentry";
0513:
0514:            /** &lt;onexit&gt; element. */
0515:            private static final String XPU_ONEX = "!*/onexit";
0516:
0517:            /** &lt;transition&gt; element. */
0518:            private static final String XPU_TR = "!*/transition";
0519:
0520:            /** &lt;finalize&gt; element. */
0521:            private static final String XPU_FIN = "!*/finalize";
0522:
0523:            //// Path Fragments, constants prefixed by XPF_
0524:            // Onentries and Onexits
0525:            /** &lt;onentry&gt; child element. */
0526:            private static final String XPF_ONEN = "/onentry";
0527:
0528:            /** &lt;onexit&gt; child element. */
0529:            private static final String XPF_ONEX = "/onexit";
0530:
0531:            // Datamodel section
0532:            /** &lt;datamodel&gt; child element. */
0533:            private static final String XPF_DM = "/datamodel";
0534:
0535:            /** Individual &lt;data&gt; elements. */
0536:            private static final String XPF_DATA = "/data";
0537:
0538:            // Initial
0539:            /** &lt;initial&gt; child element. */
0540:            private static final String XPF_INI = "/initial";
0541:
0542:            // Invoke, param and finalize
0543:            /** &lt;invoke&gt; child element of &lt;state&gt;. */
0544:            private static final String XPF_INV = "/invoke";
0545:
0546:            /** &lt;param&gt; child element of &lt;invoke&gt;. */
0547:            private static final String XPF_PRM = "/param";
0548:
0549:            /** &lt;finalize&gt; child element of &lt;invoke&gt;. */
0550:            private static final String XPF_FIN = "/finalize";
0551:
0552:            // History
0553:            /** &lt;history&gt; child element. */
0554:            private static final String XPF_HIST = "/history";
0555:
0556:            // Transition, target and exit
0557:            /** &lt;transition&gt; child element. */
0558:            private static final String XPF_TR = "/transition";
0559:
0560:            /** &lt;target&gt; child element. */
0561:            private static final String XPF_TAR = "/target";
0562:
0563:            /** &lt;exit&gt; child element. */
0564:            private static final String XPF_EXT = "/exit";
0565:
0566:            // Actions
0567:            /** &lt;var&gt; child element. */
0568:            private static final String XPF_VAR = "/var";
0569:
0570:            /** &lt;assign&gt; child element. */
0571:            private static final String XPF_ASN = "/assign";
0572:
0573:            /** &lt;log&gt; child element. */
0574:            private static final String XPF_LOG = "/log";
0575:
0576:            /** &lt;send&gt; child element. */
0577:            private static final String XPF_SND = "/send";
0578:
0579:            /** &lt;cancel&gt; child element. */
0580:            private static final String XPF_CAN = "/cancel";
0581:
0582:            /** &lt;elseif&gt; child element. */
0583:            private static final String XPF_EIF = "/elseif";
0584:
0585:            /** &lt;else&gt; child element. */
0586:            private static final String XPF_ELS = "/else";
0587:
0588:            //// Other constants
0589:            // Error messages
0590:            /**
0591:             * Null URL passed as argument.
0592:             */
0593:            private static final String ERR_NULL_URL = "Cannot parse null URL";
0594:
0595:            /**
0596:             * Null path passed as argument.
0597:             */
0598:            private static final String ERR_NULL_PATH = "Cannot parse null URL";
0599:
0600:            /**
0601:             * Null InputSource passed as argument.
0602:             */
0603:            private static final String ERR_NULL_ISRC = "Cannot parse null URL";
0604:
0605:            /**
0606:             * Parsing SCXML document has failed.
0607:             */
0608:            private static final String ERR_DOC_PARSE_FAIL = "Error parsing "
0609:                    + "SCXML document: \"{0}\", with message: \"{1}\"\n";
0610:
0611:            /**
0612:             * Parsing SCXML document InputSource has failed.
0613:             */
0614:            private static final String ERR_ISRC_PARSE_FAIL = "Could not parse SCXML InputSource";
0615:
0616:            /**
0617:             * Parser configuration error while registering data rule.
0618:             */
0619:            private static final String ERR_PARSER_CFG_DATA = "XML Parser "
0620:                    + "misconfiguration, error registering <data> element rule";
0621:
0622:            /**
0623:             * Parser configuration error while registering send rule.
0624:             */
0625:            private static final String ERR_PARSER_CFG_SEND = "XML Parser "
0626:                    + "misconfiguration, error registering <send> element rule";
0627:
0628:            /**
0629:             * Parser configuration error while registering body content rule for
0630:             * custom action.
0631:             */
0632:            private static final String ERR_PARSER_CFG_CUSTOM = "XML Parser "
0633:                    + "misconfiguration, error registering custom action rules";
0634:
0635:            /**
0636:             * Error message while attempting to define a custom action which does
0637:             * not extend the Commons SCXML Action base class.
0638:             */
0639:            private static final String ERR_CUSTOM_ACTION_TYPE = "Custom actions list"
0640:                    + " contained unknown object (not a Commons SCXML Action subtype)";
0641:
0642:            // String constants
0643:            /** Slash. */
0644:            private static final String STR_SLASH = "/";
0645:
0646:            //---------------------- PRIVATE UTILITY METHODS ----------------------//
0647:            /*
0648:             * Private utility functions for configuring digester rule base for SCXML.
0649:             */
0650:            /**
0651:             * Initialize the Digester rules for the current document.
0652:             *
0653:             * @param scxml The parent SCXML document (or null)
0654:             * @param pr The PathResolver
0655:             * @param customActions The list of custom actions this digester needs
0656:             *                      to be able to process
0657:             *
0658:             * @return scxmlRules The rule set to be used for digestion
0659:             */
0660:            private static ExtendedBaseRules initRules(final SCXML scxml,
0661:                    final PathResolver pr, final List customActions) {
0662:
0663:                ExtendedBaseRules scxmlRules = new ExtendedBaseRules();
0664:                scxmlRules.setNamespaceURI(NAMESPACE_SCXML);
0665:
0666:                //// SCXML
0667:                scxmlRules.add(XP_SM, new ObjectCreateRule(SCXML.class));
0668:                scxmlRules.add(XP_SM, new SetPropertiesRule());
0669:
0670:                //// Datamodel at document root i.e. <scxml> datamodel
0671:                addDatamodelRules(XP_SM + XPF_DM, scxmlRules, scxml, pr);
0672:
0673:                //// States
0674:                // Level one states
0675:                addStateRules(XP_SM_ST, scxmlRules, customActions, scxml, pr, 0);
0676:                scxmlRules.add(XP_SM_ST, new SetNextRule("addState"));
0677:                // Nested states
0678:                addStateRules(XPU_ST_ST, scxmlRules, customActions, scxml, pr,
0679:                        1);
0680:                scxmlRules.add(XPU_ST_ST, new SetNextRule("addChild"));
0681:
0682:                // Parallel states
0683:                addStateRules(XPU_PAR_ST, scxmlRules, customActions, scxml, pr,
0684:                        1);
0685:                scxmlRules.add(XPU_PAR_ST, new SetNextRule("addState"));
0686:                // Target states
0687:                addStateRules(XPU_TR_TAR_ST, scxmlRules, customActions, scxml,
0688:                        pr, 2);
0689:                scxmlRules.add(XPU_TR_TAR_ST, new SetNextRule("setTarget"));
0690:
0691:                //// Parallels
0692:                addParallelRules(XPU_ST_PAR, scxmlRules, pr, customActions,
0693:                        scxml);
0694:
0695:                //// Ifs
0696:                addIfRules(XPU_IF, scxmlRules, pr, customActions);
0697:
0698:                //// Custom actions
0699:                addCustomActionRules(XPU_ONEN, scxmlRules, customActions);
0700:                addCustomActionRules(XPU_ONEX, scxmlRules, customActions);
0701:                addCustomActionRules(XPU_TR, scxmlRules, customActions);
0702:                addCustomActionRules(XPU_IF, scxmlRules, customActions);
0703:                addCustomActionRules(XPU_FIN, scxmlRules, customActions);
0704:
0705:                return scxmlRules;
0706:
0707:            }
0708:
0709:            /**
0710:             * Add Digester rules for all &lt;state&gt; elements.
0711:             *
0712:             * @param xp The Digester style XPath expression of the parent
0713:             *           XML element
0714:             * @param scxmlRules The rule set to be used for digestion
0715:             * @param customActions The list of custom actions this digester needs
0716:             *                      to be able to process
0717:             * @param scxml The parent SCXML document (or null)
0718:             * @param pr The PathResolver
0719:             * @param parent The distance between this state and its parent
0720:             *               state on the Digester stack
0721:             */
0722:            private static void addStateRules(final String xp,
0723:                    final ExtendedBaseRules scxmlRules,
0724:                    final List customActions, final SCXML scxml,
0725:                    final PathResolver pr, final int parent) {
0726:                scxmlRules.add(xp, new ObjectCreateRule(State.class));
0727:                addStatePropertiesRules(xp, scxmlRules, customActions, pr,
0728:                        scxml);
0729:                addDatamodelRules(xp + XPF_DM, scxmlRules, scxml, pr);
0730:                addInvokeRules(xp + XPF_INV, scxmlRules, customActions, pr,
0731:                        scxml);
0732:                addInitialRules(xp + XPF_INI, scxmlRules, customActions, pr,
0733:                        scxml);
0734:                addHistoryRules(xp + XPF_HIST, scxmlRules, customActions, pr,
0735:                        scxml);
0736:                addParentRule(xp, scxmlRules, parent);
0737:                addTransitionRules(xp + XPF_TR, scxmlRules, "addTransition",
0738:                        pr, customActions);
0739:                addHandlerRules(xp, scxmlRules, pr, customActions);
0740:                scxmlRules.add(xp, new UpdateModelRule(scxml));
0741:            }
0742:
0743:            /**
0744:             * Add Digester rules for all &lt;parallel&gt; elements.
0745:             *
0746:             * @param xp The Digester style XPath expression of the parent
0747:             *           XML element
0748:             * @param scxmlRules The rule set to be used for digestion
0749:             * @param customActions The list of custom actions this digester needs
0750:             *                      to be able to process
0751:             * @param pr The {@link PathResolver} for this document
0752:             * @param scxml The parent SCXML document (or null)
0753:             */
0754:            private static void addParallelRules(final String xp,
0755:                    final ExtendedBaseRules scxmlRules, final PathResolver pr,
0756:                    final List customActions, final SCXML scxml) {
0757:                addSimpleRulesTuple(xp, scxmlRules, Parallel.class, null, null,
0758:                        "setParallel");
0759:                addHandlerRules(xp, scxmlRules, pr, customActions);
0760:                addParentRule(xp, scxmlRules, 1);
0761:                scxmlRules.add(xp, new UpdateModelRule(scxml));
0762:            }
0763:
0764:            /**
0765:             * Add Digester rules for all &lt;state&gt; element attributes.
0766:             *
0767:             * @param xp The Digester style XPath expression of the parent
0768:             *           XML element
0769:             * @param scxmlRules The rule set to be used for digestion
0770:             * @param customActions The list of custom actions this digester needs
0771:             *                      to be able to process
0772:             * @param pr The PathResolver
0773:             * @param scxml The root document, if this one is src'ed in
0774:             */
0775:            private static void addStatePropertiesRules(final String xp,
0776:                    final ExtendedBaseRules scxmlRules,
0777:                    final List customActions, final PathResolver pr,
0778:                    final SCXML scxml) {
0779:                scxmlRules.add(xp, new SetPropertiesRule(new String[] { "id",
0780:                        "final" }, new String[] { "id", "isFinal" }));
0781:                scxmlRules.add(xp, new DigestSrcAttributeRule(scxml,
0782:                        customActions, pr));
0783:            }
0784:
0785:            /**
0786:             * Add Digester rules for all &lt;datamodel&gt; elements.
0787:             *
0788:             * @param xp The Digester style XPath expression of the parent
0789:             *           XML element
0790:             * @param scxmlRules The rule set to be used for digestion
0791:             * @param pr The PathResolver
0792:             * @param scxml The parent SCXML document (or null)
0793:             */
0794:            private static void addDatamodelRules(final String xp,
0795:                    final ExtendedBaseRules scxmlRules, final SCXML scxml,
0796:                    final PathResolver pr) {
0797:                scxmlRules.add(xp, new ObjectCreateRule(Datamodel.class));
0798:                scxmlRules.add(xp + XPF_DATA, new ObjectCreateRule(Data.class));
0799:                scxmlRules.add(xp + XPF_DATA, new SetPropertiesRule());
0800:                scxmlRules.add(xp + XPF_DATA, new SetCurrentNamespacesRule());
0801:                scxmlRules.add(xp + XPF_DATA, new SetNextRule("addData"));
0802:                try {
0803:                    scxmlRules.add(xp + XPF_DATA, new ParseDataRule(pr));
0804:                } catch (ParserConfigurationException pce) {
0805:                    org.apache.commons.logging.Log log = LogFactory
0806:                            .getLog(SCXMLDigester.class);
0807:                    log.error(ERR_PARSER_CFG_DATA, pce);
0808:                }
0809:                scxmlRules.add(xp, new SetNextRule("setDatamodel"));
0810:            }
0811:
0812:            /**
0813:             * Add Digester rules for all &lt;invoke&gt; elements.
0814:             *
0815:             * @param xp The Digester style XPath expression of the parent
0816:             *           XML element
0817:             * @param scxmlRules The rule set to be used for digestion
0818:             * @param customActions The list of {@link CustomAction}s this digester
0819:             *              instance will process, can be null or empty
0820:             * @param pr The PathResolver
0821:             * @param scxml The parent SCXML document (or null)
0822:             */
0823:            private static void addInvokeRules(final String xp,
0824:                    final ExtendedBaseRules scxmlRules,
0825:                    final List customActions, final PathResolver pr,
0826:                    final SCXML scxml) {
0827:                scxmlRules.add(xp, new ObjectCreateRule(Invoke.class));
0828:                scxmlRules.add(xp, new SetPropertiesRule());
0829:                scxmlRules.add(xp, new SetCurrentNamespacesRule());
0830:                scxmlRules.add(xp, new SetPathResolverRule(pr));
0831:                scxmlRules.add(xp + XPF_PRM, new ObjectCreateRule(Param.class));
0832:                scxmlRules.add(xp + XPF_PRM, new SetPropertiesRule());
0833:                scxmlRules.add(xp + XPF_PRM, new SetCurrentNamespacesRule());
0834:                scxmlRules.add(xp + XPF_PRM, new SetNextRule("addParam"));
0835:                scxmlRules.add(xp + XPF_FIN, new ObjectCreateRule(
0836:                        Finalize.class));
0837:                scxmlRules.add(xp + XPF_FIN, new UpdateFinalizeRule());
0838:                addActionRules(xp + XPF_FIN, scxmlRules, pr, customActions);
0839:                scxmlRules.add(xp + XPF_FIN, new SetNextRule("setFinalize"));
0840:                scxmlRules.add(xp, new SetNextRule("setInvoke"));
0841:            }
0842:
0843:            /**
0844:             * Add Digester rules for all &lt;initial&gt; elements.
0845:             *
0846:             * @param xp The Digester style XPath expression of the parent
0847:             *           XML element
0848:             * @param scxmlRules The rule set to be used for digestion
0849:             * @param customActions The list of custom actions this digester needs
0850:             *                      to be able to process
0851:             * @param pr The PathResolver
0852:             * @param scxml The parent SCXML document (or null)
0853:             */
0854:            private static void addInitialRules(final String xp,
0855:                    final ExtendedBaseRules scxmlRules,
0856:                    final List customActions, final PathResolver pr,
0857:                    final SCXML scxml) {
0858:                scxmlRules.add(xp, new ObjectCreateRule(Initial.class));
0859:                addPseudoStatePropertiesRules(xp, scxmlRules, customActions,
0860:                        pr, scxml);
0861:                scxmlRules.add(xp, new UpdateModelRule(scxml));
0862:                addTransitionRules(xp + XPF_TR, scxmlRules, "setTransition",
0863:                        pr, customActions);
0864:                scxmlRules.add(xp, new SetNextRule("setInitial"));
0865:            }
0866:
0867:            /**
0868:             * Add Digester rules for all &lt;history&gt; elements.
0869:             *
0870:             * @param xp The Digester style XPath expression of the parent
0871:             *           XML element
0872:             * @param scxmlRules The rule set to be used for digestion
0873:             * @param customActions The list of custom actions this digester needs
0874:             *                      to be able to process
0875:             * @param pr The PathResolver
0876:             * @param scxml The parent SCXML document (or null)
0877:             */
0878:            private static void addHistoryRules(final String xp,
0879:                    final ExtendedBaseRules scxmlRules,
0880:                    final List customActions, final PathResolver pr,
0881:                    final SCXML scxml) {
0882:                scxmlRules.add(xp, new ObjectCreateRule(History.class));
0883:                addPseudoStatePropertiesRules(xp, scxmlRules, customActions,
0884:                        pr, scxml);
0885:                scxmlRules.add(xp, new UpdateModelRule(scxml));
0886:                scxmlRules.add(xp, new SetPropertiesRule(
0887:                        new String[] { "type" }, new String[] { "type" }));
0888:                addTransitionRules(xp + XPF_TR, scxmlRules, "setTransition",
0889:                        pr, customActions);
0890:                scxmlRules.add(xp, new SetNextRule("addHistory"));
0891:            }
0892:
0893:            /**
0894:             * Add Digester rules for all pseudo state (initial, history) element
0895:             * attributes.
0896:             *
0897:             * @param xp The Digester style XPath expression of the parent
0898:             *           XML element
0899:             * @param scxmlRules The rule set to be used for digestion
0900:             * @param customActions The list of custom actions this digester needs
0901:             *                      to be able to process
0902:             * @param pr The PathResolver
0903:             * @param scxml The root document, if this one is src'ed in
0904:             */
0905:            private static void addPseudoStatePropertiesRules(final String xp,
0906:                    final ExtendedBaseRules scxmlRules,
0907:                    final List customActions, final PathResolver pr,
0908:                    final SCXML scxml) {
0909:                scxmlRules.add(xp, new SetPropertiesRule(new String[] { "id" },
0910:                        new String[] { "id" }));
0911:                scxmlRules.add(xp, new DigestSrcAttributeRule(scxml,
0912:                        customActions, pr));
0913:                addParentRule(xp, scxmlRules, 1);
0914:            }
0915:
0916:            /**
0917:             * Add Digester rule for all setting parent state.
0918:             *
0919:             * @param xp The Digester style XPath expression of the parent
0920:             *           XML element
0921:             * @param scxmlRules The rule set to be used for digestion
0922:             * @param parent The distance between this state and its parent
0923:             *               state on the Digester stack
0924:             */
0925:            private static void addParentRule(final String xp,
0926:                    final ExtendedBaseRules scxmlRules, final int parent) {
0927:                if (parent < 1) {
0928:                    return;
0929:                }
0930:                scxmlRules.add(xp, new Rule() {
0931:                    // A generic version of setTopRule
0932:                    public void body(final String namespace, final String name,
0933:                            final String text) throws Exception {
0934:                        TransitionTarget t = (TransitionTarget) getDigester()
0935:                                .peek();
0936:                        TransitionTarget p = (TransitionTarget) getDigester()
0937:                                .peek(parent);
0938:                        // CHANGE - Moved parent property to TransitionTarget
0939:                        t.setParent(p);
0940:                    }
0941:                });
0942:            }
0943:
0944:            /**
0945:             * Add Digester rules for all &lt;transition&gt; elements.
0946:             *
0947:             * @param xp The Digester style XPath expression of the parent
0948:             *           XML element
0949:             * @param scxmlRules The rule set to be used for digestion
0950:             * @param setNextMethod The method name for adding this transition
0951:             *             to its parent (defined by the SCXML Java object model).
0952:             * @param pr The {@link PathResolver} for this document
0953:             * @param customActions The list of custom actions this digester needs
0954:             *                      to be able to process
0955:             */
0956:            private static void addTransitionRules(final String xp,
0957:                    final ExtendedBaseRules scxmlRules,
0958:                    final String setNextMethod, final PathResolver pr,
0959:                    final List customActions) {
0960:                scxmlRules.add(xp, new ObjectCreateRule(Transition.class));
0961:                scxmlRules.add(xp, new SetPropertiesRule(new String[] {
0962:                        "event", "cond", "target" }, new String[] { "event",
0963:                        "cond", "next" }));
0964:                scxmlRules.add(xp, new SetCurrentNamespacesRule());
0965:                scxmlRules.add(xp + XPF_TAR, new SetPropertiesRule());
0966:                addActionRules(xp, scxmlRules, pr, customActions);
0967:                scxmlRules.add(xp + XPF_EXT, new Rule() {
0968:                    public void end(final String namespace, final String name) {
0969:                        Transition t = (Transition) getDigester().peek(1);
0970:                        State exitState = new State();
0971:                        exitState.setIsFinal(true);
0972:                        t.setTarget(exitState);
0973:                    }
0974:                });
0975:                scxmlRules.add(xp, new SetNextRule(setNextMethod));
0976:            }
0977:
0978:            /**
0979:             * Add Digester rules for all &lt;onentry&gt; and &lt;onexit&gt;
0980:             * elements.
0981:             *
0982:             * @param xp The Digester style XPath expression of the parent
0983:             *           XML element
0984:             * @param scxmlRules The rule set to be used for digestion
0985:             * @param pr The {@link PathResolver} for this document
0986:             * @param customActions The list of custom actions this digester needs
0987:             *                      to be able to process
0988:             */
0989:            private static void addHandlerRules(final String xp,
0990:                    final ExtendedBaseRules scxmlRules, final PathResolver pr,
0991:                    final List customActions) {
0992:                scxmlRules.add(xp + XPF_ONEN, new ObjectCreateRule(
0993:                        OnEntry.class));
0994:                addActionRules(xp + XPF_ONEN, scxmlRules, pr, customActions);
0995:                scxmlRules.add(xp + XPF_ONEN, new SetNextRule("setOnEntry"));
0996:                scxmlRules.add(xp + XPF_ONEX,
0997:                        new ObjectCreateRule(OnExit.class));
0998:                addActionRules(xp + XPF_ONEX, scxmlRules, pr, customActions);
0999:                scxmlRules.add(xp + XPF_ONEX, new SetNextRule("setOnExit"));
1000:            }
1001:
1002:            /**
1003:             * Add Digester rules for all actions (&quot;executable&quot; elements).
1004:             *
1005:             * @param xp The Digester style XPath expression of the parent
1006:             *           XML element
1007:             * @param scxmlRules The rule set to be used for digestion
1008:             * @param pr The {@link PathResolver} for this document
1009:             * @param customActions The list of custom actions this digester needs
1010:             *                      to be able to process
1011:             */
1012:            private static void addActionRules(final String xp,
1013:                    final ExtendedBaseRules scxmlRules, final PathResolver pr,
1014:                    final List customActions) {
1015:                addActionRulesTuple(xp + XPF_ASN, scxmlRules, Assign.class);
1016:                scxmlRules.add(xp + XPF_ASN, new SetPathResolverRule(pr));
1017:                addActionRulesTuple(xp + XPF_VAR, scxmlRules, Var.class);
1018:                addActionRulesTuple(xp + XPF_LOG, scxmlRules, Log.class);
1019:                addSendRulesTuple(xp + XPF_SND, scxmlRules);
1020:                addActionRulesTuple(xp + XPF_CAN, scxmlRules, Cancel.class);
1021:                addActionRulesTuple(xp + XPF_EXT, scxmlRules, Exit.class);
1022:                //addCustomActionRules(xp, scxmlRules, customActions);
1023:            }
1024:
1025:            /**
1026:             * Add custom action rules, if any custom actions are provided.
1027:             *
1028:             * @param xp The Digester style XPath expression of the parent
1029:             *           XML element
1030:             * @param scxmlRules The rule set to be used for digestion
1031:             * @param customActions The list of custom actions this digester needs
1032:             *                      to be able to process
1033:             */
1034:            private static void addCustomActionRules(final String xp,
1035:                    final ExtendedBaseRules scxmlRules, final List customActions) {
1036:                if (customActions == null || customActions.size() == 0) {
1037:                    return;
1038:                }
1039:                for (int i = 0; i < customActions.size(); i++) {
1040:                    Object item = customActions.get(i);
1041:                    if (item == null || !(item instanceof  CustomAction)) {
1042:                        org.apache.commons.logging.Log log = LogFactory
1043:                                .getLog(SCXMLDigester.class);
1044:                        log.warn(ERR_CUSTOM_ACTION_TYPE);
1045:                    } else {
1046:                        CustomAction ca = (CustomAction) item;
1047:                        scxmlRules.setNamespaceURI(ca.getNamespaceURI());
1048:                        String xpfLocalName = STR_SLASH + ca.getLocalName();
1049:                        Class klass = ca.getActionClass();
1050:                        if (SCXMLHelper.implementationOf(klass,
1051:                                ExternalContent.class)) {
1052:                            addCustomActionRulesTuple(xp + xpfLocalName,
1053:                                    scxmlRules, klass, true);
1054:                        } else {
1055:                            addCustomActionRulesTuple(xp + xpfLocalName,
1056:                                    scxmlRules, klass, false);
1057:                        }
1058:                    }
1059:                }
1060:                scxmlRules.setNamespaceURI(NAMESPACE_SCXML);
1061:            }
1062:
1063:            /**
1064:             * Add Digester rules that are specific to the &lt;send&gt; action
1065:             * element.
1066:             *
1067:             * @param xp The Digester style XPath expression of &lt;send&gt; element
1068:             * @param scxmlRules The rule set to be used for digestion
1069:             */
1070:            private static void addSendRulesTuple(final String xp,
1071:                    final ExtendedBaseRules scxmlRules) {
1072:                addActionRulesTuple(xp, scxmlRules, Send.class);
1073:                try {
1074:                    scxmlRules.add(xp, new ParseExternalContentRule());
1075:                } catch (ParserConfigurationException pce) {
1076:                    org.apache.commons.logging.Log log = LogFactory
1077:                            .getLog(SCXMLDigester.class);
1078:                    log.error(ERR_PARSER_CFG_SEND, pce);
1079:                }
1080:            }
1081:
1082:            /**
1083:             * Add Digester rules for a simple custom action (no body content).
1084:             *
1085:             * @param xp The path to the custom action element
1086:             * @param scxmlRules The rule set to be used for digestion
1087:             * @param klass The <code>Action</code> class implementing the custom
1088:             *              action.
1089:             * @param bodyContent Whether the custom rule has body content
1090:             *              that should be parsed using
1091:             *              <code>NodeCreateRule</code>
1092:             */
1093:            private static void addCustomActionRulesTuple(final String xp,
1094:                    final ExtendedBaseRules scxmlRules, final Class klass,
1095:                    final boolean bodyContent) {
1096:                addActionRulesTuple(xp, scxmlRules, klass);
1097:                if (bodyContent) {
1098:                    try {
1099:                        scxmlRules.add(xp, new ParseExternalContentRule());
1100:                    } catch (ParserConfigurationException pce) {
1101:                        org.apache.commons.logging.Log log = LogFactory
1102:                                .getLog(SCXMLDigester.class);
1103:                        log.error(ERR_PARSER_CFG_CUSTOM, pce);
1104:                    }
1105:                }
1106:            }
1107:
1108:            /**
1109:             * Add Digester rules for all &lt;if&gt; elements.
1110:             *
1111:             * @param xp The Digester style XPath expression of the parent
1112:             *           XML element
1113:             * @param scxmlRules The rule set to be used for digestion
1114:             * @param pr The {@link PathResolver} for this document
1115:             * @param customActions The list of custom actions this digester needs
1116:             *                      to be able to process
1117:             */
1118:            private static void addIfRules(final String xp,
1119:                    final ExtendedBaseRules scxmlRules, final PathResolver pr,
1120:                    final List customActions) {
1121:                addActionRulesTuple(xp, scxmlRules, If.class);
1122:                addActionRules(xp, scxmlRules, pr, customActions);
1123:                addActionRulesTuple(xp + XPF_EIF, scxmlRules, ElseIf.class);
1124:                addActionRulesTuple(xp + XPF_ELS, scxmlRules, Else.class);
1125:            }
1126:
1127:            /**
1128:             * Add Digester rules that are common across all actions elements.
1129:             *
1130:             * @param xp The Digester style XPath expression of the parent
1131:             *           XML element
1132:             * @param scxmlRules The rule set to be used for digestion
1133:             * @param klass The class in the Java object model to be instantiated
1134:             *              in the ObjectCreateRule for this action
1135:             */
1136:            private static void addActionRulesTuple(final String xp,
1137:                    final ExtendedBaseRules scxmlRules, final Class klass) {
1138:                addSimpleRulesTuple(xp, scxmlRules, klass, null, null,
1139:                        "addAction");
1140:                scxmlRules.add(xp, new SetExecutableParentRule());
1141:                scxmlRules.add(xp, new SetCurrentNamespacesRule());
1142:            }
1143:
1144:            /**
1145:             * Add the run of the mill Digester rules for any element.
1146:             *
1147:             * @param xp The Digester style XPath expression of the parent
1148:             *           XML element
1149:             * @param scxmlRules The rule set to be used for digestion
1150:             * @param klass The class in the Java object model to be instantiated
1151:             *              in the ObjectCreateRule for this action
1152:             * @param args The attributes to be mapped into the object model
1153:             * @param props The properties that args get mapped to
1154:             * @param addMethod The method that the SetNextRule should call
1155:             */
1156:            private static void addSimpleRulesTuple(final String xp,
1157:                    final ExtendedBaseRules scxmlRules, final Class klass,
1158:                    final String[] args, final String[] props,
1159:                    final String addMethod) {
1160:                scxmlRules.add(xp, new ObjectCreateRule(klass));
1161:                if (args == null) {
1162:                    scxmlRules.add(xp, new SetPropertiesRule());
1163:                } else {
1164:                    scxmlRules.add(xp, new SetPropertiesRule(args, props));
1165:                }
1166:                scxmlRules.add(xp, new SetNextRule(addMethod));
1167:            }
1168:
1169:            /**
1170:             * Discourage instantiation since this is a utility class.
1171:             */
1172:            private SCXMLDigester() {
1173:                super ();
1174:            }
1175:
1176:            /**
1177:             * Custom digestion rule for establishing necessary associations of this
1178:             * TransitionTarget with the root SCXML object.
1179:             * These include: <br>
1180:             * 1) Updation of the SCXML object's global targets Map <br>
1181:             * 2) Obtaining a handle to the SCXML object's NotificationRegistry <br>
1182:             *
1183:             * @deprecated Will be removed in version 1.0
1184:             */
1185:            public static class UpdateModelRule extends Rule {
1186:
1187:                /**
1188:                 * The root SCXML object.
1189:                 */
1190:                private SCXML scxml;
1191:
1192:                /**
1193:                 * Constructor.
1194:                 * @param scxml The root SCXML object
1195:                 */
1196:                public UpdateModelRule(final SCXML scxml) {
1197:                    super ();
1198:                    this .scxml = scxml;
1199:                }
1200:
1201:                /**
1202:                 * @see Rule#end(String, String)
1203:                 */
1204:                public final void end(final String namespace, final String name) {
1205:                    if (scxml == null) {
1206:                        scxml = (SCXML) getDigester().peek(
1207:                                getDigester().getCount() - 1);
1208:                    }
1209:                    TransitionTarget tt = (TransitionTarget) getDigester()
1210:                            .peek();
1211:                    scxml.addTarget(tt);
1212:                }
1213:            }
1214:
1215:            /**
1216:             * Custom digestion rule for setting Executable parent of Action elements.
1217:             *
1218:             * @deprecated Will be removed in version 1.0
1219:             */
1220:            public static class SetExecutableParentRule extends Rule {
1221:
1222:                /**
1223:                 * Constructor.
1224:                 */
1225:                public SetExecutableParentRule() {
1226:                    super ();
1227:                }
1228:
1229:                /**
1230:                 * @see Rule#end(String, String)
1231:                 */
1232:                public final void end(final String namespace, final String name) {
1233:                    Action child = (Action) getDigester().peek();
1234:                    for (int i = 1; i < getDigester().getCount() - 1; i++) {
1235:                        Object ancestor = getDigester().peek(i);
1236:                        if (ancestor instanceof  Executable) {
1237:                            child.setParent((Executable) ancestor);
1238:                            return;
1239:                        }
1240:                    }
1241:                }
1242:            }
1243:
1244:            /**
1245:             * Custom digestion rule for parsing bodies of
1246:             * <code>ExternalContent</code> elements.
1247:             *
1248:             * @see ExternalContent
1249:             *
1250:             * @deprecated Will be removed in version 1.0
1251:             */
1252:            public static class ParseExternalContentRule extends NodeCreateRule {
1253:                /**
1254:                 * Constructor.
1255:                 * @throws ParserConfigurationException A JAXP configuration error
1256:                 */
1257:                public ParseExternalContentRule()
1258:                        throws ParserConfigurationException {
1259:                    super ();
1260:                }
1261:
1262:                /**
1263:                 * @see Rule#end(String, String)
1264:                 */
1265:                public final void end(final String namespace, final String name) {
1266:                    Element bodyElement = (Element) getDigester().pop();
1267:                    NodeList childNodes = bodyElement.getChildNodes();
1268:                    List externalNodes = ((ExternalContent) getDigester()
1269:                            .peek()).getExternalNodes();
1270:                    for (int i = 0; i < childNodes.getLength(); i++) {
1271:                        externalNodes.add(childNodes.item(i));
1272:                    }
1273:                }
1274:            }
1275:
1276:            /**
1277:             * Custom digestion rule for parsing bodies of &lt;data&gt; elements.
1278:             *
1279:             * @deprecated Will be removed in version 1.0
1280:             */
1281:            public static class ParseDataRule extends NodeCreateRule {
1282:
1283:                /**
1284:                 * The PathResolver used to resolve the src attribute to the
1285:                 * SCXML document it points to.
1286:                 * @see PathResolver
1287:                 */
1288:                private PathResolver pr;
1289:
1290:                /**
1291:                 * The "src" attribute, retained to check if body content is legal.
1292:                 */
1293:                private String src;
1294:
1295:                /**
1296:                 * The "expr" attribute, retained to check if body content is legal.
1297:                 */
1298:                private String expr;
1299:
1300:                /**
1301:                 * The XML tree for this data, parse as a Node, obtained from
1302:                 * either the "src" or the "expr" attributes.
1303:                 */
1304:                private Node attrNode;
1305:
1306:                /**
1307:                 * Constructor.
1308:                 *
1309:                 * @param pr The <code>PathResolver</code>
1310:                 * @throws ParserConfigurationException A JAXP configuration error
1311:                 */
1312:                public ParseDataRule(final PathResolver pr)
1313:                        throws ParserConfigurationException {
1314:                    super ();
1315:                    this .pr = pr;
1316:                }
1317:
1318:                /**
1319:                 * @see Rule#begin(String, String, Attributes)
1320:                 */
1321:                public final void begin(final String namespace,
1322:                        final String name, final Attributes attributes)
1323:                        throws Exception {
1324:                    super .begin(namespace, name, attributes);
1325:                    src = attributes.getValue("src");
1326:                    expr = attributes.getValue("expr");
1327:                    if (!SCXMLHelper.isStringEmpty(src)) {
1328:                        String path = null;
1329:                        if (pr == null) {
1330:                            path = src;
1331:                        } else {
1332:                            path = pr.resolvePath(src);
1333:                        }
1334:                        try {
1335:                            DocumentBuilderFactory dbFactory = DocumentBuilderFactory
1336:                                    .newInstance();
1337:                            DocumentBuilder db = dbFactory.newDocumentBuilder();
1338:                            attrNode = db.parse(path);
1339:                        } catch (Throwable t) { // you read that correctly
1340:                            org.apache.commons.logging.Log log = LogFactory
1341:                                    .getLog(SCXMLDigester.class);
1342:                            log.error(t.getMessage(), t);
1343:                        }
1344:                        return;
1345:                    }
1346:                }
1347:
1348:                /**
1349:                 * @see Rule#end(String, String)
1350:                 */
1351:                public final void end(final String namespace, final String name) {
1352:                    Node bodyNode = (Node) getDigester().pop();
1353:                    Data data = ((Data) getDigester().peek());
1354:                    // Prefer "src" over "expr", "expr" over child nodes
1355:                    // "expr" can only be evaluated at execution time
1356:                    if (!SCXMLHelper.isStringEmpty(src)) {
1357:                        data.setNode(attrNode);
1358:                    } else if (SCXMLHelper.isStringEmpty(expr)) {
1359:                        // both "src" and "expr" are empty
1360:                        data.setNode(bodyNode);
1361:                    }
1362:                }
1363:            }
1364:
1365:            /**
1366:             * Custom digestion rule for external sources, that is, the src attribute of
1367:             * the &lt;state&gt; element.
1368:             *
1369:             * @deprecated Will be removed in version 1.0
1370:             */
1371:            public static class DigestSrcAttributeRule extends Rule {
1372:
1373:                /**
1374:                 * The PathResolver used to resolve the src attribute to the
1375:                 * SCXML document it points to.
1376:                 * @see PathResolver
1377:                 */
1378:                private PathResolver pr;
1379:
1380:                /**
1381:                 * The root document.
1382:                 */
1383:                private SCXML root;
1384:
1385:                /**
1386:                 * The list of custom actions the parent document is capable of
1387:                 * processing (and hence, the child should be, by transitivity).
1388:                 * @see CustomAction
1389:                 */
1390:                private List customActions;
1391:
1392:                /**
1393:                 * Constructor.
1394:                 * @param pr The PathResolver
1395:                 * @param customActions The list of custom actions this digester needs
1396:                 *                      to be able to process
1397:                 *
1398:                 * @see PathResolver
1399:                 * @see CustomAction
1400:                 *
1401:                 * TODO: Remove in v1.0
1402:                 */
1403:                public DigestSrcAttributeRule(final List customActions,
1404:                        final PathResolver pr) {
1405:                    super ();
1406:                    this .customActions = customActions;
1407:                    this .pr = pr;
1408:                }
1409:
1410:                /**
1411:                 * Constructor.
1412:                 * @param root The root document, if this one is src'ed in
1413:                 * @param pr The PathResolver
1414:                 * @param customActions The list of custom actions this digester needs
1415:                 *                      to be able to process
1416:                 *
1417:                 * @see PathResolver
1418:                 * @see CustomAction
1419:                 */
1420:                public DigestSrcAttributeRule(final SCXML root,
1421:                        final List customActions, final PathResolver pr) {
1422:                    super ();
1423:                    this .root = root;
1424:                    this .customActions = customActions;
1425:                    this .pr = pr;
1426:                }
1427:
1428:                /**
1429:                 * @see Rule#begin(String, String, Attributes)
1430:                 */
1431:                public final void begin(final String namespace,
1432:                        final String name, final Attributes attributes) {
1433:                    String src = attributes.getValue("src");
1434:                    if (SCXMLHelper.isStringEmpty(src)) {
1435:                        return;
1436:                    }
1437:                    Digester digester = getDigester();
1438:                    SCXML scxml = (SCXML) digester
1439:                            .peek(digester.getCount() - 1);
1440:                    // 1) Digest the external SCXML file
1441:                    SCXML externalSCXML = null;
1442:                    String path;
1443:                    Digester externalSrcDigester;
1444:                    if (pr == null) {
1445:                        path = src;
1446:                        if (root != null) {
1447:                            externalSrcDigester = newInstance(root, null,
1448:                                    customActions);
1449:                        } else {
1450:                            externalSrcDigester = newInstance(scxml, null,
1451:                                    customActions);
1452:                        }
1453:                    } else {
1454:                        path = pr.resolvePath(src);
1455:                        if (root != null) {
1456:                            externalSrcDigester = newInstance(root, pr
1457:                                    .getResolver(src), customActions);
1458:                        } else {
1459:                            externalSrcDigester = newInstance(scxml, pr
1460:                                    .getResolver(src), customActions);
1461:                        }
1462:                    }
1463:
1464:                    try {
1465:                        externalSCXML = (SCXML) externalSrcDigester.parse(path);
1466:                    } catch (Exception e) {
1467:                        org.apache.commons.logging.Log log = LogFactory
1468:                                .getLog(SCXMLDigester.class);
1469:                        log.error(e.getMessage(), e);
1470:                    }
1471:                    // 2) Adopt the children and datamodel
1472:                    if (externalSCXML == null) {
1473:                        return;
1474:                    }
1475:                    State s = (State) digester.peek();
1476:                    Transition t = new Transition();
1477:                    t.setNext(externalSCXML.getInitialstate());
1478:                    Initial ini = new Initial();
1479:                    ini.setTransition(t);
1480:                    s.setInitial(ini);
1481:                    Map children = externalSCXML.getStates();
1482:                    Object[] ids = children.keySet().toArray();
1483:                    for (int i = 0; i < ids.length; i++) {
1484:                        s.addChild((State) children.get(ids[i]));
1485:                    }
1486:                    s.setDatamodel(externalSCXML.getDatamodel());
1487:                }
1488:            }
1489:
1490:            /**
1491:             * Custom digestion rule for setting PathResolver for runtime retrieval.
1492:             *
1493:             * @deprecated Will be removed in version 1.0
1494:             */
1495:            public static class SetPathResolverRule extends Rule {
1496:
1497:                /**
1498:                 * The PathResolver to set.
1499:                 * @see PathResolver
1500:                 */
1501:                private PathResolver pr;
1502:
1503:                /**
1504:                 * Constructor.
1505:                 * @param pr The PathResolver
1506:                 *
1507:                 * @see PathResolver
1508:                 */
1509:                public SetPathResolverRule(final PathResolver pr) {
1510:                    super ();
1511:                    this .pr = pr;
1512:                }
1513:
1514:                /**
1515:                 * @see Rule#begin(String, String, Attributes)
1516:                 */
1517:                public final void begin(final String namespace,
1518:                        final String name, final Attributes attributes) {
1519:                    PathResolverHolder prHolder = (PathResolverHolder) getDigester()
1520:                            .peek();
1521:                    prHolder.setPathResolver(pr);
1522:                }
1523:            }
1524:
1525:            /**
1526:             * Custom digestion rule for setting state parent of finalize.
1527:             *
1528:             * @deprecated Will be removed in version 1.0
1529:             */
1530:            public static class UpdateFinalizeRule extends Rule {
1531:
1532:                /**
1533:                 * @see Rule#begin(String, String, Attributes)
1534:                 */
1535:                public final void begin(final String namespace,
1536:                        final String name, final Attributes attributes) {
1537:                    Finalize finalize = (Finalize) getDigester().peek();
1538:                    // state/invoke/finalize --> peek(2)
1539:                    TransitionTarget tt = (TransitionTarget) getDigester()
1540:                            .peek(2);
1541:                    finalize.setParent(tt);
1542:                }
1543:            }
1544:
1545:            /**
1546:             * Custom digestion rule for attaching a snapshot of current namespaces
1547:             * to SCXML actions for deferred XPath evaluation.
1548:             *
1549:             */
1550:            private static class SetCurrentNamespacesRule extends Rule {
1551:
1552:                /**
1553:                 * @see Rule#begin(String, String, Attributes)
1554:                 */
1555:                public final void begin(final String namespace,
1556:                        final String name, final Attributes attributes) {
1557:                    NamespacePrefixesHolder nsHolder = (NamespacePrefixesHolder) getDigester()
1558:                            .peek();
1559:                    nsHolder
1560:                            .setNamespaces(getDigester().getCurrentNamespaces());
1561:                }
1562:            }
1563:
1564:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.