Source Code Cross Referenced for AbstractActivity.java in  » Workflow-Engines » wfmopen-2.1.1 » de » danet » an » workflow » domain » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /*
0002:         * This file is part of the WfMOpen project.
0003:         * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
0004:         * All rights reserved.
0005:         *
0006:         * This program is free software; you can redistribute it and/or modify
0007:         * it under the terms of the GNU General Public License as published by
0008:         * the Free Software Foundation; either version 2 of the License, or
0009:         * (at your option) any later version.
0010:         *
0011:         * This program is distributed in the hope that it will be useful,
0012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014:         * GNU General Public License for more details.
0015:         *
0016:         * You should have received a copy of the GNU General Public License
0017:         * along with this program; if not, write to the Free Software
0018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019:         *
0020:         * $Id: AbstractActivity.java,v 1.37.2.1 2007/11/02 16:00:33 drmlipp Exp $
0021:         *
0022:         * $Log: AbstractActivity.java,v $
0023:         * Revision 1.37.2.1  2007/11/02 16:00:33  drmlipp
0024:         * Merged bug fixes from HEAD.
0025:         *
0026:         * Revision 1.38  2007/09/21 06:19:35  mlipp
0027:         * Fixed problem with NamingException during process deletion.
0028:         *
0029:         * Revision 1.37  2007/09/14 12:34:42  drmlipp
0030:         * Improved map initialization.
0031:         *
0032:         * Revision 1.36  2007/05/03 21:58:19  mlipp
0033:         * Internal refactoring for making better use of local EJBs.
0034:         *
0035:         */
0036:        package de.danet.an.workflow.domain;
0037:
0038:        import java.io.Serializable;
0039:
0040:        import java.util.ArrayList;
0041:        import java.util.Collection;
0042:        import java.util.Collections;
0043:        import java.util.Date;
0044:        import java.util.HashMap;
0045:        import java.util.HashSet;
0046:        import java.util.Iterator;
0047:        import java.util.List;
0048:        import java.util.Map;
0049:        import java.util.Set;
0050:        import java.util.SortedMap;
0051:        import java.util.TreeMap;
0052:
0053:        import java.rmi.RemoteException;
0054:        import java.text.ParseException;
0055:
0056:        import de.danet.an.workflow.internalapi.ExtActivityLocal;
0057:        import de.danet.an.workflow.internalapi.ExtApplication;
0058:        import de.danet.an.workflow.internalapi.ExtImplementationLocal;
0059:        import de.danet.an.workflow.internalapi.ExtProcessLocal;
0060:        import de.danet.an.workflow.internalapi.ThreadInfo;
0061:        import de.danet.an.workflow.internalapi.ToolInvocationException;
0062:        import de.danet.an.workflow.internalapi.ExtActivityLocal.NotStartedState;
0063:        import de.danet.an.workflow.localapi.ActivityLocal;
0064:        import de.danet.an.workflow.localapi.ProcessLocal;
0065:        import de.danet.an.workflow.localapi.TransitionLocal;
0066:        import de.danet.an.workflow.localcoreapi.WfActivityLocal;
0067:        import de.danet.an.workflow.localcoreapi.WfProcessLocal;
0068:        import de.danet.an.workflow.omgcore.AlreadyRunningException;
0069:        import de.danet.an.workflow.omgcore.AlreadySuspendedException;
0070:        import de.danet.an.workflow.omgcore.CannotCompleteException;
0071:        import de.danet.an.workflow.omgcore.CannotResumeException;
0072:        import de.danet.an.workflow.omgcore.CannotStopException;
0073:        import de.danet.an.workflow.omgcore.CannotSuspendException;
0074:        import de.danet.an.workflow.omgcore.InvalidControlOperationException;
0075:        import de.danet.an.workflow.omgcore.InvalidDataException;
0076:        import de.danet.an.workflow.omgcore.InvalidPerformerException;
0077:        import de.danet.an.workflow.omgcore.InvalidResourceException;
0078:        import de.danet.an.workflow.omgcore.InvalidStateException;
0079:        import de.danet.an.workflow.omgcore.NotAssignedException;
0080:        import de.danet.an.workflow.omgcore.NotRunningException;
0081:        import de.danet.an.workflow.omgcore.NotSuspendedException;
0082:        import de.danet.an.workflow.omgcore.ProcessData;
0083:        import de.danet.an.workflow.omgcore.ResultNotAvailableException;
0084:        import de.danet.an.workflow.omgcore.TransitionNotAllowedException;
0085:        import de.danet.an.workflow.omgcore.UpdateNotAllowedException;
0086:        import de.danet.an.workflow.omgcore.WfAssignment;
0087:        import de.danet.an.workflow.omgcore.WfAuditEvent;
0088:        import de.danet.an.workflow.omgcore.WfResource;
0089:        import de.danet.an.workflow.omgcore.WfStateAuditEvent;
0090:        import de.danet.an.workflow.omgcore.WfExecutionObject.ClosedState;
0091:        import de.danet.an.workflow.omgcore.WfExecutionObject.NotRunningState;
0092:        import de.danet.an.workflow.omgcore.WfExecutionObject.OpenState;
0093:        import de.danet.an.workflow.omgcore.WfExecutionObject.State;
0094:
0095:        import de.danet.an.workflow.api.Activity;
0096:        import de.danet.an.workflow.api.ActivityUniqueKey;
0097:        import de.danet.an.workflow.api.AlreadyAssignedException;
0098:        import de.danet.an.workflow.api.InvalidIdException;
0099:        import de.danet.an.workflow.api.InvalidKeyException;
0100:        import de.danet.an.workflow.api.Participant;
0101:        import de.danet.an.workflow.api.ProcessDefinition;
0102:        import de.danet.an.workflow.api.Activity.ClosedCompletedState;
0103:        import de.danet.an.workflow.api.Activity.DeadlineInfo;
0104:        import de.danet.an.workflow.api.Activity.Implementation;
0105:        import de.danet.an.workflow.api.Activity.Info;
0106:        import de.danet.an.workflow.api.Activity.JoinAndSplitMode;
0107:        import de.danet.an.workflow.api.Activity.StartFinishMode;
0108:        import de.danet.an.workflow.api.Activity.SubFlowImplementation;
0109:        import de.danet.an.workflow.api.Activity.ToolImplementation;
0110:        import de.danet.an.workflow.apix.ExtActivity;
0111:
0112:        import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
0113:        import de.danet.an.workflow.spis.aii.ResultProvider.ExceptionResult;
0114:        import de.danet.an.workflow.spis.ras.ActivityFinder;
0115:
0116:        /**
0117:         * <code>AbstractActivity</code> represents a simple implementation
0118:         * of the interface {@link ActivityLocal <code>ActivityLocal</code>}.
0119:         * It has the following features:
0120:         * <ul>
0121:         * <li>It has no transition restrictions (INLINE, SPLIT, JOIN)
0122:         * </li>
0123:         * <li>The activity is an implementation activity of the type NO. 
0124:         * No SubFlows (SubProcess) or Loops can be expressed with this activity.
0125:         * </li>
0126:         * <li>The activity supports the StartMode and the FinishMode properties.
0127:         * </li>
0128:         * <li>The activity cannot act as a requester, i.e. can not start a 
0129:         * sub process.
0130:         * </li>
0131:         * </ul> 
0132:         */
0133:        public abstract class AbstractActivity extends AbstractExecutionObject
0134:                implements  TimedObject, Serializable {
0135:
0136:            private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
0137:                    .getLog(AbstractActivity.class);
0138:
0139:            // Make sure that loading this class loads the new states
0140:            static {
0141:                State s = NotStartedState.UNKNOWN;
0142:            }
0143:
0144:            // A mapping of states to sub-state to save the state during
0145:            // DebugState.FORWARDING_EXCEPTION
0146:            private static final int SUB_STATE_RUNNING = 1;
0147:            private static final int SUB_STATE_ABANDONING = 2;
0148:            private static final int SUB_STATE_ABORTING = 3;
0149:            private static final int SUB_STATE_COMPLETING = 4;
0150:            private static final int SUB_STATE_INVOKING = 5;
0151:            private static final int SUB_STATE_TERMINATING = 6;
0152:
0153:            private static final Map STATE_TO_SUB_STATE = new HashMap();
0154:            private static final Map SUB_STATE_TO_STATE = new HashMap();
0155:
0156:            static {
0157:                STATE_TO_SUB_STATE.put(RunningState.RUNNING, new Integer(
0158:                        SUB_STATE_RUNNING));
0159:                STATE_TO_SUB_STATE.put(DebugState.ABANDONING, new Integer(
0160:                        SUB_STATE_ABANDONING));
0161:                STATE_TO_SUB_STATE.put(DebugState.ABORTING, new Integer(
0162:                        SUB_STATE_ABORTING));
0163:                STATE_TO_SUB_STATE.put(DebugState.COMPLETING, new Integer(
0164:                        SUB_STATE_COMPLETING));
0165:                STATE_TO_SUB_STATE.put(DebugState.INVOKING, new Integer(
0166:                        SUB_STATE_INVOKING));
0167:                STATE_TO_SUB_STATE.put(DebugState.TERMINATING, new Integer(
0168:                        SUB_STATE_TERMINATING));
0169:                for (Iterator i = STATE_TO_SUB_STATE.entrySet().iterator(); i
0170:                        .hasNext();) {
0171:                    Map.Entry e = (Map.Entry) i.next();
0172:                    SUB_STATE_TO_STATE.put(e.getValue(), e.getKey());
0173:                }
0174:            }
0175:
0176:            private static final Map CLOSE_STATE_TO_DEBUG_STATE = new HashMap();
0177:            private static final Map DEBUG_STATE_TO_CLOSE_STATE = new HashMap();
0178:
0179:            static {
0180:                CLOSE_STATE_TO_DEBUG_STATE.put(ClosedState.ABORTED,
0181:                        DebugState.ABORTING);
0182:                CLOSE_STATE_TO_DEBUG_STATE.put(ClosedState.TERMINATED,
0183:                        DebugState.TERMINATING);
0184:                CLOSE_STATE_TO_DEBUG_STATE.put(ClosedCompletedState.NORMAL,
0185:                        DebugState.COMPLETING);
0186:                for (Iterator i = CLOSE_STATE_TO_DEBUG_STATE.entrySet()
0187:                        .iterator(); i.hasNext();) {
0188:                    Map.Entry e = (Map.Entry) i.next();
0189:                    DEBUG_STATE_TO_CLOSE_STATE.put(e.getValue(), e.getKey());
0190:                }
0191:            }
0192:
0193:            // The sorted list of transition id's for the split
0194:            private List splitList = null;
0195:
0196:            /**
0197:             * Creates a new <code>AbstractActivity</code>.
0198:             */
0199:            public AbstractActivity() {
0200:            }
0201:
0202:            //
0203:            // Persistent attribute accessors and associated methods
0204:            //
0205:
0206:            /**
0207:             * The getter method for the persistent attribute <code>actImpl</code>.
0208:             *
0209:             * @return the value of actImpl.
0210:             * @see #setPaActImpl
0211:             */
0212:            protected abstract Implementation[] getPaActImpl();
0213:
0214:            /**
0215:             * The setter method for the persistent attribute <code>actImpl</code>.
0216:             *
0217:             * @param newActImpl the new value of actImpl.
0218:             * @see #getPaActImpl
0219:             */
0220:            protected abstract void setPaActImpl(Implementation[] newActImpl);
0221:
0222:            /**
0223:             * The getter method for the persistent attribute <code>performer</code>.
0224:             *
0225:             * @return the value of performer.
0226:             * @see #setPaPerformer
0227:             */
0228:            protected abstract String getPaPerformer();
0229:
0230:            /**
0231:             * The setter method for the persistent attribute <code>performer</code>.
0232:             *
0233:             * @param newPerformer the new value of performer.
0234:             * @see #getPaPerformer
0235:             */
0236:            protected abstract void setPaPerformer(String newPerformer);
0237:
0238:            /**
0239:             * The getter method for the persistent attribute <code>executor</code>.
0240:             *
0241:             * @return the value of executor.
0242:             * @see #setPaExecStat
0243:             */
0244:            protected abstract Integer getPaExecStat();
0245:
0246:            /**
0247:             * The setter method for the persistent attribute <code>executor</code>.
0248:             *
0249:             * @param newExecutor the new value of executor.
0250:             * @see #getPaExecStat
0251:             */
0252:            protected abstract void setPaExecStat(Integer newExecutor);
0253:
0254:            /**
0255:             * The getter method for the persistent attribute <code>startMode</code>.
0256:             *
0257:             * @return the value of startMode.
0258:             * @see #setPaStartMode
0259:             */
0260:            protected abstract StartFinishMode getPaStartMode();
0261:
0262:            /**
0263:             * The setter method for the persistent attribute <code>startMode</code>.
0264:             *
0265:             * @param newStartMode the new value of startMode.
0266:             * @see #getPaStartMode
0267:             */
0268:            protected abstract void setPaStartMode(StartFinishMode newStartMode);
0269:
0270:            /**
0271:             * The getter method for the persistent attribute <code>finishMode</code>.
0272:             *
0273:             * @return the value of finishMode.
0274:             * @see #setPaFinishMode
0275:             */
0276:            protected abstract StartFinishMode getPaFinishMode();
0277:
0278:            /**
0279:             * The setter method for the persistent attribute <code>finishMode</code>.
0280:             *
0281:             * @param newFinishMode the new value of finishMode.
0282:             * @see #getPaFinishMode
0283:             */
0284:            protected abstract void setPaFinishMode(
0285:                    StartFinishMode newFinishMode);
0286:
0287:            /**
0288:             * The getter method for the persistent attribute <code>joinMode</code>.
0289:             *
0290:             * @return the value of joinMode.
0291:             * @see #setPaJoinMode
0292:             */
0293:            protected abstract JoinAndSplitMode getPaJoinMode();
0294:
0295:            /**
0296:             * The setter method for the persistent attribute <code>joinMode</code>.
0297:             *
0298:             * @param newJoinMode the new value of joinMode.
0299:             * @see #getPaJoinMode
0300:             */
0301:            protected abstract void setPaJoinMode(JoinAndSplitMode newJoinMode);
0302:
0303:            /**
0304:             * The getter method for the persistent attribute <code>splitMode</code>.
0305:             *
0306:             * @return the value of splitMode.
0307:             * @see #setPaSplitMode
0308:             */
0309:            protected abstract JoinAndSplitMode getPaSplitMode();
0310:
0311:            /**
0312:             * The setter method for the persistent attribute <code>splitMode</code>.
0313:             *
0314:             * @param newSplitMode the new value of splitMode.
0315:             * @see #getPaSplitMode
0316:             */
0317:            protected abstract void setPaSplitMode(JoinAndSplitMode newSplitMode);
0318:
0319:            /**
0320:             * The getter method for the persistent attribute 
0321:             * <code>pendingException</code>.
0322:             *
0323:             * @return the value of pendingException.
0324:             * @see #setPaPendingException
0325:             */
0326:            protected abstract String getPaPendingException();
0327:
0328:            /**
0329:             * The setter method for the persistent attribute 
0330:             * <code>pendingException</code>.
0331:             *
0332:             * @param newPendingException the new value of pendingException.
0333:             * @see #getPaPendingException
0334:             */
0335:            protected abstract void setPaPendingException(
0336:                    String newPendingException);
0337:
0338:            /**
0339:             * The getter method for the persistent flag 
0340:             * <code>pendingExceptionIsFromBlock</code>.
0341:             *
0342:             * @return the value of the flag.
0343:             * @see #setPaPendingExceptionIsFromBlock
0344:             */
0345:            protected abstract boolean getPaPendingExceptionIsFromBlock();
0346:
0347:            /**
0348:             * The setter method for the persistent flags 
0349:             * <code>pendingExceptionIsFromBlock</code>.
0350:             *
0351:             * @param newValue the new value of the flag.
0352:             * @see #getPaPendingExceptionIsFromBlock
0353:             */
0354:            protected abstract void setPaPendingExceptionIsFromBlock(
0355:                    boolean newValue);
0356:
0357:            /**
0358:             * The getter method implementation for the persistent 
0359:             * read-only attribute <code>processKey</code>.
0360:             * May be overridden by the derived class to speed up access
0361:             * in distsributed systems.
0362:             *
0363:             * @return the value of processKey.
0364:             */
0365:            protected String getPaProcessKey() {
0366:                return containerLocal().key();
0367:            }
0368:
0369:            /**
0370:             * The getter method implementation for the persistent 
0371:             * read-only attribute <code>processName</code>.
0372:             * May be overridden by the derived class to speed up access
0373:             * in distsributed systems.
0374:             *
0375:             * @return the value of processName.
0376:             */
0377:            protected String getPaProcessName() {
0378:                return containerLocal().name();
0379:            }
0380:
0381:            /**
0382:             * The getter method implementation for the persistent 
0383:             * read-only attribute <code>processMgrName</code>.
0384:             * May be overridden by the derived class to speed up access
0385:             * in distsributed systems.
0386:             *
0387:             * @return the value of processMgrName.
0388:             */
0389:            protected String getPaProcessMgrName() {
0390:                return ((ProcessLocal) containerLocal()).processDefinition()
0391:                        .mgrName();
0392:            }
0393:
0394:            /**
0395:             * The getter method implementation for the persistent 
0396:             * read-only attribute <code>processMgrVersion</code>.
0397:             * May be overridden by the derived class to speed up access
0398:             * in distsributed systems.
0399:             *
0400:             * @return the value of processMgrVersion.
0401:             */
0402:            protected String getPaProcessMgrVersion() {
0403:                return ((ProcessLocal) containerLocal()).processDefinition()
0404:                        .version();
0405:            }
0406:
0407:            /**
0408:             * The getter method for the persistent attribute <code>threadInfo</code>.
0409:             *
0410:             * @return the value of threadInfo.
0411:             * @see #setPaThreadInfo
0412:             */
0413:            protected abstract ThreadInfo getPaThreadInfo();
0414:
0415:            /**
0416:             * The setter method for the persistent attribute <code>threadInfo</code>.
0417:             *
0418:             * @param newThreadInfo the new value of threadInfo.
0419:             * @see #getPaThreadInfo
0420:             */
0421:            protected abstract void setPaThreadInfo(ThreadInfo newThreadInfo);
0422:
0423:            /**
0424:             * The getter method for the persistent attribute <code>Subflow</code>.
0425:             *
0426:             * @return the value of Subflow.
0427:             * @see #setPaSubflow
0428:             */
0429:            protected abstract String getPaSubflow();
0430:
0431:            /**
0432:             * The setter method for the persistent attribute <code>Subflow</code>.
0433:             *
0434:             * @param newSubflow the new value of Subflow.
0435:             * @see #getPaSubflow
0436:             */
0437:            protected abstract void setPaSubflow(String newSubflow);
0438:
0439:            /**
0440:             * The getter method for the persistent attribute <code>deadlines</code>.
0441:             *
0442:             * @return the value of deadlines.
0443:             * @see #setPaDeadlines
0444:             */
0445:            protected abstract List getPaDeadlines();
0446:
0447:            /**
0448:             * The setter method for the persistent attribute <code>deadlines</code>.
0449:             *
0450:             * @param newDeadlines the new value of deadlines.
0451:             * @see #getPaDeadlines
0452:             */
0453:            protected abstract void setPaDeadlines(List newDeadlines);
0454:
0455:            /**
0456:             * The getter method for the persistent attribute <code>startTime</code>.
0457:             *
0458:             * @return the value of startTime.
0459:             * @see #setPaStartTime
0460:             */
0461:            protected abstract Date getPaStartTime();
0462:
0463:            /**
0464:             * The setter method for the persistent attribute <code>startTime</code>.
0465:             *
0466:             * @param newStartTime the new value of startTime.
0467:             * @see #getPaStartTime
0468:             */
0469:            protected abstract void setPaStartTime(Date newStartTime);
0470:
0471:            /**
0472:             * The getter method for the persistent attribute <code>suspendStart</code>.
0473:             *
0474:             * @return the value of suspendStart.
0475:             * @see #setPaSuspendStart
0476:             */
0477:            protected abstract Date getPaSuspendStart();
0478:
0479:            /**
0480:             * The setter method for the persistent attribute <code>suspendStart</code>.
0481:             *
0482:             * @param newSuspendStart the new value of suspendStart.
0483:             * @see #getPaSuspendStart
0484:             */
0485:            protected abstract void setPaSuspendStart(Date newSuspendStart);
0486:
0487:            /**
0488:             * The getter method for the persistent attribute <code>suspendAccum</code>.
0489:             *
0490:             * @return the value of suspendAccum.
0491:             * @see #setPaSuspendAccum
0492:             */
0493:            protected abstract long getPaSuspendAccum();
0494:
0495:            /**
0496:             * The setter method for the persistent attribute <code>suspendAccum</code>.
0497:             *
0498:             * @param newSuspendAccum the new value of suspendAccum.
0499:             * @see #getPaSuspendAccum
0500:             */
0501:            protected abstract void setPaSuspendAccum(long newSuspendAccum);
0502:
0503:            /**
0504:             * The getter method for the persistent attribute
0505:             * <code>blockActivity</code>.
0506:             *
0507:             * @return the value of blockActivity.
0508:             * @see #setPaBlockActivity
0509:             */
0510:            protected abstract Long getPaBlockActivity();
0511:
0512:            /**
0513:             * The setter method for the persistent attribute
0514:             * <code>blockActivity</code>.
0515:             *
0516:             * @param newBlockActivity the new value of blockActivity.
0517:             * @see #getPaBlockActivity
0518:             */
0519:            protected abstract void setPaBlockActivity(Long newBlockActivity);
0520:
0521:            /**
0522:             * The getter method for the persistent attribute
0523:             * <code>waitOnProc</code>.
0524:             *
0525:             * @return the value of waitOnProc.
0526:             * @see #setPaWaitOnProc
0527:             */
0528:            protected abstract Long getPaWaitOnProc();
0529:
0530:            /**
0531:             * The setter method for the persistent attribute
0532:             * <code>waitOnProc</code>.
0533:             *
0534:             * @param newWaitOnProc the new value of waitOnProc.
0535:             * @see #getPaWaitOnProc
0536:             */
0537:            protected abstract void setPaWaitOnProc(Long newWaitOnProc);
0538:
0539:            /**
0540:             * The getter method for the persistent attribute
0541:             * <code>waitOnChan</code>.
0542:             *
0543:             * @return the value of waitOnChan.
0544:             * @see #setPaWaitOnChan
0545:             */
0546:            protected abstract String getPaWaitOnChan();
0547:
0548:            /**
0549:             * The setter method for the persistent attribute
0550:             * <code>waitOnChan</code>.
0551:             *
0552:             * @param newWaitOnChan the new value of waitOnChan.
0553:             * @see #getPaWaitOnChan
0554:             */
0555:            protected abstract void setPaWaitOnChan(String newWaitOnChan);
0556:
0557:            /**
0558:             * The getter method for the persistent attribute
0559:             * <code>subStateBackup</code>.
0560:             *
0561:             * @return the value of subStateBackup.
0562:             * @see #setPaSubStateBackup
0563:             */
0564:            protected abstract int getPaSubStateBackup();
0565:
0566:            /**
0567:             * The setter method for the persistent attribute
0568:             * <code>subStateBackup</code>.
0569:             *
0570:             * @param newSubStateBackup the new value of subStateBackup.
0571:             * @see #getPaSubStateBackup
0572:             */
0573:            protected abstract void setPaSubStateBackup(int newSubStateBackup);
0574:
0575:            /**
0576:             * The getter method for the persistent attribute
0577:             * <code>deferChoiceOnSplit</code>.
0578:             *
0579:             * @return the value of deferChoiceOnSplit.
0580:             * @see #setPaDeferChoiceOnSplit
0581:             */
0582:            protected abstract boolean getPaDeferChoiceOnSplit();
0583:
0584:            /**
0585:             * The setter method for the persistent attribute
0586:             * <code>deferChoiceOnSplit</code>.
0587:             *
0588:             * @param newDeferChoiceOnSplit the new value of deferChoiceOnSplit.
0589:             * @see #getPaDeferChoiceOnSplit
0590:             */
0591:            protected abstract void setPaDeferChoiceOnSplit(
0592:                    boolean newDeferChoiceOnSplit);
0593:
0594:            /**
0595:             * The getter method for the persistent attribute
0596:             * <code>electedInChoice</code>.
0597:             *
0598:             * @return the value of electedInChoice.
0599:             * @see #setPaPreliminarilyChosen
0600:             */
0601:            protected abstract boolean getPaPreliminarilyChosen();
0602:
0603:            /**
0604:             * The setter method for the persistent attribute
0605:             * <code>electedInChoice</code>.
0606:             *
0607:             * @param newElectedInChoice the new value of electedInChoice.
0608:             * @see #getPaPreliminarilyChosen
0609:             */
0610:            protected abstract void setPaPreliminarilyChosen(
0611:                    boolean newElectedInChoice);
0612:
0613:            /**
0614:             * The getter method for the persistent attribute
0615:             * <code>noAssignments</code>.
0616:             *
0617:             * @return the value of noAssignments.
0618:             * @see #setPaNoAssignments
0619:             */
0620:            protected abstract boolean getPaNoAssignments();
0621:
0622:            /**
0623:             * The setter method for the persistent attribute
0624:             * <code>noAssignments</code>.
0625:             *
0626:             * @param newNoAssignments the new value of noAssignments.
0627:             * @see #getPaNoAssignments
0628:             */
0629:            protected abstract void setPaNoAssignments(boolean newNoAssignments);
0630:
0631:            /**
0632:             * Initializes the class, i.e. sets all attributes to the given
0633:             * values. Note that {@link #refresh <code>refresh</code>} will be
0634:             * called subsequently.
0635:             * 
0636:             * @param blockActId if the activity is part of a block activity,
0637:             * else <code>null</code>
0638:             * @param priority a <code>Priority</code> value
0639:             * @param name the activity's name
0640:             * @param description activity description
0641:             * @param startMode the start mode
0642:             * @param finishMode the finish mode
0643:             * @param joinMode the join mode
0644:             * @param splitMode the split mode
0645:             * @param implementation the implementation description
0646:             * @param performer the performer
0647:             * @param deadlines the deadlines
0648:             * @param deferChoiceOnSplit if the split is to be made as
0649:             * deferred choice
0650:             * @param auditEventSelection the audit event selection
0651:             * @param storeAuditEvents if true, audit events are stored in the
0652:             * database
0653:             * @see #dispose
0654:             */
0655:            protected void init(Long blockActId, Priority priority,
0656:                    String name, String description, StartFinishMode startMode,
0657:                    StartFinishMode finishMode, JoinAndSplitMode joinMode,
0658:                    JoinAndSplitMode splitMode,
0659:                    Implementation[] implementation, String performer,
0660:                    List deadlines, boolean deferChoiceOnSplit,
0661:                    int auditEventSelection, boolean storeAuditEvents) {
0662:                super .init();
0663:                reset(false, false);
0664:                // (re-)init attributes
0665:                setPaSubflow(null);
0666:                setPaStartTime(null);
0667:                setPaSuspendStart(null);
0668:                setPaSuspendAccum(0);
0669:                setPaWaitOnProc(null);
0670:                setPaWaitOnChan(null);
0671:                setPaNoAssignments(true);
0672:                // set given properties
0673:                setPaBlockActivity(blockActId);
0674:                setPaPriority(priority);
0675:                setPaName(name);
0676:                setPaDescription(description);
0677:                setPaStartMode(startMode);
0678:                setPaFinishMode(finishMode);
0679:                setPaJoinMode(joinMode);
0680:                setPaSplitMode(splitMode);
0681:                setPaActImpl(implementation);
0682:                setPaPerformer(performer);
0683:                setPaDeadlines(deadlines);
0684:                setPaDeferChoiceOnSplit(deferChoiceOnSplit);
0685:                setPaAuditEventSelection(auditEventSelection);
0686:                setPaStoreAuditEvents(storeAuditEvents);
0687:            }
0688:
0689:            /**
0690:             * Called after change of persistent attributes. May be used to
0691:             * synchronise state derived from persistent attributes with
0692:             * the new values.
0693:             *
0694:             * @see #init
0695:             */
0696:            protected void refresh() {
0697:                super .refresh();
0698:            }
0699:
0700:            /**
0701:             * Releases all allocated resources. The object will be in an
0702:             * unusable state until resources are reallocated by calling
0703:             * {@link #init <code>init</code>} and
0704:             * {@link #refresh <code>refresh</code>}.
0705:             */
0706:            protected void dispose() {
0707:                super .dispose();
0708:            }
0709:
0710:            //
0711:            // Domain methods
0712:            //
0713:
0714:            /**
0715:             * Indicates if some other object is equal to this one. <P>
0716:             *
0717:             * Note that <code>obj</code> may be a stub representing the
0718:             * object. Stubs do not in general implement
0719:             * <code>equals</code> correctly, so while
0720:             * <code>this.equals(obj)</code> does indicate the equality as
0721:             * defined for this class, <code>obj.equals(this)</code> generally
0722:             * does not.
0723:             *
0724:             * @param obj the object to compare with.
0725:             * @return <code>true</code> if the other object is equal.
0726:             */
0727:            public boolean equals(Object obj) {
0728:                return (obj instanceof  AbstractActivity)
0729:                        && getPaKey().equals(((AbstractActivity) obj).key())
0730:                        || (obj instanceof  WfActivityLocal)
0731:                        && getPaKey().equals(((WfActivityLocal) obj).key());
0732:            }
0733:
0734:            /**
0735:             * Return the context of this <code>WfExecutionObject</code>.
0736:             * The process data object returned is a copy of the name value
0737:             * association, the values are not copied, however.
0738:             *
0739:             * @return the process relevant data that define the context of the 
0740:             * process.
0741:             */
0742:            public ProcessData processContext() {
0743:                return containerLocal().processContext();
0744:            }
0745:
0746:            /**
0747:             * Set new process context.
0748:             * @param newValue new value for proces context.
0749:             * @throws InvalidDataException if data is invalid
0750:             * @throws UpdateNotAllowedException if update is not allowed
0751:             */
0752:            public void setProcessContext(ProcessData newValue)
0753:                    throws InvalidDataException, UpdateNotAllowedException {
0754:                throw new UpdateNotAllowedException("Not supported");
0755:            }
0756:
0757:            /**
0758:             * The default implementation of <code>result</code> throws a 
0759:             * <code>ResultNotAvailableException</code> as this implementation does
0760:             * not provide access to the results of an activity.
0761:             *
0762:             * @return a <code>ProcessData</code> value
0763:             * @exception ResultNotAvailableException if no result is available.
0764:             * @ejb.interface-method view-type="remote"
0765:             */
0766:            public ProcessData result() throws ResultNotAvailableException {
0767:                throw new ResultNotAvailableException();
0768:            }
0769:
0770:            /**
0771:             * The default implementation of <code>setResult</code> maps the
0772:             * formal parameter names to actual process data item names and
0773:             * merges the result data in the process context.
0774:             *
0775:             * @param result the result data.
0776:             * @exception InvalidDataException if the data does not match the
0777:             * parameter list.
0778:             * @ejb.interface-method view-type="remote"
0779:             */
0780:            public void setResult(ProcessData result)
0781:                    throws InvalidDataException {
0782:                int curExec = getPaExecStat().intValue();
0783:                if (!workflowState().equals(State.OPEN)) {
0784:                    // maybe this activity is already closed by deadline event
0785:                    if (typedState().isSameOrSubState(
0786:                            ClosedCompletedState.ABANDONED)) {
0787:                        logger
0788:                                .warn("Call to setResult() ignored because "
0789:                                        + toString()
0790:                                        + " has already been abandoned (probably called "
0791:                                        + "by tool that could not be terminated).");
0792:                        return;
0793:                    }
0794:                    throw new InvalidDataException("Cannot set result for "
0795:                            + this  + ": state is " + state() + " (not open).");
0796:                }
0797:                if (curExec == 0 || curExec == Integer.MAX_VALUE) {
0798:                    throw new InvalidDataException("Cannot set result for "
0799:                            + this  + ": no tool running.");
0800:                }
0801:                ((ExtImplementationLocal) getPaActImpl()[Math.abs(curExec) - 1])
0802:                        .mergeResult(toActivityLocal(), result);
0803:                if (getPaPreliminarilyChosen()) {
0804:                    try {
0805:                        choose();
0806:                    } catch (TransitionNotAllowedException e) {
0807:                        // cannot happen because state has been checked already
0808:                        logger.error("Unexpected exception: " + e.getMessage(),
0809:                                e);
0810:                    }
0811:                }
0812:                if (getPaAuditEventSelection() == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS) {
0813:                    fireAuditEvent(new DefaultDataAuditEvent(
0814:                            auditEventBase(WfAuditEvent.ACTIVITY_RESULT_CHANGED),
0815:                            null, result));
0816:                }
0817:            }
0818:
0819:            /**
0820:             * Check if the given assignment is among the assignments of this 
0821:             * activity.
0822:             * @param member the assignment in question.
0823:             * @return true if the assignment is among the assignments of this 
0824:             * activity.
0825:             */
0826:            public boolean isMemberOfAssignments(WfAssignment member) {
0827:                throw new UnsupportedOperationException();
0828:            }
0829:
0830:            /**
0831:             * Return all performers associated with this requester.
0832:             *
0833:             * @return A {@link java.util.Collection collection} of
0834:             * associated performers.
0835:             */
0836:            public Collection performers() {
0837:                Collection res = new ArrayList();
0838:                for (Iterator i = performersLocal().iterator(); i.hasNext();) {
0839:                    res.add(((ExtProcessLocal) i.next()).toProcess());
0840:                }
0841:                return res;
0842:            }
0843:
0844:            /**
0845:             * Return all performers associated with this requester.
0846:             *
0847:             * @return A {@link java.util.Collection collection} of
0848:             * associated performers.
0849:             */
0850:            public Collection performersLocal() {
0851:                Collection res = new ArrayList();
0852:                if (getPaSubflow() != null) {
0853:                    try {
0854:                        res.add(lookupProcessLocal(getPaSubflow()));
0855:                    } catch (InvalidKeyException e) {
0856:                        // process has been deleted, avoid repeated lookup
0857:                        setPaSubflow(null);
0858:                    }
0859:                }
0860:                return res;
0861:            }
0862:
0863:            /**
0864:             * Lookup a process by its key. Can only be implemented by the
0865:             * persistence layer.
0866:             * @param key the primary key
0867:             * @return the process
0868:             * @throws InvalidKeyException if no process with the given key
0869:             * exists
0870:             */
0871:            protected abstract ExtProcessLocal lookupProcessLocal(String key)
0872:                    throws InvalidKeyException;
0873:
0874:            /**
0875:             * Called by the workflow engine if the activity is a requester.
0876:             *
0877:             * @param e the event.
0878:             * @throws InvalidPerformerException thrown by the derived
0879:             * {@link de.danet.an.workflow.localcoreapi.WfRequesterLocal 
0880:             * <code>WfRequesterLocal</code>} if it receives an event from a 
0881:             * process that is not among its performers.
0882:             */
0883:            public void receiveEvent(WfAuditEvent e)
0884:                    throws InvalidPerformerException {
0885:            }
0886:
0887:            /**
0888:             * Return the remote version of this object. 
0889:             *
0890:             * @return the client side object.
0891:             */
0892:            public abstract Activity toActivity();
0893:
0894:            /**
0895:             * Return the version of this object to be passed to as local reference. 
0896:             *
0897:             * @return the client side object.
0898:             */
0899:            protected abstract ExtActivityLocal toActivityLocal();
0900:
0901:            /**
0902:             * Returns the <code>WfProcessLocal</code> that this activity is a part of.
0903:             * @return the process.
0904:             */
0905:            public abstract WfProcessLocal containerLocal();
0906:
0907:            /**
0908:             * Return a unique key for the activity. (Note that the OMG
0909:             * interface defines the key returned by the {@link
0910:             * de.danet.an.workflow.localcoreapi.WfExecutionObjectLocal#key
0911:             * <code>key()</code>} method as unique within the scope of the
0912:             * containing process only.)
0913:             * @return value of uniqueKey.
0914:             */
0915:            public ActivityUniqueKey uniqueKey() {
0916:                return new ActivityUniqueKey(getPaProcessMgrName(),
0917:                        getPaProcessKey(), getPaKey());
0918:            }
0919:
0920:            /**
0921:             * This method returns all available information about the
0922:             * activity in a single operation.
0923:             *
0924:             * @return the resulting <code>Activity.Info</code> value
0925:             */
0926:            public Info activityInfo() {
0927:                WfProcessLocal proc = containerLocal();
0928:                return new Info(uniqueKey(), name(), description(), priority(),
0929:                        lastStateTime(), getPaProcessName(), proc.description());
0930:            }
0931:
0932:            /**
0933:             * Returns the key of the "parent" block activity. All activities
0934:             * implicitly created by a block activity share the same block
0935:             * activity key.<P>
0936:             *
0937:             * Note that there need not be an activity with the returned key,
0938:             * as an activity set is actually a template describing how to
0939:             * implement block activities. The information obtained can mainly
0940:             * be used to group all activities that have been instantiated as
0941:             * part of an activity set.<P>
0942:             *
0943:             * @return an identification of the block activity that caused
0944:             * this activity to be instantiated or <code>null</code> if this
0945:             * activity was not instantiated as part of an activity set
0946:             */
0947:            public String blockActivity() {
0948:                Long ba = getPaBlockActivity();
0949:                if (ba == null) {
0950:                    return null;
0951:                }
0952:                return ba.toString();
0953:            }
0954:
0955:            /**
0956:             * Returns an <code>WfAuditEvent</code> containing container-related
0957:             * information.
0958:             * @return the audit event 
0959:             */
0960:            protected abstract WfAuditEvent containerAuditEventBase();
0961:
0962:            /**
0963:             * List of possible modes for the activity.
0964:             * Handles the mapping between the mode name and the mode object.
0965:             */
0966:            private static Map activityModes = null;
0967:
0968:            /**
0969:             * Returns the implementation of the activity as {@link
0970:             * de.danet.an.workflow.localapi.ActivityLocal.Implementation
0971:             * <code>Implementation</code>}s.
0972:             * 
0973:             * @return an array of <code>Implementation</code>}s or
0974:             * <code>null</code> if no implementation is defined.
0975:             */
0976:            public Implementation[] implementation() {
0977:                return getPaActImpl();
0978:            }
0979:
0980:            /**
0981:             * Returns the deadlines defined for this activity.
0982:             *
0983:             * @return the deadlines
0984:             */
0985:            public DeadlineInfo[] deadlines() {
0986:                DeadlineInfo[] dli = new DeadlineInfo[getPaDeadlines().size()];
0987:                boolean closed = typedState().isSameOrSubState(State.CLOSED);
0988:                boolean running = typedState().isSameOrSubState(
0989:                        OpenState.RUNNING);
0990:                int i = 0;
0991:                for (Iterator it = getPaDeadlines().iterator(); it.hasNext(); i++) {
0992:                    Deadline dl = (Deadline) it.next();
0993:                    int state = dl.getState();
0994:                    if (closed && state == Deadline.STATE_INITIAL) {
0995:                        state = DeadlineInfo.STATE_CANCELED;
0996:                    } else if (running && state == Deadline.STATE_INITIAL) {
0997:                        state = DeadlineInfo.STATE_ACTIVE;
0998:                    }
0999:                    dli[i] = new DeadlineInfo(dl.getExecution(), dl
1000:                            .getExceptionName(), dl.getCondition(), state);
1001:                }
1002:                return dli;
1003:            }
1004:
1005:            /**
1006:             * Return the start time of the activity.
1007:             * @return result
1008:             * @throws NotRunningException if the activity has not been started yet
1009:             */
1010:            public Date startTime() throws NotRunningException {
1011:                if (getPaStartTime() == null) {
1012:                    throw new NotRunningException(state());
1013:                }
1014:                return getPaStartTime();
1015:            }
1016:
1017:            /**
1018:             * Returns the performer as string.
1019:             * @return performer as string
1020:             */
1021:            public String performer() {
1022:                return getPaPerformer();
1023:            }
1024:
1025:            /**
1026:             * Returns the current executor.
1027:             *
1028:             * @return current executor or <code>null</code> if no executor
1029:             * running.
1030:             */
1031:            public Implementation executor() {
1032:                if (getPaExecStat().intValue() <= 0
1033:                        || getPaExecStat().intValue() == Integer.MAX_VALUE) {
1034:                    return null;
1035:                }
1036:                Implementation impl = getPaActImpl()[getPaExecStat().intValue() - 1];
1037:                if (impl instanceof  ProcBasedImpl) {
1038:                    ((ProcBasedImpl) impl).setProcessKey(getPaSubflow());
1039:                }
1040:                return impl;
1041:            }
1042:
1043:            /**
1044:             * Returns the start mode.
1045:             * @return  start mode
1046:             */
1047:            protected StartFinishMode startMode() {
1048:                return getPaStartMode();
1049:            }
1050:
1051:            /**
1052:             * Returns the finish mode.
1053:             * @return  finish mode
1054:             */
1055:            protected StartFinishMode finishMode() {
1056:                return getPaFinishMode();
1057:            }
1058:
1059:            /**
1060:             * Set the join mode of the activity.
1061:             * @param joinMode the new join mode
1062:             */
1063:            public void setJoinMode(JoinAndSplitMode joinMode) {
1064:                setPaJoinMode(joinMode);
1065:            }
1066:
1067:            /**
1068:             * Returns the join mode.
1069:             * @return  join mode
1070:             */
1071:            public JoinAndSplitMode joinMode() {
1072:                return getPaJoinMode();
1073:            }
1074:
1075:            /**
1076:             * Set the join mode of the activity.
1077:             * @param splitMode the new split mode
1078:             */
1079:            public void setSplitMode(JoinAndSplitMode splitMode) {
1080:                setPaSplitMode(splitMode);
1081:            }
1082:
1083:            /**
1084:             * Returns the split mode.
1085:             * @return  split mode
1086:             */
1087:            public JoinAndSplitMode splitMode() {
1088:                return getPaSplitMode();
1089:            }
1090:
1091:            /* Comment copied from Interface. */
1092:            public void doCloseActivity(State closedState) {
1093:                updateState(closedState);
1094:            }
1095:
1096:            /**
1097:             * Returns if the activity's split is to be executed as deferred
1098:             * choice.
1099:             * @return <code>true</code> if the activity has been elected
1100:             */
1101:            public boolean deferChoiceOnSplit() {
1102:                return getPaDeferChoiceOnSplit();
1103:            }
1104:
1105:            /**
1106:             * Returns if the activity has been preliminarily chosen in a
1107:             * deferred choice.
1108:             * @return <code>true</code> if the activity has been elected
1109:             */
1110:            public boolean preliminarilyChosen() {
1111:                return getPaPreliminarilyChosen();
1112:            }
1113:
1114:            //
1115:            // State change API implementation
1116:            //
1117:
1118:            private static Map vstates = null;
1119:
1120:            /**
1121:             * Returns the {@link java.util.Map <code>Map</code>} that maps
1122:             * the activity states to a {@link java.util.Map
1123:             * <code>List</code>} of reachable process states. <P>
1124:             *
1125:             * The map returns the state transitions allowed as parameters of
1126:             * {@link
1127:             * de.danet.an.workflow.localcoreapi.WfExecutionObjectLocal#changeState
1128:             * <code>changeState</code>} only. I.e. the map does not reflect
1129:             * all possible transitions, there may be more, but those are only
1130:             * accessible to the workflow engine itself.
1131:             * @return the resulting map.
1132:             */
1133:            protected Map getStateTransitionMap() {
1134:                // Map must be initialized lazily. Static initialization holds
1135:                // danger of "race conditions" with constant initialization
1136:                // (resulting in null-entries). And new map must be fully initialized
1137:                // before assigning to member variable to avoid concurrent
1138:                // initialization.
1139:                if (vstates == null) {
1140:                    Map transMap = new HashMap();
1141:                    // Transitions from open.not_running.not_started
1142:                    List l = new ArrayList();
1143:                    transMap.put(NotStartedState.UNKNOWN, l);
1144:                    transMap.put(NotStartedState.STARTABLE, l);
1145:                    l.add(ClosedState.TERMINATED);
1146:                    // Transitions from open.running
1147:                    l = new ArrayList();
1148:                    transMap.put(RunningState.RUNNING, l);
1149:                    l.add(NotRunningState.SUSPENDED);
1150:                    l.add(ClosedState.TERMINATED);
1151:                    l.add(ClosedState.COMPLETED);
1152:                    // Transitions from open.not_running.suspended.suspended
1153:                    l = new ArrayList();
1154:                    transMap.put(SuspendedState.SUSPENDED, l);
1155:                    l.add(OpenState.RUNNING);
1156:                    l.add(ClosedState.ABORTED);
1157:                    // i.e. complete may be called, state changes later, of course.
1158:                    l.add(ClosedState.COMPLETED);
1159:                    // Transitions from open.not_running.suspended.abandoning
1160:                    l = new ArrayList();
1161:                    transMap.put(SuspendedState.ABANDONING, l);
1162:                    l.add(OpenState.RUNNING);
1163:                    l.add(SuspendedState.CLEARING_EXCEPTION);
1164:                    // Transitions from open.not_running.suspended.clearing_exception
1165:                    l = new ArrayList();
1166:                    transMap.put(SuspendedState.CLEARING_EXCEPTION, l);
1167:                    l.add(OpenState.RUNNING);
1168:                    // Transitions from debug states
1169:                    l = new ArrayList();
1170:                    transMap.put(DebugState.ABORTING, l);
1171:                    transMap.put(DebugState.COMPLETING, l);
1172:                    transMap.put(DebugState.TERMINATING, l);
1173:                    l.add(OpenState.RUNNING);
1174:                    l = new ArrayList();
1175:                    transMap.put(DebugState.INVOKING, l);
1176:                    l.add(OpenState.RUNNING);
1177:                    l.add(DebugState.SKIPPING);
1178:                    l.add(NotRunningState.SUSPENDED);
1179:                    vstates = Collections.unmodifiableMap(transMap);
1180:                }
1181:                return vstates;
1182:            }
1183:
1184:            /**
1185:             * Adds the possibility to change the state to
1186:             * <code>ClosedState.COMPLETED</code>
1187:             * (i.e. "<code>complete()</code>") to the
1188:             * <code>changeState</code> method of the superclass.<P>
1189:             * 
1190:             * Adds handling of change from 
1191:             * <code>open.not_running.suspended.abandoning</code> to
1192:             * <code>open.not_running.suspended.clearing_exception</code>.
1193:             * 
1194:             * @param newState the new state.
1195:             * @throws InvalidStateException If <code>newState</code> is an invalid
1196:             * state for the execution object.
1197:             * @throws TransitionNotAllowedException If the transition from the current
1198:             * state to <code>newState</code> is not allowed.
1199:             */
1200:            public void changeState(State newState)
1201:                    throws InvalidStateException, TransitionNotAllowedException {
1202:                try {
1203:                    if (newState.isSameOrSubState(ClosedState.COMPLETED)) {
1204:                        complete();
1205:                        return;
1206:                    }
1207:                } catch (CannotCompleteException e) {
1208:                    throw new TransitionNotAllowedException(e.getClass()
1209:                            .getName()
1210:                            + ": " + e.getMessage());
1211:                }
1212:                if (typedState().isSameOrSubState(SuspendedState.ABANDONING)
1213:                        && newState
1214:                                .isSameOrSubState(SuspendedState.CLEARING_EXCEPTION)) {
1215:                    updateImmediate(SuspendedState.SUSPENDED);
1216:                    return;
1217:                }
1218:                if (getPaDebug()) {
1219:                    State oldState = typedState();
1220:                    if (newState == DebugState.FORWARDING_EXCEPTION
1221:                            && STATE_TO_SUB_STATE.containsKey(oldState)) {
1222:                        setPaSubStateBackup(((Integer) STATE_TO_SUB_STATE
1223:                                .get(oldState)).intValue());
1224:                        setPaTypedState(newState);
1225:                        return;
1226:                    }
1227:                    if (newState == DebugState.AWAITING_EXCEPTION) {
1228:                        if (oldState == DebugState.ABANDONING) {
1229:                            // Proceed from abandoning
1230:                            setPaTypedState(newState);
1231:                            return;
1232:                        }
1233:                        throw new TransitionNotAllowedException("Change to "
1234:                                + DebugState.AWAITING_EXCEPTION
1235:                                + " is only allowed from "
1236:                                + DebugState.ABANDONING);
1237:                    }
1238:                    if (oldState.isSameOrSubState(RunningState.DEBUG)) {
1239:                        if (!newState.isSameOrSubState(OpenState.RUNNING)
1240:                                && !(oldState == DebugState.INVOKING && newState
1241:                                        .isSameOrSubState(NotRunningState.SUSPENDED))) {
1242:                            throw new TransitionNotAllowedException(
1243:                                    "Only valid change from debug states is to "
1244:                                            + OpenState.RUNNING
1245:                                            + " or sub-state");
1246:                        }
1247:
1248:                        // Resume closing with the proper state.
1249:                        State closeState = (State) DEBUG_STATE_TO_CLOSE_STATE
1250:                                .get(oldState);
1251:                        if (closeState != null) {
1252:                            // Reset to running state in order to generate proper
1253:                            // state change event later.
1254:                            setPaTypedState(RunningState.RUNNING);
1255:                            ((ExtProcessLocal) containerLocal()).closeActivity(
1256:                                    toActivityLocal(), closeState);
1257:                            return;
1258:                        }
1259:                        // Maybe continue invocation
1260:                        if (oldState == DebugState.INVOKING) {
1261:                            // Reset to running state in order to generate proper
1262:                            // state change event later.
1263:                            setPaTypedState(RunningState.RUNNING);
1264:                            if (!newState
1265:                                    .isSameOrSubState(NotRunningState.SUSPENDED)) {
1266:                                if (newState == DebugState.SKIPPING) {
1267:                                    invokeNextImpl();
1268:                                } else {
1269:                                    invokeCurrentImpl();
1270:                                }
1271:                                return;
1272:                            }
1273:                            // We cannot change the state to suspended
1274:                            // immediately. This would imply to change to a
1275:                            // state before the tool invocation. The decision
1276:                            // about the tool invocation has, however, already
1277:                            // been taken, we can only skip the actual
1278:                            // execution of the tool. If we were not running
1279:                            // in debug mode, the suspended state would also
1280:                            // be reached after the tool invocation.
1281:                            invokeCurrentImpl();
1282:                        }
1283:                    }
1284:                }
1285:                super .changeState(newState);
1286:            }
1287:
1288:            /**
1289:             * Return the activity's thread info. 
1290:             * @return the thread info.
1291:             */
1292:            public ThreadInfo threadInfo() {
1293:                return getPaThreadInfo();
1294:            }
1295:
1296:            /**
1297:             * Update the sub-state of an activity in state
1298:             * <code>NotRunningState.NOT_STARTED</code> to
1299:             * <code>NotStartedState.STARTABLE</code>. This update reflects
1300:             * internal evaluation progression only and does neither update
1301:             * last state change time nor fire an event.
1302:             *
1303:             * @param triggers the activities that caused the activity to be
1304:             * startable (one or more activities depending on the join mode).
1305:             * @param preliminarilyChosen if the activity is triggered due to a
1306:             * deferred choice
1307:             * @see #updateState
1308:             */
1309:            public void setStartable(Collection triggers,
1310:                    boolean preliminarilyChosen) {
1311:                if (!getPaTypedState().isSameOrSubState(
1312:                        NotRunningState.NOT_STARTED)) {
1313:                    throw new IllegalStateException(
1314:                            "Cannot update not started substate, activity is "
1315:                                    + getPaTypedState().toString());
1316:                }
1317:                setPaTypedState(NotStartedState.STARTABLE);
1318:                if (getPaThreadInfo() == null) {
1319:                    setPaThreadInfo(new ThreadInfo(triggers));
1320:                }
1321:                setPaPreliminarilyChosen(preliminarilyChosen);
1322:                if (logger.isDebugEnabled()) {
1323:                    logger.debug(toString() + " triggered by "
1324:                            + getPaThreadInfo());
1325:                }
1326:            }
1327:
1328:            /**
1329:             * Reset an activity to <code>NotStartedState.UNKNOWN</code>,
1330:             * i.e. have it assume exactly the same state as it has when
1331:             * newly created. An exception is the thread info which can
1332:             * (optionally) be preserved in certain cases.
1333:             * @param preserveThreadInfo preserve the thread info, 
1334:             * i.e. the information about the activity's predecessors.
1335:             * @param publishChange publish the state change, i.e. create a
1336:             * corresponding audit event
1337:             */
1338:            public void reset(boolean preserveThreadInfo, boolean publishChange) {
1339:                if (publishChange) {
1340:                    updateInterim(NotStartedState.UNKNOWN);
1341:                } else {
1342:                    setPaTypedState(NotStartedState.UNKNOWN);
1343:                }
1344:                setPaWaitOnProc(null);
1345:                setPaWaitOnChan(null);
1346:                setPaExecStat(new Integer(0));
1347:                if (!preserveThreadInfo) {
1348:                    setPaThreadInfo(null);
1349:                }
1350:                if (getPaDeadlines().size() > 0) {
1351:                    for (Iterator dli = getPaDeadlines().iterator(); dli
1352:                            .hasNext();) {
1353:                        Deadline dl = (Deadline) dli.next();
1354:                        dl.setState(Deadline.STATE_INITIAL);
1355:                    }
1356:                    // notify persistence layer about change
1357:                    setPaDeadlines(getPaDeadlines());
1358:                }
1359:            }
1360:
1361:            /**
1362:             * Terminates and resets an activity that was started
1363:             * preliminarily as part of a deferred choice.
1364:             * @param reset if the activity's state is to be reset
1365:             * @throws TransitionNotAllowedException if the activity has not
1366:             * been preliminarily chosen
1367:             */
1368:            public void withdrawPreliminaryChoice(boolean reset)
1369:                    throws TransitionNotAllowedException {
1370:                if (!getPaPreliminarilyChosen()) {
1371:                    throw new TransitionNotAllowedException(this 
1372:                            + " is not in state preliminary chosen");
1373:                }
1374:                setPaPreliminarilyChosen(false);
1375:                if (!reset) {
1376:                    return;
1377:                }
1378:                try {
1379:                    terminateImpl();
1380:                } catch (ApplicationNotStoppedException e) {
1381:                    logger
1382:                            .warn("Tool invoked in deferred choice could not be terminated: "
1383:                                    + e.getMessage());
1384:                }
1385:                reset(false, true);
1386:                releaseResources();
1387:            }
1388:
1389:            /**
1390:             * Starts an activity. This is not an OMG method, but needed
1391:             * in the communication between process and activity.
1392:             * @throws AlreadyRunningException when the process has already been 
1393:             * started.
1394:             */
1395:            public void start() throws AlreadyRunningException {
1396:                if (!typedState().isSameOrSubState(NotRunningState.NOT_STARTED)) {
1397:                    throw new AlreadyRunningException(toString()
1398:                            + " state is: " + state());
1399:                }
1400:                setPaStartTime(new Date());
1401:                Deadline.armDeadlines(this , new Date(getPaStartTime().getTime()
1402:                        + getPaSuspendAccum()),
1403:                        (ExtProcessLocal) containerLocal(), getPaDeadlines());
1404:                if (getPaStartMode() != StartFinishMode.MANUAL) {
1405:                    updateState(RunningState.RUNNING);
1406:                    autoAssignResources();
1407:                    invokeNextImpl();
1408:                } else {
1409:                    updateInterim(RunningState.RUNNING); // no handleStarted called
1410:                    updateState(SuspendedState.SUSPENDED);
1411:                }
1412:            }
1413:
1414:            /* Comment copied from Interface. */
1415:            public void suspend() throws CannotSuspendException,
1416:                    NotRunningException, AlreadySuspendedException {
1417:                super .suspend();
1418:                Implementation impl = executor();
1419:                if (impl != null && (impl instanceof  SubFlowImplementation)) {
1420:                    Collection subs = performersLocal();
1421:                    for (Iterator i = subs.iterator(); i.hasNext();) {
1422:                        WfProcessLocal p = (WfProcessLocal) i.next();
1423:                        try {
1424:                            p.suspend();
1425:                        } catch (NotRunningException e) {
1426:                            throw new CannotSuspendException(e.getMessage());
1427:                        } catch (AlreadySuspendedException e) {
1428:                            // may safely by ignored, make checkstyle happy
1429:                            continue;
1430:                        }
1431:                    }
1432:                }
1433:            }
1434:
1435:            /* Comment copied from Interface. */
1436:            public void resume() throws CannotResumeException,
1437:                    NotRunningException, NotSuspendedException {
1438:                // Check for special case "resuming exception processing"
1439:                if (typedState().isSameOrSubState(SuspendedState.ABANDONING)) {
1440:                    // Tool was invoked with suspend flag, continue "normal"
1441:                    // processing. Complete abandoning and go to running first 
1442:                    // to get consistent state changes.
1443:                    setPaExecStat(new Integer(Integer.MAX_VALUE));
1444:                    releaseResources();
1445:                    updateInterim(RunningState.RUNNING);
1446:                    // now quit if debugging
1447:                    if (getPaDebug()) {
1448:                        setPaTypedState(DebugState.ABANDONING);
1449:                        return;
1450:                    }
1451:                    updateInterim(ClosedCompletedState.ABANDONED);
1452:
1453:                    // propagate to process to cause triggering transitions
1454:                    String exception = getPaPendingException();
1455:                    setPaPendingException(null);
1456:                    ((ExtProcessLocal) containerLocal()).handleException(
1457:                            toActivityLocal(), exception);
1458:                    return;
1459:                }
1460:
1461:                // resume from normal manual suspend invocation
1462:                Implementation impl = executor();
1463:                if (impl != null && (impl instanceof  SubFlowImplementation)) {
1464:                    Collection subs = performersLocal();
1465:                    for (Iterator i = subs.iterator(); i.hasNext();) {
1466:                        WfProcessLocal p = (WfProcessLocal) i.next();
1467:                        try {
1468:                            p.resume();
1469:                        } catch (NotRunningException e) {
1470:                            throw new CannotResumeException(e.getMessage());
1471:                        } catch (NotSuspendedException e) {
1472:                            // may safely by ignored, make checkstyle happy
1473:                            continue;
1474:                        }
1475:                    }
1476:                }
1477:                super .resume();
1478:            }
1479:
1480:            /**
1481:             * Close this activity regularly. 
1482:             * @throws CannotCompleteException if the state can not be changed.
1483:             * @ejb.interface-method view-type="remote"
1484:             */
1485:            public void complete() throws CannotCompleteException {
1486:                if (!validTypedStates().contains(ClosedState.COMPLETED)) {
1487:                    if (typedState().isSameOrSubState(
1488:                            ClosedCompletedState.ABANDONED)) {
1489:                        logger
1490:                                .warn("Call to complete() ignored because "
1491:                                        + toString()
1492:                                        + " has already been abandoned (probably called "
1493:                                        + "by tool that could not be terminated).");
1494:                        return;
1495:                    }
1496:                    throw new CannotCompleteException(toString() + " is "
1497:                            + state());
1498:                }
1499:                if (getPaPreliminarilyChosen()) {
1500:                    try {
1501:                        choose();
1502:                    } catch (TransitionNotAllowedException e) {
1503:                        // cannot happen because state has been checked already
1504:                        logger.error("Unexpected exception: " + e.getMessage(),
1505:                                e);
1506:                    }
1507:                }
1508:                setPaWaitOnChan(null);
1509:                // if this is the last implementation completing and we are
1510:                // not debugging, and the activity is not suspended, then we
1511:                // may complete immediately
1512:                if (!haveMoreImpls()
1513:                        && !getPaDebug()
1514:                        && !typedState().isSameOrSubState(
1515:                                NotRunningState.SUSPENDED)) {
1516:                    setPaExecStat(new Integer(Integer.MAX_VALUE));
1517:                    if (finishMode() == StartFinishMode.MANUAL) {
1518:                        updateState(SuspendedState.SUSPENDED);
1519:                        return;
1520:                    }
1521:                    // causes state changed event to be fired
1522:                    ((ExtProcessLocal) containerLocal()).closeActivity(
1523:                            toActivityLocal(), ClosedCompletedState.NORMAL);
1524:                    return;
1525:                }
1526:                fireAuditEvent(new ImplCompleteAuditEvent(
1527:                        auditEventBase(ImplCompleteAuditEvent.TOOL_COMPLETE),
1528:                        Math.abs(getPaExecStat().intValue()) - 1));
1529:            }
1530:
1531:            /* Comment copied from Interface. */
1532:            public boolean initiateAbandoning(boolean blockException,
1533:                    String exceptionName) {
1534:                boolean isSuspended = false;
1535:                if (typedState().isSameOrSubState(OpenState.RUNNING)) {
1536:                    setPaTypedState(RunningState.ABANDONING);
1537:                    abandonImpl();
1538:                } else if (typedState().isSameOrSubState(
1539:                        SuspendedState.SUSPENDED)) {
1540:                    if (blockException) {
1541:                        // Exceptions from block activity deadlines cannot be delayed.
1542:                        updateInterim(RunningState.RUNNING);
1543:                        abandonImpl();
1544:                    } else {
1545:                        if (getPaExecStat().intValue() == 0
1546:                                || getPaExecStat().intValue() == Integer.MAX_VALUE) {
1547:                            // suspend from manual start or finish mode, exception
1548:                            // must be from deadline and is processed. Note that we
1549:                            // do not have to abandon an implementation as no
1550:                            // implementation is running.
1551:                            updateInterim(RunningState.RUNNING);
1552:                        } else {
1553:                            // if we get here, the activity has been 
1554:                            // suspended in response to an exception from a tool 
1555:                            // invocation (as exceptions from deadlines are delayed 
1556:                            // when an activity is suspended)
1557:                            isSuspended = true;
1558:                            setPaTypedState(SuspendedState.ABANDONING);
1559:                            setPaPendingException(exceptionName);
1560:                            setPaPendingExceptionIsFromBlock(blockException);
1561:                        }
1562:                    }
1563:                } else {
1564:                    return false;
1565:                }
1566:                if (getPaPreliminarilyChosen()) {
1567:                    try {
1568:                        choose();
1569:                    } catch (TransitionNotAllowedException e) {
1570:                        // cannot happen because state has been checked already
1571:                        logger.error("Unexpected exception: " + e.getMessage(),
1572:                                e);
1573:                    }
1574:                }
1575:                setPaWaitOnProc(null);
1576:                setPaWaitOnChan(null);
1577:                disarmDeadlines();
1578:                if (isSuspended) {
1579:                    setPaSuspendStart(new Date());
1580:                    setPaExecStat(new Integer(-getPaExecStat().intValue()));
1581:                    return false;
1582:                }
1583:                setPaExecStat(new Integer(Integer.MAX_VALUE));
1584:                releaseResources();
1585:                if (getPaDebug()) {
1586:                    setPaTypedState(DebugState.ABANDONING);
1587:                    return false;
1588:                }
1589:                updateInterim(ClosedCompletedState.ABANDONED);
1590:                return true;
1591:            }
1592:
1593:            private void abandonImpl() {
1594:                Implementation impl = executor();
1595:                if (impl == null || typedState() == DebugState.INVOKING) {
1596:                    return;
1597:                }
1598:                if (impl instanceof  ToolImplementation) {
1599:                    try {
1600:                        terminateTool((ToolImplementation) impl);
1601:                    } catch (ApplicationNotStoppedException ans) {
1602:                        logger.debug("Failed to terminate tool in abandon of "
1603:                                + toString() + " (ignored): "
1604:                                + ans.getMessage());
1605:                    }
1606:                }
1607:                if (impl instanceof  SubFlowImplementation) {
1608:                    Collection subs = performersLocal();
1609:                    for (Iterator i = subs.iterator(); i.hasNext();) {
1610:                        ExtProcessLocal p = (ExtProcessLocal) i.next();
1611:                        try {
1612:                            if (p.typedState().isSameOrSubState(
1613:                                    NotRunningState.SUSPENDED)) {
1614:                                p.abort();
1615:                            } else {
1616:                                try {
1617:                                    p.terminate();
1618:                                } catch (CannotStopException e) {
1619:                                    try {
1620:                                        p.suspend();
1621:                                        p.abort();
1622:                                    } catch (InvalidControlOperationException ee) {
1623:                                        logger
1624:                                                .warn("Cannot force termination of "
1625:                                                        + p
1626:                                                        + " (ignored): "
1627:                                                        + ee.getMessage());
1628:                                    }
1629:                                }
1630:                            }
1631:                        } catch (NotRunningException e) {
1632:                            logger.debug("Trying to stop not running subflow "
1633:                                    + "(propably race-condition, ignored): "
1634:                                    + e.getMessage());
1635:                        } catch (InvalidControlOperationException e) {
1636:                            logger.warn("Cannot force termination of " + p
1637:                                    + " (ignored): " + e.getMessage());
1638:                        }
1639:                    }
1640:                }
1641:            }
1642:
1643:            /* Comment copied from Interface. */
1644:            public void abort() throws CannotStopException, NotRunningException {
1645:                mayCloseCheck(ClosedState.ABORTED);
1646:                try {
1647:                    terminateImpl();
1648:                } catch (ApplicationNotStoppedException e) {
1649:                    Implementation impl = executor();
1650:                    if (impl == null
1651:                            || !(impl instanceof  SubFlowImplementation)) {
1652:                        logger.warn(toString()
1653:                                + " has been aborted, but the currently "
1654:                                + "running tool could not be stopped: "
1655:                                + e.getMessage());
1656:                    } else {
1657:                        Collection subs = performersLocal();
1658:                        for (Iterator i = subs.iterator(); i.hasNext();) {
1659:                            WfProcessLocal p = (WfProcessLocal) i.next();
1660:                            try {
1661:                                try {
1662:                                    p.suspend();
1663:                                } catch (AlreadySuspendedException as) {
1664:                                    // the better, make checkstyle happy
1665:                                    int dummy = 0;
1666:                                }
1667:                                p.abort();
1668:                            } catch (CannotSuspendException ee) {
1669:                                throw new CannotStopException(
1670:                                        "To be aborted sub-process cannot be suspended: "
1671:                                                + e.getMessage());
1672:                            } catch (NotRunningException ee) {
1673:                                // may safely by ignored, make checkstyle happy
1674:                                continue;
1675:                            }
1676:                        }
1677:                    }
1678:                }
1679:                doAbort();
1680:            }
1681:
1682:            /* Comment copied from Interface. */
1683:            public void abortRequester() {
1684:                try {
1685:                    if (!typedState().isSameOrSubState(
1686:                            NotRunningState.SUSPENDED)) {
1687:                        super .suspend();
1688:                    }
1689:                    mayCloseCheck(ClosedState.ABORTED);
1690:                } catch (InvalidControlOperationException e) {
1691:                    logger.error("Sub-process requests abortion of "
1692:                            + toString() + ", but cannot abort: "
1693:                            + e.getMessage(), e);
1694:                }
1695:                doAbort();
1696:            }
1697:
1698:            private void doAbort() {
1699:                setPaWaitOnProc(null);
1700:                setPaWaitOnChan(null);
1701:                setPaExecStat(new Integer(Integer.MAX_VALUE));
1702:                closeActivity(ClosedState.ABORTED);
1703:            }
1704:
1705:            /* Comment copied from Interface. */
1706:            public void terminate() throws CannotStopException,
1707:                    NotRunningException {
1708:                mayCloseCheck(ClosedState.TERMINATED);
1709:                try {
1710:                    terminateImpl();
1711:                } catch (ApplicationNotStoppedException e) {
1712:                    throw new CannotStopException(
1713:                            "Cannot terminate, application not stopped: "
1714:                                    + e.getMessage());
1715:                }
1716:                setPaWaitOnProc(null);
1717:                setPaWaitOnChan(null);
1718:                setPaExecStat(new Integer(Integer.MAX_VALUE));
1719:                closeActivity(ClosedState.TERMINATED);
1720:            }
1721:
1722:            private void mayCloseCheck(ClosedState s)
1723:                    throws CannotStopException, NotRunningException {
1724:                if (((ProcessLocal) containerLocal()).workflowState() == State.CLOSED) {
1725:                    if (typedState().isSameOrSubState(
1726:                            ClosedCompletedState.ABANDONED)) {
1727:                        logger
1728:                                .warn("Attempt to close ignored, "
1729:                                        + toString()
1730:                                        + " has already been abandoned (probably attempted "
1731:                                        + "by tool that could not be terminated).");
1732:                        return;
1733:                    }
1734:                    throw new NotRunningException("Cannot terminate "
1735:                            + toString() + ", process already closed.");
1736:                }
1737:                if (!validTypedStates().contains(s)) {
1738:                    if (typedState().isSameOrSubState(OpenState.RUNNING)) {
1739:                        throw new CannotStopException(toString() + " is "
1740:                                + state());
1741:                    } else {
1742:                        throw new NotRunningException(toString() + " is "
1743:                                + state());
1744:                    }
1745:                }
1746:            }
1747:
1748:            /* Comment copied from Interface. */
1749:            public void abandon(String exception)
1750:                    throws TransitionNotAllowedException {
1751:                abandon(new ExceptionResult(exception));
1752:            }
1753:
1754:            /* Comment copied from Interface. */
1755:            public void abandon(ExceptionResult result)
1756:                    throws TransitionNotAllowedException {
1757:                String exception = result.exceptionName();
1758:                // handle forwarding of exception for debugging
1759:                State oldState = typedState();
1760:                if (oldState == DebugState.AWAITING_EXCEPTION
1761:                        || oldState == DebugState.FORWARDING_EXCEPTION) {
1762:                    if (oldState == DebugState.AWAITING_EXCEPTION) {
1763:                        updateInterim(ClosedCompletedState.ABANDONED);
1764:                    } else {
1765:                        setPaTypedState((State) SUB_STATE_TO_STATE
1766:                                .get(new Integer(getPaSubStateBackup())));
1767:                    }
1768:                    // propagate to process to cause triggering transitions
1769:                    ((ExtProcessLocal) containerLocal()).handleException(
1770:                            toActivityLocal(), exception);
1771:                    return;
1772:                }
1773:
1774:                // normal procedures. Note that having a running tool implies
1775:                // that the activity is running or suspended
1776:                if ((getPaExecStat().intValue() <= 0 || getPaExecStat()
1777:                        .intValue() == Integer.MAX_VALUE)
1778:                        && !typedState()
1779:                                .isSameOrSubState(DebugState.COMPLETING)) {
1780:                    throw new TransitionNotAllowedException("No tool executing");
1781:                }
1782:
1783:                if (result.suspendActivity()) {
1784:                    // Everything that is usually done when suspend() is called is
1785:                    // either not applicable or indirectly done here. Suspending
1786:                    // subflow (done in suspend()) is not applicable, as we have
1787:                    // a tool implementation running. And everything done in
1788:                    // handleSuspendedEvent() is also done in initiateAbandoning()
1789:                    // and when resuming from ...suspended.abandoning.
1790:                    updateImmediate(SuspendedState.SUSPENDED);
1791:                }
1792:                initiateAbandoning(false, exception);
1793:
1794:                // now quit if debugging
1795:                if (getPaDebug()) {
1796:                    return;
1797:                }
1798:
1799:                // propagate to process to cause triggering transitions if activity
1800:                // has really been completed (may still be suspended.abandoning)
1801:                if (typedState().isSameOrSubState(State.CLOSED)) {
1802:                    ((ExtProcessLocal) containerLocal()).handleException(
1803:                            toActivityLocal(), exception);
1804:                }
1805:            }
1806:
1807:            /**
1808:             * Makes this activity the chosen one in a set of activities
1809:             * started by an AND split with the "deferred choice" option
1810:             * set. All other activities in the set are reset to their initial
1811:             * state.
1812:             *
1813:             * <P>If the activity does not participate in a deferred choice,
1814:             * this method does nothing and returns <code>true</code>.
1815:             *
1816:             * @return <code>true</code> if the activity could be made the
1817:             * effectively chosen one
1818:             * @throws TransitionNotAllowedException if the activity is
1819:             * neither running nor suspended
1820:             */
1821:            public boolean choose() throws TransitionNotAllowedException {
1822:                return ((ExtProcessLocal) containerLocal())
1823:                        .choose(toActivityLocal());
1824:            }
1825:
1826:            /* Comment copied from Interface. */
1827:            public void waitOnChannel(String procKey, String channel) {
1828:                setPaWaitOnProc(new Long(procKey));
1829:                setPaWaitOnChan(channel);
1830:            }
1831:
1832:            //
1833:            // Timers
1834:            //
1835:
1836:            private void disarmDeadlines() {
1837:                if (getPaDeadlines().size() == 0) {
1838:                    return;
1839:                }
1840:                if (logger.isDebugEnabled()) {
1841:                    logger.debug("Stopping timers for " + toString());
1842:                }
1843:                stopTimers();
1844:            }
1845:
1846:            /**
1847:             * Handle the timeout of a timer.
1848:             * @param info the context.
1849:             */
1850:            public void handleTimeout(Serializable info) {
1851:                int dlIndex = ((Integer) info).intValue();
1852:                Deadline dl = (Deadline) getPaDeadlines().get(dlIndex);
1853:                handleDeadline(dl);
1854:            }
1855:
1856:            private void handleDeadline(Deadline dl) {
1857:                if (logger.isDebugEnabled()) {
1858:                    logger.debug(toString() + " reached " + dl);
1859:                }
1860:                if (!(typedState().isSameOrSubState(OpenState.RUNNING) || (typedState()
1861:                        .isSameOrSubState(NotRunningState.SUSPENDED) && (getPaExecStat()
1862:                        .intValue() == 0 || getPaExecStat().intValue() == Integer.MAX_VALUE)))) {
1863:                    // if this activity is currently actively suspended, the
1864:                    // deadline will be retriggered when the activity is
1865:                    // resumed
1866:                    return;
1867:                }
1868:
1869:                // now accept deadline
1870:                dl.setState(Deadline.STATE_REACHED);
1871:                // notify persistence layer about change
1872:                setPaDeadlines(getPaDeadlines());
1873:
1874:                // now quit if debugging
1875:                if (getPaDebug()) {
1876:                    return;
1877:                }
1878:
1879:                // complete this if deadline is synchronous
1880:                if (dl.getExecution() == Deadline.SYNCHR) {
1881:                    initiateAbandoning(false, null);
1882:                }
1883:                // Due to the previous check, we only get here if the activity was
1884:                // initially running (not suspended). So it will be closed now
1885:                // (i.e. cannot be suspended.abandoning).
1886:                ((ExtProcessLocal) containerLocal()).handleException(
1887:                        toActivityLocal(), dl.getExceptionName());
1888:            }
1889:
1890:            /* Coment copied from interface. */
1891:            public String[] handledExceptions() {
1892:                Set res = new HashSet();
1893:                // exception name from deadlines
1894:                for (Iterator i = getPaDeadlines().iterator(); i.hasNext();) {
1895:                    Deadline dl = (Deadline) i.next();
1896:                    res.add(dl.getExceptionName());
1897:                }
1898:                // exception names from transitions
1899:                List allTrans = ((ProcessLocal) containerLocal())
1900:                        .transitionsLocal();
1901:                for (Iterator tri = allTrans.iterator(); tri.hasNext();) {
1902:                    TransitionLocal trans = (TransitionLocal) tri.next();
1903:                    if (key().equals(trans.from().key())
1904:                            && trans.conditionType() == de.danet.an.workflow.api.Transition.COND_TYPE_EXCEPTION) {
1905:                        res.add(trans.condition());
1906:                    }
1907:                }
1908:                return (String[]) res.toArray(new String[res.size()]);
1909:            }
1910:
1911:            //
1912:            // State change handling
1913:            //
1914:
1915:            /**
1916:             * Check if this class handles a specific event.
1917:             * @param event the event to check
1918:             * @return <code>true</code> if event is handled
1919:             */
1920:            public static boolean isHandled(WfAuditEvent event) {
1921:                if (event instanceof  ToolInvocationFailedAuditEvent) {
1922:                    return true;
1923:                }
1924:                if (event instanceof  ImplCompleteAuditEvent) {
1925:                    return true;
1926:                }
1927:                if (event.eventType().equals(
1928:                        WfAuditEvent.ACTIVITY_STATE_CHANGED)) {
1929:                    try {
1930:                        State oldState = State
1931:                                .fromString(((WfStateAuditEvent) event)
1932:                                        .oldState());
1933:                        State newState = State
1934:                                .fromString(((WfStateAuditEvent) event)
1935:                                        .newState());
1936:                        if (oldState
1937:                                .isSameOrSubState(NotRunningState.NOT_STARTED)) {
1938:                            if (newState == ClosedState.TERMINATED) {
1939:                                return true;
1940:                            }
1941:                        } else if (oldState
1942:                                .isSameOrSubState(NotRunningState.SUSPENDED)) {
1943:                            if (newState == RunningState.RUNNING) {
1944:                                return true;
1945:                            }
1946:                            if (newState == ClosedState.ABORTED) {
1947:                                return true;
1948:                            }
1949:                        } else if (oldState.isSameOrSubState(OpenState.RUNNING)) {
1950:                            if (newState == SuspendedState.SUSPENDED) {
1951:                                return true;
1952:                            }
1953:                            if (newState == ClosedCompletedState.NORMAL) {
1954:                                return true;
1955:                            }
1956:                            if (newState == ClosedState.TERMINATED) {
1957:                                return true;
1958:                            }
1959:                        }
1960:                    } catch (InvalidStateException e) {
1961:                        throw (IllegalArgumentException) (new IllegalArgumentException(
1962:                                e.getMessage())).initCause(e);
1963:                    }
1964:                }
1965:                return false;
1966:            }
1967:
1968:            /**
1969:             * Handles a suspended audit event.
1970:             * @param event the event.
1971:             */
1972:            protected void handleSuspendedEvent(WfStateAuditEvent event) {
1973:                if (getPaExecStat().intValue() == 0) {
1974:                    // this is the event received from start with start mode manual
1975:                    Deadline.armDeadlines(this , new Date(getPaStartTime()
1976:                            .getTime()
1977:                            + getPaSuspendAccum()),
1978:                            (ExtProcessLocal) containerLocal(),
1979:                            getPaDeadlines());
1980:                    return;
1981:                }
1982:                if (getPaExecStat().intValue() == Integer.MAX_VALUE) {
1983:                    // this is the event received from complete with finish mode manual
1984:                    return;
1985:                }
1986:                setPaSuspendStart(new Date());
1987:                disarmDeadlines();
1988:            }
1989:
1990:            /**
1991:             * Handles a resumed audit event.
1992:             * @param event the event.
1993:             */
1994:            protected void handleResumedEvent(WfStateAuditEvent event) {
1995:                if (getPaSuspendStart() != null) {
1996:                    setPaSuspendAccum(getPaSuspendAccum()
1997:                            + ((new Date()).getTime() - getPaSuspendStart()
1998:                                    .getTime()));
1999:                    setPaSuspendStart(null);
2000:                }
2001:                // now handle expired deadlines first
2002:                int exc = getPaExecStat().intValue();
2003:                if (exc == 0) {
2004:                    // delayed start (start mode manual), timers are running
2005:                    autoAssignResources();
2006:                    invokeNextImpl();
2007:                    return;
2008:                }
2009:                // handle all expired timers first
2010:                Date now = null;
2011:                Date base = null;
2012:                SortedMap expDls = new TreeMap();
2013:                for (Iterator i = getPaDeadlines().iterator(); i.hasNext();) {
2014:                    Deadline dl = (Deadline) i.next();
2015:                    if (dl.getState() != Deadline.STATE_INITIAL) {
2016:                        continue;
2017:                    }
2018:                    if (now == null) {
2019:                        now = new Date();
2020:                        base = new Date(getPaStartTime().getTime()
2021:                                + getPaSuspendAccum());
2022:                    }
2023:                    try {
2024:                        Date exp = dl.expirationDate(base,
2025:                                (ExtProcessLocal) containerLocal());
2026:                        if (!exp.after(now)) {
2027:                            expDls.put(exp, dl);
2028:                        }
2029:                    } catch (ParseException e) {
2030:                        logger.error(e.getMessage());
2031:                    }
2032:                }
2033:                for (Iterator i = expDls.values().iterator(); i.hasNext();) {
2034:                    Deadline dl = (Deadline) i.next();
2035:                    handleDeadline(dl);
2036:                    if (typedState().isSameOrSubState(State.CLOSED)) {
2037:                        return;
2038:                    }
2039:                }
2040:                if (exc == Integer.MAX_VALUE) {
2041:                    // resume from manual finish
2042:                    closeActivity(ClosedCompletedState.NORMAL);
2043:                    return;
2044:                }
2045:                Deadline.armDeadlines(this , base,
2046:                        (ExtProcessLocal) containerLocal(), getPaDeadlines());
2047:                if (exc < 0) {
2048:                    // tool was completed during suspend
2049:                    invokeNextImpl();
2050:                }
2051:            }
2052:
2053:            /**
2054:             * Handles a tool invocation audit event.
2055:             * @param event the event.
2056:             */
2057:            protected void handleToolInvocationFailedAuditEvent(
2058:                    ToolInvocationFailedAuditEvent event) {
2059:                if (workflowState() == State.OPEN) {
2060:                    setPaWaitOnProc(null);
2061:                    setPaWaitOnChan(null);
2062:                    setPaExecStat(new Integer(Integer.MAX_VALUE));
2063:                    closeActivity(ClosedState.TERMINATED);
2064:                }
2065:            }
2066:
2067:            /**
2068:             * Handles a tool completed audit event.
2069:             * @param event the event.
2070:             */
2071:            protected void handleImplCompletedEvent(ImplCompleteAuditEvent event) {
2072:                if (typedState().isSameOrSubState(NotRunningState.SUSPENDED)) {
2073:                    setPaWaitOnProc(null);
2074:                    int exc = getPaExecStat().intValue();
2075:                    if (exc > 0 && exc != Integer.MAX_VALUE) {
2076:                        setPaExecStat(new Integer(-exc));
2077:                    }
2078:                } else {
2079:                    invokeNextImpl();
2080:                }
2081:            }
2082:
2083:            /**
2084:             * Handles a completed audit event. This is thrown after the last
2085:             * implementation has terminated.
2086:             * @param event the event.
2087:             */
2088:            protected void handleCompletedEvent(WfStateAuditEvent event) {
2089:                disarmDeadlines();
2090:                releaseResources();
2091:            }
2092:
2093:            /**
2094:             * Handles a terminated audit event.
2095:             * @param event the event.
2096:             */
2097:            protected void handleTerminatedEvent(WfStateAuditEvent event) {
2098:                disarmDeadlines();
2099:                releaseResources();
2100:            }
2101:
2102:            /**
2103:             * Handles a aborting audit event.
2104:             * @param event the event.
2105:             */
2106:            protected void handleAbortedEvent(WfStateAuditEvent event) {
2107:                disarmDeadlines();
2108:                releaseResources();
2109:            }
2110:
2111:            /**
2112:             * Invokes the next tool.
2113:             */
2114:            private void invokeNextImpl() {
2115:                setPaWaitOnProc(null);
2116:                if (!typedState().workflowState().equals(State.OPEN)
2117:                        || typedState().isSameOrSubState(
2118:                                NotRunningState.SUSPENDED)) {
2119:                    return;
2120:                }
2121:                int exc = getPaExecStat().intValue();
2122:                if (exc == Integer.MAX_VALUE) {
2123:                    logger
2124:                            .warn("Call to invokeNextImpl after all implementations "
2125:                                    + "have been invoked indicates some kind of problem.");
2126:                    return;
2127:                }
2128:                if (!haveMoreImpls()) {
2129:                    setPaExecStat(new Integer(Integer.MAX_VALUE));
2130:                    if (finishMode() == StartFinishMode.MANUAL) {
2131:                        updateState(SuspendedState.SUSPENDED);
2132:                    } else {
2133:                        closeActivity(ClosedCompletedState.NORMAL);
2134:                    }
2135:                    return;
2136:                }
2137:                // Perform the next tool used for this activity
2138:                setPaExecStat(new Integer(Math.abs(exc) + 1));
2139:                if (!getPaDebug()) {
2140:                    invokeCurrentImpl();
2141:                } else {
2142:                    setPaTypedState(DebugState.INVOKING);
2143:                }
2144:            }
2145:
2146:            /**
2147:             * Check if there are more implementations.
2148:             */
2149:            private boolean haveMoreImpls() {
2150:                int exc = getPaExecStat().intValue();
2151:                if (exc == Integer.MAX_VALUE) {
2152:                    return false;
2153:                }
2154:                int nextExc = Math.abs(exc) + 1;
2155:                Implementation[] toolsList = getPaActImpl();
2156:                return !(toolsList == null || nextExc > toolsList.length);
2157:            }
2158:
2159:            /**
2160:             * Invoke the current tool.
2161:             */
2162:            private void invokeCurrentImpl() {
2163:                ExtImplementationLocal impl = (ExtImplementationLocal) getPaActImpl()[Math
2164:                        .abs(getPaExecStat().intValue()) - 1];
2165:                impl.invoke(toActivityLocal());
2166:                if (impl instanceof  ProcBasedImpl) {
2167:                    String key = ((ProcBasedImpl) impl).processKey();
2168:                    setPaSubflow(key);
2169:                }
2170:            }
2171:
2172:            /**
2173:             * Returns an {@link de.danet.an.workflow.spis.ras.ActivityFinder
2174:             * <code>ActivityFinder</code>} that identifies this activity
2175:             * against a resource assignment service as defined by
2176:             * {@link de.danet.an.workflow.spis.ras the ras package}.
2177:             *
2178:             * @return the activity finder.
2179:             */
2180:            public abstract ActivityFinder activityFinder();
2181:
2182:            /**
2183:             * Called when the activity enters the running state. Calls the
2184:             * resource assignment service to trigger the assignment.
2185:             */
2186:            protected void autoAssignResources() {
2187:                try {
2188:                    RASInvocationHandler ras = rasInvocationHandler();
2189:                    if (ras == null) {
2190:                        return;
2191:                    }
2192:                    Participant participant = null;
2193:                    if (performer() != null) {
2194:                        try {
2195:                            participant = ((ProcessLocal) containerLocal())
2196:                                    .processDefinition().participantById(
2197:                                            performer());
2198:                        } catch (InvalidIdException e) {
2199:                            String pid = (String) processContext().get(
2200:                                    performer());
2201:                            if (pid == null) {
2202:                                throw new InvalidIdException(
2203:                                        "Referenced data field \""
2204:                                                + performer()
2205:                                                + "\""
2206:                                                + " does not contain valid participant id.");
2207:                            }
2208:                            participant = ((ProcessLocal) containerLocal())
2209:                                    .processDefinition().participantById(pid);
2210:                        }
2211:                    }
2212:                    Collection resources = null;
2213:                    resources = ras.autoAssignResources(activityFinder(),
2214:                            getPaKey(), toActivity(),
2215:                            ((ExtProcessLocal) containerLocal())
2216:                                    .processCreator(), participant);
2217:                    Iterator i = resources.iterator();
2218:                    // Save info for optimization in releaseResources.
2219:                    setPaNoAssignments(!i.hasNext());
2220:                    if (getPaAuditEventSelection() == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS) {
2221:                        while (i.hasNext()) {
2222:                            WfResource resource = (WfResource) i.next();
2223:                            fireAuditEvent(new DefaultAssignmentAuditEvent(
2224:                                    auditEventBase(WfAuditEvent.ACTIVITY_ASSIGNMENT_CHANGED),
2225:                                    null, ras.retrieveKey(resource), null, ras
2226:                                            .retrieveName(resource)));
2227:                        }
2228:                    }
2229:                } catch (InvalidIdException iie) {
2230:                    logger.error("Invalid participant: " + iie.getMessage());
2231:                }
2232:            }
2233:
2234:            /**
2235:             * Return the list of assignments.
2236:             * @return list of assignments
2237:             * @ejb.interface-method view-type="remote"
2238:             */
2239:            public Collection assignments() {
2240:                RASInvocationHandler ras = rasInvocationHandler();
2241:                if (ras == null) {
2242:                    return new ArrayList();
2243:                }
2244:                return ras.assignments(activityFinder(), getPaKey(),
2245:                        toActivity());
2246:            }
2247:
2248:            /**
2249:             * Get the resource associated with an Assignment. The method calls
2250:             * the corresponding method of the resource assignment service.
2251:             *
2252:             * This method is intended to be used by resource assignment
2253:             * systems for implementing {@link
2254:             * de.danet.an.workflow.localcoreapi.WfAssignment#assignee
2255:             * <code>WfAssignment.assignee</code>}.<P>
2256:             *
2257:             * Clients should not use this method but rather call {@link
2258:             * de.danet.an.workflow.localcoreapi.WfAssignment#setAssignee
2259:             * <code>WfAssignment.setAssignee</code>}.
2260:             * 
2261:             * @param asnmnt the assignment
2262:             * @return the resource
2263:             */
2264:            public WfResource getResource(WfAssignment asnmnt) {
2265:                RASInvocationHandler ras = rasInvocationHandler();
2266:                if (ras == null) {
2267:                    throw new UnsupportedOperationException(
2268:                            "Resource assignment service not configured.");
2269:                }
2270:                return ras.getResource(asnmnt);
2271:            }
2272:
2273:            /**
2274:             * Change an assignment for enacting the activity. This method calls
2275:             * the corresponding method of the resource assignment service and
2276:             * creates the appropriate audit event.<P>
2277:             * 
2278:             * This method is intended to be used by resource assignment
2279:             * systems for implementing {@link
2280:             * de.danet.an.workflow.localcoreapi.WfAssignment#setAssignee
2281:             * <code>WfAssignment.setAssignee</code>}. Resource assignment
2282:             * systems are responsible for implementing
2283:             * <code>WfAssignment</code> and could therefore perform the
2284:             * reassignment directly; this would, however, leave the
2285:             * generation of notifications unexecuted. <P>
2286:             *
2287:             * Clients should not use this method but rather call {@link
2288:             * de.danet.an.workflow.localcoreapi.WfAssignment#setAssignee
2289:             * <code>WfAssignment.setAssignee</code>}.
2290:             *
2291:             * @param oldResource the resource that has its assignment removed
2292:             * @param newResource the resource to be assigned
2293:             * @throws InvalidResourceException if the resource is invalid.
2294:             * As the environment is a concurrent multi user environment, 
2295:             * <code>WfResource</code> objects may become invalid.
2296:             * @throws AlreadyAssignedException if the assignment already
2297:             * exists
2298:             * @throws NotAssignedException if there is no assignment to the
2299:             * old resource
2300:             */
2301:            public void changeAssignment(WfResource oldResource,
2302:                    WfResource newResource) throws InvalidResourceException,
2303:                    AlreadyAssignedException, NotAssignedException {
2304:                RASInvocationHandler ras = rasInvocationHandler();
2305:                if (ras == null) {
2306:                    throw new UnsupportedOperationException(
2307:                            "Resource assignment service not configured.");
2308:                }
2309:                ras.changeAssignment(activityFinder(), getPaKey(),
2310:                        toActivity(), oldResource, newResource);
2311:                // The activity may or may not have assignments now. We don't
2312:                // care, we just turn off the optimization of releaseResources.
2313:                setPaNoAssignments(false);
2314:                if (getPaAuditEventSelection() == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS) {
2315:                    fireAuditEvent(new DefaultAssignmentAuditEvent(
2316:                            auditEventBase(WfAuditEvent.ACTIVITY_ASSIGNMENT_CHANGED),
2317:                            ras.retrieveKey(oldResource), ras
2318:                                    .retrieveKey(newResource), ras
2319:                                    .retrieveName(oldResource), ras
2320:                                    .retrieveName(newResource)));
2321:                }
2322:            }
2323:
2324:            /**
2325:             * Removes an assignment for enacting the activity. This method calls
2326:             * the corresponding method of the resource assignment service and
2327:             * creates the appropriate audit event.<P>
2328:             * 
2329:             * This method is redundant, as the OMG specification already
2330:             * enables a client to remove an assignment by calling {@link
2331:             * WfResource#release
2332:             * <code>WfResource.release</code>}. <code>WfResource</code>
2333:             * objects are, however, provided by the resource management
2334:             * facility. This facility cannot create audit events, thus we
2335:             * have to provide a method that can be used by the resource
2336:             * management facility to implement <code>release</code>.
2337:             *
2338:             * @param resource the resource whose assignment is to be canceled
2339:             * @throws InvalidResourceException if the resource is invalid.
2340:             * As the environment is a concurrent multi user environment, 
2341:             * <code>WfResource</code> objects may become invalid.
2342:             * @throws NotAssignedException if there is no such assignment
2343:             */
2344:            public void removeAssignment(WfResource resource)
2345:                    throws InvalidResourceException, NotAssignedException {
2346:                RASInvocationHandler ras = rasInvocationHandler();
2347:                if (ras == null) {
2348:                    throw new UnsupportedOperationException(
2349:                            "Resource assignment service not configured.");
2350:                }
2351:                ras.removeAssignment(activityFinder(), getPaKey(),
2352:                        toActivity(), resource);
2353:                if (getPaAuditEventSelection() == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS) {
2354:                    fireAuditEvent(new DefaultAssignmentAuditEvent(
2355:                            auditEventBase(WfAuditEvent.ACTIVITY_ASSIGNMENT_CHANGED),
2356:                            ras.retrieveKey(resource), null, ras
2357:                                    .retrieveName(resource), null));
2358:                }
2359:            }
2360:
2361:            /**
2362:             * Close the activity with the given state after releasing all resources.
2363:             */
2364:            private void closeActivity(State closedState) {
2365:                if (getPaPreliminarilyChosen()
2366:                        && (closedState
2367:                                .isSameOrSubState(ClosedCompletedState.NORMAL) || (closedState
2368:                                .isSameOrSubState(ClosedState.TERMINATED) && (!((ExtProcessLocal) containerLocal())
2369:                                .typedState().isSameOrSubState(
2370:                                        RunningState.TERMINATING))))) {
2371:                    try {
2372:                        choose();
2373:                    } catch (TransitionNotAllowedException e) {
2374:                        // cannot happen because state has been checked already
2375:                        logger.error("Unexpected exception: " + e.getMessage(),
2376:                                e);
2377:                    }
2378:                }
2379:                // Debug only if process is still running normally, i.e. not
2380:                // terminating or aborting.
2381:                if (getPaDebug()
2382:                        && ((ProcessLocal) containerLocal()).typedState() == RunningState.RUNNING) {
2383:                    State debState = (State) CLOSE_STATE_TO_DEBUG_STATE
2384:                            .get(closedState);
2385:                    if (debState != null) {
2386:                        setPaTypedState(debState);
2387:                        return;
2388:                    }
2389:                }
2390:                ((ExtProcessLocal) containerLocal()).closeActivity(
2391:                        toActivityLocal(), closedState);
2392:            }
2393:
2394:            /**
2395:             * Called when the activity is closed.
2396:             */
2397:            protected void releaseResources() {
2398:                // Optimization.
2399:                if (getPaNoAssignments()) {
2400:                    return;
2401:                }
2402:                RASInvocationHandler ras = rasInvocationHandler();
2403:                if (ras == null) {
2404:                    return;
2405:                }
2406:                for (Iterator i = assignments().iterator(); i.hasNext();) {
2407:                    WfAssignment assignment = (WfAssignment) i.next();
2408:                    try {
2409:                        WfResource resource = ras.retrieveAssignee(assignment);
2410:                        ras.removeAssignment(activityFinder(), getPaKey(),
2411:                                toActivity(), resource);
2412:                        if (getPaAuditEventSelection() == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS) {
2413:                            fireAuditEvent(new DefaultAssignmentAuditEvent(
2414:                                    auditEventBase(WfAuditEvent.ACTIVITY_ASSIGNMENT_CHANGED),
2415:                                    ras.retrieveKey(resource), null, ras
2416:                                            .retrieveName(resource), null));
2417:                        }
2418:                    } catch (InvalidResourceException e) {
2419:                        logger.debug("Trying to remove unknown resource: "
2420:                                + e.getMessage(), e);
2421:                    } catch (NotAssignedException e) {
2422:                        logger.debug("Trying to remove unassigned resource: "
2423:                                + e.getMessage(), e);
2424:                    }
2425:                }
2426:                setPaNoAssignments(true);
2427:            }
2428:
2429:            /**
2430:             * Terminate any implementation currently running for this
2431:             * activity.
2432:             * @throws ApplicationNotStoppedException if implementation
2433:             * termination was not possible
2434:             */
2435:            protected void terminateImpl()
2436:                    throws ApplicationNotStoppedException {
2437:                try {
2438:                    Implementation impl = executor();
2439:                    if (impl == null) {
2440:                        return;
2441:                    }
2442:                    if (impl instanceof  ToolImplementation) {
2443:                        terminateTool((ToolImplementation) impl);
2444:                        return;
2445:                    }
2446:                    if (impl instanceof  SubFlowImplementation) {
2447:                        Collection subs = performersLocal();
2448:                        for (Iterator i = subs.iterator(); i.hasNext();) {
2449:                            WfProcessLocal p = (WfProcessLocal) i.next();
2450:                            if (p.workflowState() == State.CLOSED) {
2451:                                continue;
2452:                            }
2453:                            p.terminate();
2454:                        }
2455:                    }
2456:                } catch (CannotStopException e) {
2457:                    throw new ApplicationNotStoppedException(e.getMessage());
2458:                } catch (NotRunningException e) {
2459:                    throw new ApplicationNotStoppedException(e.getMessage());
2460:                }
2461:            }
2462:
2463:            /**
2464:             * Terminate a tool currently running for this activity.
2465:             * @throws ApplicationNotStoppedException if tool termination was
2466:             * not possible.
2467:             */
2468:            protected void terminateTool()
2469:                    throws ApplicationNotStoppedException {
2470:                Implementation impl = executor();
2471:                if (impl == null || !(impl instanceof  ToolImplementation)) {
2472:                    return;
2473:                }
2474:                terminateTool((ToolImplementation) impl);
2475:            }
2476:
2477:            /**
2478:             * Terminate the given tool.
2479:             * @throws ApplicationNotStoppedException if tool termination was
2480:             * not possible.
2481:             */
2482:            private void terminateTool(ToolImplementation impl)
2483:                    throws ApplicationNotStoppedException {
2484:                try {
2485:                    ApplicationDefinition app = (ApplicationDefinition) ((ProcessLocal) containerLocal())
2486:                            .processDefinition().applicationById(impl.id());
2487:                    toolInvocationHandler().terminate(app, toActivity());
2488:                } catch (InvalidIdException ide) {
2489:                    logger.warn("Invalid reference to tool: "
2490:                            + ide.getMessage());
2491:                }
2492:            }
2493:
2494:            /**
2495:             * Return a <code>ToolInvocationHandler</code>. Simple implementation
2496:             * that will have to be refined by the persistence/remoting layer.
2497:             * @return a handler.
2498:             */
2499:            protected ToolInvocationHandler toolInvocationHandler() {
2500:                return (new ToolInvocationHandler() {
2501:                    public void invoke(ExtApplication appl,
2502:                            ActivityUniqueKey auk, ExtActivity act, Map params)
2503:                            throws ToolInvocationException {
2504:                        try {
2505:                            appl.invoke(null, act, params);
2506:                        } catch (RemoteException e) {
2507:                            logger.error(e.getMessage(), e);
2508:                            throw new IllegalStateException(
2509:                                    "Cannot invoke tool");
2510:                        }
2511:                    }
2512:
2513:                    public void terminate(ExtApplication appl, Activity act)
2514:                            throws ApplicationNotStoppedException {
2515:                        try {
2516:                            appl.terminate(act);
2517:                        } catch (RemoteException e) {
2518:                            logger.error(e.getMessage(), e);
2519:                            throw new IllegalStateException(
2520:                                    "Cannot terminate tool");
2521:                        }
2522:                    }
2523:                });
2524:            }
2525:
2526:            /**
2527:             * Return a <code>RASInvocationHandler</code>. The default implementation
2528:             * returns <code>null</code>, i.e. there is no resource assignment service
2529:             * available.
2530:             * @return a handler.
2531:             */
2532:            protected RASInvocationHandler rasInvocationHandler() {
2533:                return null;
2534:            }
2535:
2536:            /**
2537:             * Invoke a tool for this activity.
2538:             *
2539:             * @param appl the application description of the tool.
2540:             * @param params the invocation parameters.
2541:             */
2542:            public void invokeTool(ExtApplication appl, Map params) {
2543:                try {
2544:                    toolInvocationHandler().invoke(appl, uniqueKey(),
2545:                            (ExtActivity) toActivity(), params);
2546:                } catch (ToolInvocationException e) {
2547:                    try {
2548:                        terminate();
2549:                    } catch (CannotStopException ee) {
2550:                        throw (IllegalStateException) (new IllegalStateException(
2551:                                ee.getMessage())).initCause(ee);
2552:                    } catch (NotRunningException ee) {
2553:                        throw (IllegalStateException) (new IllegalStateException(
2554:                                ee.getMessage())).initCause(ee);
2555:                    }
2556:                }
2557:            }
2558:
2559:            /**
2560:             * Returns a <code>WfAuditEvent</code> containing information about the 
2561:             * activity and its container, only.
2562:             * @param eventType event type
2563:             * @return the event containing the required information.
2564:             */
2565:            protected WfAuditEvent auditEventBase(String eventType) {
2566:                return new DefaultAuditEvent(toActivity(), eventType,
2567:                        getPaKey(), getPaName(), containerAuditEventBase());
2568:            }
2569:
2570:            /**
2571:             * Return string representation for debugging purposes.
2572:             * @return a string representation.
2573:             */
2574:            public String toString() {
2575:                return "Activity[key=" + getPaKey() + "]";
2576:            }
2577:
2578:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.