Source Code Cross Referenced for AbstractProcess.java in  » Workflow-Engines » wfmopen-2.1.1 » de » danet » an » workflow » domain » 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 » Workflow Engines » wfmopen 2.1.1 » de.danet.an.workflow.domain 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * This file is part of the WfMOpen project.
0003:         * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
0004:         * All rights reserved.
0005:         *
0006:         * This program is free software; you can redistribute it and/or modify
0007:         * it under the terms of the GNU General Public License as published by
0008:         * the Free Software Foundation; either version 2 of the License, or
0009:         * (at your option) any later version.
0010:         *
0011:         * This program is distributed in the hope that it will be useful,
0012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014:         * GNU General Public License for more details.
0015:         *
0016:         * You should have received a copy of the GNU General Public License
0017:         * along with this program; if not, write to the Free Software
0018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019:         *
0020:         * $Id: AbstractProcess.java,v 1.23.2.1 2007/11/02 16:00:33 drmlipp Exp $
0021:         *
0022:         * $Log: AbstractProcess.java,v $
0023:         * Revision 1.23.2.1  2007/11/02 16:00:33  drmlipp
0024:         * Merged bug fixes from HEAD.
0025:         *
0026:         * Revision 1.24  2007/09/21 06:19:35  mlipp
0027:         * Fixed problem with NamingException during process deletion.
0028:         *
0029:         * Revision 1.23  2007/09/14 12:34:41  drmlipp
0030:         * Improved map initialization.
0031:         *
0032:         * Revision 1.22  2007/05/03 21:58:16  mlipp
0033:         * Internal refactoring for making better use of local EJBs.
0034:         *
0035:         * Revision 1.21  2007/03/27 21:59:43  mlipp
0036:         * Fixed lots of checkstyle warnings.
0037:         *
0038:         * Revision 1.20  2007/02/27 14:34:13  drmlipp
0039:         * Some refactoring to reduce cyclic dependencies.
0040:         *
0041:         * Revision 1.19  2007/01/25 23:00:31  mlipp
0042:         * Fixed result().
0043:         *
0044:         * Revision 1.18  2006/12/03 22:44:20  mlipp
0045:         * Fixed return object of requester() for subflows.
0046:         *
0047:         * Revision 1.17  2006/11/19 21:53:47  mlipp
0048:         * Finished support for native Java types.
0049:         *
0050:         * Revision 1.16  2006/10/19 11:16:30  drmlipp
0051:         * Block activity deadlines cannot be delayed.
0052:         *
0053:         * Revision 1.15  2006/10/17 22:58:39  mlipp
0054:         * Continuing implementation of suspended exception handling.
0055:         *
0056:         * Revision 1.14  2006/10/17 15:55:12  drmlipp
0057:         * Introducing new state ...suspended.abandoning.
0058:         *
0059:         * Revision 1.13  2006/10/07 20:41:34  mlipp
0060:         * Merged J2EE 1.4 adaptions from test branch.
0061:         *
0062:         * Revision 1.12  2006/09/29 12:32:08  drmlipp
0063:         * Consistently using WfMOpen as projct name now.
0064:         *
0065:         * Revision 1.11  2006/07/18 13:18:14  drmlipp
0066:         * Merged changes from wfmopen-1.3.x branch up to 1.3.4.
0067:         *
0068:         * Revision 1.6.2.20  2006/03/15 10:46:07  drmlipp
0069:         * Fixed problems with E4X and empty input/output documents.
0070:         *
0071:         * Revision 1.6.2.19  2006/03/14 16:44:27  drmlipp
0072:         * Fixed loop.
0073:         *
0074:         * Revision 1.6.2.18  2006/03/07 13:51:32  drmlipp
0075:         * Finished transition to E4X usage for actual parameter evaluation.
0076:         *
0077:         * Revision 1.10  2006/03/08 14:46:43  drmlipp
0078:         * Synchronized with 1.3.3p5.
0079:         *
0080:         * Revision 1.9  2005/10/10 20:02:12  mlipp
0081:         * Synchronized with 1.3.3.
0082:         *
0083:         * Revision 1.8  2005/04/22 15:10:53  drmlipp
0084:         * Merged changes from 1.3 branch up to 1.3p15.
0085:         *
0086:         * Revision 1.6.2.11  2005/04/22 14:09:27  drmlipp
0087:         * Support specification of all extended attributes in Value attribute.
0088:         *
0089:         * Revision 1.6.2.10  2005/04/18 11:11:20  drmlipp
0090:         * More event handling optimization.
0091:         *
0092:         * Revision 1.6.2.9  2005/04/16 21:18:30  drmlipp
0093:         * Made audit event filtering more flexible and added possibility to turn
0094:         * off audit log.
0095:         *
0096:         * Revision 1.6.2.8  2005/04/15 21:07:39  drmlipp
0097:         * Added "storeAuditEvents" flag.
0098:         *
0099:         * Revision 1.6.2.7  2005/04/15 08:26:34  drmlipp
0100:         * Fixed isHandled.
0101:         *
0102:         * Revision 1.6.2.6  2005/04/14 21:40:52  drmlipp
0103:         * Optimized event feedback.
0104:         *
0105:         * Revision 1.6.2.5  2005/04/14 15:08:51  drmlipp
0106:         * Added "filterable" event auditing.
0107:         *
0108:         * Revision 1.7  2005/02/04 14:25:26  drmlipp
0109:         * Synchronized with 1.3rc2.
0110:         *
0111:         * Revision 1.6.2.4  2005/02/01 21:15:51  drmlipp
0112:         * Fixed audit event generation for deferred choice.
0113:         *
0114:         * Revision 1.6.2.3  2005/02/01 16:08:41  drmlipp
0115:         * Implemented deferred choice.
0116:         *
0117:         * Revision 1.6.2.2  2005/01/31 21:12:58  drmlipp
0118:         * Continued implementation of deferred choice.
0119:         *
0120:         * Revision 1.6.2.1  2005/01/31 15:41:12  drmlipp
0121:         * Started implementation of deferred choice.
0122:         *
0123:         * Revision 1.6  2005/01/21 09:34:56  drmlipp
0124:         * Moved initialization of debug attribute to proper class.
0125:         *
0126:         * Revision 1.5  2005/01/12 22:10:35  mlipp
0127:         * Added trim to string comparison.
0128:         *
0129:         * Revision 1.4  2005/01/10 22:19:35  mlipp
0130:         * Added extension attribute for debug mode.
0131:         *
0132:         * Revision 1.3  2005/01/02 20:49:13  mlipp
0133:         * First version of debug mode.
0134:         *
0135:         * Revision 1.2  2004/08/19 13:24:49  drmlipp
0136:         * Fixed AVK errors and (many) warnings.
0137:         *
0138:         * Revision 1.1.1.6  2004/08/18 15:17:38  drmlipp
0139:         * Update to 1.2
0140:         *
0141:         * Revision 1.201  2004/07/14 12:08:39  lipp
0142:         * Fixed problem with default for condition type.
0143:         *
0144:         * Revision 1.200  2004/07/14 11:06:03  lipp
0145:         * Supplied default for condition type.
0146:         *
0147:         * Revision 1.199  2004/07/04 17:34:19  lipp
0148:         * Fixed problem with event source.
0149:         *
0150:         * Revision 1.198  2004/06/30 12:05:39  lipp
0151:         * Added jelly variable scoping.
0152:         *
0153:         * Revision 1.197  2004/06/29 14:52:46  lipp
0154:         * Unpacking values from JavaScript argument evaluation.
0155:         *
0156:         * Revision 1.196  2004/06/29 13:16:29  lipp
0157:         * Fixed jelly script argument access.
0158:         *
0159:         * Revision 1.195  2004/06/28 20:32:00  lipp
0160:         * Added support for accessing process data in jelly scripts.
0161:         *
0162:         * Revision 1.194  2004/06/28 14:59:49  lipp
0163:         * Started jelly interpretation of actual XML arguments.
0164:         *
0165:         * Revision 1.193  2004/05/09 18:42:59  lipp
0166:         * Finished process instantiation restructuring.
0167:         *
0168:         * Revision 1.192  2004/05/07 15:02:27  lipp
0169:         * Removed legacy initialization code.
0170:         *
0171:         * Revision 1.191  2004/05/06 19:39:17  lipp
0172:         * Restructured block activity handling.
0173:         *
0174:         * Revision 1.190  2004/05/05 09:44:07  lipp
0175:         * Finished SAX based process creation (no cleanup of old code, yet).
0176:         *
0177:         * Revision 1.189  2004/05/04 19:48:07  lipp
0178:         * Getting on with SAX based process creation.
0179:         *
0180:         * Revision 1.188  2004/05/03 15:38:11  lipp
0181:         * Getting on with SAX based process creation.
0182:         *
0183:         * Revision 1.187  2004/04/30 13:46:19  lipp
0184:         * Getting on with SAX based initialization.
0185:         *
0186:         * Revision 1.186  2004/04/30 12:44:53  lipp
0187:         * Fixed SAX initialization bug.
0188:         *
0189:         * Revision 1.185  2004/04/29 15:39:31  lipp
0190:         * Getting on with SAX based initialization.
0191:         *
0192:         * Revision 1.184  2004/04/28 14:19:20  lipp
0193:         * Getting started with SAX based process creation.
0194:         *
0195:         * Revision 1.183  2004/04/12 19:33:52  lipp
0196:         * Clarified application invocation interface.
0197:         *
0198:         * Revision 1.182  2004/04/06 21:18:39  lipp
0199:         * Reflect value conversions in audit event.
0200:         *
0201:         * Revision 1.181  2004/04/06 15:34:19  lipp
0202:         * Supporting values of type Document.
0203:         *
0204:         * Revision 1.180  2004/04/01 20:53:04  lipp
0205:         * Fixed problem with missing Type attribute.
0206:         *
0207:         * Revision 1.179  2004/03/25 14:41:46  lipp
0208:         * Added possibility to specify actual parameters as XML.
0209:         *
0210:         * Revision 1.178  2004/03/21 12:37:12  lipp
0211:         * Removed left over event logger.
0212:         *
0213:         * Revision 1.177  2004/03/20 21:08:43  lipp
0214:         * Added access to requesting processes' channels.
0215:         *
0216:         * Revision 1.176  2004/03/20 19:28:02  lipp
0217:         * Keeping relationship to super-flow both for sync and asynch call.
0218:         *
0219:         * Revision 1.175  2004/03/18 09:14:45  lipp
0220:         * Workaround for transformer bug.
0221:         *
0222:         * Revision 1.174  2004/02/21 14:42:43  lipp
0223:         * Moved TransitionManager to domain package. Having it in its own
0224:         * package caused too many circular dependencies (and there are good
0225:         * points for having it in the domain package anyway).
0226:         *
0227:         * Revision 1.173  2004/02/16 15:38:51  lipp
0228:         * Fixed handling of non-well formed result values.
0229:         *
0230:         * Revision 1.172  2004/02/06 13:37:35  lipp
0231:         * Added channel close notification.
0232:         *
0233:         * Revision 1.171  2004/01/21 09:54:45  lipp
0234:         * Adapted to contextSignature modification.
0235:         *
0236:         * Revision 1.170  2003/12/16 21:56:02  lipp
0237:         * Track all activity closures, transition manager might be reused.
0238:         *
0239:         * Revision 1.169  2003/12/16 16:46:25  lipp
0240:         * Let process close activities to avoid inconsistent transition manager
0241:         * states.
0242:         *
0243:         * Revision 1.168  2003/11/26 16:40:12  huaiyang
0244:         * workflow for jboss calling ejbs toString.
0245:         *
0246:         * Revision 1.167  2003/11/17 16:16:36  lipp
0247:         * Fixed refresh.
0248:         *
0249:         * Revision 1.166  2003/10/28 13:24:16  lipp
0250:         * Fixed handling of RemoveException.
0251:         *
0252:         * Revision 1.165  2003/09/25 12:00:05  lipp
0253:         * Avoid client dependency on rhino.
0254:         *
0255:         * Revision 1.164  2003/09/25 11:01:20  lipp
0256:         * Fixed usage of jsScope (may not be used remotely).
0257:         *
0258:         * Revision 1.163  2003/09/24 13:48:49  lipp
0259:         * Fixed JavaScript access to process relevant data of type Date. Fixed
0260:         * thread handling for block activities.
0261:         *
0262:         * Revision 1.162  2003/09/23 17:05:04  lipp
0263:         * Fixed various problems with block activities.
0264:         *
0265:         * Revision 1.161  2003/09/22 20:50:12  lipp
0266:         * Most of deadline handling for block activities.
0267:         *
0268:         * Revision 1.160  2003/09/22 15:53:44  lipp
0269:         * Receiving deadline events.
0270:         *
0271:         * Revision 1.159  2003/09/22 12:51:44  lipp
0272:         * Fixed key creation for block activity (must be unique).
0273:         *
0274:         * Revision 1.158  2003/09/22 12:32:57  lipp
0275:         * Implemented deadline creation for block activities.
0276:         *
0277:         * Revision 1.157  2003/09/21 21:28:14  lipp
0278:         * Introducing "virtual" block activity.
0279:         *
0280:         * Revision 1.156  2003/09/19 13:11:13  lipp
0281:         * New way of handling timeouts for subflows.
0282:         *
0283:         * Revision 1.155  2003/09/18 14:08:16  lipp
0284:         * Added abandon method to handle deadlines.
0285:         *
0286:         * Revision 1.154  2003/09/15 15:43:40  lipp
0287:         * Initial version of handling exceptions in transition manager.
0288:         *
0289:         * Revision 1.153  2003/09/04 08:46:44  lipp
0290:         * Fixed client dependency on rhino.jar.
0291:         *
0292:         * Revision 1.152  2003/07/09 13:25:14  lipp
0293:         * Accept strings as values for fields of type performer.
0294:         *
0295:         * Revision 1.151  2003/07/04 15:54:14  lipp
0296:         * Fixed handling of W3C DOM result.
0297:         *
0298:         * Revision 1.150  2003/06/27 08:51:45  lipp
0299:         * Fixed copyright/license information.
0300:         *
0301:         * Revision 1.149  2003/06/26 22:08:04  lipp
0302:         * Added handling of JDOM results.
0303:         *
0304:         * Revision 1.148  2003/06/05 21:21:20  lipp
0305:         * Real fix of state table problem.
0306:         *
0307:         * Revision 1.147  2003/06/05 17:24:44  lipp
0308:         * Fixed bug in transition table.
0309:         *
0310:         * Revision 1.146  2003/05/31 20:05:25  lipp
0311:         * Added support for different condition types.
0312:         *
0313:         * Revision 1.145  2003/05/25 20:47:00  lipp
0314:         * Fixed initialization.
0315:         *
0316:         * Revision 1.144  2003/05/16 08:08:49  lipp
0317:         * Handling OTHERWISE condition type.
0318:         *
0319:         * Revision 1.143  2003/05/07 14:45:49  lipp
0320:         * Implemented synchronous subflow.
0321:         *
0322:         * Revision 1.142  2003/05/05 14:39:50  lipp
0323:         * Moved code for removing process automatically to event handling.
0324:         *
0325:         * Revision 1.141  2003/05/05 07:04:51  lipp
0326:         * Handling parameters for sub-flow now.
0327:         *
0328:         * Revision 1.140  2003/05/02 14:55:59  lipp
0329:         * Resolved some more package dependencies.
0330:         *
0331:         * Revision 1.139  2003/04/26 18:56:24  lipp
0332:         * Moved extended interfaces to own package.
0333:         *
0334:         * Revision 1.138  2003/04/26 16:11:15  lipp
0335:         * Moved some classes to reduce package dependencies.
0336:         *
0337:         * Revision 1.137  2003/04/25 14:50:59  lipp
0338:         * Fixed javadoc errors and warnings.
0339:         *
0340:         * Revision 1.136  2003/04/24 20:50:13  lipp
0341:         * Fixed some warnings.
0342:         *
0343:         * Revision 1.135  2003/04/23 14:27:35  lipp
0344:         * Improved modelling of header data.
0345:         *
0346:         * Revision 1.134  2003/04/19 18:33:29  lipp
0347:         * Improved handling of info.
0348:         *
0349:         * Revision 1.133  2003/04/16 09:52:48  lipp
0350:         * Added initialization of formal parameters as data fields.
0351:         *
0352:         * Revision 1.132  2003/04/09 07:51:26  lipp
0353:         * Storing description now.
0354:         *
0355:         * Revision 1.131  2003/04/08 13:08:45  lipp
0356:         * Fixed null pointer exception.
0357:         *
0358:         * Revision 1.130  2003/04/03 11:44:06  lipp
0359:         * Support for W3C DOM arguments.
0360:         *
0361:         * Revision 1.129  2003/04/02 11:20:06  lipp
0362:         * Moved type adaption to framework.
0363:         *
0364:         * Revision 1.128  2003/04/02 09:30:05  lipp
0365:         * Supporting more data types.
0366:         *
0367:         * Revision 1.127  2003/03/31 16:50:28  huaiyang
0368:         * Logging using common-logging.
0369:         *
0370:         * Revision 1.126  2003/03/28 14:42:35  lipp
0371:         * Moved some code to XPDLUtil.
0372:         *
0373:         * Revision 1.125  2003/03/28 12:44:08  lipp
0374:         * Moved XPDL related constants to XPDLUtil.
0375:         *
0376:         * Revision 1.124  2003/03/28 11:41:59  lipp
0377:         * More changes for data type support.
0378:         *
0379:         * Revision 1.123  2003/03/27 16:32:20  lipp
0380:         * Started support for addditional data types.
0381:         *
0382:         * Revision 1.122  2003/03/13 14:07:13  lipp
0383:         * Improved implementation of condition evaluation.
0384:         *
0385:         */
0386:        package de.danet.an.workflow.domain;
0387:
0388:        import java.io.IOException;
0389:        import java.io.Serializable;
0390:        import java.io.StringReader;
0391:
0392:        import java.util.ArrayList;
0393:        import java.util.Collection;
0394:        import java.util.Collections;
0395:        import java.util.Date;
0396:        import java.util.HashMap;
0397:        import java.util.Iterator;
0398:        import java.util.List;
0399:        import java.util.Map;
0400:
0401:        import java.lang.reflect.Method;
0402:        import java.text.ParseException;
0403:
0404:        import javax.xml.parsers.ParserConfigurationException;
0405:        import javax.xml.parsers.SAXParserFactory;
0406:        import javax.xml.stream.XMLStreamException;
0407:        import javax.xml.stream.XMLStreamReader;
0408:        import javax.xml.transform.Transformer;
0409:        import javax.xml.transform.TransformerConfigurationException;
0410:        import javax.xml.transform.TransformerException;
0411:        import javax.xml.transform.TransformerFactory;
0412:        import javax.xml.transform.dom.DOMSource;
0413:        import javax.xml.transform.sax.SAXResult;
0414:
0415:        import org.apache.commons.jelly.JellyContext;
0416:        import org.apache.commons.jelly.JellyException;
0417:        import org.apache.commons.jelly.Script;
0418:        import org.apache.commons.jelly.XMLOutput;
0419:        import org.apache.commons.jelly.parser.XMLParser;
0420:        import org.apache.xmlbeans.XmlCursor;
0421:        import org.apache.xmlbeans.XmlException;
0422:        import org.apache.xmlbeans.XmlObject;
0423:        import org.apache.xmlbeans.XmlOptions;
0424:        import org.apache.xmlbeans.XmlSaxHandler;
0425:
0426:        import org.dom4j.io.SAXContentHandler;
0427:        import org.jdom.Document;
0428:        import org.jdom.Element;
0429:        import org.jdom.JDOMException;
0430:        import org.jdom.input.DOMBuilder;
0431:        import org.jdom.output.SAXOutputter;
0432:        import org.mozilla.javascript.Context;
0433:        import org.mozilla.javascript.Function;
0434:        import org.mozilla.javascript.JavaScriptException;
0435:        import org.mozilla.javascript.Scriptable;
0436:        import org.mozilla.javascript.ScriptableObject;
0437:        import org.mozilla.javascript.Wrapper;
0438:        import org.mozilla.javascript.xml.XMLObject;
0439:        import org.xml.sax.Attributes;
0440:        import org.xml.sax.ContentHandler;
0441:        import org.xml.sax.InputSource;
0442:        import org.xml.sax.SAXException;
0443:        import org.xml.sax.XMLReader;
0444:        import org.xml.sax.helpers.DefaultHandler;
0445:        import org.xml.sax.helpers.XMLFilterImpl;
0446:
0447:        import de.danet.an.util.XMLUtil;
0448:        import de.danet.an.util.sax.BodyFilter;
0449:        import de.danet.an.util.sax.HandlerStack;
0450:        import de.danet.an.util.sax.NamespaceAttributesFilter;
0451:        import de.danet.an.util.sax.StackedHandler;
0452:        import de.danet.an.util.sax.XmlnsUrisPatcher;
0453:
0454:        import de.danet.an.workflow.util.SAXEventBufferImpl;
0455:        import de.danet.an.workflow.util.XPDLUtil;
0456:
0457:        import de.danet.an.workflow.internalapi.ExtActivityLocal;
0458:        import de.danet.an.workflow.internalapi.ExtProcessLocal;
0459:        import de.danet.an.workflow.internalapi.ScriptException;
0460:        import de.danet.an.workflow.localapi.ActivityLocal;
0461:        import de.danet.an.workflow.localapi.ProcessLocal;
0462:        import de.danet.an.workflow.localapi.TransitionLocal;
0463:        import de.danet.an.workflow.localcoreapi.WfActivityLocal;
0464:        import de.danet.an.workflow.localcoreapi.WfProcessLocal;
0465:        import de.danet.an.workflow.omgcore.AlreadyRunningException;
0466:        import de.danet.an.workflow.omgcore.CannotChangeRequesterException;
0467:        import de.danet.an.workflow.omgcore.CannotStartException;
0468:        import de.danet.an.workflow.omgcore.CannotStopException;
0469:        import de.danet.an.workflow.omgcore.InvalidControlOperationException;
0470:        import de.danet.an.workflow.omgcore.InvalidDataException;
0471:        import de.danet.an.workflow.omgcore.InvalidPriorityException;
0472:        import de.danet.an.workflow.omgcore.InvalidStateException;
0473:        import de.danet.an.workflow.omgcore.NotRunningException;
0474:        import de.danet.an.workflow.omgcore.ProcessData;
0475:        import de.danet.an.workflow.omgcore.ProcessDataInfo;
0476:        import de.danet.an.workflow.omgcore.ResultNotAvailableException;
0477:        import de.danet.an.workflow.omgcore.TransitionNotAllowedException;
0478:        import de.danet.an.workflow.omgcore.UpdateNotAllowedException;
0479:        import de.danet.an.workflow.omgcore.WfAuditEvent;
0480:        import de.danet.an.workflow.omgcore.WfRequester;
0481:        import de.danet.an.workflow.omgcore.WfStateAuditEvent;
0482:        import de.danet.an.workflow.omgcore.WfExecutionObject.ClosedState;
0483:        import de.danet.an.workflow.omgcore.WfExecutionObject.NotRunningState;
0484:        import de.danet.an.workflow.omgcore.WfExecutionObject.OpenState;
0485:        import de.danet.an.workflow.omgcore.WfExecutionObject.State;
0486:
0487:        import de.danet.an.workflow.api.CannotRemoveException;
0488:        import de.danet.an.workflow.api.DefaultProcessData;
0489:        import de.danet.an.workflow.api.ExternalReference;
0490:        import de.danet.an.workflow.api.FormalParameter;
0491:        import de.danet.an.workflow.api.InvalidKeyException;
0492:        import de.danet.an.workflow.api.Participant;
0493:        import de.danet.an.workflow.api.ProcessDefinition;
0494:        import de.danet.an.workflow.api.SAXEventBuffer;
0495:        import de.danet.an.workflow.api.Transition;
0496:        import de.danet.an.workflow.api.Activity.ClosedCompletedState;
0497:        import de.danet.an.workflow.api.Activity.Implementation;
0498:        import de.danet.an.workflow.api.Activity.JoinAndSplitMode;
0499:        import de.danet.an.workflow.api.Activity.StartFinishMode;
0500:        import de.danet.an.workflow.api.Activity.SubFlowImplementation;
0501:        import de.danet.an.workflow.api.Process;
0502:
0503:        /**
0504:         * <code>AbstractProcess</code> represents the base implementation
0505:         * of the interface {@link ProcessLocal <code>ProcessLocal</code>}.<P>
0506:         *
0507:         * With logger level <code>DEBUG</code>, event handling information
0508:         * and information about process context changes will be logged.
0509:         */
0510:        public abstract class AbstractProcess extends AbstractExecutionObject
0511:                implements  TimedObject, Serializable {
0512:
0513:            private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
0514:                    .getLog(AbstractProcess.class);
0515:
0516:            /** The immutable root for JavaScript evaluation. */
0517:            private static final ScriptableObject GLOBAL_JS_SCOPE = (new Context())
0518:                    .initStandardObjects(null, false);
0519:            static {
0520:                Context cx = Context.enter();
0521:                try {
0522:                    cx.evaluateString(GLOBAL_JS_SCOPE, "java", "<init>", 1,
0523:                            null);
0524:                } catch (JavaScriptException e) {
0525:                    logger.warn("Cannot initialize \"java\" in rhino context: "
0526:                            + e.getMessage());
0527:                }
0528:                try {
0529:                    cx.evaluateString(GLOBAL_JS_SCOPE, "new XML()", "<init>",
0530:                            1, null);
0531:                } catch (JavaScriptException e) {
0532:                    logger.warn("Cannot initialize \"XML\" in rhino context: "
0533:                            + e.getMessage());
0534:                }
0535:                GLOBAL_JS_SCOPE.sealObject();
0536:                Context.exit();
0537:            }
0538:
0539:            private static class TimeoutInfo implements  Serializable {
0540:                public Long activity;
0541:                public int dlIndex;
0542:
0543:                public TimeoutInfo(Long a, int d) {
0544:                    activity = a;
0545:                    dlIndex = d;
0546:                }
0547:
0548:                public String toString() {
0549:                    return "TimeoutInfo[activity=" + activity
0550:                            + ",deadlineIndex=" + dlIndex + "]";
0551:                }
0552:            }
0553:
0554:            private Collection participants = null;
0555:
0556:            /** The TransitionManager for this process. */
0557:            private TransitionManager transitionMgrCache = null;
0558:
0559:            /** The JavaScript scope for this process. */
0560:            private ScriptableObject jsScopeCache = null;
0561:
0562:            /** The jelly context for this process. */
0563:            private JellyContext jellyContextCache = null;
0564:
0565:            /** All block activity representations by key. */
0566:            private Map baRepresentations = new HashMap();
0567:
0568:            /** Set in init, cleared in subsequent refresh */
0569:            private boolean initedBeforeRefresh = false;
0570:
0571:            /**
0572:             * Creates a new <code>AbstractProcess</code>.
0573:             */
0574:            public AbstractProcess() {
0575:            }
0576:
0577:            //
0578:            // Persistent attribute accessors and associated methods
0579:            //
0580:
0581:            /**
0582:             * The getter method for the persistent attribute <code>requester</code>.
0583:             *
0584:             * @return the value of requester.
0585:             */
0586:            protected abstract WfRequester getPaRequester();
0587:
0588:            /**
0589:             * The getter method for the persistent attribute <code>id</code>.
0590:             *
0591:             * @return the value of process id.
0592:             * @see #setPaId
0593:             */
0594:            protected abstract String getPaId();
0595:
0596:            /**
0597:             * The setter method for the persistent attribute <code>Id</code>.
0598:             *
0599:             * @param newId the new value of process id.
0600:             * @see #getPaId
0601:             */
0602:            protected abstract void setPaId(String newId);
0603:
0604:            /**
0605:             * The getter method for the persistent attribute <code>createTime</code>.
0606:             *
0607:             * @return the value of createTime.
0608:             */
0609:            protected abstract Date getPaCreateTime();
0610:
0611:            /**
0612:             * The getter method for the persistent attribute
0613:             * <code>processMgrName</code>.
0614:             *
0615:             * @return the value of processMgrName.
0616:             * @see #setPaProcessMgrName
0617:             */
0618:            protected abstract String getPaProcessMgrName();
0619:
0620:            /**
0621:             * The setter method for the persistent attribute
0622:             * <code>processMgrName</code>.
0623:             *
0624:             * @param newProcessMgrName the new value of processMgrName.
0625:             * @see #getPaProcessMgrName
0626:             */
0627:            protected abstract void setPaProcessMgrName(String newProcessMgrName);
0628:
0629:            /**
0630:             * The getter method for the persistent attribute
0631:             * <code>processMgrVersion</code>.
0632:             *
0633:             * @return the value of processMgrVersion.
0634:             * @see #setPaProcessMgrVersion
0635:             */
0636:            protected abstract String getPaProcessMgrVersion();
0637:
0638:            /**
0639:             * The setter method for the persistent attribute
0640:             * <code>processMgrVersion</code>.
0641:             *
0642:             * @param newProcessMgrVersion the new value of processMgrVersion.
0643:             * @see #getPaProcessMgrVersion
0644:             */
0645:            protected abstract void setPaProcessMgrVersion(
0646:                    String newProcessMgrVersion);
0647:
0648:            /**
0649:             * The getter method for the persistent attribute <code>processDef</code>.
0650:             *
0651:             * @return the value of processDef.
0652:             * @see #setPaProcessDef
0653:             */
0654:            protected abstract ProcessDefinition getPaProcessDef();
0655:
0656:            /**
0657:             * The setter method for the persistent attribute <code>processDef</code>.
0658:             *
0659:             * @param newProcessDef the new value of processDef.
0660:             * @see #getPaProcessDef
0661:             */
0662:            protected abstract void setPaProcessDef(
0663:                    ProcessDefinition newProcessDef);
0664:
0665:            /**
0666:             * The getter method for the persistent attribute <code>processData</code>.
0667:             *
0668:             * @return the value of processData.
0669:             */
0670:            protected abstract ProcessData getPaProcessData();
0671:
0672:            /**
0673:             * The getter method for the persistent attribute <code>priority</code>.
0674:             *
0675:             * @return the value of priority.
0676:             * @see #setPriority
0677:             */
0678:            protected abstract Priority getPaPriority();
0679:
0680:            /**
0681:             * The setter method for the persistent attribute <code>priority</code>.
0682:             *
0683:             * @param newPriority the new value of priority.
0684:             * @see #getPaPriority
0685:             */
0686:            protected abstract void setPaPriority(Priority newPriority);
0687:
0688:            /**
0689:             * The getter method for the persistent attribute
0690:             * <code>blockDeadlines</code>.
0691:             *
0692:             * @return the value of blockDeadlines.
0693:             */
0694:            protected abstract Map getPaBlockDeadlines();
0695:
0696:            /**
0697:             * Returns the transition manager.
0698:             * @return the transition manager
0699:             */
0700:            protected TransitionManager transitionManager() {
0701:                if (transitionMgrCache == null) {
0702:                    // create new transition manager
0703:                    transitionMgrCache = new TransitionManager(this );
0704:                }
0705:                return transitionMgrCache;
0706:            }
0707:
0708:            /**
0709:             * Initializes the class, i.e. resets all attributes to default
0710:             * values. Note that 
0711:             * {@link #refresh <code>refresh</code>} will be called subsequently.
0712:             * 
0713:             * @param procDef the process definition.
0714:             * @see #dispose
0715:             */
0716:            protected void init(ProcessDefinition procDef) {
0717:                super .init();
0718:                jsScopeCache = null;
0719:                jellyContextCache = null;
0720:                setPaProcessDef(procDef);
0721:                setPaTypedState(NotRunningState.NOT_STARTED);
0722:                setPaProcessMgrName(procDef.mgrName());
0723:                setPaProcessMgrVersion(procDef.version());
0724:                setPaDescription(procDef.processHeader().description());
0725:                setPaAuditEventSelection(procDef.auditEventSelection());
0726:                setPaStoreAuditEvents(procDef.storeAuditEvents());
0727:                baRepresentations.clear();
0728:
0729:                setPaPriority(Priority.NORMAL);
0730:                HandlerStack hs = new HandlerStack(new SAXInitializer());
0731:                hs.setContextData("packageId", procDef.packageId());
0732:                try {
0733:                    procDef.toSAX().emit(hs.contentHandler());
0734:                } catch (SAXException e) {
0735:                    logger.error(e.getMessage(), e);
0736:                    throw new IllegalArgumentException(e.getMessage());
0737:                }
0738:
0739:                // fire an appropriate audit event
0740:                if (getPaAuditEventSelection() == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS) {
0741:                    fireAuditEvent(new DefaultCreateProcessAuditEvent(
0742:                            auditEventBase(WfAuditEvent.PROCESS_CREATED),
0743:                            activityRequesterInfo(getPaRequester())));
0744:                    fireAuditEvent(new DefaultDataAuditEvent(
0745:                            auditEventBase(WfAuditEvent.PROCESS_CONTEXT_CHANGED),
0746:                            null, getPaProcessData()));
0747:                }
0748:            }
0749:
0750:            /**
0751:             * Called after change of persistent attributes. May be used to
0752:             * synchronise state derived from persistent attributes with
0753:             * the new values.
0754:             *
0755:             * @see #init
0756:             */
0757:            protected void refresh() {
0758:                super .refresh();
0759:                transitionMgrCache = null;
0760:                jsScopeCache = null;
0761:                jellyContextCache = null;
0762:                participants = null;
0763:                if (initedBeforeRefresh) {
0764:                    initedBeforeRefresh = false;
0765:                } else {
0766:                    baRepresentations.clear();
0767:                }
0768:            }
0769:
0770:            /**
0771:             * Releases all allocated resources. The object will be in an
0772:             * unusable state until resources are reallocated by calling
0773:             * {@link #init <code>init</code>} and
0774:             * {@link #refresh <code>refresh</code>}.
0775:             */
0776:            protected void dispose() {
0777:                super .dispose();
0778:                participants = null;
0779:                // deallocate TransitionManager
0780:                transitionMgrCache = null;
0781:                baRepresentations.clear();
0782:            }
0783:
0784:            //
0785:            // Domain methods
0786:            //
0787:
0788:            /**
0789:             * Indicates if some other object is equal to this one. <P>
0790:             *
0791:             * Note that <code>obj</code> may be a stub representing the
0792:             * object. Stubs do not in general implement
0793:             * <code>equals</code> correctly, so while
0794:             * <code>this.equals(obj)</code> does indicate the equality as
0795:             * defined for this class, <code>obj.equals(this)</code> generally
0796:             * does not.
0797:             *
0798:             * @param obj the object to compare with.
0799:             * @return <code>true</code> if the other object is equal.
0800:             */
0801:            public boolean equals(Object obj) {
0802:                return (obj instanceof  AbstractProcess)
0803:                        && getPaKey().equals(((AbstractProcess) obj).key())
0804:                        || (obj instanceof  WfProcessLocal)
0805:                        && getPaKey().equals(((WfProcessLocal) obj).key());
0806:            }
0807:
0808:            /**
0809:             * Provide a new unique activity key.
0810:             *
0811:             * @return the key.
0812:             */
0813:            protected abstract Long createActivityKey();
0814:
0815:            /**
0816:             * Returns the requester for this process. Method of the omg interface.
0817:             * @return requester for this process. 
0818:             */
0819:            public WfRequester requester() {
0820:                WfRequester req = getPaRequester();
0821:                if (req instanceof  SubProcRequester) {
0822:                    try {
0823:                        return lookupActivityLocal(
0824:                                ((SubProcRequester) req).requestingActivity())
0825:                                .toActivity();
0826:                    } catch (InvalidKeyException e) {
0827:                        return null;
0828:                    }
0829:                }
0830:                return req;
0831:            }
0832:
0833:            /**
0834:             * Returns the requester for this process without resolving the
0835:             * internally used SubProcRequester to the associated WfActivity.
0836:             * @return requester for this process. 
0837:             */
0838:            public WfRequester unresolvedRequester() {
0839:                return getPaRequester();
0840:            }
0841:
0842:            /**
0843:             * Return the process this process is a subflow of.
0844:             * @return the process or <code>null</code> if this process is not
0845:             * a subflow
0846:             */
0847:            public Process requestingProcess() {
0848:                if (!(getPaRequester() instanceof  SubProcRequester)) {
0849:                    return null;
0850:                }
0851:                String key = ((SubProcRequester) getPaRequester())
0852:                        .requestingActivity();
0853:                try {
0854:                    ActivityLocal act = lookupActivityLocal(key);
0855:                    return ((ExtProcessLocal) act.containerLocal()).toProcess();
0856:                } catch (InvalidKeyException e) {
0857:                    logger.warn(toString()
0858:                            + " cannot find requesting activity " + key + " : "
0859:                            + e.getMessage());
0860:                    return null;
0861:                }
0862:            }
0863:
0864:            /**
0865:             * Returns the creation time of the process.
0866:             * @return the creation time.
0867:             */
0868:            public Date createTime() {
0869:                return getPaCreateTime();
0870:            }
0871:
0872:            /**
0873:             * For the first iteration throws an
0874:             * CannotChangeRequesterException. Method of the omg interface.
0875:             * @param requester the requester.
0876:             * @throws CannotChangeRequesterException if modification is not allowed.
0877:             * @ejb.interface-method view-type="remote"
0878:             */
0879:            public void setRequester(WfRequester requester)
0880:                    throws CannotChangeRequesterException {
0881:                throw new CannotChangeRequesterException();
0882:            }
0883:
0884:            /**
0885:             * Return the context of this <code>WfExecutionObject</code>.
0886:             * The process data object returned is a copy of the name value
0887:             * association, the values are not copied, however.
0888:             *
0889:             * @return the process relevant data that define the context of the 
0890:             * process.
0891:             */
0892:            public ProcessData processContext() {
0893:                return new DefaultProcessData(getPaProcessData());
0894:            }
0895:
0896:            /**
0897:             * Filter out duplicate endDocument events.
0898:             */
0899:            private class DupEndFilter extends XMLFilterImpl {
0900:                private boolean gotEnd = false;
0901:
0902:                public DupEndFilter(ContentHandler parent) {
0903:                    setContentHandler(parent);
0904:                }
0905:
0906:                public void endDocument() throws SAXException {
0907:                    if (!gotEnd) {
0908:                        super .endDocument();
0909:                        gotEnd = true;
0910:                    }
0911:                }
0912:            }
0913:
0914:            /**
0915:             * Updates process context of the execution object.
0916:             * @param newValues the name-value pairs to be set.
0917:             * @throws InvalidDataException If a name or value type does not match
0918:             * the signature of this process.
0919:             * @throws UpdateNotAllowedException If the update is not allowed.
0920:             */
0921:            public void setProcessContext(ProcessData newValues)
0922:                    throws InvalidDataException, UpdateNotAllowedException {
0923:                if (!workflowState().equals(State.OPEN)) {
0924:                    throw new UpdateNotAllowedException(
0925:                            "Process is not in state open.");
0926:                }
0927:                // verify first to avoid partial change.
0928:                ProcessDataInfo sig = getPaProcessDef().contextSignature();
0929:                for (Iterator i = newValues.keySet().iterator(); i.hasNext();) {
0930:                    String name = (String) i.next();
0931:                    Object type = sig.get(name);
0932:                    if (type == null) {
0933:                        throw new InvalidDataException("No such data field: "
0934:                                + name);
0935:                    }
0936:                    Object v = newValues.get(name);
0937:                    if (v == null) {
0938:                        continue;
0939:                    }
0940:                    if ((type instanceof  ExternalReference)
0941:                            && XPDLUtil.isJavaType((ExternalReference) type)) {
0942:                        Class vc = null;
0943:                        try {
0944:                            vc = XPDLUtil.getJavaType((ExternalReference) type);
0945:                        } catch (ClassNotFoundException e) {
0946:                            throw (InvalidDataException) (new InvalidDataException(
0947:                                    "Required Java class no longer available: "
0948:                                            + e.getMessage())).initCause(e);
0949:                        }
0950:                        if (vc.isAssignableFrom(v.getClass())) {
0951:                            continue;
0952:                        } else {
0953:                            throw new InvalidDataException("Context entry "
0954:                                    + name + " is " + v.getClass().getName()
0955:                                    + " must be instance of " + vc.getName());
0956:                        }
0957:                    }
0958:                    if ((type instanceof  SAXEventBuffer)
0959:                            || (type instanceof  ExternalReference)
0960:                            || type.equals(org.w3c.dom.Element.class)) {
0961:                        boolean elemList = false;
0962:                        if (v instanceof  List) {
0963:                            if (((List) v).size() == 0) {
0964:                                elemList = true;
0965:                            } else {
0966:                                Iterator ti = ((List) v).iterator();
0967:                                if (ti.next() instanceof  Element) {
0968:                                    elemList = true;
0969:                                }
0970:                            }
0971:                        }
0972:                        if (!((v instanceof  Element) || (v instanceof  Document)
0973:                                || elemList
0974:                                || (v instanceof  org.w3c.dom.Element)
0975:                                || (v instanceof  org.w3c.dom.DocumentFragment)
0976:                                || (v instanceof  org.w3c.dom.Document) || (v instanceof  SAXEventBuffer))) {
0977:                            throw new InvalidDataException(
0978:                                    "Not a usable XML representation: " + name);
0979:                        }
0980:                        continue;
0981:                    }
0982:                    if (type instanceof  Class) {
0983:                        Class vc = v.getClass();
0984:                        if (v instanceof  Float) {
0985:                            vc = Double.class;
0986:                        } else if (v instanceof  Integer) {
0987:                            vc = Long.class;
0988:                        }
0989:                        if (type == Participant.class) {
0990:                            type = String.class;
0991:                        }
0992:                        if (!((Class) type).isAssignableFrom(vc)) {
0993:                            throw new InvalidDataException(
0994:                                    "Values for data field \"" + name
0995:                                            + "\" must be of type "
0996:                                            + ((Class) type).getName()
0997:                                            + " (is " + v.getClass().getName()
0998:                                            + ")");
0999:                        }
1000:                        continue;
1001:                    }
1002:                    throw new InvalidDataException(
1003:                            "Invalid type for data field \"" + name + "\": "
1004:                                    + ((Class) type).getName());
1005:                }
1006:                // now do changes
1007:                DOMBuilder builder = null;
1008:                ProcessData oldValues = new DefaultProcessData();
1009:                for (Iterator i = (new ArrayList(newValues.keySet()))
1010:                        .iterator(); i.hasNext();) {
1011:                    String name = (String) i.next();
1012:                    oldValues.put(name, getPaProcessData().get(name));
1013:                    Object v = newValues.get(name);
1014:                    if (logger.isDebugEnabled()) {
1015:                        logger.debug("Setting context data item " + name
1016:                                + " = " + v);
1017:                    }
1018:                    Object type = sig.get(name);
1019:                    if ((type instanceof  ExternalReference)
1020:                            && XPDLUtil.isJavaType((ExternalReference) type)) {
1021:                        // accept literally
1022:                    } else if (v instanceof  Float) {
1023:                        v = new Double(((Float) v).doubleValue());
1024:                        newValues.put(name, v);
1025:                    } else if (v instanceof  Integer) {
1026:                        v = new Long(((Integer) v).longValue());
1027:                        newValues.put(name, v);
1028:                    } else if ((v instanceof  Element)
1029:                            || (v instanceof  Document) || (v instanceof  List)) {
1030:                        try {
1031:                            if (logger.isDebugEnabled()) {
1032:                                logger.debug("Convering item " + name
1033:                                        + " from JDOM to SAX");
1034:                            }
1035:                            SAXOutputter outputter = new SAXOutputter();
1036:                            SAXEventBufferImpl b = new SAXEventBufferImpl();
1037:                            outputter.setContentHandler(b);
1038:                            outputter.setLexicalHandler(b);
1039:                            if (v instanceof  Document) {
1040:                                outputter.output((Document) v);
1041:                            } else {
1042:                                List l;
1043:                                if (v instanceof  List) {
1044:                                    l = (List) v;
1045:                                } else {
1046:                                    l = new ArrayList();
1047:                                    l.add(v);
1048:                                }
1049:                                outputter.output(l);
1050:                            }
1051:                            b.pack();
1052:                            v = b;
1053:                            newValues.put(name, v);
1054:                        } catch (JDOMException e) {
1055:                            logger.error(e.getMessage(), e);
1056:                            throw new InvalidDataException(e.getMessage());
1057:                        }
1058:                    } else if ((v instanceof  org.w3c.dom.Element)
1059:                            || (v instanceof  org.w3c.dom.DocumentFragment)
1060:                            || (v instanceof  org.w3c.dom.Document)) {
1061:                        try {
1062:                            if (logger.isDebugEnabled()) {
1063:                                logger.debug("Convering item " + name
1064:                                        + " from W3C DOM to SAX");
1065:                            }
1066:                            TransformerFactory tf = TransformerFactory
1067:                                    .newInstance();
1068:                            Transformer t = tf.newTransformer();
1069:                            SAXEventBufferImpl b = new SAXEventBufferImpl();
1070:                            // There seems to be a bug in Xalan that causes it to 
1071:                            // fire two endDocument events when transforming a
1072:                            // DocumentFragment, filter it out.
1073:                            t.transform(new DOMSource((org.w3c.dom.Node) v),
1074:                                    new SAXResult(new DupEndFilter(b)));
1075:                            b.pack();
1076:                            v = b;
1077:                            newValues.put(name, v);
1078:                        } catch (TransformerConfigurationException e) {
1079:                            String s = "Error converting DOM to SAX: "
1080:                                    + e.getMessage();
1081:                            logger.error(s, e);
1082:                            throw new IllegalStateException(s);
1083:                        } catch (TransformerException e) {
1084:                            String s = "Error converting DOM to SAX: "
1085:                                    + e.getMessage();
1086:                            logger.error(s, e);
1087:                            throw new InvalidDataException(s);
1088:                        }
1089:                    }
1090:                    getPaProcessData().put(name, v);
1091:                }
1092:
1093:                // fire appropriate audit event
1094:                if (getPaAuditEventSelection() == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS) {
1095:                    fireAuditEvent(new DefaultDataAuditEvent(
1096:                            auditEventBase(WfAuditEvent.PROCESS_CONTEXT_CHANGED),
1097:                            oldValues, newValues));
1098:                }
1099:            }
1100:
1101:            /**
1102:             * The <code>result</code> method returns the process context.
1103:             *
1104:             * @return the result.
1105:             * @exception ResultNotAvailableException not thrown, intermediate results
1106:             * are available.
1107:             * @ejb.interface-method view-type="remote"
1108:             */
1109:            public ProcessData result() throws ResultNotAvailableException {
1110:                ProcessDataInfo resSig = processDefinition().resultSignature();
1111:                ProcessData procCtx = getPaProcessData();
1112:                ProcessData resData = new DefaultProcessData();
1113:                for (Iterator i = resSig.keySet().iterator(); i.hasNext();) {
1114:                    String key = (String) i.next();
1115:                    resData.put(key, procCtx.get(key));
1116:                }
1117:                return resData;
1118:            }
1119:
1120:            /**
1121:             * Returns a collection of activities of the process. This can usually
1122:             * be handled more efficiently by the derived class that provides the
1123:             * persistence. The default implementation simply wraps each local
1124:             * objects. 
1125:             * 
1126:             * @return collection of activities of the process
1127:             */
1128:            public Collection steps() {
1129:                Collection res = new ArrayList();
1130:                for (Iterator i = stepsLocal().iterator(); i.hasNext();) {
1131:                    ExtActivityLocal act = (ExtActivityLocal) i.next();
1132:                    res.add(act.toActivity());
1133:                }
1134:                return res;
1135:            }
1136:
1137:            /**
1138:             * Returns all WfActivityLocals associated with this <code>WfProcess</code>.
1139:             * @return the collection of all the WfActivities. 
1140:             */
1141:            public abstract Collection stepsLocal();
1142:
1143:            /**
1144:             * Returns the {@link ActivityLocal <code>Activity</code>} with the
1145:             * given key.
1146:             * @param key the 
1147:             * {@link de.danet.an.workflow.localcoreapi.WfActivityLocal#key key} 
1148:             * of the activity
1149:             * @return the activity associated with the key
1150:             * @throws InvalidKeyException if no activity with the given key
1151:             * exists
1152:             */
1153:            public abstract ActivityLocal activityByKeyLocal(String key)
1154:                    throws InvalidKeyException;
1155:
1156:            /**
1157:             * Returns all transitions associated with this <code>WfProcess</code>.
1158:             * @return the collection of all the WfActivities. 
1159:             */
1160:            public abstract List transitionsLocal();
1161:
1162:            /**
1163:             * Return all <code>WfActivity</code> objects that are in a certain state.
1164:             * @param state the given state.
1165:             * @return the collection of all WfActivities.
1166:             * @throws InvalidStateException if an invalid state has been specified.
1167:             */
1168:            public Collection activitiesInState(String state)
1169:                    throws InvalidStateException {
1170:                State s = State.fromString(state);
1171:                Collection returnList = new ArrayList();
1172:
1173:                Iterator it = stepsLocal().iterator();
1174:                while (it.hasNext()) {
1175:                    ExtActivityLocal act = (ExtActivityLocal) it.next();
1176:                    if (act.typedState().isSameOrSubState(s)) {
1177:                        returnList.add(act.toActivity());
1178:                    }
1179:                }
1180:                return returnList;
1181:            }
1182:
1183:            /**
1184:             * Return all <code>WfActivity</code> objects that belong to the
1185:             * given block activity.
1186:             * @param blockActivity the given block activity
1187:             * @return the collection of all WfActivities
1188:             */
1189:            public Collection activitiesOfBlockActivity(String blockActivity) {
1190:                Collection returnList = new ArrayList();
1191:
1192:                Iterator it = stepsLocal().iterator();
1193:                while (it.hasNext()) {
1194:                    ActivityLocal act = (ActivityLocal) it.next();
1195:                    String ba = act.blockActivity();
1196:                    if (ba != null && ba.equals(blockActivity)) {
1197:                        returnList.add(act);
1198:                    }
1199:                }
1200:                return returnList;
1201:            }
1202:
1203:            /**
1204:             * Returns the associated process defintion.
1205:             * @return the process definition
1206:             */
1207:            public ProcessDefinition processDefinition() {
1208:                return getPaProcessDef();
1209:            }
1210:
1211:            /**
1212:             * Returns the cleanup mode for the process as defined in its process
1213:             * definition.
1214:             * @return the cleanup mode.
1215:             */
1216:            protected int cleanupMode() {
1217:                return processDefinition().cleanupMode();
1218:            }
1219:
1220:            /**
1221:             * Return the remote version of this object. This may be, but need
1222:             * not be <code>this</code>, depending on the way remote objects
1223:             * are implemented.
1224:             *
1225:             * @return the client side object.
1226:             */
1227:            public abstract Process toProcess();
1228:
1229:            /**
1230:             * Return the version of this object to be passed to as local reference. 
1231:             *
1232:             * @return the client side object.
1233:             */
1234:            public abstract ExtProcessLocal toProcessLocal();
1235:
1236:            /**
1237:             * Helper for implementing access to process data in JavaScript.
1238:             */
1239:            public class DataAccessor implements  Serializable {
1240:                private String itemName;
1241:                private Scriptable scope;
1242:
1243:                /**
1244:                 * Create a new <code>DataAccessor</code> for the given item.
1245:                 * @param item the process data item to access.
1246:                 */
1247:                public DataAccessor(Scriptable scope, String item) {
1248:                    this .scope = scope;
1249:                    itemName = item;
1250:                }
1251:
1252:                /**
1253:                 * Return the the value of the item this object was constructed for.
1254:                 * @param so needed to match rhino's interface requirements, ignored.
1255:                 * @return the value.
1256:                 */
1257:                public Object getValue(ScriptableObject so) {
1258:                    Object res = getPaProcessData().get(itemName);
1259:                    if (res instanceof  Date) {
1260:                        try {
1261:                            res = Context.getCurrentContext().newObject(
1262:                                    so,
1263:                                    "Date",
1264:                                    new Object[] { new Long(((Date) res)
1265:                                            .getTime()) });
1266:                        } catch (JavaScriptException e) {
1267:                            logger.error(e.getMessage(), e);
1268:                        }
1269:                        return res;
1270:                    }
1271:                    if (res instanceof  SAXEventBuffer) {
1272:                        try {
1273:                            XmlSaxHandler sh = XmlObject.Factory
1274:                                    .newXmlSaxHandler();
1275:                            ((SAXEventBuffer) res).emit(sh.getContentHandler());
1276:                            XmlObject xo = sh.getObject();
1277:                            XmlCursor cur = xo.newCursor();
1278:                            while (!cur.isStart()) {
1279:                                if (cur.isEnddoc()) {
1280:                                    try {
1281:                                        Context cx = Context.enter();
1282:                                        return cx.evaluateString(scope,
1283:                                                "<></>", "<script>", 1, null);
1284:                                    } finally {
1285:                                        Context.exit();
1286:                                    }
1287:                                }
1288:                                cur.toNextToken();
1289:                            }
1290:                            xo = cur.getObject();
1291:                            Object wxo = Context.javaToJS(xo, scope);
1292:                            res = Context.getCurrentContext().newObject(scope,
1293:                                    "XML", new Object[] { wxo });
1294:                        } catch (SAXException e) {
1295:                            logger.error(e.getMessage(), e);
1296:                        } catch (XmlException e) {
1297:                            logger.error(e.getMessage(), e);
1298:                        }
1299:                        return res;
1300:                    }
1301:                    return res;
1302:                }
1303:            }
1304:
1305:            /**
1306:             * Return a scope for evaluating JavaScript. The scope includes
1307:             * the process relevant data as top-level variables. This scope
1308:             * may be used as prototype for a thread specific evaluation
1309:             * context only. This implies that it can not be used to modify
1310:             * process data. This behaviour is intended.
1311:             * @return the process specific sope.
1312:             */
1313:            public Scriptable jsScope() {
1314:                if (jsScopeCache == null) {
1315:                    try {
1316:                        jsScopeCache = (ScriptableObject) (new Context())
1317:                                .newObject(GLOBAL_JS_SCOPE);
1318:                        jsScopeCache.setPrototype(GLOBAL_JS_SCOPE);
1319:                        jsScopeCache.setParentScope(null);
1320:                        Method getter = DataAccessor.class.getMethod(
1321:                                "getValue",
1322:                                new Class[] { ScriptableObject.class });
1323:                        Map procData = getPaProcessData();
1324:                        for (Iterator i = procData.keySet().iterator(); i
1325:                                .hasNext();) {
1326:                            String key = (String) i.next();
1327:                            DataAccessor da = new DataAccessor(jsScopeCache,
1328:                                    key);
1329:                            try {
1330:                                jsScopeCache.defineProperty(key, da, getter,
1331:                                        null, 0);
1332:                            } catch (JavaScriptException e) {
1333:                                logger.error(e.getMessage(), e);
1334:                            }
1335:                        }
1336:                        jsScopeCache.sealObject();
1337:                    } catch (NoSuchMethodException e) {
1338:                        logger.error(e.getMessage(), e);
1339:                    } catch (JavaScriptException e) {
1340:                        logger.error(e.getMessage(), e);
1341:                    }
1342:                }
1343:                return jsScopeCache;
1344:            }
1345:
1346:            /**
1347:             * Evaluate the given script using the process specific scope as
1348:             * returned by {@link #jsScope <code>jsScope</code>}. <P>
1349:             *
1350:             * results of type JavaScript Date are converted to Java Date.
1351:             *
1352:             * @param script the script
1353:             * @return the result
1354:             * @throws ScriptException if evaluation fails
1355:             */
1356:            public Serializable evalScript(String script)
1357:                    throws ScriptException {
1358:                Context cx = Context.enter();
1359:                try {
1360:                    Scriptable proto = jsScope();
1361:                    Scriptable scope = cx.newObject(proto);
1362:                    scope.setPrototype(proto);
1363:                    scope.setParentScope(null);
1364:
1365:                    Object res = cx.evaluateString(scope, script, "<script>",
1366:                            1, null);
1367:                    if (res instanceof  Wrapper) {
1368:                        res = ((Wrapper) res).unwrap();
1369:                    } else if (res instanceof  XMLObject) {
1370:                        SAXEventBufferImpl seb = new SAXEventBufferImpl();
1371:                        if (((XMLObject) res).getClassName().equals("XMLList")) {
1372:                            seb.startDocument();
1373:                            for (int i = 0; true; i++) {
1374:                                Object item = ((XMLObject) res).get(i,
1375:                                        (XMLObject) res);
1376:                                if (item.equals(Scriptable.NOT_FOUND)) {
1377:                                    break;
1378:                                }
1379:                                xmlObjectToSax(seb, (XMLObject) item, true);
1380:                            }
1381:                            seb.endDocument();
1382:                        } else {
1383:                            xmlObjectToSax(seb, (XMLObject) res, false);
1384:                        }
1385:                        seb.pack();
1386:                        return seb;
1387:                    } else if ((res instanceof  Scriptable)
1388:                            && ((Scriptable) res).getClassName().equals("Date")) {
1389:                        Scriptable s = (Scriptable) res;
1390:                        Object gt = Scriptable.NOT_FOUND;
1391:                        for (Scriptable c = s; c != null
1392:                                && gt.equals(Scriptable.NOT_FOUND); c = c
1393:                                .getPrototype()) {
1394:                            gt = c.get("getTime", s);
1395:                        }
1396:                        Number millis = (Number) ((Function) gt).call(cx,
1397:                                scope, s, new Object[] {});
1398:                        return new Date(millis.longValue());
1399:                    }
1400:                    return (Serializable) res;
1401:                } catch (JavaScriptException e) {
1402:                    logger.error(e.getMessage(), e);
1403:                    throw new ScriptException(e.getMessage(),
1404:                            (e.getValue() instanceof  Throwable) ? (Throwable) e
1405:                                    .getValue() : e);
1406:                } catch (SAXException e) {
1407:                    logger.error(e.getMessage(), e);
1408:                    throw new ScriptException(e.getMessage(), e);
1409:                } finally {
1410:                    Context.exit();
1411:                }
1412:            }
1413:
1414:            /**
1415:             * Serialize a JavaScript XML object into the SAX event buffer.
1416:             * 
1417:             * @param seb the SAX event buffer
1418:             * @param xmlObj the XML object
1419:             * @param fragment if <code>startDocument</code> and 
1420:             * <code>endDocument</code> events are to be suppressed 
1421:             * @throws SAXException
1422:             */
1423:            private void xmlObjectToSax(SAXEventBufferImpl seb,
1424:                    XMLObject xmlObj, boolean fragment) throws SAXException {
1425:                Wrapper wrap = (Wrapper) ScriptableObject.callMethod(
1426:                        (XMLObject) xmlObj, "getXmlObject", new Object[0]);
1427:                XmlObject result = (XmlObject) wrap.unwrap();
1428:                XmlCursor cursor = result.newCursor();
1429:                result = cursor.getObject();
1430:                ContentHandler ch = seb;
1431:                if (fragment) {
1432:                    ch = new BodyFilter(ch);
1433:                }
1434:                result.save(ch, seb, (new XmlOptions()).setSaveOuter());
1435:            }
1436:
1437:            /**
1438:             * Evaluate the given expressions using the process specific data
1439:             * (the scope as returned by {@link #jsScope
1440:             * <code>jsScope</code>} for JavaScript).
1441:             * @param expressionData an array of object arrays containing the result
1442:             * type and the expression
1443:             * @return an array that contains the result of each evaluation.
1444:             * Note that the result may be an exception.
1445:             */
1446:            public Serializable[] evalExpressions(Object[][] expressionData) {
1447:                Serializable[] res = new Serializable[expressionData.length];
1448:                for (int i = 0; i < expressionData.length; i++) {
1449:                    try {
1450:                        Object[] item = expressionData[i];
1451:                        Object resType = item[0];
1452:                        String expr = (String) item[1];
1453:                        if (XPDLUtil.isXMLType(resType) && expr.length() > 0
1454:                                && expr.startsWith("<j:jelly")) {
1455:                            res[i] = evalXML(expr);
1456:                        } else {
1457:                            res[i] = evalScript(expr);
1458:                        }
1459:                    } catch (Exception e) {
1460:                        res[i] = e;
1461:                    }
1462:                }
1463:                return res;
1464:            }
1465:
1466:            private Serializable evalXML(String xml) throws SAXException,
1467:                    IOException {
1468:                try {
1469:                    SAXParserFactory spf = SAXParserFactory.newInstance();
1470:                    spf.setValidating(false);
1471:                    spf.setNamespaceAware(true);
1472:                    spf.setFeature(
1473:                            "http://xml.org/sax/features/namespace-prefixes",
1474:                            true);
1475:                    XMLReader xr = null;
1476:                    try {
1477:                        spf.setFeature(
1478:                                "http://xml.org/sax/features/xmlns-uris", true);
1479:                        xr = spf.newSAXParser().getXMLReader();
1480:                    } catch (SAXException e) {
1481:                        xr = new XmlnsUrisPatcher(spf.newSAXParser()
1482:                                .getXMLReader());
1483:                    }
1484:                    SAXEventBufferImpl seb = new SAXEventBufferImpl();
1485:                    XMLFilterImpl filter = new XMLFilterImpl() {
1486:                        private int level = 0;
1487:
1488:                        public void startElement(String uri, String localName,
1489:                                String qName, Attributes atts)
1490:                                throws SAXException {
1491:                            if (level > 0) {
1492:                                super .startElement(uri, localName, qName, atts);
1493:                            }
1494:                            level += 1;
1495:                        }
1496:
1497:                        public void endElement(String uri, String localName,
1498:                                String qName) throws SAXException {
1499:                            level -= 1;
1500:                            if (level > 0) {
1501:                                super .endElement(uri, localName, qName);
1502:                            }
1503:                        }
1504:                    };
1505:                    filter.setContentHandler(seb);
1506:                    xr.setContentHandler(filter);
1507:                    xr.parse(new InputSource(new StringReader(
1508:                            "<temporary-root>" + xml + "</temporary-root>")));
1509:                    seb.pack();
1510:                    XMLStreamReader rdr = seb.createXMLStreamReader();
1511:                    while (rdr.next() != XMLStreamReader.START_ELEMENT) {
1512:                    }
1513:                    if (rdr.getNamespaceURI().equals("jelly:core")
1514:                            && rdr.getLocalName().equals("jelly")) {
1515:                        return evalJelly(seb);
1516:                    }
1517:                    return seb;
1518:                } catch (ParserConfigurationException e) {
1519:                    throw new IllegalArgumentException(
1520:                            "Error initiliazing schema type: " + e.getMessage());
1521:                } catch (SAXException e) {
1522:                    throw new IllegalArgumentException(
1523:                            "Error initiliazing schema type: " + e.getMessage());
1524:                } catch (XMLStreamException e) {
1525:                    throw new IllegalArgumentException(
1526:                            "Error initiliazing schema type: " + e.getMessage());
1527:                } catch (IOException e) {
1528:                    throw new IllegalArgumentException(
1529:                            "Error initiliazing schema type: " + e.getMessage());
1530:                }
1531:            }
1532:
1533:            private class ExtXMLParser extends XMLParser {
1534:                public void configure() {
1535:                    super .configure();
1536:                }
1537:            }
1538:
1539:            private JellyContext jellyContext() {
1540:                if (jellyContextCache == null) {
1541:                    jellyContextCache = new JellyContext() {
1542:                        private Map xmlVals = new HashMap();
1543:
1544:                        public Object getVariable(String name) {
1545:                            if (getPaProcessData().containsKey(name)) {
1546:                                Object v = getPaProcessData().get(name);
1547:                                if (v instanceof  SAXEventBuffer) {
1548:                                    if (!xmlVals.containsKey(name)) {
1549:                                        SAXContentHandler hdlr = new SAXContentHandler();
1550:                                        try {
1551:                                            ((SAXEventBuffer) v).emit(hdlr);
1552:                                        } catch (SAXException e) {
1553:                                            throw (IllegalArgumentException) (new IllegalArgumentException(
1554:                                                    "Error converting SAX events: "
1555:                                                            + e.getMessage()))
1556:                                                    .initCause(e);
1557:                                        }
1558:                                        xmlVals.put(name, hdlr.getDocument());
1559:                                    }
1560:                                    return xmlVals.get(name);
1561:                                }
1562:                                return v;
1563:                            } else {
1564:                                return super .getVariable(name);
1565:                            }
1566:                        }
1567:                    };
1568:                }
1569:                return jellyContextCache;
1570:            }
1571:
1572:            private SAXEventBufferImpl evalJelly(SAXEventBufferImpl seb)
1573:                    throws SAXException {
1574:                if (logger.isDebugEnabled()) {
1575:                    logger.debug("Evaluating jelly script");
1576:                }
1577:                try {
1578:                    JellyContext context = new JellyContext(jellyContext());
1579:                    ExtXMLParser jellyParser = new ExtXMLParser();
1580:                    jellyParser.setContext(context);
1581:                    jellyParser.configure();
1582:                    seb.emit(new NamespaceAttributesFilter(jellyParser));
1583:                    Script script = jellyParser.getScript();
1584:                    script.compile();
1585:                    SAXEventBufferImpl jres = new SAXEventBufferImpl();
1586:                    jres.startDocument();
1587:                    script.run(context, new XMLOutput(jres));
1588:                    jres.endDocument();
1589:                    jres.pack();
1590:                    return jres;
1591:                } catch (JellyException e) {
1592:                    throw (IllegalArgumentException) (new IllegalArgumentException(
1593:                            "Error evaluating jelly script: " + e.getMessage()))
1594:                            .initCause(e);
1595:                }
1596:            }
1597:
1598:            /* Comment copied from Interface. */
1599:            public void closeActivity(ExtActivityLocal activity,
1600:                    State closedState) {
1601:                // initialize transition manager before changing activity state!
1602:                TransitionManager tm = transitionManager();
1603:                activity.doCloseActivity(closedState);
1604:                tm.update(activity);
1605:                // everything else is done when the activity's close event is
1606:                // received, because we want to do it in another transaction
1607:            }
1608:
1609:            /* Comment copied from Interface. */
1610:            public boolean choose(ExtActivityLocal activity)
1611:                    throws TransitionNotAllowedException {
1612:                State state = activity.typedState();
1613:                if (state.isSameOrSubState(NotRunningState.NOT_STARTED)) {
1614:                    // this activity has been reset by some other activity
1615:                    return false;
1616:                }
1617:                if (!state.isSameOrSubState(OpenState.RUNNING)
1618:                        && !state.isSameOrSubState(NotRunningState.SUSPENDED)) {
1619:                    throw new TransitionNotAllowedException(
1620:                            "Cannot choose activity in state " + state
1621:                                    + " must be " + OpenState.RUNNING + " or "
1622:                                    + NotRunningState.SUSPENDED);
1623:                }
1624:                if (!activity.preliminarilyChosen()) {
1625:                    return true;
1626:                }
1627:                transitionManager().resetCompeting(activity);
1628:                return true;
1629:            }
1630:
1631:            //
1632:            // State change API implementation
1633:            //
1634:
1635:            private static Map vstates = null;
1636:
1637:            /**
1638:             * Returns the {@link java.util.Map <code>Map</code>} that maps
1639:             * the process states to a {@link java.util.Map <code>List</code>}
1640:             * of reachable process states. <P>
1641:             *
1642:             * The map returns the state transitions allowed as parameters of
1643:             * {@link
1644:             * de.danet.an.workflow.localcoreapi.WfExecutionObjectLocal#changeState
1645:             * <code>changeState</code>} only. I.e. the map does not reflect
1646:             * all possible transitions, there may be more, but those are only
1647:             * accessible to the workflow engine itself.
1648:             * @return the resulting map.
1649:             */
1650:            protected Map getStateTransitionMap() {
1651:                // Map must be initialized lazily. Static initialization holds
1652:                // danger of "race conditions" with constant initialization
1653:                // (resulting in null-entries). And new map must be fully initialized
1654:                // before assigning to member variable to avoid concurrent
1655:                // initialization.
1656:                if (vstates == null) {
1657:                    Map transMap = new HashMap();
1658:                    // Transitions from open.not_running.not_started
1659:                    List l = new ArrayList();
1660:                    transMap.put(NotRunningState.NOT_STARTED, l);
1661:                    l.add(ClosedState.TERMINATED);
1662:                    l.add(OpenState.RUNNING);
1663:                    // Transitions from open.running
1664:                    l = new ArrayList();
1665:                    transMap.put(RunningState.RUNNING, l);
1666:                    l.add(NotRunningState.SUSPENDED);
1667:                    l.add(ClosedState.TERMINATED);
1668:                    // Transitions from open.not_running.suspended
1669:                    l = new ArrayList();
1670:                    transMap.put(SuspendedState.SUSPENDED, l);
1671:                    l.add(OpenState.RUNNING);
1672:                    l.add(ClosedState.ABORTED);
1673:                    vstates = Collections.unmodifiableMap(transMap);
1674:                }
1675:                return vstates;
1676:            }
1677:
1678:            /**
1679:             * Adds the possibility to change the state to
1680:             * <code>OpenState.RUNNING</code> (i.e. "<code>start()</code>") to
1681:             * the <code>changeState</code> method of the superclass.
1682:             * 
1683:             * @param newState the new state.
1684:             * @throws InvalidStateException If <code>newState</code> is an invalid
1685:             * state for the execution object.
1686:             * @throws TransitionNotAllowedException If the transition from the current
1687:             * state to <code>newState</code> is not allowed.
1688:             */
1689:            public void changeState(State newState)
1690:                    throws InvalidStateException, TransitionNotAllowedException {
1691:                try {
1692:                    if (typedState() == NotRunningState.NOT_STARTED
1693:                            && newState == OpenState.RUNNING) {
1694:                        start();
1695:                        return;
1696:                    }
1697:                } catch (CannotStartException e) {
1698:                    throw new TransitionNotAllowedException(e.getClass()
1699:                            .getName()
1700:                            + ": " + e.getMessage());
1701:                } catch (AlreadyRunningException e) {
1702:                    throw new TransitionNotAllowedException(e.getClass()
1703:                            .getName()
1704:                            + ": " + e.getMessage());
1705:                }
1706:                super .changeState(newState);
1707:            }
1708:
1709:            /**
1710:             * Starts a process.
1711:             * @throws CannotStartException when the process cannot be started (e.g.,
1712:             * because it is not properly initialized).
1713:             * @throws AlreadyRunningException when the process has already been 
1714:             * started.
1715:             * @ejb.interface-method view-type="remote"
1716:             */
1717:            public void start() throws CannotStartException,
1718:                    AlreadyRunningException {
1719:                if (typedState() != NotRunningState.NOT_STARTED) {
1720:                    throw new AlreadyRunningException(toString()
1721:                            + " state is: " + state());
1722:                }
1723:                updateState(RunningState.RUNNING);
1724:            }
1725:
1726:            /**
1727:             * Enable or disable debugging of the activity.
1728:             * @param debug if the activity is to be debugged
1729:             * @throws InvalidStateException if changing debug mode is not
1730:             * allowed
1731:             */
1732:            public void setDebugEnabled(boolean debug)
1733:                    throws InvalidStateException {
1734:                setPaDebug(debug);
1735:                Iterator it = stepsLocal().iterator();
1736:                while (it.hasNext()) {
1737:                    ExtActivityLocal act = (ExtActivityLocal) it.next();
1738:                    act.setDebugEnabled(true);
1739:                }
1740:                return;
1741:            }
1742:
1743:            /* Comment copied from Interface. */
1744:            public void terminate() throws CannotStopException,
1745:                    NotRunningException {
1746:                mayCloseCheck(ClosedState.TERMINATED);
1747:                if (stepsLocal() != null) {
1748:                    for (Iterator it = stepsLocal().iterator(); it.hasNext();) {
1749:                        ActivityLocal act = (ActivityLocal) it.next();
1750:                        State s = act.typedState();
1751:                        if (s.isSameOrSubState(NotRunningState.SUSPENDED)
1752:                                || s == ClosedState.ABORTED) {
1753:                            throw new CannotStopException(act.toString()
1754:                                    + " is suspended.");
1755:                        }
1756:                    }
1757:                    String unstoppable = null;
1758:                    try {
1759:                        setPaTypedState(RunningState.TERMINATING);
1760:                        for (Iterator it = stepsLocal().iterator(); it
1761:                                .hasNext();) {
1762:                            ActivityLocal act = (ActivityLocal) it.next();
1763:                            if (act.workflowState() == State.OPEN
1764:                                    && (!act.typedState().isSameOrSubState(
1765:                                            NotRunningState.NOT_STARTED))) {
1766:                                try {
1767:                                    act.terminate();
1768:                                } catch (CannotStopException e) {
1769:                                    unstoppable = act.toString()
1770:                                            + " cannot be terminated: "
1771:                                            + e.getMessage();
1772:                                } catch (NotRunningException e) {
1773:                                    // cannot happen
1774:                                    logger.error(e.getMessage(), e);
1775:                                }
1776:                            }
1777:                        }
1778:                    } finally {
1779:                        setPaTypedState(RunningState.RUNNING);
1780:                    }
1781:                    if (unstoppable != null) {
1782:                        throw new CannotStopException(unstoppable);
1783:                    }
1784:                }
1785:                updateState(ClosedState.TERMINATED);
1786:            }
1787:
1788:            /* Comment copied from Interface. */
1789:            public void abort() throws CannotStopException, NotRunningException {
1790:                mayCloseCheck(ClosedState.ABORTED);
1791:                doAbort();
1792:            }
1793:
1794:            private void doAbort() throws CannotStopException {
1795:                if (stepsLocal() != null) {
1796:                    String unstoppable = null;
1797:                    try {
1798:                        setPaTypedState(SuspendedState.ABORTING);
1799:                        for (Iterator it = stepsLocal().iterator(); it
1800:                                .hasNext();) {
1801:                            ActivityLocal act = (ActivityLocal) it.next();
1802:                            try {
1803:                                if (act.typedState().isSameOrSubState(
1804:                                        NotRunningState.SUSPENDED)) {
1805:                                    act.abort();
1806:                                } else if (act.typedState().isSameOrSubState(
1807:                                        OpenState.RUNNING)) {
1808:                                    try {
1809:                                        act.terminate();
1810:                                    } catch (CannotStopException e) {
1811:                                        act.suspend();
1812:                                        act.abort();
1813:                                    }
1814:                                }
1815:                            } catch (CannotStopException e) {
1816:                                unstoppable = act.toString()
1817:                                        + " cannot be closed: "
1818:                                        + e.getMessage();
1819:                            } catch (InvalidControlOperationException e) {
1820:                                // cannot happen, we check states before changing
1821:                                logger.error(e.getMessage(), e);
1822:                            }
1823:                        }
1824:                    } finally {
1825:                        setPaTypedState(SuspendedState.SUSPENDED);
1826:                    }
1827:                    if (unstoppable != null) {
1828:                        throw new CannotStopException(unstoppable);
1829:                    }
1830:                }
1831:                updateState(ClosedState.ABORTED);
1832:            }
1833:
1834:            private void mayCloseCheck(ClosedState s)
1835:                    throws CannotStopException, NotRunningException {
1836:                if (!validTypedStates().contains(s)) {
1837:                    if (typedState().isSameOrSubState(OpenState.RUNNING)) {
1838:                        throw new CannotStopException(toString() + " is "
1839:                                + state());
1840:                    } else {
1841:                        throw new NotRunningException(toString() + " is "
1842:                                + state());
1843:                    }
1844:                }
1845:            }
1846:
1847:            //
1848:            // Timers
1849:            //
1850:
1851:            /**
1852:             * Handle the timeout of a timer.
1853:             * @param info the context.
1854:             */
1855:            public void handleTimeout(Serializable info) {
1856:                TimeoutInfo toi = (TimeoutInfo) info;
1857:                List dls = (List) getPaBlockDeadlines().get(toi.activity);
1858:                Deadline dl = (Deadline) dls.get(toi.dlIndex);
1859:                if (logger.isDebugEnabled()) {
1860:                    logger.debug(toString() + " received timeout for " + dl);
1861:                }
1862:                // now accept deadline
1863:                dl.setState(Deadline.STATE_REACHED);
1864:                // notify persistence layer about change
1865:                getPaBlockDeadlines().put(toi.activity,
1866:                        getPaBlockDeadlines().get(toi.activity));
1867:
1868:                // now find not completed/not started activities and/or abandon
1869:                Collection openActs = new ArrayList();
1870:                for (Iterator i = activitiesOfBlockActivity(
1871:                        toi.activity.toString()).iterator(); i.hasNext();) {
1872:                    ExtActivityLocal a = (ExtActivityLocal) i.next();
1873:                    if (a.typedState().isSameOrSubState(OpenState.RUNNING)
1874:                            || a.typedState().isSameOrSubState(
1875:                                    NotRunningState.SUSPENDED)) {
1876:                        openActs.add(a);
1877:                        // complete this if deadline is synchronous
1878:                        if (dl.getExecution() == Deadline.SYNCHR) {
1879:                            a.initiateAbandoning(true, dl.getExceptionName());
1880:                            transitionManager().update(a);
1881:                        }
1882:                    }
1883:                }
1884:                if (openActs.size() > 0) {
1885:                    BAForExceptionHandling ba = (BAForExceptionHandling) blockActivityRepresentation(toi.activity
1886:                            .toString());
1887:                    ba
1888:                            .update(
1889:                                    dls,
1890:                                    dl.getExecution() == Deadline.SYNCHR ? (State) ClosedCompletedState.ABANDONED
1891:                                            : (State) RunningState.RUNNING,
1892:                                    openActs);
1893:                    handleException(ba, dl.getExceptionName());
1894:                }
1895:            }
1896:
1897:            //
1898:            // State change handling
1899:            //
1900:
1901:            /**
1902:             * Check if this class handles a specific event.
1903:             * @param event the event to check
1904:             * @return <code>true</code> if event is handled
1905:             */
1906:            public static boolean isHandled(WfAuditEvent event) {
1907:                try {
1908:                    if (!(event instanceof  WfStateAuditEvent)) {
1909:                        return false;
1910:                    }
1911:                    if (event.eventType().equals(
1912:                            WfAuditEvent.ACTIVITY_STATE_CHANGED)) {
1913:                        State newState = State
1914:                                .fromString(((WfStateAuditEvent) event)
1915:                                        .newState());
1916:                        if (newState.isSameOrSubState(State.CLOSED)) {
1917:                            return true;
1918:                        }
1919:                    } else if (event.eventType().equals(
1920:                            WfAuditEvent.PROCESS_STATE_CHANGED)) {
1921:                        State oldState = State
1922:                                .fromString(((WfStateAuditEvent) event)
1923:                                        .oldState());
1924:                        State newState = State
1925:                                .fromString(((WfStateAuditEvent) event)
1926:                                        .newState());
1927:                        if (oldState
1928:                                .isSameOrSubState(NotRunningState.NOT_STARTED)) {
1929:                            if (newState == RunningState.RUNNING) {
1930:                                return true;
1931:                            }
1932:                        } else if (oldState
1933:                                .isSameOrSubState(NotRunningState.NOT_STARTED)) {
1934:                            if (newState == ClosedState.TERMINATED) {
1935:                                return true;
1936:                            }
1937:                        } else if (oldState
1938:                                .isSameOrSubState(NotRunningState.SUSPENDED)) {
1939:                            if (newState == RunningState.RUNNING) {
1940:                                return true;
1941:                            }
1942:                            if (newState == ClosedState.ABORTED) {
1943:                                return true;
1944:                            }
1945:                        } else if (oldState.isSameOrSubState(OpenState.RUNNING)) {
1946:                            if (newState == ClosedCompletedState.NORMAL) {
1947:                                return true;
1948:                            }
1949:                            if (newState == ClosedState.TERMINATED) {
1950:                                return true;
1951:                            }
1952:                        }
1953:                    }
1954:                } catch (InvalidStateException e) {
1955:                    throw (IllegalArgumentException) (new IllegalArgumentException(
1956:                            e.getMessage())).initCause(e);
1957:                }
1958:                return false;
1959:            }
1960:
1961:            /**
1962:             * Handles the given audit event.
1963:             * @param event the event.
1964:             * @ejb.interface-method view-type="remote"
1965:             */
1966:            public void handleAuditEvent(WfAuditEvent event) {
1967:                if (event.activityKey() == null) {
1968:                    super .handleAuditEvent(event);
1969:                    return;
1970:                }
1971:                // One of our activities has closed (events are pre-filtered)
1972:                State ps = typedState();
1973:                if (ps.isSameOrSubState(RunningState.TERMINATING)
1974:                        || ps.isSameOrSubState(SuspendedState.ABORTING)) {
1975:                    return;
1976:                }
1977:                State closedState = null;
1978:                try {
1979:                    closedState = State.fromString(((WfStateAuditEvent) event)
1980:                            .newState());
1981:                } catch (InvalidStateException e) {
1982:                    // actually, this is impossible
1983:                    logger.error(e.getMessage());
1984:                    return;
1985:                }
1986:                if (closedState.isSameOrSubState(ClosedState.ABORTED)) {
1987:                    if (ps.isSameOrSubState(OpenState.RUNNING)) {
1988:                        updateInterim(SuspendedState.SUSPENDED);
1989:                    } else if ((!ps.isSameOrSubState(NotRunningState.SUSPENDED))) {
1990:                        return;
1991:                    }
1992:                    try {
1993:                        doAbort();
1994:                    } catch (CannotStopException e) {
1995:                        logger.warn("Cannot abort process: " + e.getMessage());
1996:                    }
1997:                    return;
1998:                }
1999:                if (ps == RunningState.RUNNING) {
2000:                    continueProcessing();
2001:                }
2002:            }
2003:
2004:            /**
2005:             * Handles a terminated audit event.
2006:             * @param event the event.
2007:             */
2008:            protected void handleTerminatedEvent(WfStateAuditEvent event) {
2009:                WfRequester req = unresolvedRequester();
2010:                if ((req instanceof  SubProcRequester)
2011:                        && (((SubProcRequester) req).execution() == SubFlowImplementation.SYNCHR)) {
2012:                    String key = ((SubProcRequester) req).requestingActivity();
2013:                    try {
2014:                        ActivityLocal act = lookupActivityLocal(key);
2015:                        if (act.typedState() != RunningState.ABANDONING
2016:                                && act.typedState() != ClosedCompletedState.ABANDONED) {
2017:                            act.terminate();
2018:                        }
2019:                    } catch (InvalidKeyException e) {
2020:                        logger.warn(toString()
2021:                                + " cannot notify requesting activity " + key
2022:                                + " : " + e.getMessage());
2023:                    } catch (InvalidControlOperationException e) {
2024:                        logger.warn(toString()
2025:                                + " cannot terminate requesting activity "
2026:                                + key + " : " + e.getMessage());
2027:                    }
2028:                }
2029:                handleClosedEvent(event);
2030:            }
2031:
2032:            /**
2033:             * Handles a aborting audit event.
2034:             * @param event the event.
2035:             */
2036:            protected void handleAbortedEvent(WfStateAuditEvent event) {
2037:                WfRequester req = unresolvedRequester();
2038:                if ((req instanceof  SubProcRequester)
2039:                        && (((SubProcRequester) req).execution() == SubFlowImplementation.SYNCHR)) {
2040:                    String key = ((SubProcRequester) req).requestingActivity();
2041:                    try {
2042:                        ExtActivityLocal act = lookupActivityLocal(key);
2043:                        act.abortRequester();
2044:                    } catch (InvalidKeyException e) {
2045:                        logger.warn(toString()
2046:                                + " cannot notify requesting activity " + key
2047:                                + " : " + e.getMessage());
2048:                    }
2049:                }
2050:                handleClosedEvent(event);
2051:            }
2052:
2053:            /**
2054:             * Handles a completed audit event.
2055:             * @param event the event.
2056:             */
2057:            protected void handleCompletedEvent(WfStateAuditEvent event) {
2058:                WfRequester req = unresolvedRequester();
2059:                if ((req instanceof  SubProcRequester)
2060:                        && (((SubProcRequester) req).execution() == SubFlowImplementation.SYNCHR)) {
2061:                    String key = ((SubProcRequester) req).requestingActivity();
2062:                    try {
2063:                        ActivityLocal act = lookupActivityLocal(key);
2064:                        if (act.typedState() != RunningState.ABANDONING
2065:                                && act.typedState() != ClosedCompletedState.ABANDONED) {
2066:                            ProcessData res = processContext();
2067:                            FormalParameter[] fps = processDefinition()
2068:                                    .formalParameters();
2069:                            ProcessData pd = new ProcessDataWithParams(fps);
2070:                            for (int i = 0; i < fps.length; i++) {
2071:                                FormalParameter fp = fps[i];
2072:                                if (fp.mode() == FormalParameter.Mode.IN) {
2073:                                    continue;
2074:                                }
2075:                                String fpn = fps[i].id();
2076:                                pd.put(fpn, res.get(fpn));
2077:                            }
2078:                            act.setResult(pd);
2079:                            act.complete();
2080:                        }
2081:                    } catch (InvalidKeyException e) {
2082:                        logger.warn(toString()
2083:                                + " cannot notify requesting activity " + key
2084:                                + " : " + e.getMessage());
2085:                    } catch (InvalidDataException e) {
2086:                        logger.warn(toString()
2087:                                + " cannot set data on requesting activity "
2088:                                + key + " : " + e.getMessage());
2089:                    } catch (InvalidControlOperationException e) {
2090:                        logger.warn(toString()
2091:                                + " cannot notify requesting activity " + key
2092:                                + " : " + e.getMessage());
2093:                    }
2094:                }
2095:                handleClosedEvent(event);
2096:            }
2097:
2098:            /**
2099:             * Called when the process is closed. Derived classes should
2100:             * should override this method and notify clients waiting on
2101:             * channels that the channel is closed and clean up any data
2102:             * structures associated with channels.
2103:             */
2104:            protected void closeChannels() {
2105:            }
2106:
2107:            private void handleClosedEvent(WfStateAuditEvent event) {
2108:                stopTimers();
2109:                closeChannels();
2110:                int cleanupMode = cleanupMode();
2111:                if (cleanupMode == ProcessDefinition.REMOVE_AUTOMATIC
2112:                        || (cleanupMode == ProcessDefinition.REMOVE_COMPLETED && event
2113:                                .newState().startsWith("closed.completed"))) {
2114:                    try {
2115:                        removeThis();
2116:                    } catch (CannotRemoveException e) {
2117:                        // cannot happen, we got this event because process
2118:                        // was closed, so it must be removable
2119:                        logger.error("Closed process not removable (?): "
2120:                                + e.getMessage(), e);
2121:                    }
2122:                }
2123:            }
2124:
2125:            /* Comment copied from interface. */
2126:            public void handleException(ExtActivityLocal activity,
2127:                    String exceptionName) {
2128:                transitionManager().update(activity, exceptionName);
2129:                if (typedState() == RunningState.RUNNING) {
2130:                    continueProcessing();
2131:                }
2132:            }
2133:
2134:            /**
2135:             * Remove this process. Since this involves the persistence layer,
2136:             * this method must be provided by the derived class.
2137:             * @throws CannotRemoveException if the process is still in progress
2138:             */
2139:            protected abstract void removeThis() throws CannotRemoveException;
2140:
2141:            /**
2142:             * Handles a started audit event.
2143:             * @param event the event.
2144:             */
2145:            protected void handleStartedEvent(WfStateAuditEvent event) {
2146:                // start all activities
2147:                continueProcessing();
2148:            }
2149:
2150:            /**
2151:             * Handles a resumed audit event.
2152:             * @param event the event.
2153:             */
2154:            protected void handleResumedEvent(WfStateAuditEvent event) {
2155:                continueProcessing();
2156:            }
2157:
2158:            private void continueProcessing() {
2159:                // checkAllActivities
2160:                TransitionManager tm = transitionManager();
2161:                if (tm.isAtEnd()) {
2162:                    State resState = ClosedCompletedState.NORMAL;
2163:                    for (Iterator i = stepsLocal().iterator(); i.hasNext();) {
2164:                        State s = ((ActivityLocal) i.next()).typedState();
2165:                        if (s.isSameOrSubState(ClosedState.TERMINATED)) {
2166:                            resState = ClosedState.TERMINATED;
2167:                            break; // can't get worse, aborted activity
2168:                            // is handled separately.
2169:                        }
2170:                    }
2171:                    updateState(resState);
2172:                    return;
2173:                }
2174:                // start all runnableActivities
2175:                Collection activitiesToStart = tm.startableActivities();
2176:                for (Iterator it = activitiesToStart.iterator(); it.hasNext();) {
2177:                    ExtActivityLocal a = (ExtActivityLocal) it.next();
2178:                    try {
2179:                        String ba = a.blockActivity();
2180:                        if (ba != null && tm.isTransitionSource(ba)) {
2181:                            // We are about to start an activity that is part
2182:                            // of a block activity with exception
2183:                            // condition. Find out if it is the first activity
2184:                            // to be started in the set.
2185:                            boolean isFirst = true;
2186:                            for (Iterator i = activitiesOfBlockActivity(ba)
2187:                                    .iterator(); i.hasNext();) {
2188:                                ActivityLocal bm = (ActivityLocal) i.next();
2189:                                if (!bm.typedState().isSameOrSubState(
2190:                                        NotRunningState.NOT_STARTED)) {
2191:                                    isFirst = false;
2192:                                    break;
2193:                                }
2194:                            }
2195:                            if (isFirst) {
2196:                                armDeadlines(ba);
2197:                            }
2198:                        }
2199:                        a.start();
2200:                    } catch (AlreadyRunningException e) {
2201:                        // can't do much about this, shouldn't happen
2202:                        logger.error(e.getMessage(), e);
2203:                    }
2204:                }
2205:            }
2206:
2207:            private void armDeadlines(String ba) {
2208:                if (logger.isDebugEnabled()) {
2209:                    logger.debug("Starting first activity of "
2210:                            + "block activity " + ba);
2211:                }
2212:                try {
2213:                    int dlIndex = 0;
2214:                    Date now = new Date();
2215:                    Long bak = new Long(ba);
2216:                    for (Iterator dli = ((List) getPaBlockDeadlines().get(bak))
2217:                            .iterator(); dli.hasNext(); dlIndex += 1) {
2218:                        Deadline dl = (Deadline) dli.next();
2219:                        if (dl.getState() != Deadline.STATE_INITIAL) {
2220:                            continue;
2221:                        }
2222:                        dl.arm(this , now, toProcessLocal(), new TimeoutInfo(
2223:                                bak, dlIndex));
2224:                    }
2225:                } catch (NumberFormatException e) {
2226:                    // can't do much about this, shouldn't happen
2227:                    logger.error(e.getMessage(), e);
2228:                }
2229:            }
2230:
2231:            /**
2232:             * Returns an audit event object with process relevant information
2233:             * initialized.
2234:             * @param eventType event type
2235:             * @return the process related information.
2236:             */
2237:            protected WfAuditEvent auditEventBase(String eventType) {
2238:                return new DefaultAuditEvent(toProcess(), eventType,
2239:                        getPaKey(), getPaName(), getPaProcessMgrName(),
2240:                        getPaProcessMgrVersion(), getPaAuditEventSelection(),
2241:                        getPaStoreAuditEvents());
2242:            }
2243:
2244:            //
2245:            // Helpers
2246:            //
2247:
2248:            /**
2249:             * Return an arbitrary activity with the given key. The activity
2250:             * need not belong to this process.
2251:             * @param key activity key
2252:             * @return the activity
2253:             * @throws InvalidKeyException if the activity cannot be found
2254:             */
2255:            protected abstract ExtActivityLocal lookupActivityLocal(String key)
2256:                    throws InvalidKeyException;
2257:
2258:            /**
2259:             * Retrieve the base event information about a requesting activity.
2260:             * @param req the requester.
2261:             * @return the base info using an audit event as DTO.
2262:             */
2263:            protected abstract WfAuditEvent activityRequesterInfo(
2264:                    WfRequester req);
2265:
2266:            /**
2267:             * Return a runtime representation of a block activity. Block
2268:             * activities are not persisted. However, the persistence layer
2269:             * needs a representation to assign a "from"-activity to exception
2270:             * transitions starting at block activities. This representation
2271:             * is subsequently used by the domain layer only and therefore
2272:             * provided by the domain layer.
2273:             * @param key the block activity key
2274:             * @return the block activity representation
2275:             */
2276:            protected ActivityLocal blockActivityRepresentation(String key) {
2277:                ActivityLocal act = (ActivityLocal) baRepresentations.get(key);
2278:                if (act == null) {
2279:                    act = new BAForExceptionHandling(key);
2280:                    baRepresentations.put(key, act);
2281:                }
2282:                return act;
2283:            }
2284:
2285:            /**
2286:             * Return string representation for debugging purposes.
2287:             * @return a string representation.
2288:             */
2289:            public String toString() {
2290:                return "Process[key=" + getPaKey() + "]";
2291:            }
2292:
2293:            //
2294:            // Process instantiation
2295:            //
2296:
2297:            /**
2298:             * Helper class for retrieving the initialization information from
2299:             * the process definition.
2300:             */
2301:            public class SAXInitializer extends StackedHandler {
2302:
2303:                private Map actIdMap = null;
2304:                private Map trefsMap = null;
2305:                private Map actSetDefs = null;
2306:
2307:                private String actSetId = null;
2308:                private SAXEventBufferImpl actSetDef = null;
2309:
2310:                private ProcessData procDataMap = getPaProcessData();
2311:
2312:                private String extAttrName = null;
2313:                private String extAttrValue = null;
2314:
2315:                /**
2316:                 * Create a new SAX initializer with the given parameters.
2317:                 */
2318:                public SAXInitializer() {
2319:                    actIdMap = new HashMap();
2320:                    trefsMap = new HashMap();
2321:                    actSetDefs = new HashMap();
2322:                }
2323:
2324:                /**
2325:                 * Receive notification of the beginning of an element.
2326:                 *
2327:                 * @param uri the Namespace URI, or the empty string if the
2328:                 * element has no Namespace URI or if Namespace processing is not
2329:                 * being performed.
2330:                 * @param loc the local name (without prefix), or the empty string
2331:                 * if Namespace processing is not being performed.
2332:                 * @param raw the raw XML 1.0 name (with prefix), or the empty
2333:                 * string if raw names are not available.
2334:                 * @param a the attributes attached to the element. If there are
2335:                 * no attributes, it shall be an empty Attributes object.
2336:                 * @throws SAXException not thrown.
2337:                 */
2338:                public void startElement(String uri, String loc, String raw,
2339:                        Attributes a) throws SAXException {
2340:                    if (loc.equals("WorkflowProcess")) {
2341:                        setPaName(a.getValue("Name"));
2342:                        setPaId(a.getValue("Id"));
2343:                    } else if (loc.equals("Applications")) {
2344:                        getStack().push(new DefaultHandler());
2345:                    } else if (loc.equals("DataField")
2346:                            || loc.equals("FormalParameter")) {
2347:                        setContextData("ProcDataId", a.getValue("Id"));
2348:                        setContextData("InitialValue", null);
2349:                    } else if (loc.equals("DataType")) {
2350:                        getStack().push(new XPDLUtil.SAXDataTypeHandler());
2351:                    } else if (loc.equals("Activity")) {
2352:                        getStack().push(
2353:                                new ActivityInitializer(actIdMap, trefsMap,
2354:                                        actSetDefs, null));
2355:                    } else if (loc.equals("Transition")) {
2356:                        getStack().push(
2357:                                new TransitionInitializer(actIdMap, trefsMap,
2358:                                        null));
2359:                    } else if (loc.equals("ActivitySet")) {
2360:                        actSetId = a.getValue("Id");
2361:                        actSetDef = new SAXEventBufferImpl();
2362:                        getStack().push(actSetDef);
2363:                    } else if (loc.equals("ExtendedAttribute")
2364:                            && getStack().getRelativeDepth() == 4) {
2365:                        extAttrName = a.getValue("Name");
2366:                        extAttrValue = a.getValue("Value");
2367:                    }
2368:                }
2369:
2370:                /**
2371:                 * Receive notification of the end of an element.
2372:                 *
2373:                 * @param uri the Namespace URI, or the empty string if the
2374:                 * element has no Namespace URI or if Namespace processing is not
2375:                 * being performed.
2376:                 * @param loc the local name (without prefix), or the empty string
2377:                 * if Namespace processing is not being performed.
2378:                 * @param raw the raw XML 1.0 name (with prefix), or the empty
2379:                 * string if raw names are not available.
2380:                 * @throws SAXException not thrown.
2381:                 */
2382:                public void endElement(String uri, String loc, String raw)
2383:                        throws SAXException {
2384:                    if (loc.equals("Priority")) {
2385:                        try {
2386:                            setPaPriority(Priority.fromInt(Integer
2387:                                    .parseInt(text().trim())));
2388:                        } catch (InvalidPriorityException e) {
2389:                            logger.error(e.getMessage(), e);
2390:                            throw new SAXException(e);
2391:                        }
2392:                    } else if (loc.equals("InitialValue")) {
2393:                        Object dt = getContextData("DataType");
2394:                        try {
2395:                            if (dt.equals(String.class)) {
2396:                                setContextData("InitialValue", text());
2397:                            } else if (dt.equals(Double.class)) {
2398:                                setContextData("InitialValue", new Double(
2399:                                        text()));
2400:                            } else if (dt.equals(Long.class)) {
2401:                                setContextData("InitialValue", new Long(text()));
2402:                            } else if (dt.equals(Date.class)) {
2403:                                setContextData("InitialValue", XMLUtil
2404:                                        .parseXsdDateTime(text()));
2405:                            } else if (dt.equals(Boolean.class)) {
2406:                                setContextData("InitialValue", new Boolean(
2407:                                        text()));
2408:                            } else if (dt.equals(Participant.class)) {
2409:                                setContextData("InitialValue", text());
2410:                            } else if ((dt instanceof  ExternalReference)
2411:                                    || (dt instanceof  SAXEventBuffer)
2412:                                    || dt.equals(org.w3c.dom.Element.class)) {
2413:                                setContextData("InitialValue",
2414:                                        parseInitialXMLValue(text()));
2415:                            }
2416:                        } catch (NumberFormatException e) {
2417:                            throw new SAXException("Cannot convert to type: "
2418:                                    + e.getMessage());
2419:                        } catch (ParseException e) {
2420:                            throw new SAXException("Cannot convert to type: "
2421:                                    + e.getMessage());
2422:                        }
2423:                    } else if (loc.equals("DataField")
2424:                            || loc.equals("FormalParameter")) {
2425:                        procDataMap.put(getContextData("ProcDataId"),
2426:                                getContextData("InitialValue"));
2427:                    } else if (loc.equals("ActivitySet")) {
2428:                        actSetDefs.put(actSetId, actSetDef);
2429:                    } else if (loc.equals("ExtendedAttribute")
2430:                            && extAttrName != null) {
2431:                        if (extAttrValue == null) {
2432:                            extAttrValue = text().trim();
2433:                        }
2434:                        if (extAttrName.equals("Debug")
2435:                                && extAttrValue.equalsIgnoreCase("true")) {
2436:                            try {
2437:                                setDebugEnabled(true);
2438:                            } catch (InvalidStateException e) {
2439:                                logger.error("Cannot set debug enabled: "
2440:                                        + e.getMessage(), e);
2441:                            }
2442:                        }
2443:                        extAttrName = null;
2444:                        extAttrValue = null;
2445:                    }
2446:                }
2447:            }
2448:
2449:            private SAXEventBuffer parseInitialXMLValue(String text) {
2450:                try {
2451:                    SAXParserFactory spf = SAXParserFactory.newInstance();
2452:                    spf.setValidating(false);
2453:                    spf.setNamespaceAware(true);
2454:                    spf.setFeature(
2455:                            "http://xml.org/sax/features/namespace-prefixes",
2456:                            true);
2457:                    XMLReader xr = null;
2458:                    try {
2459:                        spf.setFeature(
2460:                                "http://xml.org/sax/features/xmlns-uris", true);
2461:                        xr = spf.newSAXParser().getXMLReader();
2462:                    } catch (SAXException e) {
2463:                        xr = new XmlnsUrisPatcher(spf.newSAXParser()
2464:                                .getXMLReader());
2465:                    }
2466:                    SAXEventBufferImpl seb = new SAXEventBufferImpl();
2467:                    XMLFilterImpl filter = new XMLFilterImpl() {
2468:                        private int level = 0;
2469:
2470:                        public void startElement(String uri, String localName,
2471:                                String qName, Attributes atts)
2472:                                throws SAXException {
2473:                            if (level > 0) {
2474:                                super .startElement(uri, localName, qName, atts);
2475:                            }
2476:                            level += 1;
2477:                        }
2478:
2479:                        public void endElement(String uri, String localName,
2480:                                String qName) throws SAXException {
2481:                            level -= 1;
2482:                            if (level > 0) {
2483:                                super .endElement(uri, localName, qName);
2484:                            }
2485:                        }
2486:                    };
2487:                    filter.setContentHandler(seb);
2488:                    xr.setContentHandler(filter);
2489:                    xr.parse(new InputSource(new StringReader(
2490:                            "<temporary-root>" + text + "</temporary-root>")));
2491:                    seb.pack();
2492:                    return seb;
2493:                } catch (ParserConfigurationException e) {
2494:                    throw new IllegalArgumentException(
2495:                            "Error initiliazing schema type: " + e.getMessage());
2496:                } catch (SAXException e) {
2497:                    throw new IllegalArgumentException(
2498:                            "Error initiliazing schema type: " + e.getMessage());
2499:                } catch (IOException e) {
2500:                    throw new IllegalArgumentException(
2501:                            "Error initiliazing schema type: " + e.getMessage());
2502:                }
2503:            }
2504:
2505:            /**
2506:             * Helper class for retrieving the Activity information from
2507:             * the process definition.
2508:             */
2509:            public class ActivityInitializer extends StackedHandler {
2510:
2511:                private Map actIdMap = null;
2512:                private Map trefsMap = null;
2513:                private Map actSetDefs = null;
2514:                private String blkActKey = null;
2515:
2516:                private String actId = null;
2517:                private Priority priority = Priority.NORMAL;
2518:                private String name = null;
2519:                private String description = null;
2520:                private StartFinishMode startMode = StartFinishMode.AUTOMATIC;
2521:                private StartFinishMode finishMode = StartFinishMode.AUTOMATIC;
2522:                private JoinAndSplitMode joinMode = JoinAndSplitMode.AND;
2523:                private JoinAndSplitMode splitMode = JoinAndSplitMode.AND;
2524:                private String performer = null;
2525:                private List deadlines = new ArrayList();
2526:
2527:                private boolean waitingForStartMode = false;
2528:                private boolean waitingForFinishMode = false;
2529:                private List trefs = null;
2530:                private List impls = null;
2531:                private String actSetRef = null;
2532:                private int dlMode;
2533:                private String dlCond = null;
2534:                private String dlException = null;
2535:                private boolean deferredChoice = false;
2536:
2537:                private String extAttrName = null;
2538:                private String extAttrValue = null;
2539:
2540:                /**
2541:                 * Create a new initializer with the given parameters.
2542:                 * @param actIds activity id map
2543:                 * @param trefs transition reference map
2544:                 * @param actSets activity set definition map
2545:                 * @param blkActKey the key of the block activity this
2546:                 * activity belongs to or <code>null</code>
2547:                 */
2548:                public ActivityInitializer(Map actIds, Map trefs, Map actSets,
2549:                        String blkActKey) {
2550:                    actIdMap = actIds;
2551:                    trefsMap = trefs;
2552:                    actSetDefs = actSets;
2553:                    this .blkActKey = blkActKey;
2554:                }
2555:
2556:                /**
2557:                 * Receive notification of the beginning of an element.
2558:                 *
2559:                 * @param uri the Namespace URI, or the empty string if the
2560:                 * element has no Namespace URI or if Namespace processing is not
2561:                 * being performed.
2562:                 * @param loc the local name (without prefix), or the empty string
2563:                 * if Namespace processing is not being performed.
2564:                 * @param raw the raw XML 1.0 name (with prefix), or the empty
2565:                 * string if raw names are not available.
2566:                 * @param a the attributes attached to the element. If there are
2567:                 * no attributes, it shall be an empty Attributes object.
2568:                 * @throws SAXException not thrown.
2569:                 */
2570:                public void startElement(String uri, String loc, String raw,
2571:                        Attributes a) throws SAXException {
2572:                    if (loc.equals("Activity")) {
2573:                        actId = a.getValue("Id");
2574:                        name = a.getValue("Name");
2575:                        trefs = new ArrayList();
2576:                        impls = new ArrayList();
2577:                    } else if (loc.equals("StartMode")) {
2578:                        waitingForStartMode = true;
2579:                    } else if (loc.equals("FinishMode")) {
2580:                        waitingForFinishMode = true;
2581:                    } else if (loc.equals("Automatic")) {
2582:                        if (waitingForStartMode) {
2583:                            startMode = StartFinishMode.AUTOMATIC;
2584:                        } else if (waitingForFinishMode) {
2585:                            finishMode = StartFinishMode.AUTOMATIC;
2586:                        }
2587:                    } else if (loc.equals("Manual")) {
2588:                        if (waitingForStartMode) {
2589:                            startMode = StartFinishMode.MANUAL;
2590:                        } else if (waitingForFinishMode) {
2591:                            finishMode = StartFinishMode.MANUAL;
2592:                        }
2593:                    } else if (loc.equals("Join")) {
2594:                        joinMode = JoinAndSplitMode.fromString(a
2595:                                .getValue("Type"));
2596:                    } else if (loc.equals("Split")) {
2597:                        splitMode = JoinAndSplitMode.fromString(a
2598:                                .getValue("Type"));
2599:                    } else if (loc.equals("TransitionRef")) {
2600:                        trefs.add(a.getValue("Id"));
2601:                    } else if (loc.equals("Tool")) {
2602:                        getStack().push(ToolBasedImpl.saxConstructor());
2603:                    } else if (loc.equals("SubFlow")) {
2604:                        getStack().push(ProcBasedImpl.saxConstructor());
2605:                    } else if (loc.equals("Deadline")) {
2606:                        dlMode = Deadline.SYNCHR;
2607:                        if (a.getValue("Execution") != null
2608:                                && a.getValue("Execution").equals("ASYNCHR")) {
2609:                            dlMode = Deadline.ASYNCHR;
2610:                        }
2611:                    } else if (loc.equals("BlockActivity")) {
2612:                        actSetRef = a.getValue("BlockId");
2613:                    } else if (loc.equals("ExtendedAttribute")
2614:                            && getStack().getRelativeDepth() == 2) {
2615:                        extAttrName = a.getValue("Name");
2616:                        extAttrValue = a.getValue("Value");
2617:                    }
2618:                }
2619:
2620:                /**
2621:                 * Receive notification of the end of an element.
2622:                 *
2623:                 * @param uri the Namespace URI, or the empty string if the
2624:                 * element has no Namespace URI or if Namespace processing is not
2625:                 * being performed.
2626:                 * @param loc the local name (without prefix), or the empty string
2627:                 * if Namespace processing is not being performed.
2628:                 * @param raw the raw XML 1.0 name (with prefix), or the empty
2629:                 * string if raw names are not available.
2630:                 * @throws SAXException not thrown.
2631:                 */
2632:                public void endElement(String uri, String loc, String raw)
2633:                        throws SAXException {
2634:                    if (loc.equals("Activity")) {
2635:                        if (actSetRef != null) {
2636:                            // create block activity, i.e. the activities defined
2637:                            // in the activity set
2638:                            Long baKey = new Long(-createActivityKey()
2639:                                    .longValue());
2640:                            BlockActivity ba = new BAForProcessInstantiation(
2641:                                    AbstractProcess.this , baKey.toString(),
2642:                                    (SAXEventBuffer) actSetDefs.get(actSetRef),
2643:                                    (String) getContextData("packageId"),
2644:                                    actSetDefs, actId, joinMode, splitMode);
2645:                            actIdMap.put(actId, ba);
2646:                            getPaBlockDeadlines().put(baKey, deadlines);
2647:                        } else {
2648:                            // create a simple activity
2649:                            WfActivityLocal act = createActivity(
2650:                                    blkActKey,
2651:                                    priority,
2652:                                    name,
2653:                                    description,
2654:                                    startMode,
2655:                                    finishMode,
2656:                                    joinMode,
2657:                                    splitMode,
2658:                                    impls.size() == 0 ? null
2659:                                            : ((Implementation[]) impls
2660:                                                    .toArray(new Implementation[impls
2661:                                                            .size()])),
2662:                                    performer, deadlines, deferredChoice,
2663:                                    getPaAuditEventSelection(),
2664:                                    getPaStoreAuditEvents());
2665:                            actIdMap.put(actId, act);
2666:                        }
2667:                        trefsMap.put(actId, trefs);
2668:                    } else if (loc.equals("Priority")) {
2669:                        try {
2670:                            priority = Priority.fromInt(Integer.parseInt(text()
2671:                                    .trim()));
2672:                        } catch (InvalidPriorityException e) {
2673:                            throw new SAXException(e);
2674:                        }
2675:                    } else if (loc.equals("Description")) {
2676:                        description = text().trim();
2677:                    } else if (loc.equals("StartMode")) {
2678:                        waitingForStartMode = false;
2679:                    } else if (loc.equals("FinishMode")) {
2680:                        waitingForFinishMode = false;
2681:                    } else if (loc.equals("Performer")) {
2682:                        performer = text().trim();
2683:                    } else if (loc.equals("Tool") || loc.equals("SubFlow")) {
2684:                        impls.add(getContextData("implementation"));
2685:                    } else if (loc.equals("DeadlineCondition")) {
2686:                        dlCond = text();
2687:                    } else if (loc.equals("ExceptionName")) {
2688:                        dlException = text();
2689:                    } else if (loc.equals("Deadline")) {
2690:                        deadlines
2691:                                .add(new Deadline(dlMode, dlCond, dlException));
2692:                    } else if (loc.equals("ExtendedAttribute")
2693:                            && extAttrName != null) {
2694:                        if (extAttrValue == null) {
2695:                            extAttrValue = text().trim();
2696:                        }
2697:                        if (extAttrName.equals("DeferredChoice")
2698:                                && extAttrValue.equalsIgnoreCase("true")) {
2699:                            deferredChoice = true;
2700:                        }
2701:                        extAttrName = null;
2702:                        extAttrValue = null;
2703:                    }
2704:                }
2705:            }
2706:
2707:            /**
2708:             * Return a new initializer with the given parameters.
2709:             * @param actIds activity id map
2710:             * @param trefs transition reference map
2711:             * @param actSets activity set definition map
2712:             * @param blkActKey the id of the containing block activity or
2713:             * <code>null</code>
2714:             * @return the initializer
2715:             */
2716:            ActivityInitializer activityInitializer(Map actIds, Map trefs,
2717:                    Map actSets, String blkActKey) {
2718:                return new ActivityInitializer(actIds, trefs, actSets,
2719:                        blkActKey);
2720:            }
2721:
2722:            /**
2723:             * Factory method that create new persistent objects of type
2724:             * <code>WfActivity</code>. Must be implement by the persistence
2725:             * layer.
2726:             *
2727:             * @param blockActId if the activity is part of a block activity,
2728:             * else <code>null</code>
2729:             * @param priority a <code>Priority</code> value
2730:             * @param name the activity's name
2731:             * @param description activity description
2732:             * @param startMode the start mode
2733:             * @param finishMode the finish mode
2734:             * @param joinMode the join mode
2735:             * @param splitMode the split mode
2736:             * @param implementation the implementation description
2737:             * @param performer the performer
2738:             * @param deadlines the deadlines
2739:             * @param deferredChoice if true, the split is to be made as
2740:             * deferred choice
2741:             * @param auditEventSelection the audit event selection
2742:             * @param storeAuditEvents if true, audit events are stored in the
2743:             * database
2744:             * @return the created activity.
2745:             */
2746:            protected abstract WfActivityLocal createActivity(
2747:                    String blockActId, Priority priority, String name,
2748:                    String description, StartFinishMode startMode,
2749:                    StartFinishMode finishMode, JoinAndSplitMode joinMode,
2750:                    JoinAndSplitMode splitMode,
2751:                    Implementation[] implementation, String performer,
2752:                    List deadlines, boolean deferredChoice,
2753:                    int auditEventSelection, boolean storeAuditEvents);
2754:
2755:            /**
2756:             * Helper class for retrieving the transition information from
2757:             * the process definition.
2758:             */
2759:            public class TransitionInitializer extends StackedHandler {
2760:
2761:                private Map actIdMap = null;
2762:                private Map trefsMap = null;
2763:                private String blkActId = null;
2764:
2765:                private String transId = null;
2766:                private String fromId = null;
2767:                private String toId = null;
2768:                private String condType = null;
2769:                private String condExpr = null;
2770:
2771:                /**
2772:                 * Create a new initializer with the given parameters.
2773:                 * @param actIds activity id map
2774:                 * @param trefs transition reference map
2775:                 * @param blkActId the Id of the block activity being
2776:                 * created, i.e. to which the transitions belong.
2777:                 */
2778:                public TransitionInitializer(Map actIds, Map trefs,
2779:                        String blkActId) {
2780:                    actIdMap = actIds;
2781:                    trefsMap = trefs;
2782:                    this .blkActId = blkActId;
2783:                }
2784:
2785:                /**
2786:                 * Receive notification of the beginning of an element.
2787:                 *
2788:                 * @param uri the Namespace URI, or the empty string if the
2789:                 * element has no Namespace URI or if Namespace processing is not
2790:                 * being performed.
2791:                 * @param loc the local name (without prefix), or the empty string
2792:                 * if Namespace processing is not being performed.
2793:                 * @param raw the raw XML 1.0 name (with prefix), or the empty
2794:                 * string if raw names are not available.
2795:                 * @param a the attributes attached to the element. If there are
2796:                 * no attributes, it shall be an empty Attributes object.
2797:                 * @throws SAXException not thrown.
2798:                 */
2799:                public void startElement(String uri, String loc, String raw,
2800:                        Attributes a) throws SAXException {
2801:                    if (loc.equals("Transition")) {
2802:                        transId = a.getValue("Id");
2803:                        fromId = a.getValue("From");
2804:                        toId = a.getValue("To");
2805:                    } else if (loc.equals("Condition")) {
2806:                        condType = a.getValue("Type");
2807:                        if (condType == null) {
2808:                            condType = "CONDITION";
2809:                        }
2810:                    }
2811:                }
2812:
2813:                /**
2814:                 * Receive notification of the end of an element.
2815:                 *
2816:                 * @param uri the Namespace URI, or the empty string if the
2817:                 * element has no Namespace URI or if Namespace processing is not
2818:                 * being performed.
2819:                 * @param loc the local name (without prefix), or the empty string
2820:                 * if Namespace processing is not being performed.
2821:                 * @param raw the raw XML 1.0 name (with prefix), or the empty
2822:                 * string if raw names are not available.
2823:                 * @throws SAXException not thrown.
2824:                 */
2825:                public void endElement(String uri, String loc, String raw)
2826:                        throws SAXException {
2827:                    if (loc.equals("Condition")) {
2828:                        condExpr = text();
2829:                    } else if (loc.equals("Transition")) {
2830:                        createTransition(actIdMap, trefsMap, transId, fromId,
2831:                                toId, condType, condExpr, blkActId);
2832:                    }
2833:                }
2834:            }
2835:
2836:            /**
2837:             * Return a new initializer with the given parameters.
2838:             * @param actIds activity id map
2839:             * @param trefs transition reference map
2840:             * @param blkActId the Id of the block activity being
2841:             * created, i.e. to which the transitions belong.
2842:             * @return the initializer
2843:             */
2844:            TransitionInitializer transitionInitializer(Map actIds, Map trefs,
2845:                    String blkActId) {
2846:                return new TransitionInitializer(actIds, trefs, blkActId);
2847:            }
2848:
2849:            private void createTransition(Map actIdMap, Map trefsMap,
2850:                    String transId, String fromId, String toId,
2851:                    String condType, String condExpr, String blkActId) {
2852:                // find associated "from"-activities
2853:                int order = evalTransitionOrder(transId, fromId, trefsMap);
2854:
2855:                ActivityLocal fromAct = (ActivityLocal) actIdMap.get(fromId);
2856:                BAForProcessInstantiation fromBA = null;
2857:                List fromActivities = new ArrayList();
2858:                if (fromAct instanceof  BlockActivity) {
2859:                    // we do not generate exception transitions from block
2860:                    // internals to block externals
2861:                    if (condExpr != null
2862:                            && (condType.equals("EXCEPTION") || condType
2863:                                    .equals("DEFAULTEXCEPTION"))) {
2864:                        fromActivities.add(blockActivityRepresentation(fromAct
2865:                                .key()));
2866:                    } else {
2867:                        fromBA = (BAForProcessInstantiation) fromAct;
2868:                        fromActivities.addAll(fromBA.exitActivities());
2869:                    }
2870:                } else {
2871:                    fromActivities.add(fromAct);
2872:                }
2873:
2874:                ActivityLocal toAct = (ActivityLocal) actIdMap.get(toId);
2875:                BAForProcessInstantiation toBA = null;
2876:                List toActivities = new ArrayList();
2877:                if (toAct instanceof  BlockActivity) {
2878:                    toBA = (BAForProcessInstantiation) toAct;
2879:                    toActivities.addAll(toBA.entryActivities());
2880:                } else {
2881:                    toActivities.add(toAct);
2882:                }
2883:
2884:                // create all the possible transitions 
2885:                for (Iterator fromIt = fromActivities.iterator(); fromIt
2886:                        .hasNext();) {
2887:                    ActivityLocal fa = (ActivityLocal) fromIt.next();
2888:                    for (Iterator toIt = toActivities.iterator(); toIt
2889:                            .hasNext();) {
2890:                        ActivityLocal ta = (ActivityLocal) toIt.next();
2891:
2892:                        // enhance transition id if block activities are
2893:                        // involved
2894:                        String id = transId;
2895:                        if (blkActId != null) {
2896:                            id += "/" + blkActId;
2897:                        }
2898:                        if (fromBA != null) {
2899:                            id += "/" + fromBA.setId() + "/"
2900:                                    + fromBA.getMemberId(fa.key());
2901:                        }
2902:                        if (toBA != null) {
2903:                            id += "/" + toBA.setId() + "/"
2904:                                    + toBA.getMemberId(ta.key());
2905:                        }
2906:
2907:                        // create and register transition(s)
2908:                        int ct = Transition.COND_TYPE_CONDITION;
2909:                        if (condExpr != null) {
2910:                            if (condType.equals("OTHERWISE")) {
2911:                                ct = Transition.COND_TYPE_OTHERWISE;
2912:                            } else if (condType.equals("EXCEPTION")) {
2913:                                ct = Transition.COND_TYPE_EXCEPTION;
2914:                            } else if (condType.equals("DEFAULTEXCEPTION")) {
2915:                                ct = Transition.COND_TYPE_DEFAULTEXCEPTION;
2916:                            }
2917:                        }
2918:                        doCreateTransition(id, transId, order, fa, ta, ct,
2919:                                condExpr);
2920:                    }
2921:                }
2922:            }
2923:
2924:            /**
2925:             * Returns the transition order of the given transition id as defined with 
2926:             * the set of transitions assigned to a given activity id - using the given
2927:             * map of transition refrences.
2928:             * @param transId the transition id to define the order for
2929:             * @param actId the activity id to determine the order for
2930:             * @param trefsMap the map of transition references
2931:             * @return the order value
2932:             */
2933:            private int evalTransitionOrder(String transId, String actId,
2934:                    Map trefsMap) {
2935:                int order = 0;
2936:                List trefs = (List) trefsMap.get(actId);
2937:                if (trefs == null) {
2938:                    return Integer.MAX_VALUE;
2939:                }
2940:                Iterator refIt = trefs.iterator();
2941:                while (refIt.hasNext()) {
2942:                    String refId = (String) refIt.next();
2943:                    if (transId.equals(refId)) {
2944:                        break;
2945:                    }
2946:                    order += 1;
2947:                }
2948:                return order;
2949:            }
2950:
2951:            /**
2952:             * Persist a new transition with given id, from-activity,
2953:             * to-activity. The created transitions must be made persistent by
2954:             * the persistence layer.
2955:             * @param id the transition id
2956:             * @param group the transition group id
2957:             * @param order the transition priority
2958:             * @param fromAct the from activity
2959:             * @param toAct the to activity
2960:             * @param condType the type of the condition
2961:             * @param condition condition of this transition
2962:             * @return the created transition.
2963:             */
2964:            protected abstract TransitionLocal doCreateTransition(String id,
2965:                    String group, int order, ActivityLocal fromAct,
2966:                    ActivityLocal toAct, int condType, String condition);
2967:
2968:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.