/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: ProcRuns.java 2856 2008-12-12 22:24:16Z mlipp $
*
* $Log$
* Revision 1.4 2006/10/13 13:58:32 drmlipp
* Adapted to new environment.
*
* Revision 1.3 2006/10/07 20:41:34 mlipp
* Merged J2EE 1.4 adaptions from test branch.
*
* Revision 1.2 2006/09/29 12:32:10 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.1.1.3 2004/08/18 15:18:47 drmlipp
* Update to 1.2
*
* Revision 1.6 2004/01/27 11:45:33 lipp
* Preserve newlines when reading process definitions.
*
* Revision 1.5 2003/10/21 21:00:45 lipp
* Moved EJBClientTest to new junit sub-package.
*
* Revision 1.4 2003/10/08 11:52:55 huaiyang
* make test weblogic compatible.
*
* Revision 1.3 2003/09/19 13:12:29 lipp
* Adapted to closed.completed having a substate.
*
* Revision 1.2 2003/06/27 09:44:13 lipp
* Fixed copyright/license information.
*
* Revision 1.1 2003/04/26 16:46:55 lipp
* Made unittests and systemtests coexist in eclipse.
*
* Revision 1.19 2003/04/16 19:25:04 lipp
* Adapted to jdk 1.4
*
* Revision 1.18 2003/02/25 17:08:27 lipp
* Reorganized requester implementation.
*
* Revision 1.17 2003/02/24 10:46:41 lipp
* Removed usage of System.out and .err.
*
* Revision 1.16 2003/02/05 15:57:06 lipp
* Replaced DummyRequester with DefaultRequester.
*
* Revision 1.15 2002/12/09 10:52:57 lipp
* Updated to abort() modifications.
*
* Revision 1.14 2002/11/20 15:31:55 huaiyang
* Add test method of removeClosedProcessjut1.
*
* Revision 1.13 2002/11/19 15:14:52 lipp
* New transition manager.
*
* Revision 1.12 2002/11/06 13:27:17 barzik
* add test case for removing a process from the system
*
* Revision 1.11 2002/10/23 11:36:47 lipp
* Got them running again.
*
* Revision 1.10 2002/10/23 07:29:15 lipp
* Adapted to state handling changes.
*
* Revision 1.9 2002/10/22 17:19:01 lipp
* Still adapting to state handling changes.
*
* Revision 1.8 2002/09/08 18:49:18 lipp
* Proper use of packageId and processId.
*
* Revision 1.7 2002/09/04 20:50:44 lipp
* Adapted to new process manager name schema.
*
* Revision 1.6 2002/08/30 13:37:05 lipp
* Using Workflow engine facade now.
*
* Revision 1.5 2002/08/26 20:23:14 lipp
* Lots of method renames.
*
* Revision 1.4 2002/08/21 22:06:48 lipp
* Finished transition to ProcessMgrStub.
*
* Revision 1.3 2002/08/19 13:58:14 lipp
* Javadoc fixes.
*
* Revision 1.2 2002/08/16 12:52:00 huaiyang
* Add the test of ProcessAPI.
*
* Revision 1.1 2002/08/16 12:08:52 huaiyang
* Initial.
*
*
*/
package process;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import common.UTLoginContext;
import javax.security.auth.login.LoginException;
import de.danet.an.util.EJBUtil;
import de.danet.an.util.junit.EJBClientTest;
import de.danet.an.workflow.api.CannotRemoveException;
import de.danet.an.workflow.api.DefaultRequester;
import de.danet.an.workflow.api.FactoryConfigurationError;
import de.danet.an.workflow.api.Process;
import de.danet.an.workflow.api.ProcessDefinitionDirectory;
import de.danet.an.workflow.api.ProcessDirectory;
import de.danet.an.workflow.api.ProcessMgr;
import de.danet.an.workflow.api.WorkflowService;
import de.danet.an.workflow.api.WorkflowServiceFactory;
import de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectoryHome;
import de.danet.an.workflow.ejbs.admin.ProcessDirectoryHome;
import de.danet.an.workflow.omgcore.WfActivity;
import de.danet.an.workflow.omgcore.WfExecutionObject;
import de.danet.an.workflow.omgcore.WfProcess;
import de.danet.an.workflow.omgcore.WfRequester;
/**
* Test the life cycle of different processes.
*/
public class ProcRuns extends TestCase {
private static UTLoginContext plc = null;
static {
try {
plc = new UTLoginContext();
plc.login();
} catch (LoginException e) {
throw new IllegalStateException (e.getMessage ());
}
}
/**
* A process directory reference.
*/
private ProcessDirectory pdd = null;
/**
* Constructor of this TestCase
*/
public ProcRuns(String name) {
super (name);
}
/**
* Stellt diese TestSuite zusammen.
*/
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new ProcRuns("importProcessDefinitions"));
suite.addTest(new ProcRuns("processjut2"));
suite.addTest(new ProcRuns("processjut4"));
suite.addTest(new ProcRuns("processjut6"));
suite.addTest(new ProcRuns("processAPI"));
suite.addTest(new ProcRuns("removejut1"));
suite.addTest(new ProcRuns("removeClosedProcessjut1"));
return new EJBClientTest (plc, suite);
}
private static final String OPEN_RUNNING
= WfExecutionObject.OpenState.RUNNING.toString();
private static final String OPEN_NOT_RUNNING
= WfExecutionObject.OpenState.NOT_RUNNING.toString();
private static final String CLOSED_COMPLETED
= WfExecutionObject.ClosedState.COMPLETED.toString();
private static final String CLOSED_ABORTED
= WfExecutionObject.ClosedState.ABORTED.toString();
private static final String NOT_STARTED
= WfExecutionObject.NotRunningState.NOT_STARTED.toString();
private WorkflowService workflowService = null;
/**
* Initialisierung.
*/
protected void setUp() throws Exception {
try {
WorkflowServiceFactory wfsf
= WorkflowServiceFactory.newInstance ();
workflowService = wfsf.newWorkflowService();
} catch (FactoryConfigurationError e) {
throw new IllegalStateException (e.getMessage());
}
}
protected void tearDown() throws Exception {
workflowService.release (workflowService);
workflowService = null;
}
private static WorkflowService wfsCache = null;
/**
* Import the process definitions from a XPDL file
* unsing the ProcessDefinitionDirectory bean.
*/
public void importProcessDefinitions() throws Exception {
// Create process definition directory bean
ProcessDefinitionDirectory pdd
= workflowService.processDefinitionDirectory();
InputStream is = getClass()
.getResourceAsStream("/process/testXPDL.xml");
assertTrue (is != null);
BufferedReader br = new BufferedReader
(new InputStreamReader(is, "ISO-8859-1"));
StringBuffer sb = new StringBuffer();
String st;
while ((st = br.readLine()) != null) {
sb.append(st + "\n");
}
pdd.importProcessDefinitions(sb.toString());
Collection processDefinitions = pdd.processDefinitions();
assertTrue (processDefinitions.size() > 0);
}
private WfProcess createProcess
(String pkgId, String prcId, WfRequester req)
throws Exception {
ProcessDefinitionDirectory procDir = null;
try {
procDir = workflowService.processDefinitionDirectory();
ProcessMgr pmgr = procDir.processMgr(pkgId, prcId);
return pmgr.createProcess (req);
} finally {
workflowService.release (procDir);
}
}
/**
* Test a simple process definition. The activities will be started
* manually and stopped manually one after another.
* <pre>
* A21 --> A22 --> A23 --> A24
* </pre>
* without any branched activity.
*/
public void processjut2() throws Exception {
WfRequester req = new DefaultRequester(workflowService);
// create the process
WfProcess process = createProcess("ut-process", "jut2", req);
assertTrue(process.state().equals("open.not_running.not_started"));
// start the process
process.start();
assertTrue(process.state().startsWith("open.running"));
Thread.sleep (1000);
// start the activities and stop it.
for (int i = 1; i <= 4; i++) {
Collection c = process.steps();
WfActivity a = null;
for (Iterator it = c.iterator(); it.hasNext();) {
a = (WfActivity)it.next();
if (a.name().equals ("A2" + i)) {
break;
}
}
assertTrue(a.state() != null);
boolean exceptionCaught = false;
assertTrue
(a.name() + " not open.not_running.suspended: " + a.state(),
a.state().startsWith("open.not_running.suspended"));
a.resume();
Thread.sleep (1000);
a.resume();
Thread.sleep (1000);
assertTrue(a.name() + " not closed.completed: " + a.state(),
a.state().startsWith("closed.completed"));
}
assertTrue(process.state().startsWith("closed.completed"));
}
/**
* Test a process definition with XOR-splitted activity.
* The activities will be started manually and stopped manually one
* after another.
* <pre>
* |--> A42 --|
* A41 --| --| --> A44
* |--> A43 --|
* </pre>
*/
public void processjut4() throws Exception {
WfRequester req = new DefaultRequester(workflowService);
// create the process
WfProcess process = createProcess("ut-process", "jut4", req);
assertTrue(process.state().equals("open.not_running.not_started"));
// start the process
process.start();
assertTrue(process.state().startsWith("open.running"));
Thread.sleep (1000);
// start the activities and stop it.
Object[] actArray = process.steps().toArray();
assertTrue(actArray.length == 4);
Arrays.sort (actArray, new Comparator () {
public int compare (Object o1, Object o2) {
return ((WfActivity)o1).toString()
.compareTo (((WfActivity)o2).toString());
}
});
WfActivity a41 = (WfActivity)actArray[0];
WfActivity a42 = (WfActivity)actArray[1];
WfActivity a43 = (WfActivity)actArray[2];
WfActivity a44 = (WfActivity)actArray[3];
// start A41
assertTrue(a41.state().startsWith("open.not_running.suspended"));
a41.resume();
Thread.sleep (1000);
assertTrue(a42.state().startsWith("open.not_running.suspended"));
assertTrue(a43.state().startsWith("open.not_running.not_started"));
assertTrue(a44.state().startsWith("open.not_running.not_started"));
// start A42
a42.resume();
Thread.sleep (1000);
assertTrue(a43.state().startsWith("open.not_running.not_started"));
assertTrue(a44.state().startsWith("open.not_running.suspended"));
// start A44
a44.resume();
Thread.sleep (1000);
// process terminated
assertTrue(process.state().startsWith("closed.completed"));
}
/**
* Test a complex process definition.
* The activities will be finished manually.
*/
public void processjut6() throws Exception {
WfRequester req = new DefaultRequester(workflowService);
// create the process
WfProcess process = createProcess("ut-process", "jut6", req);
assertTrue(process.state().equals("open.not_running.not_started"));
// start the process
process.start();
assertTrue(process.state().startsWith("open.running"));
Thread.sleep (1000);
// start the activities and stop it.
Object[] actArray = process.steps().toArray();
assertTrue(actArray.length == 8);
Arrays.sort (actArray, new Comparator () {
public int compare (Object o1, Object o2) {
return ((WfActivity)o1).toString()
.compareTo (((WfActivity)o2).toString());
}
});
WfActivity a61 = (WfActivity)actArray[0];
WfActivity a62 = (WfActivity)actArray[1];
WfActivity a63 = (WfActivity)actArray[2];
WfActivity a64 = (WfActivity)actArray[3];
WfActivity a65 = (WfActivity)actArray[4];
WfActivity a66 = (WfActivity)actArray[5];
WfActivity a67 = (WfActivity)actArray[6];
WfActivity a68 = (WfActivity)actArray[7];
// start A61
assertTrue(a61.state().startsWith("open.not_running.suspended"));
a61.resume();
Thread.sleep (1000);
assertTrue(a62.state().startsWith("open.not_running.not_started"));
assertTrue(a63.state().startsWith("open.not_running.suspended"));
assertTrue(a64.state().startsWith("open.not_running.not_started"));
// start A63
a63.resume();
Thread.sleep (1000);
assertTrue(a66.state().startsWith("open.not_running.suspended"));
assertTrue(a65.state().startsWith("open.not_running.not_started"));
// start A66 and then stop it.
a66.resume();
Thread.sleep (1000);
// start A67
a67.resume();
Thread.sleep (1000);
// start A68
a68.resume();
Thread.sleep (1000);
// process terminated
assertTrue(process.state().startsWith("closed.completed"));
}
public void processAPI() throws Exception {
abortProcess();
//suspendresumeProcess();
}
//Abort Process
private void abortProcess() throws Exception {
WfRequester req = new DefaultRequester(workflowService);
WfProcess process = createProcess("ut-process", "jut2", req);
assertTrue(process.state().equals("open.not_running.not_started"));
process.start();
assertTrue(process.state().startsWith("open.running"));
process.suspend();
process.abort();
assertTrue(process.state().equals("closed.aborted"));
}
//Suspend Process then resume it
private void suspendresumeProcess() throws Exception {
WfRequester req = new DefaultRequester(workflowService);
WfProcess process = createProcess("ut-process", "jut2", req);
assertTrue(process.state().equals("open.not_running.not_started"));
process.start();
assertTrue(process.state().equals("open.running"));
process.suspend();
assertTrue(process.state().equals("open.not_running.suspended"));
process.resume();
assertTrue(process.state().equals("open.running"));
}
private boolean allActivitiesOfProcessHaveState (WfProcess proc,
String state)
throws Exception {
Iterator it = proc.steps().iterator();
while (it.hasNext()) {
WfActivity a = (WfActivity)it.next();
if (!a.state().startsWith(state)) {
return false;
}
}
return true;
}
/**
* Test a simple process definition according to remove the process.
* A process may be removed only and if only its state is CLOSED.
* Tests:
* 1.) remove not closed process
* 2.) remove closed process
* Please note definitions matching the (logical) code flow, e.g. start and
* finish mode of the corresponding activities.
*/
public void removejut1() throws Exception {
WfRequester req = new DefaultRequester(workflowService);
// create the process
Process process = (Process)(createProcess("ut-process", "jut1", req));
assertTrue(process.state().equals("open.not_running.not_started"));
// start the process
process.start();
assertTrue(process.state().startsWith("open.running"));
Thread.sleep (1000);
// start the first two activities and stop it.
Collection c = process.steps();
for (int i = 1; i <= 2; i++) {
WfActivity a = null;
for (Iterator it = c.iterator(); it.hasNext();) {
a = (WfActivity)it.next();
if (a.name().equals ("A1" + i)) {
break;
}
}
if (a.name().equals("A12")) {
Thread.sleep (1000);
a.resume();
}
Thread.sleep (1000);
assertTrue(a.name() + " not closed.completed: " + a.state(),
a.state().startsWith("closed.completed"));
}
assertTrue(!process.state().equals("closed.completed"));
// try to remove the process (should result into an exception)
boolean removeExceptionCaught = false;
try {
//Process p = processDirectory().lookupProcess(null, process.key());
processDirectory().removeProcess(process);
assertTrue(false);
} catch (CannotRemoveException cre) {
removeExceptionCaught = true;
} catch (Exception e) {
e.printStackTrace();
assertTrue("Unexpected exception caugth", false);
}
assertTrue("did not receive CannotRemoveException for a process "
+ "that has not been terminated",
removeExceptionCaught);
// start the last activity and stop it.
for (int i = 3; i <= 3; i++) {
WfActivity a = null;
for (Iterator it = c.iterator(); it.hasNext();) {
a = (WfActivity)it.next();
if (a.name().equals ("A1" + i)) {
break;
}
}
assertTrue(a.state() != null);
boolean exceptionCaught = false;
assertTrue
(a.name() + " not open.not_running.suspended: " + a.state(),
a.state().startsWith("open.not_running.suspended"));
a.resume();
Thread.sleep (1000);
a.resume();
Thread.sleep (1000);
assertTrue(a.name() + " not closed.completed: " + a.state(),
a.state().startsWith("closed.completed"));
}
assertTrue(process + " not closed.completed: " + process.state(),
process.state().startsWith("closed.completed"));
// finally remove the process and retry to access it
boolean exceptionCaught = false;
Process p = processDirectory().lookupProcess(null, process.key());
processDirectory().removeProcess(process);
try {
process.start();
} catch (Exception e) {
//e.printStackTrace();
exceptionCaught = true;
}
assertTrue("Could start a removed process", exceptionCaught);
}
/**
* Test a simple process definition according to remove the process.
* A process can be removed automatically only if its state is CLOSED and
* the extendedAttribute of removeClosedProcess in procss definition is
* AUTOMATIC (Default: AUTOMATIC).
*/
public void removeClosedProcessjut1() throws Exception {
WfRequester req = new DefaultRequester(workflowService);
ProcessDirectory procDir = processDirectory();
// create the process
Process process = (Process)(createProcess("ut-process", "jut5", req));
String processKey = process.key();
assertTrue(process.state().equals("open.not_running.not_started"));
// start the process
process.start();
assertTrue(process.state().startsWith("open.running"));
Thread.sleep (1000);
process.suspend();
process.abort();
Thread.sleep (2000);
boolean procExists = true;
try {
procDir.lookupProcess("ut-process/jut5", processKey);
} catch (Exception e) {
procExists = false;
}
assertTrue(!procExists);
}
/**
* Returns a reference to a process directory.
* @return the process directory
*/
private ProcessDirectory processDirectory() throws Exception {
if (pdd == null){
pdd = workflowService.processDirectory();
}
return pdd;
}
}