001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: ProcBasedImpl.java,v 1.6 2007/05/03 21:58:18 mlipp Exp $
021: *
022: * $Log: ProcBasedImpl.java,v $
023: * Revision 1.6 2007/05/03 21:58:18 mlipp
024: * Internal refactoring for making better use of local EJBs.
025: *
026: */
027: package de.danet.an.workflow.domain;
028:
029: import java.util.ArrayList;
030: import java.util.List;
031: import java.util.Map;
032:
033: import org.xml.sax.Attributes;
034: import org.xml.sax.SAXException;
035:
036: import de.danet.an.util.sax.StackedHandler;
037:
038: import de.danet.an.workflow.internalapi.ExtActivityLocal;
039: import de.danet.an.workflow.internalapi.ExtProcessLocal;
040: import de.danet.an.workflow.localapi.ActivityLocal;
041: import de.danet.an.workflow.localapi.ProcessLocal;
042: import de.danet.an.workflow.localapi.ProcessDefinitionDirectoryLocal;
043: import de.danet.an.workflow.localcoreapi.WfProcessLocal;
044: import de.danet.an.workflow.omgcore.AlreadyRunningException;
045: import de.danet.an.workflow.omgcore.CannotCompleteException;
046: import de.danet.an.workflow.omgcore.CannotStartException;
047: import de.danet.an.workflow.omgcore.CannotStopException;
048: import de.danet.an.workflow.omgcore.InvalidDataException;
049: import de.danet.an.workflow.omgcore.InvalidRequesterException;
050: import de.danet.an.workflow.omgcore.NotEnabledException;
051: import de.danet.an.workflow.omgcore.NotRunningException;
052: import de.danet.an.workflow.omgcore.ProcessData;
053: import de.danet.an.workflow.omgcore.RequesterRequiredException;
054: import de.danet.an.workflow.omgcore.UpdateNotAllowedException;
055: import de.danet.an.workflow.omgcore.WfRequester;
056:
057: import de.danet.an.workflow.api.DefaultProcessData;
058: import de.danet.an.workflow.api.FormalParameter;
059: import de.danet.an.workflow.api.InvalidKeyException;
060: import de.danet.an.workflow.api.ProcessDefinition;
061: import de.danet.an.workflow.api.Activity.SubFlowImplementation;
062:
063: /**
064: * This class represents a sub-process based activity implementation,
065: * i.e. it implements {@link
066: * de.danet.an.workflow.localapi.ActivityLocal.SubFlowImplementation
067: * <code>SubFlowImplementation</code>}.
068: *
069: * @author <a href="mailto:mnl@mnl.de">Michael N. Lipp</a>
070: * @version $Revision: 1.6 $
071: */
072: public final class ProcBasedImpl extends ActImplBase implements
073: SubFlowImplementation {
074:
075: /** Unique id. */
076: static final long serialVersionUID = 5223962486120295143L;
077:
078: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
079: .getLog(ProcBasedImpl.class);
080:
081: private String packageId;
082: private String processId;
083: private int execMode = SYNCHR;
084:
085: /** The actual parameters. */
086: private Object[] actualParams = null;
087:
088: private String startedProcess = null;
089:
090: /**
091: * Creates an instance of <code>ProcBasedImpl</code>
092: * with all attributes initialized to default values.
093: */
094: private ProcBasedImpl() {
095: }
096:
097: /* Comment copied from interface. */
098: public String packageId() {
099: return packageId;
100: }
101:
102: /* Comment copied from interface. */
103: public String processId() {
104: return processId;
105: }
106:
107: /* Comment copied from interface. */
108: public String processKey() {
109: return startedProcess;
110: }
111:
112: /**
113: * The key is not persisted persisted here. Rather it is part of the
114: * persistent state of the invoking activity and restored when the
115: * implementation is retrieved.
116: */
117: public void setProcessKey(String key) {
118: startedProcess = key;
119: }
120:
121: /**
122: * Return the actual parameters.
123: * @return actualParameters.
124: */
125: public Object[] actualParameters() {
126: return actualParams;
127: }
128:
129: /* Comment copied from interface. */
130: public int execution() {
131: return execMode;
132: }
133:
134: /**
135: * Triggers the execution of a subprocess for the given activity.
136: * @param act the activity
137: */
138: public void invoke(ExtActivityLocal act) {
139: try {
140: try {
141: ExtProcessLocal process = (ExtProcessLocal) act
142: .containerLocal();
143: ProcessDefinitionDirectoryLocal pdd = (ProcessDefinitionDirectoryLocal) process
144: .processDefinitionDirectoryLocal();
145: WfRequester req = new SubProcRequester(act, execMode);
146: ProcessData pd = new DefaultProcessData(parameterMap(
147: process, act, pdd));
148: WfProcessLocal p = pdd.createProcessLocal(packageId(),
149: processId(), req);
150: p.setProcessContext(pd);
151: p.start();
152: startedProcess = p.key();
153: if (execMode == ASYNCHR) {
154: act.complete();
155: }
156: } catch (InvalidDataException e) {
157: act.terminate();
158: } catch (UpdateNotAllowedException e) {
159: act.terminate();
160: } catch (AlreadyRunningException e) {
161: act.terminate();
162: } catch (CannotStartException e) {
163: act.terminate();
164: } catch (NotEnabledException e) {
165: act.terminate();
166: } catch (InvalidKeyException e) {
167: act.terminate();
168: } catch (InvalidRequesterException e) {
169: act.terminate();
170: } catch (RequesterRequiredException e) {
171: act.terminate();
172: } catch (CannotCompleteException e) {
173: act.terminate();
174: }
175: return;
176: } catch (NotRunningException e) {
177: // cannot happen
178: logger.error(e.getMessage(), e);
179: } catch (CannotStopException e) {
180: // cannot happen
181: logger.error(e.getMessage(), e);
182: }
183: }
184:
185: /**
186: * Create the parameter map for sub-process based on the
187: * activity's context, the formal parameters of the sub-process
188: * and the values of the actual parameters.<P>
189: *
190: * Note that all parameters could be derived from the activity.
191: * This method is intended to be used in cases where the additional
192: * parameters are available anyway.
193: *
194: * @param process the containing process
195: * @param act the activity to which this tool implementation description
196: * is to be applied
197: * @param pdd the process definition directory
198: * @return the parameter map
199: */
200: public Map parameterMap(ExtProcessLocal process, ActivityLocal act,
201: ProcessDefinitionDirectoryLocal pdd) {
202: try {
203: ProcessDefinition pd = pdd.lookupProcessDefinition(
204: packageId(), processId());
205: FormalParameter[] fps = pd.formalParameters();
206: return parameterMap(process, act, fps);
207: } catch (InvalidKeyException e) {
208: // cannot happen since procdef is initially verified
209: logger.error(e.getMessage(), e);
210: throw new IllegalStateException(e.getMessage());
211: }
212: }
213:
214: /**
215: * Merge the result returned by an implementation into the process
216: * data. The names of the result data items must be formal parameter
217: * names which are mapped to process data items as defined by the
218: * actual parameters.
219: *
220: * @param act the activity related with the implementation invocation.
221: * @param result the result data.
222: * @throws InvalidDataException if the entries in the result do not
223: * match formal parameter names or excessive entries exist.
224: */
225: public void mergeResult(ActivityLocal act, Map result)
226: throws InvalidDataException {
227: if (!(result instanceof ProcessDataWithParams)) {
228: throw new InvalidDataException("Need ProcDataWithParams");
229: }
230: ProcessLocal process = (ProcessLocal) act.containerLocal();
231: FormalParameter[] fps = ((ProcessDataWithParams) result)
232: .formalParameters();
233: mergeResult(process, fps, result);
234: }
235:
236: /**
237: * Return a string representation of this object.
238: * @return the representation
239: */
240: public String toString() {
241: return "Process[" + packageId() + "/" + processId() + "]";
242: }
243:
244: /**
245: * Helper class for retrieving the tool based implementation from
246: * the process definition.
247: */
248: public class SAXInitializer extends StackedHandler {
249:
250: private List apList = new ArrayList();
251:
252: /**
253: * Receive notification of the beginning of an element.
254: *
255: * @param uri the Namespace URI, or the empty string if the
256: * element has no Namespace URI or if Namespace processing is not
257: * being performed.
258: * @param loc the local name (without prefix), or the empty string
259: * if Namespace processing is not being performed.
260: * @param raw the raw XML 1.0 name (with prefix), or the empty
261: * string if raw names are not available.
262: * @param a the attributes attached to the element. If there are
263: * no attributes, it shall be an empty Attributes object.
264: * @throws SAXException not thrown.
265: */
266: public void startElement(String uri, String loc, String raw,
267: Attributes a) throws SAXException {
268: if (loc.equals("SubFlow")) {
269: setContextData("implementation", ProcBasedImpl.this );
270: packageId = (String) getContextData("packageId");
271: processId = a.getValue("Id");
272: if (logger.isDebugEnabled()) {
273: logger.debug("Creating sub flow invocation for: "
274: + packageId + "/" + processId);
275: }
276: String em = a.getValue("Execution");
277: if (em != null && em.equals("ASYNCHR")) {
278: execMode = ASYNCHR;
279: }
280: }
281: }
282:
283: /**
284: * Receive notification of the end of an element.
285: *
286: * @param uri the Namespace URI, or the empty string if the
287: * element has no Namespace URI or if Namespace processing is not
288: * being performed.
289: * @param loc the local name (without prefix), or the empty string
290: * if Namespace processing is not being performed.
291: * @param raw the raw XML 1.0 name (with prefix), or the empty
292: * string if raw names are not available.
293: * @throws SAXException not thrown.
294: */
295: public void endElement(String uri, String loc, String raw)
296: throws SAXException {
297: if (loc.equals("ActualParameter")) {
298: apList.add(text().trim());
299: } else if (loc.equals("SubFlow")) {
300: actualParams = (String[]) apList
301: .toArray(new String[apList.size()]);
302: }
303: }
304: }
305:
306: /**
307: * Return a handler that can be used to initialize an object
308: * from SAX events. The instance created is returned in the
309: * HandlerStack's context data as "implementation".
310: * @return the handler.
311: */
312: public static StackedHandler saxConstructor() {
313: return (new ProcBasedImpl()).newSaxInitializer();
314: }
315:
316: private StackedHandler newSaxInitializer() {
317: return new SAXInitializer();
318: }
319: }
|