001: /*
002: * Danet GmbH
003: * Beratung und Software-Entwicklung
004: * Geschäftstelle AN
005: *
006: * $Id: TransMgr.java,v 1.3 2007/05/03 21:58:24 mlipp Exp $
007: *
008: * $Log: TransMgr.java,v $
009: * Revision 1.3 2007/05/03 21:58:24 mlipp
010: * Internal refactoring for making better use of local EJBs.
011: *
012: * Revision 1.2 2007/03/27 21:59:42 mlipp
013: * Fixed lots of checkstyle warnings.
014: *
015: * Revision 1.1.1.3 2004/08/18 15:18:46 drmlipp
016: * Update to 1.2
017: *
018: * Revision 1.43 2004/05/05 09:44:07 lipp
019: * Finished SAX based process creation (no cleanup of old code, yet).
020: *
021: * Revision 1.42 2004/02/21 14:42:43 lipp
022: * Moved TransitionManager to domain package. Having it in its own
023: * package caused too many circular dependencies (and there are good
024: * points for having it in the domain package anyway).
025: *
026: * Revision 1.41 2003/09/19 13:12:29 lipp
027: * Adapted to closed.completed having a substate.
028: *
029: * Revision 1.40 2003/05/31 20:05:25 lipp
030: * Added support for different condition types.
031: *
032: * Revision 1.39 2003/04/26 16:12:35 lipp
033: * Moved some classes to reduce package dependencies.
034: *
035: * Revision 1.38 2003/04/24 20:51:21 lipp
036: * Fixed some warnings.
037: *
038: * Revision 1.37 2003/02/03 10:09:27 lipp
039: * Adapted to latest changes in src.
040: *
041: * Revision 1.36 2002/11/25 21:16:23 lipp
042: * Adapted to transition interface changes.
043: *
044: * Revision 1.35 2002/11/19 15:14:52 lipp
045: * New transition manager.
046: *
047: * Revision 1.34 2002/11/15 15:13:54 lipp
048: * Clarified usage of transitions as attribute. Included in caching.
049: *
050: * Revision 1.33 2002/11/11 12:20:45 lipp
051: * Some fixes.
052: *
053: * Revision 1.32 2002/11/04 08:40:25 barzik
054: * adapted to several modifications in the workflow component
055: *
056: * Revision 1.31 2002/10/21 19:08:05 lipp
057: * Continuing implementation of new state handling.
058: *
059: * Revision 1.30 2002/10/09 15:17:51 lipp
060: * Improved start mode handling.
061: *
062: * Revision 1.29 2002/10/09 14:27:33 lipp
063: * Intermediate, compilable state.
064: *
065: * Revision 1.28 2002/09/11 14:17:22 lipp
066: * Execptions using msgs now.
067: *
068: * Revision 1.27 2002/09/08 18:46:39 lipp
069: * Clean up.
070: *
071: * Revision 1.26 2002/08/30 13:37:05 lipp
072: * Using Workflow engine facade now.
073: *
074: * Revision 1.25 2002/08/30 09:06:40 lipp
075: * Renamed internal state to typed state and use polymorphism for type
076: * names where possible.
077: *
078: * Revision 1.24 2002/08/28 12:58:03 lipp
079: * Fixed unittests.
080: *
081: * Revision 1.23 2002/08/28 12:47:20 lipp
082: * Starting new process generation.
083: *
084: * Revision 1.22 2002/08/22 15:19:34 lipp
085: * Redesign of EJB persistence.
086: *
087: * Revision 1.21 2002/08/21 22:06:48 lipp
088: * Finished transition to ProcessMgrStub.
089: *
090: * Revision 1.20 2002/08/02 09:28:53 huaiyang
091: * Use JDOM.
092: *
093: * Revision 1.19 2002/06/27 10:47:35 lipp
094: * Adapted to change in return type.
095: *
096: * Revision 1.18 2002/05/27 14:55:29 lipp
097: * Adapted to API changes.
098: *
099: * Revision 1.17 2002/02/04 22:43:12 lipp
100: * Adapted tests to changed.
101: *
102: * Revision 1.16 2002/02/04 15:18:55 lipp
103: * Made ActivityFinderAndKey visible in EJB Remote interface.
104: *
105: * Revision 1.15 2002/02/03 21:41:41 lipp
106: * Cleaned up unittests.
107: *
108: * Revision 1.14 2002/01/23 15:42:04 lipp
109: * Adapted to interface changes.
110: *
111: * Revision 1.13 2001/12/20 09:39:03 lipp
112: * Adapted to modified method signature.
113: *
114: * Revision 1.12 2001/12/18 22:16:53 lipp
115: * Restructured DOM generation, implemented "assignments" method from ras.
116: *
117: * Revision 1.11 2001/12/15 12:47:07 lipp
118: * Getting an ActivityFinder implemented.
119: *
120: * Revision 1.10 2001/12/13 21:00:05 lipp
121: * Simplified temporary implementation of a requester.
122: *
123: * Revision 1.9 2001/12/13 09:41:04 lipp
124: * equals and hashCode methods added.
125: *
126: * Revision 1.8 2001/10/25 17:15:51 lipp
127: * Renamed getTransitionsRefs() to getNextActivities() (more appropriate
128: * name) and added TransitionRefs to DOM representatiosn.
129: *
130: * Revision 1.7 2001/10/23 14:07:15 lipp
131: * Adapted to interface changes.
132: *
133: * Revision 1.6 2001/10/09 11:55:07 montag
134: * TransitionManager now without ejbs.
135: * transitionref list now contains Activity elements.
136: *
137: * Revision 1.5 2001/10/09 07:43:51 montag
138: * BaseElement reactivated
139: *
140: * Revision 1.4 2001/10/08 10:58:24 lipp
141: * Adapted to interface/implementation separation in domain.
142: *
143: * Revision 1.3 2001/10/04 08:01:54 montag
144: * unittests adopt for new transitionmanager
145: *
146: * Revision 1.2 2001/09/27 07:26:08 montag
147: * Default behavior for activities is now
148: * AND-Join and AND-Split.
149: * TO DO: XOR-Join and XOR-Split
150: *
151: * Revision 1.1 2001/09/26 08:15:39 montag
152: * allToActivities() implemented.
153: * test case for transition manager.
154: *
155: *
156: */
157: package domain;
158:
159: import java.util.ArrayList;
160: import java.util.Collection;
161: import java.util.Iterator;
162: import java.util.List;
163: import java.util.Vector;
164:
165: import java.rmi.RemoteException;
166:
167: import de.danet.an.workflow.localapi.ActivityLocal;
168: import de.danet.an.workflow.localcoreapi.WfActivityLocal;
169: import de.danet.an.workflow.omgcore.AlreadyRunningException;
170: import de.danet.an.workflow.omgcore.CannotStartException;
171: import de.danet.an.workflow.omgcore.InvalidDataException;
172: import de.danet.an.workflow.omgcore.InvalidStateException;
173: import de.danet.an.workflow.omgcore.ProcessData;
174: import de.danet.an.workflow.omgcore.TransitionNotAllowedException;
175: import de.danet.an.workflow.omgcore.UpdateNotAllowedException;
176: import de.danet.an.workflow.omgcore.WfActivity;
177: import de.danet.an.workflow.omgcore.WfExecutionObject.ClosedState;
178: import de.danet.an.workflow.omgcore.WfExecutionObject.OpenState;
179: import de.danet.an.workflow.omgcore.WfExecutionObject.State;
180:
181: import de.danet.an.workflow.api.Activity;
182: import de.danet.an.workflow.api.Transition;
183: import de.danet.an.workflow.api.Activity.JoinAndSplitMode;
184: import de.danet.an.workflow.api.Activity.StartFinishMode;
185:
186: import de.danet.an.workflow.domain.TransitionDefinition;
187: import de.danet.an.workflow.domain.TransitionDefinitionLocal;
188: import de.danet.an.workflow.domain.TransitionManager;
189:
190: import junit.framework.Test;
191: import junit.framework.TestCase;
192: import junit.framework.TestSuite;
193:
194: /**
195: * Zusammenstellung aller TransitionMgrTests.
196: * @author <a href="mailto:lipp@danet.de"></a>
197: * @version 1.0
198: */
199: public class TransMgr extends TestCase {
200:
201: /**
202: * Konstruktor zum Erzeugen eines TestCase
203: * @param name a <code>String</code> value
204: */
205: public TransMgr(String name) {
206: super (name);
207: }
208:
209: /**
210: * Stellt diese TestSuite zusammen.
211: * @return a <code>Test</code> value
212: */
213: public static Test suite() {
214: TestSuite suite = new TestSuite();
215: // Because the transition manager currently
216: // works only on EJB, the tests are deactivated
217: // until there are new interfaces for process and
218: // activity to e.g. retrieve the transition ref list
219: // from a process.
220: suite.addTest(new TransMgr("transTest1"));
221: suite.addTest(new TransMgr("joinAndSplit1"));
222: return suite;
223: }
224:
225: /**
226: * Test for Process with activities and transitions
227: * @exception Exception if an error occurs
228: */
229: public void transTest1() throws Exception {
230: TestProcess p = getProcess();
231: assertTrue(p != null);
232: ActivityLocal a1 = getActivity(p, 1);
233: assertTrue(a1 != null);
234: ActivityLocal a2 = getActivity(p, 2);
235: assertTrue(a2 != null);
236: Collection c = new Vector();
237: c.add(a1);
238: c.add(a2);
239: p.setActivities(c);
240: String group = "t";
241: int order = 0;
242: p.createTransition("t", group, order, a1, a2);
243: p.testTransitionManager();
244: }
245:
246: /**
247: * Test for Process with activities and transitions
248: * @exception Exception if an error occurs
249: */
250: public void joinAndSplit1() throws Exception {
251: TestProcess p = getProcess();
252: assertTrue(p != null);
253: TestActivity[] a = new TestActivity[9];
254: Collection c = new Vector();
255: for (int i = 0; i < 9; i++) {
256: a[i] = (TestActivity) getActivity(p, i);
257: a[i].setJoinMode(JoinAndSplitMode.AND);
258: a[i].setSplitMode(JoinAndSplitMode.AND);
259: c.add(a[i]);
260: }
261: p.setActivities(c);
262: List tr = new ArrayList();
263: TransitionDefinitionLocal[] t = new TransitionDefinitionLocal[12];
264: t[0] = new TransitionDefinitionLocal(p.key(), "0", "0", 0,
265: a[0], a[1], Transition.COND_TYPE_CONDITION, null);
266: t[1] = new TransitionDefinitionLocal(p.key(), "1", "1", 0,
267: a[0], a[2], Transition.COND_TYPE_CONDITION, null);
268: t[2] = new TransitionDefinitionLocal(p.key(), "2", "2", 0,
269: a[1], a[3], Transition.COND_TYPE_CONDITION, null);
270: t[3] = new TransitionDefinitionLocal(p.key(), "3", "3", 0,
271: a[1], a[4], Transition.COND_TYPE_CONDITION, null);
272: t[4] = new TransitionDefinitionLocal(p.key(), "4", "4", 0,
273: a[2], a[4], Transition.COND_TYPE_CONDITION, null);
274: t[5] = new TransitionDefinitionLocal(p.key(), "5", "5", 0,
275: a[2], a[5], Transition.COND_TYPE_CONDITION, null);
276: t[6] = new TransitionDefinitionLocal(p.key(), "6", "6", 0,
277: a[3], a[6], Transition.COND_TYPE_CONDITION, null);
278: t[7] = new TransitionDefinitionLocal(p.key(), "7", "7", 0,
279: a[4], a[6], Transition.COND_TYPE_CONDITION, null);
280: t[8] = new TransitionDefinitionLocal(p.key(), "8", "8", 0,
281: a[4], a[7], Transition.COND_TYPE_CONDITION, null);
282: t[9] = new TransitionDefinitionLocal(p.key(), "9", "9", 0,
283: a[5], a[7], Transition.COND_TYPE_CONDITION, null);
284: t[10] = new TransitionDefinitionLocal(p.key(), "10", "10", 0,
285: a[6], a[8], Transition.COND_TYPE_CONDITION, null);
286: t[11] = new TransitionDefinitionLocal(p.key(), "11", "11", 0,
287: a[7], a[8], Transition.COND_TYPE_CONDITION, null);
288: for (int i = 0; i < 12; i++) {
289: p.createTransition(t[i].id(), t[i].group(), t[i].order(),
290: t[i].from(), t[i].to());
291: }
292: p.start();
293:
294: for (int i = 0; i < 9; i++) {
295: assertTrue(a[i].state().startsWith("closed.completed"));
296: }
297:
298: }
299:
300: //////////////////////////////////////////////////////////
301:
302: private TestProcess getProcess() {
303: return new TestProcess("p1");
304: }
305:
306: /**
307: * Describe class <code>TestProcess</code> here.
308: *
309: */
310: public class TestProcess extends VolatileProcess {
311:
312: /**
313: * Creates a new <code>TestProcess</code> instance.
314: *
315: * @param key a <code>String</code> value
316: */
317: public TestProcess(String key) {
318: super (key);
319: }
320:
321: /**
322: * Test the TransitionManager.<p>
323: * Preconditions:
324: * <ul>
325: * <li>The process has not been started.</li>
326: * <li>There a two activities an one transition
327: * between these two activities.</li>
328: * </ul>
329: * @exception Exception if an error occurs
330: */
331: public void testTransitionManager() throws Exception {
332: assertTrue(transitionsLocal().size() > 0);
333: TransitionManager tm = transitionManager();
334: assertTrue(tm != null);
335: Collection a = steps();
336: // Test allOpenableActivities()
337: Collection c = tm.startableActivities();
338: // only the first activity should be openable
339: assertTrue(c.size() == 1);
340: }
341:
342: /**
343: * Describe <code>start</code> method here.
344: *
345: * @exception CannotStartException if an error occurs
346: * @exception AlreadyRunningException if an error occurs
347: */
348: public void start() throws CannotStartException,
349: AlreadyRunningException {
350: // set process state
351: super .start();
352:
353: // start all activities
354: TransitionManager tm = transitionManager();
355: Collection activitiesToStart = tm.startableActivities();
356: Iterator it = activitiesToStart.iterator();
357: while (it.hasNext()) {
358: WfActivityLocal a = (WfActivityLocal) it.next();
359: try {
360: // Due to concurrency, an activity
361: // could be started interim.
362: if (!a.workflowState().equals(State.CLOSED)
363: && a.state().equals(
364: "open.not_running.not_runnable")) {
365: a.setProcessContext(null);
366: }
367: } catch (InvalidDataException ide) {
368: throw new CannotStartException("");
369: } catch (UpdateNotAllowedException ue) {
370: throw new CannotStartException("");
371: }
372: }
373: }
374:
375: /**
376: * This method notifies the process that one of its
377: * activities has changed its state. For the 1. iteration
378: * an activity signals that it has been completed.
379: * The next activity (if exists) are searched and started.
380: * @param i a <code>Long</code> value
381: * @param s the actual state of the activity
382: */
383: public void complete(Long i, State s) {
384: try {
385: // checkAllActivities
386: if (transitionManager().isAtEnd()) {
387: // TODO: remove condition check
388: if (!State.fromString(state()).isSameOrSubState(
389: ClosedState.ABORTED)) {
390: // last activity executed, finish process
391: updateState(ClosedState.COMPLETED);
392: }
393: } else {
394: // start all runnableActivities
395: Collection activitiesToStart = transitionManager()
396: .startableActivities();
397: Iterator it = activitiesToStart.iterator();
398: while (it.hasNext()) {
399: WfActivity a = (WfActivity) it.next();
400: try {
401: // Due to concurrency, an activity
402: // could be started interim.
403: if (!a.workflowState().equals(State.CLOSED)
404: && a
405: .state()
406: .equals(
407: "open.not_running.not_runnable")) {
408: a.setProcessContext(null);
409: }
410: } catch (UpdateNotAllowedException ue) {
411: ue.printStackTrace();
412: }
413: }
414: }
415: } catch (RemoteException re) {
416: re.printStackTrace();
417: } catch (InvalidStateException re) {
418: re.printStackTrace();
419: } catch (InvalidDataException re) {
420: re.printStackTrace();
421: }
422: }
423: }
424:
425: private ActivityLocal getActivity(TestProcess p, int i) {
426: return new TestActivity(p, i);
427: }
428:
429: /**
430: * Describe class <code>TestActivity</code> here.
431: *
432: */
433: public class TestActivity extends VolatileActivity {
434:
435: private int id;
436:
437: /**
438: * Describe <code>thisRemote</code> method here.
439: *
440: * @return an <code>Activity</code> value
441: */
442: protected Activity this Remote() {
443: return new ActivityRemoteWrapper(this );
444: }
445:
446: /**
447: * Creates a new <code>TestActivity</code> instance.
448: *
449: * @param p a <code>TestProcess</code> value
450: * @param i an <code>int</code> value
451: */
452: public TestActivity(TestProcess p, int i) {
453: super (p, "ta" + i);
454: id = i;
455: setPaName("ta" + i);
456: setPaDescription("ta" + i);
457: }
458:
459: /**
460: * Describe <code>setProcessContext</code> method here.
461: *
462: * @param newValue a <code>ProcessData</code> value
463: * @exception InvalidDataException if an error occurs
464: * @exception UpdateNotAllowedException if an error occurs
465: */
466: public void setProcessContext(ProcessData newValue)
467: throws InvalidDataException, UpdateNotAllowedException {
468:
469: try {
470: updateState(OpenState.NOT_RUNNING);
471:
472: if (startMode() == StartFinishMode.MANUAL) {
473: // hold state
474: } else {
475: if (finishMode() == StartFinishMode.MANUAL) {
476: changeState("open.running");
477: } else {
478: changeState("open.running");
479: updateState(ClosedState.COMPLETED);
480: }
481: }
482: } catch (InvalidStateException ie) {
483: throw new UpdateNotAllowedException(ie.getMessage());
484: } catch (TransitionNotAllowedException te) {
485: throw new UpdateNotAllowedException(te.getMessage());
486: }
487: }
488:
489: /**
490: * Describe <code>pubSetState</code> method here.
491: *
492: * @param s a <code>State</code> value
493: * @exception InvalidStateException if an error occurs
494: */
495: public void pubSetState(State s) throws InvalidStateException {
496: updateState(s);
497: }
498:
499: }
500: }
|