001: package org.obe.client.api.tool;
002:
003: import org.apache.commons.logging.Log;
004: import org.apache.commons.logging.LogFactory;
005: import org.obe.client.api.WMClient;
006: import org.obe.client.api.repository.ToolAgentMetaData;
007: import org.obe.xpdl.model.activity.ToolType;
008: import org.wfmc.wapi.WMWorkflowException;
009:
010: import java.io.IOException;
011: import java.io.Serializable;
012: import java.io.Writer;
013:
014: /**
015: * Encapsulates the invocation of a tool (application or procedure). This class
016: * can be used directly by thick Java clients (apps & applets), in order to
017: * support tool types other than native executables. Thin clients can use this
018: * class to generate the JavaScript to invoke the requisite application from an
019: * HTML browser.
020: *
021: * @author Adrian Price
022: * @see WMClient#executeWorkItem
023: */
024: public final class ToolInvocation implements Serializable {
025: private static final long serialVersionUID = -3204963265630362248L;
026: private static final Log _logger = LogFactory
027: .getLog(ToolInvocation.class);
028: private static final String NULL_METADATA = "null meta-data";
029: private static final String NULL_AGENT = "null agent";
030: private static final String ILLEGAL_STATUS = "illegal status";
031: public static final int META_DATA = 0x1;
032: public static final int TOOL_AGENT = 0x2;
033: public final String procInstId;
034: public final String workItemName;
035: public final String workItemId;
036: public final String toolId;
037: public final int toolIndex;
038: public final ToolAgentMetaData metaData;
039: public final ToolType toolType;
040: public final ToolAgent agent;
041: public final Parameter[] parameters;
042: public final String description;
043: public Exception exception;
044:
045: public ToolInvocation(String procInstId, String workItemName,
046: String workItemId, String toolId, int toolIndex,
047: ToolAgentMetaData metaData, ToolType toolType,
048: ToolAgent agent, Parameter[] parameters, String description) {
049:
050: this .procInstId = procInstId;
051: this .workItemName = workItemName;
052: this .workItemId = workItemId;
053: this .toolId = toolId;
054: this .toolIndex = toolIndex;
055: this .metaData = metaData;
056: this .agent = agent;
057: this .parameters = parameters;
058: this .toolType = toolType;
059: this .description = description;
060: }
061:
062: /**
063: * Invokes the tool agent, synchronously or asynchronously.
064: *
065: * @param client The client connection to use. This must be valid if called
066: * by a remote client, and must be <code>null</code> when called internally
067: * by the workflow engine to invoke a procedure.
068: * @param sync <code>true</code> to invoke the tool synchronously.
069: */
070: public void invokeTool(final WMClient client, boolean sync) {
071: if (agent == null)
072: throw new IllegalStateException(NULL_AGENT);
073: if (agent.requestAppStatus() != ToolAgent.WAITING)
074: throw new IllegalStateException(ILLEGAL_STATUS);
075:
076: Runnable runner = new Runnable() {
077: public void run() {
078: int retCode = ToolAgent.EXIT_CANCEL;
079: try {
080: // Inform the workflow engine that the tool is starting.
081: if (client != null)
082: client.toolStarted(procInstId, workItemId);
083:
084: // Invoke the tool.
085: retCode = agent
086: .invokeApplication(ToolInvocation.this );
087: } catch (Exception e) {
088: exception = e;
089: _logger.error("Error starting tool: " + toolId, e);
090: } finally {
091: try {
092: // Inform the workflow engine that the tool has finished.
093: if (client != null) {
094: client
095: .toolFinished(
096: procInstId,
097: workItemId,
098: agent.requestAppStatus(),
099: retCode == ToolAgent.EXIT_NORMAL ? parameters
100: : null);
101: }
102: } catch (WMWorkflowException e) {
103: _logger.error("Error from workflow engine", e);
104: }
105: }
106: }
107: };
108: // Invoke the tool either on this thread or another, depending on
109: // execution mode.
110: if (sync)
111: runner.run();
112: else {
113: String name = "ToolAgent[id=" + metaData.getId()
114: + ", workItemId=" + workItemId + ']';
115: new Thread(runner, name).start();
116: }
117: }
118:
119: /**
120: * Renders the JavaScript necessary to invoke the tool from an HTML browser.
121: * The implementation optionally calls {@link WMClient#toolStarted} to
122: * signal to the workflow engine that tool execution has begun.
123: *
124: * @param client The client connection to use.
125: * @param writer The writer to which the JavaScript should be written.
126: * @throws IOException If a problem occurred when writing the JavaScript.
127: * @throws WMWorkflowException If a problem occurred when calling the client.
128: */
129: public void renderInvocationScript(WMClient client, Writer writer)
130: throws IOException, WMWorkflowException {
131:
132: if (metaData == null)
133: throw new IllegalStateException(NULL_METADATA);
134: if (agent == null)
135: throw new IllegalStateException(NULL_AGENT);
136:
137: // Inform the workflow engine that the tool is starting.
138: if (client != null)
139: client.toolStarted(procInstId, workItemId);
140:
141: // Render the JavaScript.
142: agent.renderInvocationScript(this , writer);
143: }
144:
145: public int requestAppStatus() {
146: if (agent == null)
147: throw new IllegalStateException(NULL_AGENT);
148: return agent.requestAppStatus();
149: }
150:
151: public void terminateApp() {
152: if (agent == null)
153: throw new IllegalStateException(NULL_AGENT);
154: agent.terminateApp();
155: }
156: }
|