osworkflow.xml
<osworkflow>
<persistence class="com.opensymphony.workflow.spi.memory.MemoryWorkflowStore" />
<factory class="com.opensymphony.workflow.loader.XMLWorkflowFactory">
<property key="resource" value="workflows.xml" />
</factory>
</osworkflow>
workflows.xml
<workflows>
<workflow name="docworkflow" type="resource" location="myworkflow.xml"/>
</workflows>
myworkflow.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.6//EN" "http://www.opensymphony.com/osworkflow/workflow_2_8.dtd">
<workflow>
<registers>
<register type="class" variable-name="log">
<arg name="class.name">com.opensymphony.workflow.util.LogRegister</arg>
<arg name="addInstanceId">true</arg>
</register>
</registers>
<initial-actions>
<action id="100" name="Start Ordinary Workflow">
<results>
<unconditional-result old-status="Finished"
status="Queued" step="1" />
</results>
</action>
<action id="200" name="Start Emergent Workflow">
<results>
<unconditional-result old-status="Finished"
status="Queued" step="5" />
</results>
</action>
</initial-actions>
<steps>
<step id="1" name="Initiate Doc">
<actions>
<action id="1" name="Initial Work">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.StatusCondition
</arg>
<arg name="status">Queued</arg>
</condition>
</conditions>
</restrict-to>
<validators>
<validator type="class">
<arg name="class.name">
org.abin.lee.validator.TitleValidator
</arg>
</validator>
</validators>
<pre-functions>
<function type="class">
<arg name="class.name">
com.opensymphony.workflow.util.Caller
</arg>
<arg name="stepId">1</arg>
</function>
<function type="beanshell">
<arg name="script">
transientVars.get("log").info("Initiate Work");
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Prepared" step="1" owner="${caller}" />
</results>
<post-functions>
<function type="beanshell">
<arg name="script">
propertySet.setString("title",
(String)transientVars.get("title"));
</arg>
</function>
</post-functions>
</action>
<action id="2" name="Deliver Work">
<restrict-to>
<conditions type="AND">
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.StatusCondition
</arg>
<arg name="status">Prepared</arg>
<arg name="stepId">1</arg>
</condition>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.AllowOwnerOnlyCondition
</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="beanshell">
<arg name="script">
transientVars.get("log").info("Deliver Doc to Boss A and B");
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Prepared" split="1" />
</results>
</action>
</actions>
</step>
<step id="2" name="Review Doc In Boss A">
<external-permissions>
<permission name="permA">
<restrict-to>
<conditions type="AND">
<condition name="check.status" type="class">
<arg name="class.name">com.opensymphony.workflow.util.StatusCondition</arg>
<arg name="status">Prepared</arg>
</condition>
<condition name="allow.owner.only" type="class">
<arg name="class.name">com.opensymphony.workflow.util.AllowOwnerOnlyCondition</arg>
</condition>
</conditions>
</restrict-to>
</permission>
</external-permissions>
<actions>
<action id="3" name="Review Work By A">
<pre-functions>
<function type="beanshell">
<arg name="script">
transientVars.get("log").info("Doc Reviewed By Boss A")
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Underway" join="1" />
</results>
</action>
</actions>
</step>
<step id="3" name="Review Doc In Boss B">
<external-permissions>
<permission name="permA">
<restrict-to>
<conditions type="AND">
<condition name="check.status" type="class">
<arg name="class.name">com.opensymphony.workflow.util.StatusCondition</arg>
<arg name="status">Prepared</arg>
</condition>
<condition name="allow.owner.only" type="class">
<arg name="class.name">com.opensymphony.workflow.util.AllowOwnerOnlyCondition</arg>
</condition>
</conditions>
</restrict-to>
</permission>
</external-permissions>
<actions>
<action id="4" name="Review Work By B">
<pre-functions>
<function type="beanshell">
<arg name="script">
transientVars.get("log").info("Doc Reviewed By Boss B")
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Underway" join="1" />
</results>
</action>
</actions>
</step>
<step id="4" name="Finish Ordinary Work">
<pre-functions>
<function type="beanshell">
<arg name="script">
System.out.println("Finish Doc Review. \nTitle:"+propertySet.getString("title")+".");
</arg>
</function>
</pre-functions>
</step>
<step id="5" name="Finish Emergent Work">
<pre-functions>
<function type="beanshell">
<arg name="script">
System.out.println("Emergency Handler");
</arg>
</function>
</pre-functions>
</step>
</steps>
<splits>
<split id="1">
<unconditional-result old-status="Finished"
status="Prepared" step="2" />
<unconditional-result old-status="Finished"
status="Prepared" step="3" />
</split>
</splits>
<joins>
<join id="1">
<conditions type="AND">
<condition type="beanshell">
<arg name="script"><![CDATA[ "Finished".equals(jn.getStep(2).getStatus()) && "Finished".equals(jn.getStep(3).getStatus()) ]]></arg>
</condition>
</conditions>
<unconditional-result old-status="Finished"
status="Reviewed" step="4" />
</join>
</joins>
</workflow>
TitleValidator.java
package org.abin.lee.validator;
import java.util.Map;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.workflow.InvalidInputException;
import com.opensymphony.workflow.Validator;
import com.opensymphony.workflow.WorkflowException;
public class TitleValidator implements Validator {
public void validate(Map transientVars, Map args, PropertySet ps)
throws InvalidInputException, WorkflowException {
System.out.println("TitleValidator is running");
String title = (String) transientVars.get("title");
if (title == null)
throw new InvalidInputException("Missing title");
if (title.length() > 30)
throw new InvalidInputException("Title too long");
}
}
SimpleSample.java
package org.abin.lee.workflow;
import java.util.HashMap;
import com.opensymphony.workflow.InvalidActionException;
import com.opensymphony.workflow.InvalidEntryStateException;
import com.opensymphony.workflow.InvalidInputException;
import com.opensymphony.workflow.InvalidRoleException;
import com.opensymphony.workflow.Workflow;
import com.opensymphony.workflow.WorkflowException;
import com.opensymphony.workflow.basic.BasicWorkflow;
import com.opensymphony.workflow.config.DefaultConfiguration;
public class SimpleSample {
public static void main(String[] args) {
try {
Workflow workflow = new BasicWorkflow("abin");
DefaultConfiguration config = new DefaultConfiguration();
workflow.setConfiguration(config);
long workflowId = workflow.initialize("docworkflow", 100, null);
HashMap inputs = new HashMap();
inputs.put("title", "openopen");
workflow.doAction(workflowId, 1, inputs);
workflow.doAction(workflowId, 2, null);
workflow.doAction(workflowId, 3, null);
workflow.doAction(workflowId, 4, null);
} catch (InvalidActionException e) {
System.out.println(e.getMessage());
} catch (InvalidRoleException e) {
System.out.println(e.getMessage());
} catch (InvalidInputException e) {
System.out.println(e.getMessage());
} catch (InvalidEntryStateException e) {
System.out.println(e.getMessage());
} catch (WorkflowException e) {
System.out.println(e.getMessage());
}
}
}
log4j.properties
log4j.rootCategory=info,log,console
log4j.logger.org.apache.axis2.enterprise=FATAL
log4j.logger.de.hunsicker.jalopy.io=FATAL
log4j.logger.httpclient.wire.header=FATAL
log4j.logger.org.apache.commons.httpclient=FATAL
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n
log4j.appender.log=org.apache.log4j.DailyRollingFileAppender
log4j.appender.log.File=logs/osworkflow.log
log4j.appender.log.layout=org.apache.log4j.PatternLayout
log4j.appender.log.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n
http://blog.sina.com.cn/s/blog_544a96ce0100nvjy.html
http://blog.csdn.net/tanruitian/article/details/498167
http://www.cnblogs.com/jacky73/archive/2008/12/17/1357134.html