Source Code Cross Referenced for WfProcessEJB.java in  » Workflow-Engines » wfmopen-2.1.1 » de » danet » an » workflow » ejbs » core » 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.ejbs.core 
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: WfProcessEJB.java,v 1.22.2.2 2007/11/02 22:12:11 mlipp Exp $
0021:         *      
0022:         * $Log: WfProcessEJB.java,v $
0023:         * Revision 1.22.2.2  2007/11/02 22:12:11  mlipp
0024:         * Added missing import.
0025:         *
0026:         * Revision 1.22.2.1  2007/11/02 16:00:33  drmlipp
0027:         * Merged bug fixes from HEAD.
0028:         *
0029:         * Revision 1.23  2007/09/21 06:19:35  mlipp
0030:         * Fixed problem with NamingException during process deletion.
0031:         *
0032:         * Revision 1.22  2007/07/04 21:32:22  mlipp
0033:         * Using local interface whereever possible.
0034:         *
0035:         * Revision 1.21  2007/07/04 20:51:05  mlipp
0036:         * Using local interface whereever possible.
0037:         *
0038:         * Revision 1.20  2007/06/10 05:55:30  drmlipp
0039:         * Using local interface for optimization.
0040:         *
0041:         * Revision 1.19  2007/05/03 21:58:16  mlipp
0042:         * Internal refactoring for making better use of local EJBs.
0043:         *
0044:         */
0045:        package de.danet.an.workflow.ejbs.core;
0046:
0047:        import java.io.IOException;
0048:        import java.io.Serializable;
0049:
0050:        import java.util.ArrayList;
0051:        import java.util.Collection;
0052:        import java.util.Collections;
0053:        import java.util.Comparator;
0054:        import java.util.Date;
0055:        import java.util.HashMap;
0056:        import java.util.HashSet;
0057:        import java.util.Iterator;
0058:        import java.util.List;
0059:        import java.util.Map;
0060:        import java.util.Set;
0061:
0062:        import java.rmi.RemoteException;
0063:        import java.security.Principal;
0064:        import java.security.ProviderException;
0065:        import java.sql.Connection;
0066:        import java.sql.PreparedStatement;
0067:        import java.sql.ResultSet;
0068:        import java.sql.SQLException;
0069:        import java.sql.Timestamp;
0070:
0071:        import javax.ejb.CreateException;
0072:        import javax.ejb.EJBException;
0073:        import javax.ejb.EJBLocalObject;
0074:        import javax.ejb.EntityBean;
0075:        import javax.ejb.EntityContext;
0076:        import javax.ejb.FinderException;
0077:        import javax.ejb.NoSuchEntityException;
0078:        import javax.ejb.NoSuchObjectLocalException;
0079:        import javax.ejb.ObjectNotFoundException;
0080:        import javax.ejb.RemoveException;
0081:        import javax.ejb.TimedObject;
0082:        import javax.ejb.Timer;
0083:        import javax.naming.NamingException;
0084:        import javax.sql.DataSource;
0085:
0086:        import de.danet.an.util.CollectionsUtil;
0087:        import de.danet.an.util.EJBUtil;
0088:        import de.danet.an.util.JDBCUtil;
0089:        import de.danet.an.util.PersistentMap;
0090:        import de.danet.an.util.ResourceNotAvailableException;
0091:        import de.danet.an.util.SimplePrincipal;
0092:        import de.danet.an.util.UniversalPrepStmt;
0093:        import de.danet.an.util.persistentmaps.PersistentMapSQLException;
0094:
0095:        import de.danet.an.workflow.internalapi.ExtActivityLocal;
0096:        import de.danet.an.workflow.internalapi.ExtProcessLocal;
0097:        import de.danet.an.workflow.internalapi.ExtTransitionLocal;
0098:        import de.danet.an.workflow.localapi.ActivityLocal;
0099:        import de.danet.an.workflow.localapi.ProcessDefinitionDirectoryLocal;
0100:        import de.danet.an.workflow.localapi.ProcessLocal;
0101:        import de.danet.an.workflow.localapi.TransitionLocal;
0102:        import de.danet.an.workflow.omgcore.AlreadyRunningException;
0103:        import de.danet.an.workflow.omgcore.CannotCompleteException;
0104:        import de.danet.an.workflow.omgcore.CannotStartException;
0105:        import de.danet.an.workflow.omgcore.CannotStopException;
0106:        import de.danet.an.workflow.omgcore.HistoryNotAvailableException;
0107:        import de.danet.an.workflow.omgcore.InvalidDataException;
0108:        import de.danet.an.workflow.omgcore.InvalidPriorityException;
0109:        import de.danet.an.workflow.omgcore.InvalidStateException;
0110:        import de.danet.an.workflow.omgcore.NotRunningException;
0111:        import de.danet.an.workflow.omgcore.ProcessData;
0112:        import de.danet.an.workflow.omgcore.TransitionNotAllowedException;
0113:        import de.danet.an.workflow.omgcore.WfAuditEvent;
0114:        import de.danet.an.workflow.omgcore.WfProcessMgr;
0115:        import de.danet.an.workflow.omgcore.WfRequester;
0116:        import de.danet.an.workflow.omgcore.WfExecutionObject.NotRunningState;
0117:        import de.danet.an.workflow.omgcore.WfExecutionObject.State;
0118:        import de.danet.an.workflow.spis.aii.ResultProvider.ExceptionResult;
0119:
0120:        import de.danet.an.workflow.api.Activity;
0121:        import de.danet.an.workflow.api.Process;
0122:        import de.danet.an.workflow.api.CannotRemoveException;
0123:        import de.danet.an.workflow.api.DefaultProcessData;
0124:        import de.danet.an.workflow.api.ImportException;
0125:        import de.danet.an.workflow.api.InvalidKeyException;
0126:        import de.danet.an.workflow.api.ProcessDefinition;
0127:        import de.danet.an.workflow.api.Activity.Implementation;
0128:        import de.danet.an.workflow.api.Activity.JoinAndSplitMode;
0129:        import de.danet.an.workflow.api.Activity.StartFinishMode;
0130:        import de.danet.an.workflow.apix.ExtActivity;
0131:
0132:        import de.danet.an.workflow.domain.AbstractProcess;
0133:        import de.danet.an.workflow.domain.Deadline;
0134:        import de.danet.an.workflow.domain.DefaultAuditEvent;
0135:        import de.danet.an.workflow.domain.DefaultProcessDefinition;
0136:        import de.danet.an.workflow.domain.SubProcRequester;
0137:        import de.danet.an.workflow.domain.TransitionDefinition;
0138:        import de.danet.an.workflow.domain.TransitionDefinitionLocal;
0139:
0140:        import de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectoryHome;
0141:        import de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectoryLocalHome;
0142:        import de.danet.an.workflow.ejbs.admin.ProcessMgrStub;
0143:        import de.danet.an.workflow.ejbs.admin.WorkflowEngineLocal;
0144:        import de.danet.an.workflow.ejbs.admin.WorkflowEngineLocalHome;
0145:        import de.danet.an.workflow.ejbs.util.QueuerLocal;
0146:        import de.danet.an.workflow.ejbs.util.QueuerLocalHome;
0147:
0148:        /**
0149:         * The entity bean <code>WfProcessEJB</code> represent a process
0150:         * in the workflow.
0151:         *
0152:         * @ejb.bean name="ProcessBean" display-name="ProcessBean" type="BMP"
0153:         * jndi-name="ejb/@@@_JNDI_Name_Prefix_@@@ProcessBean"
0154:         * reentrant="true" view-type="both"
0155:         * @jonas.bean ejb-name="ProcessBean"
0156:         * @ejb.pk class="java.lang.Long" generate="false"
0157:         * @ejb.home remote-class="de.danet.an.workflow.ejbs.core.WfProcessHome"
0158:         * local-class="de.danet.an.workflow.ejbs.core.WfProcessLocalHome"
0159:         * @ejb.interface
0160:         * extends="javax.ejb.EJBObject, de.danet.an.workflow.apix.ExtProcess"
0161:         * remote-class="de.danet.an.workflow.ejbs.core.WfProcess"
0162:         * local-extends="javax.ejb.EJBLocalObject,
0163:         * de.danet.an.workflow.internalapi.ExtProcessLocal"
0164:         * local-class="de.danet.an.workflow.ejbs.core.WfProcessLocal"
0165:         * @ejb.transaction type="Required"
0166:         * @ejb.security-identity run-as="WfMOpenAdmin"
0167:         * sunone-principal="WfMCorePrincipalForAdmin"
0168:         * @weblogic.run-as-identity-principal WfMCorePrincipalForAdmin
0169:         * @ejb.ejb-ref ejb-name="WorkflowEngine" view-type="local"
0170:         * @ejb.ejb-ref ejb-name="Queuer" view-type="local"
0171:         * @ejb.ejb-ref ejb-name="ActivityBean" view-type="remote"
0172:         * @ejb.ejb-ref ejb-name="ActivityBean" view-type="local"
0173:         * @ejb.ejb-ref ejb-name="ProcessDefinitionDirectory" view-type="remote"
0174:         * @ejb.ejb-ref ejb-name="ProcessDefinitionDirectory" view-type="local"
0175:         * @ejb.ejb-external-ref ref-name="ejb/JdbcKeyGenLocal" link="KeyGen"
0176:         * type="Session" view-type="local" home="de.danet.an.util.KeyGenLocalHome" 
0177:         * business="de.danet.an.util.KeyGenLocal"
0178:         * @ejb.resource-ref res-ref-name="jdbc/WfEngine"
0179:         * res-type="javax.sql.DataSource" res-auth="Container"
0180:         * @jonas.resource res-ref-name="jdbc/WfEngine" jndi-name="jdbc_1"
0181:         * @weblogic.enable-call-by-reference True
0182:         * @weblogic.resource-description
0183:         * res-ref-name="jdbc/WfEngine" jndi-name="DefaultDS"
0184:         * @ejb.permission role-name="WfMOpenAdmin"
0185:         * @weblogic.transaction-isolation TRANSACTION_READ_COMMITTED
0186:         * @weblogic.cache concurrency-strategy="Exclusive"
0187:         */
0188:        public class WfProcessEJB extends AbstractProcess implements 
0189:                EntityBean, TimedObject {
0190:
0191:            private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
0192:                    .getLog(WfProcessEJB.class);
0193:
0194:            /**
0195:             * A lazily loading implementation for deadline storage. Not all
0196:             * methods are implemented.
0197:             */
0198:            private class DeadlineMap extends HashMap {
0199:                /**
0200:                 * Returns the deadlines for the activity with the given key.
0201:                 * @param key activity key
0202:                 * @return the value to which this map maps the specified key,
0203:                 * or null if the map contains no mapping for this key
0204:                 * @throws ClassCastException if the key is of an
0205:                 * inappropriate type for this map.
0206:                 * @throws NullPointerException key is null
0207:                 */
0208:                public Object get(Object key) throws ClassCastException,
0209:                        NullPointerException {
0210:                    Object res = super .get(key);
0211:                    if (res == null) {
0212:                        // try to load from db
0213:                        try {
0214:                            res = loadDeadlines(ds, (Long) key);
0215:                            super .put(key, res);
0216:                        } catch (SQLException e) {
0217:                            throw new EJBException(e);
0218:                        } catch (IOException e) {
0219:                            throw new EJBException(e);
0220:                        }
0221:                    }
0222:                    return res;
0223:                }
0224:
0225:                /**
0226:                 * Not supported.
0227:                 * @param key key whose presence in this map is to be tested.
0228:                 * @return true if this map contains a mapping for the specified key. 
0229:                 */
0230:                public boolean containsKey(Object key) {
0231:                    throw new UnsupportedOperationException();
0232:                }
0233:
0234:                /**
0235:                 * Not supported.
0236:                 * @param value value whose presence in this map is to be tested.
0237:                 * @return true if this map maps one or more keys to the
0238:                 * specified value.
0239:                 */
0240:                public boolean containsValue(Object value) {
0241:                    throw new UnsupportedOperationException();
0242:                }
0243:
0244:                /**
0245:                 * Not supported.
0246:                 * @return  set view of the keys contained in this map.
0247:                 */
0248:                public Set keySet() {
0249:                    throw new UnsupportedOperationException();
0250:                }
0251:
0252:                /**
0253:                 * Not supported.
0254:                 * @return a collection view of the values contained in this map.
0255:                 */
0256:                public Collection values() {
0257:                    throw new UnsupportedOperationException();
0258:                }
0259:
0260:                /**
0261:                 * Not supported.
0262:                 * @return a set view of the mappings contained in this map.
0263:                 */
0264:                public Set entrySet() {
0265:                    throw new UnsupportedOperationException();
0266:                }
0267:            }
0268:
0269:            /** Entity context. */
0270:            private EntityContext ctx;
0271:
0272:            /** The data source of the database. */
0273:            private DataSource ds = null;
0274:
0275:            /** Indicates if the database supports select for update. */
0276:            private Boolean haveSelForUp = null;
0277:
0278:            /** Database name. */
0279:            private static final String DB_NAME = "java:comp/env/jdbc/WfEngine";
0280:
0281:            private QueuerLocal queuerCache = null;
0282:
0283:            /** Associated activities. */
0284:            private Map activityMapCache;
0285:            private Map activityLocalMapCache;
0286:
0287:            /** Used for fast lookup of process definition. */
0288:            private String packageId = null;
0289:
0290:            /** Used for fast lookup of process definition. */
0291:            private String processId = null;
0292:
0293:            /** Creating principal. */
0294:            private String processCreator = null;
0295:
0296:            /** The cached workflow engine. */
0297:            private WorkflowEngineLocal engineLocalCache = null;
0298:
0299:            /** The cached home interface of the activity. */
0300:            private WfActivityHome activityHomeCache = null;
0301:            private WfActivityLocalHome activityLocalHomeCache = null;
0302:
0303:            /** The cached home interface of the processDefinitionDirectory. */
0304:            private ProcessDefinitionDirectoryHome processDefinitionDirectoryHomeCache = null;
0305:            private ProcessDefinitionDirectoryLocalHome processDefinitionDirectoryLocalHomeCache = null;
0306:
0307:            /** Delayed events. */
0308:            private List delayedEvents = null;
0309:
0310:            /** Cached transition information. */
0311:            private List transitionsCache = null;
0312:
0313:            /** Cached transition information. */
0314:            private List transitionsLocalCache = null;
0315:
0316:            /** Local process definition as string, to be stored. */
0317:            private String myProcDef = null;
0318:
0319:            /** List of updated transitions (need to be stored). */
0320:            private Set updatedTransitions = new HashSet();
0321:
0322:            //
0323:            // Provide the persistent attributes
0324:            //
0325:
0326:            /** Indicates change of a persistent attribute. */
0327:            private boolean persistentAttributeModified = false;
0328:
0329:            /** Indicates change of a persistent attribute description. */
0330:            private boolean paDescriptionModified = false;
0331:
0332:            /** Persistent attribute <code>createTime</code>. */
0333:            private Date paCreateTime;
0334:
0335:            /** Persistent attribute <code>name</code>. */
0336:            private String paName;
0337:
0338:            /** Persistent attribute <code>id</code>. */
0339:            private String paId;
0340:
0341:            /** Persistent attribute <code>description</code>. */
0342:            private String paDescription;
0343:
0344:            /** Persistent attribute <code>priority</code>. */
0345:            private Priority paPriority;
0346:
0347:            /** Persistent attribute <code>typedState</code>. */
0348:            private State paTypedState;
0349:
0350:            /** Persistent attribute <code>lastStateTime</code>. */
0351:            private Date paLastStateTime;
0352:
0353:            /** Persistent attribute <code>requester</code>. */
0354:            private WfRequester paRequester;
0355:
0356:            /** Persistent attribute <code>processMgrName</code>. */
0357:            private String paProcessMgrName;
0358:
0359:            /** Persistent attribute <code>processMgrVersion</code>. */
0360:            private String paProcessMgrVersion;
0361:
0362:            /** Persistent attribute <code>processDef</code>. */
0363:            private ProcessDefinition paProcessDef;
0364:
0365:            /** Persistent attribute <code>processData</code>. */
0366:            private ProcessData paProcessData;
0367:
0368:            /** Persistent attribute <code>blockDeadlines</code>. */
0369:            private Map paBlockDeadlines;
0370:
0371:            /** 
0372:             * Persistent attribute <code>flags</code>. This attribute is not
0373:             * exposed, it serves as space efficient storage for various
0374:             * attributes that are exposed. 
0375:             */
0376:            private int paFlags;
0377:
0378:            private static final int FLAGS_DEBUG = 1;
0379:            private static final int FLAGS_AUDIT_SELECTION_SHIFT = 1;
0380:            private static final int FLAGS_AUDIT_SELECTION_MASK = 7 << 1;
0381:            private static final int FLAGS_STORE_AUDIT_EVENTS = 16;
0382:
0383:            /* Transition flags. */
0384:            private static int FLAGS_HAS_PENDING_TOKEN = 1;
0385:
0386:            /**
0387:             * Contructor.
0388:             */
0389:            public WfProcessEJB() {
0390:            }
0391:
0392:            //
0393:            // Accessor methods for cached attributes
0394:            //
0395:
0396:            /**
0397:             * The workflow engine.
0398:             * @return the workflow engine
0399:             */
0400:            private WorkflowEngineLocal engineLocal()
0401:                    throws ResourceNotAvailableException {
0402:                if (engineLocalCache == null) {
0403:                    engineLocalCache = (WorkflowEngineLocal) EJBUtil
0404:                            .createSession(WorkflowEngineLocalHome.class,
0405:                                    "java:comp/env/ejb/WorkflowEngineLocal");
0406:                }
0407:                return engineLocalCache;
0408:            }
0409:
0410:            /**
0411:             * The home interface of the WfActivityBean.
0412:             * @return home interface of the WfActivityBean
0413:             */
0414:            private WfActivityHome activityHome()
0415:                    throws ResourceNotAvailableException {
0416:                if (activityHomeCache == null) {
0417:                    activityHomeCache = (WfActivityHome) EJBUtil
0418:                            .retrieveEJBHome(WfActivityHome.class,
0419:                                    "java:comp/env/ejb/ActivityBean");
0420:                }
0421:                return activityHomeCache;
0422:            }
0423:
0424:            /**
0425:             * The home interface of the WfActivityBean.
0426:             * @return home interface of the WfActivityBean
0427:             */
0428:            private WfActivityLocalHome activityLocalHome()
0429:                    throws ResourceNotAvailableException {
0430:                if (activityLocalHomeCache == null) {
0431:                    activityLocalHomeCache = (WfActivityLocalHome) EJBUtil
0432:                            .retrieveEJBLocalHome(WfActivityLocalHome.class,
0433:                                    "java:comp/env/ejb/ActivityBeanLocal");
0434:                }
0435:                return activityLocalHomeCache;
0436:            }
0437:
0438:            /**
0439:             * The home interface of the ProcessDefinitionDirectoryBean.
0440:             * @return home interface of the ProcessDefinitionDirectoryBean
0441:             */
0442:            private ProcessDefinitionDirectoryHome processDefinitionDirectoryHome()
0443:                    throws ResourceNotAvailableException {
0444:                if (processDefinitionDirectoryHomeCache == null) {
0445:                    processDefinitionDirectoryHomeCache = (ProcessDefinitionDirectoryHome) EJBUtil
0446:                            .retrieveEJBHome(
0447:                                    ProcessDefinitionDirectoryHome.class,
0448:                                    "java:comp/env/ejb/ProcessDefinitionDirectory");
0449:                }
0450:                return processDefinitionDirectoryHomeCache;
0451:            }
0452:
0453:            /**
0454:             * The home interface of the ProcessDefinitionDirectoryBean.
0455:             * @return home interface of the ProcessDefinitionDirectoryBean
0456:             */
0457:            private ProcessDefinitionDirectoryLocalHome processDefinitionDirectoryLocalHome()
0458:                    throws ResourceNotAvailableException {
0459:                if (processDefinitionDirectoryLocalHomeCache == null) {
0460:                    processDefinitionDirectoryLocalHomeCache = (ProcessDefinitionDirectoryLocalHome) EJBUtil
0461:                            .retrieveEJBLocalHome(
0462:                                    ProcessDefinitionDirectoryLocalHome.class,
0463:                                    "java:comp/env/ejb/ProcessDefinitionDirectoryLocal");
0464:                }
0465:                return processDefinitionDirectoryLocalHomeCache;
0466:            }
0467:
0468:            /**
0469:             * Returns the associated activities as map by key.
0470:             * @return activities for this process by key.
0471:             */
0472:            private Map activityMap() throws RemoteException {
0473:                if (activityMapCache == null) {
0474:                    activityMapCache = new HashMap();
0475:                    try {
0476:                        for (Iterator i = activityHome().findByProcess(
0477:                                (Long) ctx.getPrimaryKey()).iterator(); i
0478:                                .hasNext();) {
0479:                            ExtActivity a = (ExtActivity) i.next();
0480:                            cacheActivity(a);
0481:                        }
0482:                    } catch (FinderException e) {
0483:                        throw new EJBException(e);
0484:                    }
0485:                }
0486:                return activityMapCache;
0487:            }
0488:
0489:            /**
0490:             * Returns the associated activities as map by key.
0491:             * @return activities for this process by key.
0492:             */
0493:            private Map activityLocalMap() {
0494:                if (activityLocalMapCache == null) {
0495:                    activityLocalMapCache = new HashMap();
0496:                    try {
0497:                        for (Iterator i = activityLocalHome().findByProcess(
0498:                                (Long) ctx.getPrimaryKey()).iterator(); i
0499:                                .hasNext();) {
0500:                            ExtActivityLocal a = (ExtActivityLocal) i.next();
0501:                            cacheActivityLocal(a);
0502:                        }
0503:                    } catch (FinderException e) {
0504:                        throw new EJBException(e);
0505:                    } catch (ResourceNotAvailableException e) {
0506:                        throw new EJBException(e);
0507:                    }
0508:                }
0509:                return activityLocalMapCache;
0510:            }
0511:
0512:            /**
0513:             * Returns the associated activities.
0514:             * @return list of activities for this process
0515:             */
0516:            private Collection activitiesLocal() {
0517:                return activityLocalMap().values();
0518:            }
0519:
0520:            /**
0521:             * Put the given activity in the cache. An
0522:             * <code>ActivityProxy</code> around the activity ensures that the
0523:             * cache is cleared (and thus reloaded when retrying the call) if
0524:             * a <code>RemoteException</code> occurs.
0525:             */
0526:            private ExtActivity cacheActivity(ExtActivity act)
0527:                    throws RemoteException {
0528:                ExtActivity a = ActivityProxy.wrap(act, (Process) toProcess(),
0529:                        false);
0530:                activityMapCache.put(a.key(), a);
0531:                return a;
0532:            }
0533:
0534:            /**
0535:             * Put the given local activity in the cache. An
0536:             * <code>ActivityProxy</code> around the activity ensures that the
0537:             * cache is cleared (and thus reloaded when retrying the call) if
0538:             * a <code>RemoteException</code> occurs.
0539:             */
0540:            private ExtActivityLocal cacheActivityLocal(ExtActivityLocal act) {
0541:                activityLocalMap().put(act.key(), act);
0542:                return act;
0543:            }
0544:
0545:            /**
0546:             * The remote interface of the ProcessDefinitionDirectoryBean.
0547:             * @return remote interface of the ProcessDefinitionDirectoryBean
0548:             */
0549:            private ProcessDefinitionDirectoryLocal getProcessDefinitionDirectoryLocal()
0550:                    throws CreateException, NamingException, RemoteException {
0551:                return (ProcessDefinitionDirectoryLocal) processDefinitionDirectoryLocalHome()
0552:                        .create();
0553:            }
0554:
0555:            /**
0556:             * Access cached event queuer.
0557:             * @return the event queuer
0558:             */
0559:            private QueuerLocal queuer() throws ResourceNotAvailableException {
0560:                if (queuerCache == null) {
0561:                    queuerCache = (QueuerLocal) EJBUtil.createSession(
0562:                            QueuerLocalHome.class, "java:comp/env/ejb/Queuer");
0563:                }
0564:                return queuerCache;
0565:            }
0566:
0567:            //
0568:            // EJB container contract
0569:            //
0570:
0571:            /**
0572:             * Set the associated session context. The container calls this method 
0573:             * after the instance creation.
0574:             * @see javax.ejb.EntityBean
0575:             * @throws EJBException Throws on any error.
0576:             * @param context - A SessionContext interface for the instance
0577:             */
0578:            public void setEntityContext(EntityContext context)
0579:                    throws EJBException {
0580:                try {
0581:                    ctx = context;
0582:                    ds = JDBCUtil.refreshDS(null, DB_NAME);
0583:                    // we can always use the same object for process data.
0584:                    paProcessData = new ProcessDataStore(ds);
0585:                } catch (Exception ex) {
0586:                    throw new EJBException(ex);
0587:                }
0588:            }
0589:
0590:            /**
0591:             * Unset the associated session context. 
0592:             * @see javax.ejb.EntityBean
0593:             */
0594:            public void unsetEntityContext() throws EJBException {
0595:                engineLocalCache = null;
0596:                activityHomeCache = null;
0597:                processDefinitionDirectoryLocalHomeCache = null;
0598:                ds = null;
0599:                ctx = null;
0600:            }
0601:
0602:            /**
0603:             * This method looks up a process EJB by its primary key (dbid).
0604:             * @param primaryKey the process primary key.
0605:             * @return the process EJB (remote interface).
0606:             * @throws FinderException if no process found.
0607:             */
0608:            public Long ejbFindByPrimaryKey(Long primaryKey)
0609:                    throws FinderException {
0610:
0611:                boolean result = false;
0612:                try {
0613:                    result = selectByPrimaryKey(primaryKey);
0614:                } catch (SQLException ex) {
0615:                    throw new EJBException(ex);
0616:                }
0617:                if (!result) {
0618:                    throw new ObjectNotFoundException("Row for id "
0619:                            + primaryKey + " not found.");
0620:                }
0621:                return primaryKey;
0622:            }
0623:
0624:            /**
0625:             * This method looks up a process by its
0626:             * {@link de.danet.an.workflow.omgcore.WfProcess#key key}.
0627:             * @param key the process key.
0628:             * @return the process EJB (remote interface).
0629:             * @throws FinderException if no process found.
0630:             */
0631:            public Long ejbFindByProcessKey(String key) throws FinderException {
0632:
0633:                Long pk = null;
0634:                try {
0635:                    pk = Long.valueOf(key);
0636:                } catch (NumberFormatException nex) {
0637:                    throw new ObjectNotFoundException(
0638:                            "Invalid key format for key = " + key);
0639:                }
0640:                return ejbFindByPrimaryKey(pk);
0641:            }
0642:
0643:            /**
0644:             * This method looks up a process by the key {@link
0645:             * de.danet.an.workflow.omgcore.WfActivity#key key} of one of its
0646:             * activities.
0647:             * @param key the activity key.
0648:             * @return the process EJB (remote interface).
0649:             * @throws FinderException if no process found.
0650:             */
0651:            public Long ejbFindByActivityKey(String key) throws FinderException {
0652:
0653:                Long pk = null;
0654:                try {
0655:                    pk = selectByActivityKey(Long.valueOf(key));
0656:                } catch (NumberFormatException nex) {
0657:                    throw new ObjectNotFoundException(
0658:                            "Invalid key format for key = " + key);
0659:                } catch (SQLException ex) {
0660:                    throw new EJBException(ex);
0661:                }
0662:                if (pk == null) {
0663:                    throw new ObjectNotFoundException("Row for id " + key
0664:                            + " not found.");
0665:                }
0666:                return pk;
0667:            }
0668:
0669:            /**
0670:             * This method looks up all the process by its process type.
0671:             * @param processMgrName the process type.
0672:             * @return a Collection object with remote interface of WfProcess.
0673:             * @throws FinderException because of the EJB syntax.
0674:             */
0675:            public Collection ejbFindByProcessMgrName(String processMgrName)
0676:                    throws FinderException {
0677:                Collection col = null;
0678:                try {
0679:                    col = selectByProcessMgrName(processMgrName);
0680:                } catch (SQLException ex) {
0681:                    throw new EJBException(ex);
0682:                }
0683:                return col;
0684:            }
0685:
0686:            /**
0687:             * This method looks up all processes without a local copy of the
0688:             * process definition by their process type.
0689:             * @param processMgrName the process type.
0690:             * @return a Collection object with remote interface of WfProcess.
0691:             * @throws FinderException because of the EJB syntax.
0692:             */
0693:            public Collection ejbFindWithoutDefinitionByProcessMgrName(
0694:                    String processMgrName) throws FinderException {
0695:                Collection col = null;
0696:                try {
0697:                    col = selectWithoutDefinitionByProcessMgrName(processMgrName);
0698:                } catch (SQLException ex) {
0699:                    throw new EJBException(ex);
0700:                }
0701:                return col;
0702:            }
0703:
0704:            /**
0705:             * This method looks up all processes that have a requester with
0706:             * the given hash value.
0707:             * @param hash the hash value.
0708:             * @return a Collection object with remote interface of WfProcess.
0709:             * @throws FinderException because of the EJB syntax.
0710:             */
0711:            public Collection ejbFindByRequesterHash(int hash)
0712:                    throws FinderException {
0713:                Collection col = null;
0714:                try {
0715:                    col = selectByRequesterHash(hash);
0716:                } catch (SQLException ex) {
0717:                    throw new EJBException(ex);
0718:                }
0719:                return col;
0720:            }
0721:
0722:            /**
0723:             * Look up all processes of a given type that have a given value
0724:             * in a particular process data item. Note that this method may
0725:             * only be used for data items of type string.
0726:             *
0727:             * @param processMgr the process type
0728:             * @param itemName the name of the process data item
0729:             * @param itemValue the value of the process data item
0730:             * @return a Collection object with remote interface of WfProcess.
0731:             * @throws FinderException because of the EJB syntax.
0732:             */
0733:            public Collection ejbFindByProcessTypeAndDataItem(
0734:                    String processMgr, String itemName, String itemValue)
0735:                    throws FinderException {
0736:                Connection con = null;
0737:                try {
0738:                    try {
0739:                        con = ds.getConnection();
0740:                        return ((ProcessDataStore) paProcessData)
0741:                                .findProcessesByTypeAndDataItem(con,
0742:                                        processMgr, itemName, itemValue);
0743:                    } finally {
0744:                        JDBCUtil.closeAll(null, null, con);
0745:                    }
0746:                } catch (SQLException ex) {
0747:                    throw new EJBException(ex);
0748:                } catch (IOException ex) {
0749:                    throw new EJBException(ex);
0750:                }
0751:            }
0752:
0753:            /**
0754:             * This method looks up all processes.
0755:             * @return a Collection object with remote interface of WfProcess.
0756:             * @throws FinderException because of the EJB syntax.
0757:             */
0758:            public Collection ejbFindAll() throws FinderException {
0759:                Collection col = null;
0760:                try {
0761:                    col = selectAll();
0762:                } catch (SQLException ex) {
0763:                    throw new EJBException(ex);
0764:                }
0765:                return col;
0766:            }
0767:
0768:            /**
0769:             * The activate method is called when the instance is activated from its 
0770:             * "passive" state. The instance should acquire any resource that it has 
0771:             * released earlier in the ejbPassivate() method.
0772:             * This method gets the primary key from container.
0773:             * @see javax.ejb.EntityBean
0774:             */
0775:            public void ejbActivate() throws EJBException {
0776:                // "bind" entity container to primary key
0777:                ((ProcessDataStore) paProcessData).setMapId((Long) ctx
0778:                        .getPrimaryKey());
0779:                activityMapCache = null;
0780:                activityLocalMapCache = null;
0781:                transitionsCache = null;
0782:                transitionsLocalCache = null;
0783:                updatedTransitions.clear();
0784:            }
0785:
0786:            /**
0787:             * The passivate method is called before the instance enters the 
0788:             * "passive" state. The instance should release any resources that it 
0789:             * can re-acquire later in the ejbActivate() method.
0790:             * @see javax.ejb.EntityBean
0791:             */
0792:            public void ejbPassivate() throws EJBException {
0793:                paProcessDef = null;
0794:                activityMapCache = null;
0795:                activityLocalMapCache = null;
0796:                transitionsCache = null;
0797:                transitionsLocalCache = null;
0798:                updatedTransitions.clear();
0799:                paBlockDeadlines = null;
0800:                dispose();
0801:            }
0802:
0803:            /**
0804:             * Create an process and save it into database.
0805:             * It throws <code>EJBException</code> if any error occurs.
0806:             * @param procDef process definition
0807:             * @param req requester of the process
0808:             * @return Long primary key of the process
0809:             * @throws CreateException no
0810:             * @ejb.create-method
0811:             * view-type="local"
0812:             */
0813:            public Long ejbCreate(
0814:                    de.danet.an.workflow.api.ProcessDefinition procDef,
0815:                    WfRequester req) throws CreateException {
0816:                try {
0817:                    Long processPk = null;
0818:                    // create new processPk
0819:                    processPk = new Long(EJBUtil.newPrimaryKey("process"));
0820:                    // "bind" entity container to primary key
0821:                    ((ProcessDataStore) paProcessData).setMapId(processPk);
0822:                    ((ProcessDataStore) paProcessData).setNewMap();
0823:                    return processPk;
0824:                } catch (RemoteException ex) {
0825:                    logger.error(ex.getMessage(), ex);
0826:                    throw new CreateException(ex.getMessage());
0827:                }
0828:            }
0829:
0830:            /**
0831:             * Create an process and save it into database. First are created 
0832:             * activities, transitions and transitions references.
0833:             * @param procDef process definition
0834:             * @param req requester of the process
0835:             * @throws CreateException if the process can not be created.
0836:             */
0837:            public void ejbPostCreate(ProcessDefinition procDef, WfRequester req)
0838:                    throws CreateException {
0839:                try {
0840:                    // initialize private attributes
0841:                    packageId = procDef.packageId();
0842:                    processId = procDef.processId();
0843:                    if (req instanceof  SubProcRequester) {
0844:                        processCreator = ((SubProcRequester) req).creator();
0845:                    } else {
0846:                        processCreator = ctx.getCallerPrincipal().getName();
0847:                    }
0848:                    activityLocalMapCache = new HashMap();
0849:                    // initialize persistent attributes
0850:                    paRequester = req;
0851:                    paCreateTime = new Date();
0852:                    transitionsLocalCache = new ArrayList();
0853:                    transitionsCache = null;
0854:                    updatedTransitions.clear();
0855:                    paProcessDef = procDef;
0856:                    paBlockDeadlines = CollectionsUtil
0857:                            .trackedMap(new DeadlineMap());
0858:                    // initialize underlying domain object. Delay events
0859:                    // because event processing tries to lookup the process in
0860:                    // the database, and it isn't there yet. This is probably
0861:                    // only necessary in the JBoss environment (and may even
0862:                    // not be sufficient) because the creation of the process
0863:                    // and the queuing of events should be in one transaction
0864:                    // and become visible to the event handler EJB at the same
0865:                    // time.
0866:                    delayedEvents = new ArrayList();
0867:                    init(procDef);
0868:                    Collections.sort(transitionsLocalCache, new Comparator() {
0869:                        public int compare(Object o1, Object o2) {
0870:                            return ((TransitionDefinitionLocal) o1).order()
0871:                                    - ((TransitionDefinitionLocal) o2).order();
0872:                        }
0873:                    });
0874:                    refresh();
0875:                    // save the new process into database
0876:                    insertProcess(paId);
0877:                    insertTransitions();
0878:                    persistentAttributeModified = false;
0879:                    while (delayedEvents.size() > 0) {
0880:                        queuer().queue(
0881:                                (DefaultAuditEvent) delayedEvents.remove(0));
0882:                    }
0883:                    delayedEvents = null;
0884:                } catch (RemoteException re) {
0885:                    throw new EJBException(re);
0886:                } catch (SQLException e) {
0887:                    throw new EJBException(e);
0888:                } catch (IOException ioe) {
0889:                    logger.error(ioe.getMessage(), ioe);
0890:                    throw new CreateException(ioe.getMessage());
0891:                }
0892:            }
0893:
0894:            /**
0895:             * A container invokes this method before it ends the life of the session 
0896:             * object. This happens as a result of a client's invoking a remove 
0897:             * operation, or when a container decides to terminate the session object 
0898:             * after a timeout.
0899:             * @throws RemoveException if the activity is not closed.
0900:             * @see javax.ejb.EntityBean
0901:             */
0902:            public void ejbRemove() throws RemoveException {
0903:                // Note that #removeThis must be adapted if RemoveException is
0904:                // thrown due to any other cause. And prepareRemove must be
0905:                // adapted if there are any more preconditions to meet.
0906:                try {
0907:                    if (getPaTypedState().workflowState() != State.CLOSED
0908:                            && (!getPaTypedState().isSameOrSubState(
0909:                                    NotRunningState.NOT_STARTED))) {
0910:                        throw new RemoveException("Cannot remove " + toString()
0911:                                + ": still running.");
0912:                    }
0913:                    removeProcess();
0914:                    dispose();
0915:                    paProcessDef = null;
0916:                    activityMapCache = null;
0917:                    activityLocalMapCache = null;
0918:                    transitionsCache = null;
0919:                    transitionsLocalCache = null;
0920:                    updatedTransitions.clear();
0921:                    paBlockDeadlines = null;
0922:                    engineLocal().removeAuditEvents(
0923:                            ((Long) ctx.getPrimaryKey()).toString());
0924:                } catch (RemoteException ex) {
0925:                    throw new EJBException(ex);
0926:                } catch (IOException ex) {
0927:                    throw new EJBException(ex);
0928:                } catch (SQLException ex) {
0929:                    throw new EJBException(ex);
0930:                }
0931:            }
0932:
0933:            /**
0934:             * A container invokes this method to synchronize the state of an 
0935:             * enterprise bean instance with the entity object's state in the database.
0936:             * @see javax.ejb.EntityBean
0937:             */
0938:            public void ejbLoad() throws EJBException {
0939:                try {
0940:                    // load process attributes from persistent store
0941:                    loadProcess();
0942:                    paBlockDeadlines = CollectionsUtil
0943:                            .trackedMap(new DeadlineMap());
0944:                    updatedTransitions.clear();
0945:                    // notify underlying domain object
0946:                    refresh();
0947:                } catch (SQLException e) {
0948:                    throw new EJBException(e);
0949:                } catch (IOException e) {
0950:                    throw new EJBException(e);
0951:                } catch (FinderException e) {
0952:                    throw new EJBException(e);
0953:                }
0954:            }
0955:
0956:            /**
0957:             * A container invokes this method to synchronize the state of the
0958:             * entity object in the database with the state of the enterprise bean
0959:             * instancee.
0960:             * @see javax.ejb.EntityBean
0961:             */
0962:            public void ejbStore() throws EJBException {
0963:                try {
0964:                    // moved the check for persistentAttributeModified
0965:                    // to storeProcess because of paProcessData handling
0966:                    storeProcess();
0967:                    persistentAttributeModified = false;
0968:                } catch (SQLException ex) {
0969:                    throw new EJBException(ex);
0970:                } catch (IOException ex) {
0971:                    throw new EJBException(ex);
0972:                }
0973:            }
0974:
0975:            /*********************** Database Routines *************************/
0976:            /**
0977:             * This method checks if the process exists.
0978:             * @param primaryKey key to check
0979:             * @return If it is ok, it returns true.
0980:             */
0981:            private boolean selectByPrimaryKey(Long primaryKey)
0982:                    throws SQLException {
0983:                Connection con = null;
0984:                PreparedStatement prepStmt = null;
0985:                ResultSet rs = null;
0986:                try {
0987:                    con = ds.getConnection();
0988:                    String selectStatement = "SELECT DBId FROM process WHERE DBId = ? ";
0989:                    prepStmt = con.prepareStatement(selectStatement);
0990:                    prepStmt.setLong(1, primaryKey.longValue());
0991:                    rs = prepStmt.executeQuery();
0992:                    boolean result = rs.next();
0993:                    return result;
0994:                } finally {
0995:                    JDBCUtil.closeAll(rs, prepStmt, con);
0996:                }
0997:            }
0998:
0999:            /**
1000:             * This method retrieves an activity's container
1001:             * @param key activity key
1002:             * @return primary key of process
1003:             */
1004:            private Long selectByActivityKey(Long key) throws SQLException {
1005:                Connection con = null;
1006:                PreparedStatement prepStmt = null;
1007:                ResultSet rs = null;
1008:                try {
1009:                    con = ds.getConnection();
1010:                    prepStmt = con
1011:                            .prepareStatement("SELECT ProcessDBId FROM Activity WHERE DBId = ? ");
1012:                    prepStmt.setLong(1, key.longValue());
1013:                    rs = prepStmt.executeQuery();
1014:                    if (!rs.next()) {
1015:                        return null;
1016:                    }
1017:                    return new Long(rs.getLong(1));
1018:                } finally {
1019:                    JDBCUtil.closeAll(rs, prepStmt, con);
1020:                }
1021:            }
1022:
1023:            private Collection selectByProcessMgrName(String processMgrName)
1024:                    throws SQLException {
1025:                Connection con = null;
1026:                PreparedStatement prepStmt = null;
1027:                ResultSet rs = null;
1028:                try {
1029:                    Collection processes = new ArrayList();
1030:                    con = ds.getConnection();
1031:                    String selectStatement = "SELECT dbid FROM process "
1032:                            + " WHERE processmgr = ? " + " ORDER BY dbid ";
1033:                    prepStmt = con.prepareStatement(selectStatement);
1034:                    prepStmt.setString(1, processMgrName);
1035:                    rs = prepStmt.executeQuery();
1036:                    while (rs.next()) {
1037:                        processes.add(new Long(rs.getLong(1)));
1038:                    }
1039:                    return processes;
1040:                } finally {
1041:                    JDBCUtil.closeAll(rs, prepStmt, con);
1042:                }
1043:            }
1044:
1045:            private Collection selectWithoutDefinitionByProcessMgrName(
1046:                    String processMgrName) throws SQLException {
1047:                Connection con = null;
1048:                PreparedStatement prepStmt = null;
1049:                ResultSet rs = null;
1050:                try {
1051:                    Collection processes = new ArrayList();
1052:                    con = ds.getConnection();
1053:                    String selectStatement = "SELECT dbid FROM process "
1054:                            + " WHERE processmgr = ? AND xpdl IS NULL "
1055:                            + " ORDER BY dbid ";
1056:                    prepStmt = con.prepareStatement(selectStatement);
1057:                    prepStmt.setString(1, processMgrName);
1058:                    rs = prepStmt.executeQuery();
1059:                    while (rs.next()) {
1060:                        processes.add(new Long(rs.getLong(1)));
1061:                    }
1062:                    return processes;
1063:                } finally {
1064:                    JDBCUtil.closeAll(rs, prepStmt, con);
1065:                }
1066:            }
1067:
1068:            private Collection selectByRequesterHash(int hash)
1069:                    throws SQLException {
1070:                Connection con = null;
1071:                PreparedStatement prepStmt = null;
1072:                ResultSet rs = null;
1073:                try {
1074:                    Collection processes = new ArrayList();
1075:                    con = ds.getConnection();
1076:                    prepStmt = con
1077:                            .prepareStatement("SELECT dbid FROM process WHERE ReqHash = ? ORDER BY dbid");
1078:                    prepStmt.setInt(1, hash);
1079:                    rs = prepStmt.executeQuery();
1080:                    while (rs.next()) {
1081:                        processes.add(new Long(rs.getLong(1)));
1082:                    }
1083:                    return processes;
1084:                } finally {
1085:                    JDBCUtil.closeAll(rs, prepStmt, con);
1086:                }
1087:            }
1088:
1089:            private Collection selectAll() throws SQLException {
1090:                Connection con = null;
1091:                PreparedStatement prepStmt = null;
1092:                ResultSet rs = null;
1093:                try {
1094:                    Collection processes = new ArrayList();
1095:                    con = ds.getConnection();
1096:                    String selectStatement = "SELECT dbid FROM process "
1097:                            + " ORDER BY dbid ";
1098:                    prepStmt = con.prepareStatement(selectStatement);
1099:                    rs = prepStmt.executeQuery();
1100:                    while (rs.next()) {
1101:                        processes.add(new Long(rs.getLong(1)));
1102:                    }
1103:                    return processes;
1104:                } finally {
1105:                    JDBCUtil.closeAll(rs, prepStmt, con);
1106:                }
1107:            }
1108:
1109:            /**
1110:             * Insert a new process info into the database.
1111:             * @param processDefinitionID the ID of the process definition
1112:             */
1113:            private void insertProcess(String processDefinitionID)
1114:                    throws SQLException, IOException {
1115:                Connection con = null;
1116:                UniversalPrepStmt prepStmt = null;
1117:                try {
1118:                    con = ds.getConnection();
1119:                    prepStmt = new UniversalPrepStmt(
1120:                            ds,
1121:                            con,
1122:                            "INSERT INTO process ("
1123:                                    + "DBId, PackageId, ProcessId, Name, State, StateTime, "
1124:                                    + "Priority"
1125:                                    + (paRequester != null ? ", Requester, ReqHash"
1126:                                            : "")
1127:                                    + ", Creator, ProcessMgr, "
1128:                                    + "MgrVersion, CreateTime, Description, Flags) "
1129:                                    + "VALUES (?, ?, ?, ?, ?, ?, ?"
1130:                                    + (paRequester != null ? ", ?, ?" : "")
1131:                                    + ", ?, ?, ?, ?, ?, ?)");
1132:                    int offset = 1;
1133:                    Long procKey = (Long) ctx.getPrimaryKey();
1134:                    prepStmt.setLong(offset++, procKey.longValue());
1135:                    prepStmt.setString(offset++, packageId);
1136:                    prepStmt.setString(offset++, processId);
1137:                    prepStmt.setString(offset++, paName);
1138:                    prepStmt.setString(offset++, paTypedState.toString());
1139:                    prepStmt.setTimestamp(offset++, new Timestamp(
1140:                            paLastStateTime.getTime()));
1141:                    prepStmt.setInt(offset++, paPriority.toInt());
1142:                    if (paRequester != null) {
1143:                        prepStmt.setBinary(offset++, paRequester);
1144:                        prepStmt.setInt(offset++, paRequester.hashCode());
1145:                    }
1146:                    prepStmt.setString(offset++, processCreator);
1147:                    prepStmt.setString(offset++, paProcessMgrName);
1148:                    prepStmt.setString(offset++, paProcessMgrVersion);
1149:                    prepStmt.setTimestamp(offset++, new Timestamp(paCreateTime
1150:                            .getTime()));
1151:                    prepStmt.setString(offset++, paDescription);
1152:                    prepStmt.setInt(offset++, paFlags);
1153:                    prepStmt.executeUpdate();
1154:                    ((ProcessDataStore) paProcessData).setConnection(con);
1155:                    try {
1156:                        ((PersistentMap) paProcessData).store();
1157:                    } catch (PersistentMapSQLException e) {
1158:                        throw (SQLException) e.getCause();
1159:                    }
1160:                    for (Iterator i = CollectionsUtil.modifiedEntries(
1161:                            paBlockDeadlines).iterator(); i.hasNext();) {
1162:                        Long key = (Long) i.next();
1163:                        updateDeadlines(ds, con, (Long) ctx.getPrimaryKey(),
1164:                                key, (List) paBlockDeadlines.get(key), false);
1165:                    }
1166:                } catch (RemoteException e) {
1167:                    throw new EJBException(e);
1168:                } catch (NumberFormatException e) {
1169:                    throw new IOException("Activity key not a long:"
1170:                            + e.getMessage());
1171:                } finally {
1172:                    ((ProcessDataStore) paProcessData).setConnection(null);
1173:                    JDBCUtil.closeAll(null, prepStmt, con);
1174:                }
1175:            }
1176:
1177:            /**
1178:             * Store process info in the database. The 
1179:             * transitions of a process does not need
1180:             * to be stored.
1181:             */
1182:            private void storeProcess() throws SQLException, IOException {
1183:                Connection con = null;
1184:                UniversalPrepStmt prepStmt = null;
1185:                try {
1186:                    if (persistentAttributeModified || myProcDef != null) {
1187:                        con = ds.getConnection();
1188:                        prepStmt = new UniversalPrepStmt(
1189:                                ds,
1190:                                con,
1191:                                "UPDATE process SET Name = ?, State = ?, "
1192:                                        + "StateTime = ?, Priority = ?, Flags = ?"
1193:                                        + (paDescriptionModified ? ", Description = ? "
1194:                                                : "")
1195:                                        + (myProcDef != null ? ", Xpdl = ? "
1196:                                                : "") + " WHERE DBId = ? ");
1197:                        int offset = 1;
1198:                        prepStmt.setString(offset++, paName);
1199:                        prepStmt.setString(offset++, paTypedState.toString());
1200:                        prepStmt.setTimestamp(offset++, new Timestamp(
1201:                                paLastStateTime.getTime()));
1202:                        prepStmt.setInt(offset++, paPriority.toInt());
1203:                        prepStmt.setInt(offset++, paFlags);
1204:                        if (paDescriptionModified) {
1205:                            prepStmt.setString(offset++, paDescription);
1206:                            paDescriptionModified = false;
1207:                        }
1208:                        if (myProcDef != null) {
1209:                            prepStmt.setLargeString(offset++, myProcDef);
1210:                        }
1211:                        // for where clause
1212:                        prepStmt.setLong(offset++, ((Long) ctx.getPrimaryKey())
1213:                                .longValue());
1214:                        int rowCount = prepStmt.executeUpdate();
1215:                        myProcDef = null;
1216:                        if (rowCount == 0) {
1217:                            throw new NoSuchEntityException(
1218:                                    "Storing row for DBId "
1219:                                            + (Long) ctx.getPrimaryKey()
1220:                                            + " failed.");
1221:                        }
1222:                    }
1223:                    if (((ProcessDataStore) paProcessData).isModified()) {
1224:                        if (con == null) {
1225:                            con = ds.getConnection();
1226:                        }
1227:                        ((ProcessDataStore) paProcessData).setConnection(con);
1228:                        try {
1229:                            ((PersistentMap) paProcessData).store();
1230:                        } catch (PersistentMapSQLException e) {
1231:                            throw (SQLException) e.getCause();
1232:                        }
1233:                    }
1234:                    if (CollectionsUtil.hasBeenModified(paBlockDeadlines)) {
1235:                        if (con == null) {
1236:                            con = ds.getConnection();
1237:                        }
1238:                        for (Iterator i = CollectionsUtil.modifiedEntries(
1239:                                paBlockDeadlines).iterator(); i.hasNext();) {
1240:                            Long key = (Long) i.next();
1241:                            updateDeadlines(ds, con,
1242:                                    (Long) ctx.getPrimaryKey(), key,
1243:                                    (List) paBlockDeadlines.get(key), true);
1244:                        }
1245:                    }
1246:                    if (updatedTransitions.size() > 0) {
1247:                        if (con == null) {
1248:                            con = ds.getConnection();
1249:                        }
1250:                        updateTransitions(con);
1251:                    }
1252:                } catch (RemoteException re) {
1253:                    throw new EJBException(re);
1254:                } finally {
1255:                    ((ProcessDataStore) paProcessData).setConnection(null);
1256:                    JDBCUtil.closeAll(null, prepStmt, con);
1257:                }
1258:                // transitions does not need to be stored 
1259:            }
1260:
1261:            /**
1262:             * Load process info from the database. Loads also
1263:             * the transitions of the process.
1264:             * After sucessful loading, the process attribute structure 
1265:             * is set with the values just loaded.
1266:             */
1267:            private void loadProcess() throws SQLException, FinderException,
1268:                    IOException {
1269:                Connection con = null;
1270:                PreparedStatement prepStmt = null;
1271:                ResultSet rs = null;
1272:                try {
1273:                    con = ds.getConnection();
1274:                    if (haveSelForUp == null) {
1275:                        haveSelForUp = new Boolean(JDBCUtil.dbProperties(ds,
1276:                                con).supportsSelectForUpdate());
1277:                    }
1278:                    prepStmt = con
1279:                            .prepareStatement("SELECT PackageId, ProcessId, Name, State, StateTime, "
1280:                                    + "Priority, Requester, Creator, ProcessMgr, MgrVersion, "
1281:                                    + "CreateTime, Description, Flags "
1282:                                    + "FROM process WHERE DBId = ? "
1283:                                    + (haveSelForUp.booleanValue() ? " FOR UPDATE"
1284:                                            : ""));
1285:                    Long procKey = (Long) ctx.getPrimaryKey();
1286:                    prepStmt.setLong(1, procKey.longValue());
1287:                    rs = prepStmt.executeQuery();
1288:                    if (!rs.next()) {
1289:                        throw new NoSuchEntityException("Row for id "
1290:                                + (Long) ctx.getPrimaryKey()
1291:                                + " not found in database.");
1292:                    }
1293:                    // read process from db
1294:                    int offset = 1;
1295:                    packageId = rs.getString(offset++);
1296:                    processId = rs.getString(offset++);
1297:                    paName = rs.getString(offset++);
1298:                    paTypedState = State.fromString(rs.getString(offset++));
1299:                    paLastStateTime = rs.getTimestamp(offset++);
1300:                    paPriority = Priority.fromInt(rs.getInt(offset++));
1301:                    paRequester = (WfRequester) JDBCUtil
1302:                            .getBinary(rs, offset++);
1303:                    processCreator = rs.getString(offset++);
1304:                    paProcessMgrName = rs.getString(offset++);
1305:                    paProcessMgrVersion = rs.getString(offset++);
1306:                    paCreateTime = rs.getTimestamp(offset++);
1307:                    paDescription = rs.getString(offset++);
1308:                    paDescriptionModified = false;
1309:                    paFlags = rs.getInt(offset++);
1310:                    ((ProcessDataStore) paProcessData).setConnection(con);
1311:                    try {
1312:                        ((PersistentMap) paProcessData).load();
1313:                    } catch (PersistentMapSQLException e) {
1314:                        throw (SQLException) e.getCause();
1315:                    }
1316:                } catch (InvalidPriorityException ipe) {
1317:                    logger.error(ipe.getMessage(), ipe);
1318:                    throw new SQLException(ipe.getMessage());
1319:                } catch (InvalidStateException ise) {
1320:                    logger.error(ise.getMessage(), ise);
1321:                    throw new SQLException(ise.getMessage());
1322:                } catch (ClassNotFoundException e) {
1323:                    logger.error(e.getMessage(), e);
1324:                    throw new SQLException(e.getMessage());
1325:                } finally {
1326:                    ((ProcessDataStore) paProcessData).setConnection(null);
1327:                    JDBCUtil.closeAll(rs, prepStmt, con);
1328:                }
1329:            }
1330:
1331:            /**
1332:             * Returns the process definition of this process.
1333:             * @return the definition for this process in Document.
1334:             */
1335:            private String loadProcDef() throws SQLException, NamingException {
1336:                Connection con = null;
1337:                PreparedStatement prepStmt = null;
1338:                ResultSet rs = null;
1339:                try {
1340:                    con = ds.getConnection();
1341:                    String selectStatement = "SELECT Xpdl FROM process WHERE DBId = ? ";
1342:                    prepStmt = con.prepareStatement(selectStatement);
1343:                    prepStmt.setLong(1, ((Long) ctx.getPrimaryKey())
1344:                            .longValue());
1345:                    rs = prepStmt.executeQuery();
1346:                    if (!rs.next()) {
1347:                        throw new NoSuchEntityException(
1348:                                "No process with DBId = " + ctx.getPrimaryKey());
1349:                    }
1350:                    return JDBCUtil.getString(ds, rs, 1);
1351:                } catch (IOException e) {
1352:                    throw new EJBException(e);
1353:                } finally {
1354:                    try {
1355:                        JDBCUtil.closeAll(rs, prepStmt, con);
1356:                    } catch (SQLException e) {
1357:                        logger.warn(e.getMessage(), e);
1358:                    }
1359:                }
1360:            }
1361:
1362:            /**
1363:             * Remove process info from the database.
1364:             */
1365:            private void removeProcess() throws SQLException, IOException,
1366:                    RemoveException {
1367:                Connection con = null;
1368:                PreparedStatement prepStmt = null;
1369:                try {
1370:                    removeActivities();
1371:                    long procId = ((Long) ctx.getPrimaryKey()).longValue();
1372:                    con = ds.getConnection();
1373:                    removeTransitions(con, procId);
1374:                    ((ProcessDataStore) paProcessData).setConnection(con);
1375:                    paProcessData.clear();
1376:                    try {
1377:                        ((PersistentMap) paProcessData).store();
1378:                    } catch (PersistentMapSQLException e) {
1379:                        throw (SQLException) e.getCause();
1380:                    }
1381:                    String deleteStatement = "DELETE FROM process WHERE DBId = ? ";
1382:                    prepStmt = con.prepareStatement(deleteStatement);
1383:                    prepStmt.setLong(1, procId);
1384:                    prepStmt.executeUpdate();
1385:                    prepStmt.close();
1386:                    prepStmt = null;
1387:                    prepStmt = new UniversalPrepStmt(ds, con,
1388:                            "DELETE FROM Deadline WHERE Process = ?");
1389:                    prepStmt.setLong(1, ((Long) ctx.getPrimaryKey())
1390:                            .longValue());
1391:                    prepStmt.executeUpdate();
1392:                    prepStmt.close();
1393:                    prepStmt = null;
1394:                    prepStmt = new UniversalPrepStmt(ds, con,
1395:                            "DELETE FROM SimpleAppl WHERE ProcessKey = ?");
1396:                    prepStmt.setString(1, ((Long) ctx.getPrimaryKey())
1397:                            .toString());
1398:                    prepStmt.executeUpdate();
1399:                } finally {
1400:                    ((ProcessDataStore) paProcessData).setConnection(null);
1401:                    JDBCUtil.closeAll(null, prepStmt, con);
1402:                }
1403:            }
1404:
1405:            /**
1406:             * Remove transitions info as associated to the process from the database.
1407:             * @param procKey the process key for to remove the transitions
1408:             * @throws SQLException in case of any SQL errors
1409:             * @throws IOException in case of any IO errors
1410:             */
1411:            private void removeTransitions(Connection con, long procKey)
1412:                    throws SQLException, IOException {
1413:                PreparedStatement prepStmt = null;
1414:                try {
1415:                    String deleteStatement = "DELETE FROM transition "
1416:                            + "WHERE ProcessDBId = ? ";
1417:                    prepStmt = con.prepareStatement(deleteStatement);
1418:                    prepStmt.setLong(1, procKey);
1419:                    prepStmt.executeUpdate();
1420:                } finally {
1421:                    JDBCUtil.closeAll(null, prepStmt, null);
1422:                }
1423:            }
1424:
1425:            /**
1426:             * Remove activities as associated to the process.
1427:             * @param procKey the process key for to remove the transitions
1428:             * @throws SQLException in case of any SQL errors
1429:             * @throws IOException in case of any IO errors
1430:             */
1431:            private void removeActivities() throws RemoveException,
1432:                    RemoteException {
1433:                // remove the activities from the system
1434:                for (Iterator i = activitiesLocal().iterator(); i.hasNext();) {
1435:                    EJBLocalObject activity = ((EJBLocalObject) i.next());
1436:                    activity.remove();
1437:                }
1438:                activityMapCache = null;
1439:            }
1440:
1441:            /**
1442:             * Load the deadlines for the activity with the given primary key
1443:             * from the given datasource.<P>
1444:             *
1445:             * This is provided as a static package visible method as it is
1446:             * used by <code>WfActivityEJB</code> as well. The deadline table
1447:             * is considered a shared resource. As a process and its
1448:             * activities operate on a distinct set of deadlines, there is no
1449:             * need for activities to access the deadlines via the process
1450:             * (and we can save the overhead).
1451:             *
1452:             * @param ds the data source to use
1453:             * @param pk the key of the activity
1454:             * @return the list of deadlines
1455:             * @throws SQLException if an error occurs
1456:             * @throws IOException if an error occurs
1457:             */
1458:            static List loadDeadlines(DataSource ds, Long pk)
1459:                    throws SQLException, IOException {
1460:                Connection con = null;
1461:                PreparedStatement prepStmt = null;
1462:                ResultSet rs = null;
1463:                try {
1464:                    List res = new ArrayList();
1465:                    con = ds.getConnection();
1466:                    String selectStatement = "SELECT "
1467:                            + "DeadlineCond, ExceptionName, Execution "
1468:                            + "FROM Deadline WHERE Activity = ? ORDER BY Entry";
1469:                    prepStmt = con.prepareStatement(selectStatement);
1470:                    prepStmt.setLong(1, pk.longValue());
1471:                    rs = prepStmt.executeQuery();
1472:                    while (rs.next()) {
1473:                        res.add(new Deadline(rs.getInt(3), JDBCUtil.getString(
1474:                                ds, rs, 1), rs.getString(2)));
1475:                    }
1476:                    return res;
1477:                } finally {
1478:                    JDBCUtil.closeAll(rs, prepStmt, con);
1479:                }
1480:            }
1481:
1482:            /**
1483:             * Updates the deadlines for the activity with the given primary key
1484:             * using the given connection.<P>
1485:             *
1486:             * This is provided as a static package visible method as it is
1487:             * used by <code>WfActivityEJB</code> as well. The deadline table
1488:             * is considered a shared resource. As a process and its
1489:             * activities operate on a distinct set of deadlines, there is no
1490:             * need for activities to access the deadlines via the process
1491:             * (and we can save the overhead).
1492:             *
1493:             * @param ds the data source
1494:             * @param con the connection to the database
1495:             * @param pk the key of the process
1496:             * @param ak the key of the activity
1497:             * @param dls the list of deadlines
1498:             * @param doDelete if old values should be deleted (should only be
1499:             * set to <code>false</code> if updating the deadlines for a newly
1500:             * created activity
1501:             * @throws SQLException if an error occurs
1502:             * @throws IOException if an error occurs
1503:             */
1504:            public static void updateDeadlines(DataSource ds, Connection con,
1505:                    Long pk, Long ak, List dls, boolean doDelete)
1506:                    throws SQLException, IOException {
1507:                UniversalPrepStmt prepStmt = null;
1508:                try {
1509:                    if (doDelete) {
1510:                        prepStmt = new UniversalPrepStmt(ds, con,
1511:                                "DELETE FROM Deadline WHERE Activity = ?");
1512:                        prepStmt.setLong(1, ak.longValue());
1513:                        prepStmt.executeUpdate();
1514:                        prepStmt.close();
1515:                        prepStmt = null;
1516:                    }
1517:                    if (dls != null && dls.size() > 0) {
1518:                        prepStmt = new UniversalPrepStmt(
1519:                                ds,
1520:                                con,
1521:                                "INSERT INTO Deadline (Process, Activity, Entry, "
1522:                                        + "DeadlineCond, ExceptionName, Execution, State) "
1523:                                        + "VALUES (?, ?, ?, ?, ?, ?, ?)",
1524:                                new String[] { "Activity", "Entry" });
1525:                        int entry = 0;
1526:                        for (Iterator i = dls.iterator(); i.hasNext();) {
1527:                            Deadline dl = (Deadline) i.next();
1528:                            int offset = 1;
1529:                            prepStmt.setLong(offset++, pk.longValue());
1530:                            prepStmt.setLong(offset++, ak.longValue());
1531:                            prepStmt.setInt(offset++, entry++);
1532:                            prepStmt
1533:                                    .setLargeString(offset++, dl.getCondition());
1534:                            prepStmt.setString(offset++, dl.getExceptionName());
1535:                            prepStmt.setInt(offset++, dl.getExecution());
1536:                            prepStmt.setInt(offset++, dl.getState());
1537:                            prepStmt.executeUpdate();
1538:                        }
1539:                    }
1540:                } finally {
1541:                    JDBCUtil.closeAll(null, prepStmt, null);
1542:                }
1543:            }
1544:
1545:            //
1546:            // Domain methods and helpers
1547:            //
1548:
1549:            /**
1550:             * Indicates if some other object is equal to this one. <P>
1551:             *
1552:             * Note that <code>obj</code> must implement the process's 
1553:             * remote interface. Comparing a domain object usually
1554:             * indicates some violation of the constraints of our
1555:             * implementation environment.
1556:             *
1557:             * @param obj the object to compare with.
1558:             * @return <code>true</code> if the other object is equal.
1559:             */
1560:            public boolean equals(Object obj) {
1561:                try {
1562:                    return ctx.getPrimaryKey().toString().equals(
1563:                            ((WfProcess) obj).key());
1564:                } catch (RemoteException e) {
1565:                    throw new EJBException(e);
1566:                }
1567:            }
1568:
1569:            /**
1570:             *  Return the hash code.<P>
1571:             *  @return the result.
1572:             */
1573:            public int hashCode() {
1574:                return ctx.getPrimaryKey().toString().hashCode();
1575:            }
1576:
1577:            /**
1578:             * Starts a process.
1579:             * @throws CannotStartException when the process cannot be started (e.g.,
1580:             * because it is not properly initialized).
1581:             * @throws AlreadyRunningException when the process has already been 
1582:             * started.
1583:             * @ejb.interface-method view-type="remote"
1584:             */
1585:            public void start() throws CannotStartException,
1586:                    AlreadyRunningException {
1587:                super .start();
1588:            }
1589:
1590:            /**
1591:             * Returns a collection of activities of the process.
1592:             * @return collection of activities of the process
1593:             */
1594:            public Collection steps() {
1595:                // HashMap.values() returns a Collection implementation that
1596:                // is not serializable. Besides we really do not need to
1597:                // transfer the whole map, so let's create a new
1598:                // collection-container.
1599:                try {
1600:                    return new ArrayList(activityMap().values());
1601:                } catch (RemoteException e) {
1602:                    throw new EJBException(e);
1603:                }
1604:            }
1605:
1606:            /**
1607:             * Returns a collection of activities of the process.
1608:             * @return collection of activities of the process
1609:             */
1610:            public Collection stepsLocal() {
1611:                // HashMap.values() returns a Collection implementation that
1612:                // is not serializable. Besides we really do not need to
1613:                // transfer the whole map, so let's create a new
1614:                // collection-container.
1615:                return new ArrayList(activitiesLocal());
1616:            }
1617:
1618:            /**
1619:             * Retrieve the base event information about a requesting activity.
1620:             * @param req the requester.
1621:             * @return the base info using an audit event as DTO.
1622:             */
1623:            protected WfAuditEvent activityRequesterInfo(WfRequester req) {
1624:                if (!(req instanceof  ExtActivity)) {
1625:                    return null;
1626:                }
1627:                try {
1628:                    ExtActivity act = (ExtActivity) req;
1629:                    return act.auditEventBase();
1630:                } catch (RemoteException e) {
1631:                    throw new EJBException(e);
1632:                }
1633:            }
1634:
1635:            /**
1636:             * Set a new name of the process. The change must be forwarded
1637:             * to the activity EJBs as they cache the name.
1638:             * @param newValue new name.
1639:             */
1640:            public void setName(String newValue) {
1641:                super .setName(newValue);
1642:                for (Iterator i = activitiesLocal().iterator(); i.hasNext();) {
1643:                    ExtActivityLocal a = (ExtActivityLocal) i.next();
1644:                    a.updateProcessName(newValue);
1645:                }
1646:            }
1647:
1648:            /**
1649:             * Returns the process manager which created this process.
1650:             * @return the associated process manager.
1651:             */
1652:            public WfProcessMgr manager() {
1653:                ProcessDefinition def = getPaProcessDef();
1654:                try {
1655:                    return new ProcessMgrStub(def.packageId(), def.processId(),
1656:                            def.mgrName(), key(),
1657:                            processDefinitionDirectoryHome(),
1658:                            (WfProcessHome) ctx.getEJBHome());
1659:                } catch (ResourceNotAvailableException e) {
1660:                    throw new EJBException(e);
1661:                }
1662:            }
1663:
1664:            /**
1665:             * Factory method that create new persistent objects of type
1666:             * <code>WfActivity</code>. Must be implement by the persistence
1667:             * layer.
1668:             *
1669:             * @param blockActId if the activity is part of a block activity,
1670:             * else <code>null</code>
1671:             * @param priority a <code>Priority</code> value
1672:             * @param name the activity's name
1673:             * @param description activity description
1674:             * @param startMode the start mode
1675:             * @param finishMode the finish mode
1676:             * @param joinMode the join mode
1677:             * @param splitMode the split mode
1678:             * @param implementation the implementation description
1679:             * @param performer the performer
1680:             * @param deadlines the deadlines
1681:             * @param deferChoiceOnSplit if true, choice is to be deferred
1682:             * @param auditEventSelection the audit event selection
1683:             * @param storeAuditEvents if true, audit events are stored in the
1684:             * database
1685:             * @return the created activity.
1686:             */
1687:            protected de.danet.an.workflow.localcoreapi.WfActivityLocal createActivity(
1688:                    String blockActId, Priority priority, String name,
1689:                    String description, StartFinishMode startMode,
1690:                    StartFinishMode finishMode, JoinAndSplitMode joinMode,
1691:                    JoinAndSplitMode splitMode,
1692:                    Implementation[] implementation, String performer,
1693:                    List deadlines, boolean deferChoiceOnSplit,
1694:                    int auditEventSelection, boolean storeAuditEvents) {
1695:                try {
1696:                    ExtActivityLocal act = activityLocalHome().create(
1697:                            (WfProcessLocal) ctx.getEJBLocalObject(),
1698:                            (Long) ctx.getPrimaryKey(), auditEventBase(),
1699:                            blockActId == null ? null : new Long(blockActId),
1700:                            priority, name, description, startMode, finishMode,
1701:                            joinMode, splitMode, implementation, performer,
1702:                            deadlines, deferChoiceOnSplit, auditEventSelection,
1703:                            storeAuditEvents);
1704:                    return cacheActivityLocal(act);
1705:                } catch (CreateException ce) {
1706:                    logger.error(ce.getMessage(), ce);
1707:                    throw new IllegalStateException(ce.getMessage());
1708:                } catch (RemoteException re) {
1709:                    logger.error(re.getMessage(), re);
1710:                    throw new IllegalStateException(re.getMessage());
1711:                }
1712:            }
1713:
1714:            /**
1715:             * Provide a new unique activity key.
1716:             *
1717:             * @return the key.
1718:             */
1719:            protected Long createActivityKey() {
1720:                try {
1721:                    return new Long(EJBUtil.newPrimaryKey("activity"));
1722:                } catch (ResourceNotAvailableException e) {
1723:                    throw new EJBException(e);
1724:                }
1725:            }
1726:
1727:            /**
1728:             * Create a new transition with given id, from-activity,
1729:             * to-activity.
1730:             * @param id the transition id
1731:             * @param group the transition group id
1732:             * @param order the transition priority
1733:             * @param fromAct the from Activity
1734:             * @param toAct the to Activity
1735:             * @param condType type of the condition
1736:             * @param condition condition of this transition
1737:             * @return the created transition.
1738:             */
1739:            protected TransitionLocal doCreateTransition(String id,
1740:                    String group, int order, ActivityLocal fromAct,
1741:                    ActivityLocal toAct, int condType, String condition) {
1742:                TransitionLocal trans = new InternalTransitionDefinition(this ,
1743:                        ((Long) ctx.getPrimaryKey()).toString(), id, group,
1744:                        order, fromAct, toAct, condType, condition, false);
1745:                transitionsLocalCache.add(trans);
1746:                return trans;
1747:            }
1748:
1749:            /**
1750:             * Gets a list of transitions for this process.
1751:             * @return list of transitions for this process
1752:             */
1753:            public List transitions() {
1754:                if (transitionsCache == null) {
1755:                    List ts = new ArrayList();
1756:                    for (Iterator i = transitionsLocal().iterator(); i
1757:                            .hasNext();) {
1758:                        TransitionDefinitionLocal def = (TransitionDefinitionLocal) i
1759:                                .next();
1760:                        ts.add(new TransitionDefinition(def));
1761:                    }
1762:                    transitionsCache = ts;
1763:                }
1764:                return transitionsCache;
1765:            }
1766:
1767:            /**
1768:             * Gets a list of transitions for this process.
1769:             * The method is public, because the transition manager needs
1770:             * access to the transitions of a process.
1771:             * @return list of transitions for this process
1772:             */
1773:            public List transitionsLocal() {
1774:                if (transitionsLocalCache == null) {
1775:                    try {
1776:                        transitionsLocalCache = loadTransitions();
1777:                    } catch (RemoteException e) {
1778:                        throw new EJBException(e);
1779:                    } catch (SQLException e) {
1780:                        throw new EJBException(e);
1781:                    }
1782:                }
1783:                return transitionsLocalCache;
1784:            }
1785:
1786:            /**
1787:             * Return the process definition directory.
1788:             * While there is no immediate relation between a process
1789:             * instance and the known process definitions, the definitions
1790:             * nevertheless make up part of the environment of a process.
1791:             * Specifically, this method is needed to start a sub-process
1792:             * in an activity.
1793:             * @return the process definition directory
1794:             */
1795:            public ProcessDefinitionDirectoryLocal processDefinitionDirectoryLocal() {
1796:                try {
1797:                    return getProcessDefinitionDirectoryLocal();
1798:                } catch (RemoteException e) {
1799:                    throw new EJBException(e);
1800:                } catch (NamingException e) {
1801:                    throw new EJBException(e);
1802:                } catch (CreateException e) {
1803:                    throw new EJBException(e);
1804:                }
1805:            }
1806:
1807:            /**
1808:             * Returns the {@link Activity <code>Activity</code>} with the given key.
1809:             * The OMG interface only defines a {@link WfProcess#steps 
1810:             * method for listing all the activities} associated with the process.
1811:             * While, of course, one could select the activity with a certain key
1812:             * from that list, this would be rather insufficient.
1813:             * @param key the 
1814:             * {@link de.danet.an.workflow.omgcore.WfActivity#key key} of the process.
1815:             * @return the activity associated with the key.
1816:             * @throws InvalidKeyException if no activity with the given key
1817:             * exists.
1818:             */
1819:            public Activity activityByKey(String key)
1820:                    throws InvalidKeyException {
1821:                try {
1822:                    Activity act = (Activity) activityMap().get(key);
1823:                    if (act != null) {
1824:                        return act;
1825:                    }
1826:                } catch (RemoteException e) {
1827:                    throw new EJBException(e);
1828:                }
1829:                throw new InvalidKeyException("Key " + key + " is invalid.");
1830:            }
1831:
1832:            /**
1833:             * Returns the {@link Activity <code>ActivityLocal</code>} with the given
1834:             * key. The OMG interface only defines a {@link WfProcess#steps 
1835:             * method for listing all the activities} associated with the process.
1836:             * While, of course, one could select the activity with a certain key
1837:             * from that list, this would be rather insufficient.
1838:             * @param key the 
1839:             * {@link de.danet.an.workflow.omgcore.WfActivity#key key} of the process.
1840:             * @return the activity associated with the key.
1841:             * @throws InvalidKeyException if no activity with the given key
1842:             * exists.
1843:             */
1844:            public ActivityLocal activityByKeyLocal(String key)
1845:                    throws InvalidKeyException {
1846:                ActivityLocal act = (ActivityLocal) activityLocalMap().get(key);
1847:                if (act != null) {
1848:                    return act;
1849:                }
1850:                throw new InvalidKeyException("Key " + key + " is invalid.");
1851:            }
1852:
1853:            /**
1854:             * Loads the transitions of the process from the db.
1855:             * @param con db connection
1856:             * @return list of transitions for this process.
1857:             */
1858:            private List loadTransitions() throws SQLException, RemoteException {
1859:                Connection con = null;
1860:                PreparedStatement prepStmt = null;
1861:                ResultSet rs = null;
1862:                try {
1863:                    con = ds.getConnection();
1864:                    String selectStatement = "SELECT "
1865:                            + "TransitionId, FromActivity, ToActivity, TransGroup, "
1866:                            + "TransOrder, CondType, TransCond, Flags "
1867:                            + "FROM transition WHERE ProcessDBId = ? "
1868:                            + "ORDER BY TransOrder ";
1869:                    prepStmt = con.prepareStatement(selectStatement);
1870:                    Long pk = (Long) ctx.getPrimaryKey();
1871:                    prepStmt.setLong(1, pk.longValue());
1872:                    rs = prepStmt.executeQuery();
1873:                    List trans = new ArrayList();
1874:                    String pks = pk.toString();
1875:                    while (rs.next()) {
1876:                        String id = rs.getString(1);
1877:                        Long from = new Long(rs.getLong(2));
1878:                        Long to = new Long(rs.getLong(3));
1879:                        String group = rs.getString(4);
1880:                        int order = rs.getInt(5);
1881:                        int condType = rs.getInt(6);
1882:                        String condition = JDBCUtil.getString(ds, rs, 7);
1883:                        int flags = rs.getInt(8);
1884:                        // add transition
1885:                        trans
1886:                                .add(new InternalTransitionDefinition(
1887:                                        this ,
1888:                                        pks,
1889:                                        id,
1890:                                        group,
1891:                                        order,
1892:                                        from.longValue() < 0 ? blockActivityRepresentation(from
1893:                                                .toString())
1894:                                                : activityByKeyLocal(from
1895:                                                        .toString()),
1896:                                        activityByKeyLocal(to.toString()),
1897:                                        condType, condition,
1898:                                        (flags & FLAGS_HAS_PENDING_TOKEN) != 0));
1899:                    }
1900:                    return trans;
1901:                } catch (IOException e) {
1902:                    throw new EJBException(e);
1903:                } catch (InvalidKeyException e) {
1904:                    throw new EJBException(e);
1905:                } finally {
1906:                    JDBCUtil.closeAll(rs, prepStmt, con);
1907:                }
1908:            }
1909:
1910:            /**
1911:             * insert the transitions into the db.
1912:             */
1913:            private void insertTransitions() throws SQLException {
1914:                Connection con = null;
1915:                UniversalPrepStmt prepStmt = null;
1916:                try {
1917:                    con = ds.getConnection();
1918:                    Iterator it = transitionsLocalCache.iterator();
1919:                    prepStmt = new UniversalPrepStmt(
1920:                            ds,
1921:                            con,
1922:                            "INSERT INTO transition ("
1923:                                    + "TransitionId, ProcessDBId, FromActivity, ToActivity, "
1924:                                    + "TransGroup, TransOrder, CondType, TransCond) "
1925:                                    + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
1926:                    while (it.hasNext()) {
1927:                        TransitionLocal t = (TransitionLocal) it.next();
1928:                        TransitionDefinitionLocal td = (TransitionDefinitionLocal) t;
1929:                        try {
1930:                            int offset = 1;
1931:                            prepStmt.setString(offset++, t.id());
1932:                            prepStmt.setLong(offset++, ((Long) ctx
1933:                                    .getPrimaryKey()).longValue());
1934:                            prepStmt.setLong(offset++, Long.parseLong(t.from()
1935:                                    .key()));
1936:                            prepStmt.setLong(offset++, Long.parseLong(t.to()
1937:                                    .key()));
1938:                            prepStmt.setString(offset++, td.group());
1939:                            prepStmt.setInt(offset++, td.order());
1940:                            prepStmt.setInt(offset++, td.conditionType());
1941:                            prepStmt.setString(offset++, td.condition());
1942:                        } catch (NumberFormatException re) {
1943:                            throw new SQLException(re.getMessage());
1944:                        }
1945:                        prepStmt.executeUpdate();
1946:                    }
1947:                } finally {
1948:                    try {
1949:                        JDBCUtil.closeAll(null, prepStmt, con);
1950:                    } catch (SQLException e) {
1951:                        logger.error("Error while closing: " + e.getMessage(),
1952:                                e);
1953:                    }
1954:                }
1955:            }
1956:
1957:            private void updateTransitions(Connection con) throws SQLException,
1958:                    RemoteException {
1959:                UniversalPrepStmt prepStmt = null;
1960:                try {
1961:                    Iterator it = updatedTransitions.iterator();
1962:                    prepStmt = new UniversalPrepStmt(
1963:                            ds,
1964:                            con,
1965:                            "UPDATE transition SET Flags = ?"
1966:                                    + " WHERE ProcessDBId = ? AND TransitionId = ?");
1967:                    while (it.hasNext()) {
1968:                        ExtTransitionLocal t = (ExtTransitionLocal) it.next();
1969:                        if (logger.isDebugEnabled()) {
1970:                            logger.debug("Storing " + t);
1971:                        }
1972:                        int offset = 1;
1973:                        prepStmt.setInt(offset++,
1974:                                ((t.hasPendingToken() ? FLAGS_HAS_PENDING_TOKEN
1975:                                        : 0)));
1976:                        prepStmt.setLong(offset++, ((Long) ctx.getPrimaryKey())
1977:                                .longValue());
1978:                        prepStmt.setString(offset++, t.id());
1979:                        prepStmt.executeUpdate();
1980:                    }
1981:                    updatedTransitions.clear();
1982:                } finally {
1983:                    try {
1984:                        JDBCUtil.closeAll(null, prepStmt, null);
1985:                    } catch (SQLException e) {
1986:                        logger.error("Error while closing: " + e.getMessage(),
1987:                                e);
1988:                    }
1989:                }
1990:            }
1991:
1992:            /**
1993:             * Notify about the change of a transition.
1994:             * @param transition the changed transition
1995:             */
1996:            public void transitionUpdated(ExtTransitionLocal transition) {
1997:                updatedTransitions.add(transition);
1998:            }
1999:
2000:            /**
2001:             * Return the remote version of this object. This is the client side
2002:             * implementation of the remote interface (i.e. the EJB object).
2003:             * 
2004:             * @return the remote stub.
2005:             */
2006:            public Process toProcess() {
2007:                return (Process) ctx.getEJBObject();
2008:            }
2009:
2010:            /* (non-Javadoc)
2011:             * Comment copied from interface or superclass.
2012:             */
2013:            public ExtProcessLocal toProcessLocal() {
2014:                return (ExtProcessLocal) ctx.getEJBLocalObject();
2015:            }
2016:
2017:            /**
2018:             * Remove this process.
2019:             * @throws CannotRemoveException if the process is still in progress
2020:             */
2021:            protected void removeThis() throws CannotRemoveException {
2022:                try {
2023:                    ctx.getEJBObject().remove();
2024:                } catch (RemoteException e) {
2025:                    throw new EJBException(e);
2026:                } catch (RemoveException e) {
2027:                    // the process being still in process is the only
2028:                    // prossible cause
2029:                    throw new CannotRemoveException(e.getMessage());
2030:                }
2031:            }
2032:
2033:            /**
2034:             * Forward the state change to the given activity calling
2035:             * <code>changeState</code>. This method is used by
2036:             * <code>ActivityProxy</code> to first involve the process in the
2037:             * transaction. This avoids a lot of deadlocks.
2038:             *
2039:             * @param activity the activity
2040:             * @param state the state
2041:             * @throws InvalidStateException if the state change is not
2042:             * possible
2043:             * @throws TransitionNotAllowedException if the state change is
2044:             * not possible
2045:             * @ejb.interface-method view-type="remote"
2046:             */
2047:            public void forwardStateChange(Activity activity, State state)
2048:                    throws InvalidStateException, TransitionNotAllowedException {
2049:                try {
2050:                    activity.changeState(state);
2051:                } catch (RemoteException e) {
2052:                    throw new EJBException(e);
2053:                }
2054:            }
2055:
2056:            /**
2057:             * Forward the state change to the given activity. This method is
2058:             * used by <code>ActivityProxy</code> to first involve the process
2059:             * in the transaction. This avoids a lot of deadlocks.
2060:             *
2061:             * @param activity the activity
2062:             * @param result the exception data
2063:             * @throws TransitionNotAllowedException if the state change is
2064:             * not possible
2065:             * @ejb.interface-method view-type="remote"
2066:             */
2067:            public void forwardAbandon(Activity activity, ExceptionResult result)
2068:                    throws TransitionNotAllowedException {
2069:                try {
2070:                    ((ExtActivity) activity).abandon(result);
2071:                } catch (RemoteException e) {
2072:                    throw new EJBException(e);
2073:                }
2074:            }
2075:
2076:            /**
2077:             * Forward the state change to the given activity. This method is
2078:             * used by <code>ActivityProxy</code> to first involve the process
2079:             * in the transaction. This avoids a lot of deadlocks.
2080:             *
2081:             * @param activity the activity
2082:             * @throws CannotCompleteException if the state change is
2083:             * not possible
2084:             * @ejb.interface-method view-type="remote"
2085:             */
2086:            public void forwardComplete(Activity activity)
2087:                    throws CannotCompleteException {
2088:                try {
2089:                    activity.complete();
2090:                } catch (RemoteException e) {
2091:                    throw new EJBException(e);
2092:                }
2093:            }
2094:
2095:            /**
2096:             * Forward the state change to the given activity. This method is
2097:             * used by <code>ActivityProxy</code> to first involve the process
2098:             * in the transaction. This avoids a lot of deadlocks.
2099:             *
2100:             * @param activity the activity
2101:             * @throws CannotStopException if the state change is
2102:             * not possible
2103:             * @throws NotRunningException if the state change is
2104:             * not possible
2105:             * @ejb.interface-method view-type="remote"
2106:             */
2107:            public void forwardTerminate(Activity activity)
2108:                    throws CannotStopException, NotRunningException {
2109:                try {
2110:                    activity.terminate();
2111:                } catch (RemoteException e) {
2112:                    throw new EJBException(e);
2113:                }
2114:            }
2115:
2116:            /**
2117:             * Forward the state change to the given activity. This method is
2118:             * used by <code>ActivityProxy</code> to first involve the process
2119:             * in the transaction. This avoids a lot of deadlocks.
2120:             *
2121:             * @param activity the activity
2122:             * @throws CannotStopException if the state change is
2123:             * not possible
2124:             * @throws NotRunningException if the state change is
2125:             * not possible
2126:             * @ejb.interface-method view-type="remote"
2127:             */
2128:            public void forwardAbort(Activity activity)
2129:                    throws CannotStopException, NotRunningException {
2130:                try {
2131:                    activity.abort();
2132:                } catch (RemoteException e) {
2133:                    throw new EJBException(e);
2134:                }
2135:            }
2136:
2137:            /**
2138:             * Forward the result to the given activity. This method is used
2139:             * by <code>ActivityProxy</code> to first involve the process in
2140:             * the transaction. This avoids a lot of deadlocks.
2141:             *
2142:             * @param activity the activity
2143:             * @param result the result
2144:             * @throws InvalidDataException if the result cannot be set
2145:             * @ejb.interface-method view-type="remote"
2146:             */
2147:            public void forwardResult(Activity activity, ProcessData result)
2148:                    throws InvalidDataException {
2149:                try {
2150:                    activity.setResult(result);
2151:                } catch (RemoteException e) {
2152:                    throw new EJBException(e);
2153:                }
2154:            }
2155:
2156:            /**
2157:             * Forward the request for the activity info to the given
2158:             * activity. This method is used by <code>ActivityProxy</code> to
2159:             * first involve the process in the transaction (activity info
2160:             * includes the process' description). This avoids a lot of
2161:             * deadlocks.
2162:             *
2163:             * @param activity the activity
2164:             * @return the activity info
2165:             * @ejb.interface-method view-type="remote"
2166:             */
2167:            public Activity.Info forwardActivityInfo(Activity activity) {
2168:                try {
2169:                    return activity.activityInfo();
2170:                } catch (RemoteException e) {
2171:                    throw new EJBException(e);
2172:                }
2173:            }
2174:
2175:            /**
2176:             * Choose the given activity for further processing in deferred choice.
2177:             * 
2178:             * @param activity the activity
2179:             * @return <code>true</code> if the activity could be made the
2180:             * effectively chosen one
2181:             * @throws TransitionNotAllowedException if the activity is
2182:             * neither running nor suspended
2183:             * @ejb.interface-method view-type="remote"
2184:             */
2185:            public boolean forwardChoose(Activity activity)
2186:                    throws TransitionNotAllowedException {
2187:                try {
2188:                    return activity.choose();
2189:                } catch (RemoteException e) {
2190:                    throw new EJBException(e);
2191:                }
2192:            }
2193:
2194:            /**
2195:             * Return an arbitrary activity with the given key. The activity
2196:             * need not belong to this process.
2197:             * @param key activity key
2198:             * @return the activity
2199:             * @throws InvalidKeyException if the activity cannot be found
2200:             */
2201:            protected ExtActivityLocal lookupActivityLocal(String key)
2202:                    throws InvalidKeyException {
2203:                // Search via process to get process into transaction first
2204:                try {
2205:                    ProcessLocal proc = ((WfProcessLocalHome) ctx
2206:                            .getEJBLocalHome()).findByActivityKey(key);
2207:                    return (ExtActivityLocal) proc.activityByKeyLocal(key);
2208:                } catch (FinderException e) {
2209:                    logger.debug(e.getMessage(), e);
2210:                    throw new InvalidKeyException(e.getMessage());
2211:                }
2212:            }
2213:
2214:            /**
2215:             * Return the Principal that created this process.
2216:             * @return the principal.
2217:             * @ejb.interface-method
2218:             * view-type="remote"
2219:             */
2220:            public Principal processCreator() {
2221:                return new SimplePrincipal(processCreator);
2222:            }
2223:
2224:            /**
2225:             * Returns an audit event object with process relevant information
2226:             * initialized.
2227:             * @return the process related information.
2228:             * @ejb.interface-method
2229:             * view-type="remote"
2230:             */
2231:            public WfAuditEvent auditEventBase() {
2232:                return auditEventBase(null);
2233:            }
2234:
2235:            /**
2236:             * Process newly generated event.
2237:             * @param evt Event
2238:             */
2239:            protected void fireAuditEvent(WfAuditEvent evt) {
2240:                if (delayedEvents != null) {
2241:                    delayedEvents.add(evt);
2242:                } else {
2243:                    try {
2244:                        queuer().queue((DefaultAuditEvent) evt);
2245:                    } catch (RemoteException e) {
2246:                        throw new EJBException(e);
2247:                    }
2248:                }
2249:            }
2250:
2251:            /**
2252:             * Returns a collection of <code>WfAuditEvent</code>s associated with
2253:             * this process describing its history.
2254:             * @return the collection of audit events
2255:             * @throws HistoryNotAvailableException in case the history is not 
2256:             * available for any reason
2257:             */
2258:            public Collection history() throws HistoryNotAvailableException {
2259:                try {
2260:                    return engineLocal().history(toProcess());
2261:                } catch (RemoteException rex) {
2262:                    throw new EJBException(rex);
2263:                }
2264:            }
2265:
2266:            /**
2267:             * Copy the process definition in xpdl string in this process. If the 
2268:             * process definition need to be removed, use this method to copy process
2269:             * definition in the database field of xpdl so that the process definition 
2270:             * can still be reconstructed.
2271:             * 
2272:             * @param procDefXpdl the given process definition in xpdl string.
2273:             */
2274:            public void copyProcessDefinition(String procDefXpdl) {
2275:                myProcDef = procDefXpdl;
2276:            }
2277:
2278:            /**
2279:             * Deliver a message on the given channel to a receiver tool
2280:             * listening on that channel.
2281:             *
2282:             * @param channel the channel name
2283:             * @param message the message
2284:             * @return <code>true</code> if the mesage could be delivered,
2285:             * <code>false</code> if no activity was listening
2286:             * @throws InvalidDataException if the message contains invalid data
2287:             * @ejb.interface-method view-type="remote"
2288:             */
2289:            public boolean deliverChannelMessage(String channel, Map message)
2290:                    throws InvalidDataException {
2291:                ActivityLocal act = null;
2292:                try {
2293:                    act = activityLocalHome().findByWaitingOn(
2294:                            (Long) ctx.getPrimaryKey(), channel);
2295:                    if (logger.isDebugEnabled()) {
2296:                        logger.debug("Delivering message "
2297:                                + CollectionsUtil.toString(message)
2298:                                + " from channel " + channel
2299:                                + " to waiting activity " + act);
2300:                    }
2301:                    try {
2302:                        act.setResult(new DefaultProcessData(message));
2303:                        act.complete();
2304:                    } catch (CannotCompleteException e) {
2305:                        logger.error("Activity " + act
2306:                                + " listening on channel "
2307:                                + "but cannot be completed?!: "
2308:                                + e.getMessage(), e);
2309:                        throw new IllegalStateException(
2310:                                "Receiving activity cannot be completed");
2311:                    }
2312:                    return true;
2313:                } catch (ObjectNotFoundException e) {
2314:                    return false;
2315:                } catch (RemoteException rex) {
2316:                    throw new EJBException(rex);
2317:                } catch (FinderException e) {
2318:                    throw new EJBException(e);
2319:                }
2320:            }
2321:
2322:            /**
2323:             * Deliver a message on the given channel to a receiver tool
2324:             * listening on that channel. If no tool is listening, store the
2325:             * message.
2326:             *
2327:             * @param channel the channel name
2328:             * @param message the message
2329:             * @throws InvalidDataException if the message contains invalid data
2330:             * @ejb.interface-method view-type="remote"
2331:             */
2332:            public void submitChannelMessage(String channel, Map message)
2333:                    throws InvalidDataException {
2334:                try {
2335:                    if (!deliverChannelMessage(channel, message)) {
2336:                        if (logger.isDebugEnabled()) {
2337:                            logger.debug("Putting message from channel "
2338:                                    + channel + " on queue");
2339:                        }
2340:                        queuer().queueChannelMessage(
2341:                                ((Long) ctx.getPrimaryKey()).toString(),
2342:                                channel, message);
2343:                    }
2344:                } catch (RemoteException rex) {
2345:                    throw new EJBException(rex);
2346:                }
2347:            }
2348:
2349:            /**
2350:             * Looks for a message on the given channel and if found returns it.
2351:             *
2352:             * @param channel the channel name
2353:             * @return the message or <code>null</code>
2354:             * @ejb.interface-method view-type="remote"
2355:             */
2356:            public Map lookForMessage(String channel) {
2357:                try {
2358:                    return queuer().lookForChannelMessage(
2359:                            ((Long) ctx.getPrimaryKey()).toString(), channel);
2360:                } catch (RemoteException e) {
2361:                    throw new EJBException(e);
2362:                }
2363:            }
2364:
2365:            /**
2366:             * Closes all channels.
2367:             */
2368:            protected void closeChannels() {
2369:                try {
2370:                    queuer().closeChannels(
2371:                            ((Long) ctx.getPrimaryKey()).toString());
2372:                } catch (ResourceNotAvailableException e) {
2373:                    throw new EJBException(e);
2374:                }
2375:            }
2376:
2377:            //
2378:            // Timers
2379:            //
2380:
2381:            /**
2382:             * Start a timer that will call <code>handleTimeout</code> at the
2383:             * given date with the given info.
2384:             * @param due target date
2385:             * @param info the context
2386:             */
2387:            public void startTimer(Date due, Serializable info) {
2388:                // Adjust duration
2389:                long duration = due.getTime() - System.currentTimeMillis();
2390:                if (duration <= 0) {
2391:                    logger.warn("Deadline with zero or negative duration ("
2392:                            + ((double) duration / 1000) + "s) for "
2393:                            + toString() + " will be triggered immediately.");
2394:                    duration = 1;
2395:                }
2396:                if (ctx.getClass().getName().startsWith("org.jboss.ejb.")) {
2397:                    // create a timer with interval to circumvent JBoss bug JBAS-2274
2398:                    ctx.getTimerService().createTimer(duration, 3600 * 1000,
2399:                            info);
2400:                } else {
2401:                    ctx.getTimerService().createTimer(duration, info);
2402:                }
2403:            }
2404:
2405:            /**
2406:             * Stop all timers that this object has created.
2407:             */
2408:            public void stopTimers() {
2409:                for (Iterator i = ctx.getTimerService().getTimers().iterator(); i
2410:                        .hasNext();) {
2411:                    Timer timer = (Timer) i.next();
2412:                    timer.cancel();
2413:                }
2414:            }
2415:
2416:            /**
2417:             * Handle the timeout of a timer.
2418:             * @param timer the timer that has expired.
2419:             */
2420:            public void ejbTimeout(Timer timer) {
2421:                try {
2422:                    if (logger.isDebugEnabled()) {
2423:                        logger.debug("Received timeout from " + timer + " for "
2424:                                + toString());
2425:                    }
2426:                    try {
2427:                        handleTimeout(timer.getInfo());
2428:                        if (ctx.getClass().getName().startsWith(
2429:                                "org.jboss.ejb.")) {
2430:                            // Because of JBoss bug JBAS-2274 we have an interval and 
2431:                            // must therefore cancel the timer
2432:                            timer.cancel();
2433:                        }
2434:                    } catch (NoSuchObjectLocalException e) {
2435:                        // JBoss may call this method with a canceled timer
2436:                        if (timer.getClass().getName().equals(
2437:                                "org.jboss.ejb.txtimer.TimerImpl")) {
2438:                            logger.debug("Exception \"" + e.getMessage()
2439:                                    + "\" ignored, caused by JBoss bug.");
2440:                            return;
2441:                        }
2442:                        throw e;
2443:                    }
2444:                } catch (EJBException e) {
2445:                    throw e;
2446:                } catch (Throwable e) {
2447:                    logger.error("Problem handling timer event " + timer
2448:                            + "(discarded): " + e.getMessage(), e);
2449:                }
2450:            }
2451:
2452:            //
2453:            // Implement accessor methods for the persistent attributes
2454:            //
2455:
2456:            /**
2457:             * The getter method implementation for the persistent 
2458:             * attribute <code>key</code>.
2459:             *
2460:             * @return the value of key.
2461:             */
2462:            protected String getPaKey() {
2463:                return ((Long) ctx.getPrimaryKey()).toString();
2464:            }
2465:
2466:            /**
2467:             * The getter method implementation for the persistent 
2468:             * attribute <code>createTime</code>.
2469:             *
2470:             * @return the value of createTime.
2471:             */
2472:            protected Date getPaCreateTime() {
2473:                return paCreateTime;
2474:            }
2475:
2476:            /**
2477:             * The getter method implementation for the persistent 
2478:             * attribute <code>name</code>.
2479:             *
2480:             * @see #setPaName
2481:             * @return the value of name.
2482:             */
2483:            protected String getPaName() {
2484:                return paName;
2485:            }
2486:
2487:            /**
2488:             * The setter method implementation for the persistent 
2489:             * attribute <code>name</code>.
2490:             *
2491:             * @param newName the new value of name.
2492:             * @see #getPaName
2493:             */
2494:            protected void setPaName(String newName) {
2495:                paName = newName;
2496:                persistentAttributeModified = true;
2497:            }
2498:
2499:            /**
2500:             * The getter method implementation for the persistent 
2501:             * attribute <code>description</code>.
2502:             *
2503:             * @see #setPaDescription
2504:             * @return the value of description.
2505:             */
2506:            protected String getPaDescription() {
2507:                return paDescription;
2508:            }
2509:
2510:            /**
2511:             * The setter method implementation for the persistent 
2512:             * attribute <code>description</code>.
2513:             *
2514:             * @param newDescription the new value of description.
2515:             * @see #getPaDescription
2516:             */
2517:            protected void setPaDescription(String newDescription) {
2518:                paDescription = newDescription;
2519:                paDescriptionModified = true;
2520:                persistentAttributeModified = true;
2521:            }
2522:
2523:            /**
2524:             * The getter method implementation for the persistent 
2525:             * attribute <code>priority</code>.
2526:             *
2527:             * @see #setPaPriority
2528:             * @return the value of priority.
2529:             */
2530:            protected Priority getPaPriority() {
2531:                return paPriority;
2532:            }
2533:
2534:            /**
2535:             * The setter method implementation for the persistent 
2536:             * attribute <code>priority</code>.
2537:             *
2538:             * @param newPriority the new value of priority.
2539:             * @see #getPaPriority
2540:             */
2541:            protected void setPaPriority(Priority newPriority) {
2542:                paPriority = newPriority;
2543:                persistentAttributeModified = true;
2544:            }
2545:
2546:            /**
2547:             * The getter method implementation for the persistent 
2548:             * attribute <code>typedState</code>.
2549:             *
2550:             * @see #setPaTypedState
2551:             * @return the value of typedState.
2552:             */
2553:            protected State getPaTypedState() {
2554:                return paTypedState;
2555:            }
2556:
2557:            /**
2558:             * The getter method implementation for the persistent 
2559:             * attribute <code>lastStateTime</code>.
2560:             *
2561:             * @see #setPaLastStateTime
2562:             * @return the value of lastStateTime.
2563:             */
2564:            protected Date getPaLastStateTime() {
2565:                return paLastStateTime;
2566:            }
2567:
2568:            /**
2569:             * The setter method implementation for the persistent 
2570:             * attribute <code>lastStateTime</code>.
2571:             *
2572:             * @param newLastStateTime the new value of lastStateTime.
2573:             * @see #getPaLastStateTime
2574:             */
2575:            protected void setPaLastStateTime(Date newLastStateTime) {
2576:                paLastStateTime = newLastStateTime;
2577:                persistentAttributeModified = true;
2578:            }
2579:
2580:            /**
2581:             * The setter method implementation for the persistent 
2582:             * attribute <code>typedState</code>.
2583:             *
2584:             * @param newTypedState the new value of typedState.
2585:             * @see #getPaTypedState
2586:             */
2587:            protected void setPaTypedState(State newTypedState) {
2588:                paTypedState = newTypedState;
2589:                persistentAttributeModified = true;
2590:            }
2591:
2592:            /**
2593:             * The getter method implementation for the persistent 
2594:             * attribute <code>processMgrName</code>.
2595:             *
2596:             * @see #setPaProcessMgrName
2597:             * @return the value of processMgrName.
2598:             */
2599:            protected String getPaProcessMgrName() {
2600:                return paProcessMgrName;
2601:            }
2602:
2603:            /**
2604:             * The setter method implementation for the persistent 
2605:             * attribute <code>processMgrName</code>.
2606:             *
2607:             * @param newProcessMgrName the new value of processMgrName.
2608:             * @see #getPaProcessMgrName
2609:             */
2610:            protected void setPaProcessMgrName(String newProcessMgrName) {
2611:                paProcessMgrName = newProcessMgrName;
2612:                persistentAttributeModified = true;
2613:            }
2614:
2615:            /**
2616:             * The getter method implementation for the persistent 
2617:             * attribute <code>processMgrVersion</code>.
2618:             *
2619:             * @see #setPaProcessMgrVersion
2620:             * @return the value of processMgrVersion.
2621:             */
2622:            protected String getPaProcessMgrVersion() {
2623:                return paProcessMgrVersion;
2624:            }
2625:
2626:            /**
2627:             * The setter method implementation for the persistent 
2628:             * attribute <code>processMgrVersion</code>.
2629:             *
2630:             * @param newProcessMgrVersion the new value of processMgrVersion.
2631:             * @see #getPaProcessMgrVersion
2632:             */
2633:            protected void setPaProcessMgrVersion(String newProcessMgrVersion) {
2634:                paProcessMgrVersion = newProcessMgrVersion;
2635:                persistentAttributeModified = true;
2636:            }
2637:
2638:            /**
2639:             * The getter method implementation for the persistent 
2640:             * attribute <code>requester</code>.
2641:             *
2642:             * @return the value of requester.
2643:             */
2644:            protected WfRequester getPaRequester() {
2645:                return paRequester;
2646:            }
2647:
2648:            /**
2649:             * The setter method implementation for the persistent 
2650:             * attribute <code>id</code>.
2651:             *
2652:             * @param newId the new value of process Id.
2653:             * @see #getPaId
2654:             */
2655:            protected void setPaId(String newId) {
2656:                paId = newId;
2657:                persistentAttributeModified = true;
2658:            }
2659:
2660:            /**
2661:             * The getter method implementation for the persistent 
2662:             * attribute <code>id</code>.
2663:             *
2664:             * @see #setPaId
2665:             * @return the value of process Id.
2666:             */
2667:            protected String getPaId() {
2668:                return paId;
2669:            }
2670:
2671:            /**
2672:             * The getter method implementation for the persistent attribute
2673:             * <code>processDef</code>. Three fields in the database
2674:             * contribute to the persistence implementation for the process
2675:             * definition: PackageId, ProcessId and Xpdl. If the
2676:             * process definition for the process has not been changed
2677:             * specifically and if the process definition still exists in the
2678:             * process definition directory, then packageId and processId are
2679:             * used to lookup the process definition.<P>
2680:             *
2681:             * If the definition of the process has changed, e.g. by inserting
2682:             * an additional activity or the process definition has been
2683:             * removed from the process definition directory. the string in
2684:             * field xpdl is used to reconstruct a process definition.
2685:             *
2686:             * @see #setPaProcessDef
2687:             * @return the value of processDef.
2688:             */
2689:            protected ProcessDefinition getPaProcessDef() {
2690:                if (paProcessDef == null) {
2691:                    ProcessDefinitionDirectoryLocal pdd = null;
2692:                    try {
2693:                        String def = loadProcDef();
2694:                        if (def != null) {
2695:                            paProcessDef = new DefaultProcessDefinition(def);
2696:                        } else {
2697:                            pdd = getProcessDefinitionDirectoryLocal();
2698:                            paProcessDef = pdd.lookupProcessDefinition(
2699:                                    packageId, processId);
2700:                        }
2701:                    } catch (SQLException sex) {
2702:                        logger.error(sex.getMessage(), sex);
2703:                        throw new ProviderException(sex.getMessage());
2704:                    } catch (IOException ioe) {
2705:                        logger.error(ioe.getMessage(), ioe);
2706:                        throw new ProviderException(ioe.getMessage());
2707:                    } catch (ImportException pe) {
2708:                        logger.error(pe.getMessage(), pe);
2709:                        throw new ProviderException(pe.getMessage());
2710:                    } catch (NamingException nex) {
2711:                        logger.error(nex.getMessage(), nex);
2712:                        throw new ProviderException(nex.getMessage());
2713:                    } catch (CreateException cex) {
2714:                        logger.error(cex.getMessage(), cex);
2715:                        throw new ProviderException(cex.getMessage());
2716:                    } catch (InvalidKeyException kex) {
2717:                        logger.error(kex.getMessage(), kex);
2718:                        throw new IllegalStateException(kex.getMessage());
2719:                    } finally {
2720:                        EJBUtil.removeSession(pdd);
2721:                    }
2722:                }
2723:                return paProcessDef;
2724:            }
2725:
2726:            /**
2727:             * The setter method implementation for the persistent 
2728:             * attribute <code>processDef</code>.
2729:             *
2730:             * @param newProcessDef the new value of processDef.
2731:             * @see #getPaProcessDef
2732:             */
2733:            protected void setPaProcessDef(ProcessDefinition newProcessDef) {
2734:                paProcessDef = newProcessDef;
2735:                persistentAttributeModified = true;
2736:            }
2737:
2738:            /**
2739:             * The getter method implementation for the persistent 
2740:             * attribute <code>processData</code>.
2741:             *
2742:             * @return the value of processData.
2743:             */
2744:            protected ProcessData getPaProcessData() {
2745:                return paProcessData;
2746:            }
2747:
2748:            /**
2749:             * The getter method implementation for the persistent 
2750:             * attribute <code>blockDeadlines</code>.
2751:             *
2752:             * @return the value of blockDeadlines.
2753:             */
2754:            protected Map getPaBlockDeadlines() {
2755:                return paBlockDeadlines;
2756:            }
2757:
2758:            /**
2759:             * The getter method implementation for the persistent 
2760:             * attribute <code>debug</code>.
2761:             *
2762:             * @see #setPaDebug
2763:             * @return the value of debug.
2764:             */
2765:            protected boolean getPaDebug() {
2766:                return (paFlags & FLAGS_DEBUG) != 0;
2767:            }
2768:
2769:            /**
2770:             * The setter method implementation for the persistent 
2771:             * attribute <code>debug</code>.
2772:             *
2773:             * @param newDebug the new value of debug.
2774:             * @see #getPaDebug
2775:             */
2776:            protected void setPaDebug(boolean newDebug) {
2777:                paFlags = (paFlags & FLAGS_DEBUG)
2778:                        | (newDebug ? FLAGS_DEBUG : 0);
2779:                persistentAttributeModified = true;
2780:            }
2781:
2782:            /**
2783:             * The getter method implementation for the persistent 
2784:             * attribute <code>auditEventSelection</code>.
2785:             *
2786:             * @see #setPaAuditEventSelection
2787:             * @return the value of auditEventSelection.
2788:             */
2789:            protected int getPaAuditEventSelection() {
2790:                return (paFlags & FLAGS_AUDIT_SELECTION_MASK) >> FLAGS_AUDIT_SELECTION_SHIFT;
2791:            }
2792:
2793:            /**
2794:             * The setter method implementation for the persistent 
2795:             * attribute <code>auditEventSelection</code>.
2796:             *
2797:             * @param newValue the new value of auditEventSelection.
2798:             * @see #getPaAuditEventSelection
2799:             */
2800:            protected void setPaAuditEventSelection(int newValue) {
2801:                paFlags = (paFlags & ~FLAGS_AUDIT_SELECTION_MASK)
2802:                        | (newValue << FLAGS_AUDIT_SELECTION_SHIFT);
2803:                persistentAttributeModified = true;
2804:            }
2805:
2806:            /**
2807:             * The getter method implementation for the persistent 
2808:             * attribute <code>storeAuditEvents</code>.
2809:             *
2810:             * @see #setPaStoreAuditEvents
2811:             * @return the value of storeAuditEvents.
2812:             */
2813:            protected boolean getPaStoreAuditEvents() {
2814:                return (paFlags & FLAGS_STORE_AUDIT_EVENTS) != 0;
2815:            }
2816:
2817:            /**
2818:             * The setter method implementation for the persistent 
2819:             * attribute <code>storeAuditEvents</code>.
2820:             *
2821:             * @param newValue the new value of storeAuditEvents.
2822:             * @see #getPaStoreAuditEvents
2823:             */
2824:            protected void setPaStoreAuditEvents(boolean newValue) {
2825:                paFlags = (paFlags & ~FLAGS_STORE_AUDIT_EVENTS)
2826:                        | (newValue ? FLAGS_STORE_AUDIT_EVENTS : 0);
2827:                persistentAttributeModified = true;
2828:            }
2829:
2830:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.