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: ApplicationDefinition.java,v 1.11 2007/05/03 21:58:16 mlipp Exp $
021: *
022: * $Log: ApplicationDefinition.java,v $
023: * Revision 1.11 2007/05/03 21:58:16 mlipp
024: * Internal refactoring for making better use of local EJBs.
025: *
026: * Revision 1.10 2007/02/27 14:34:12 drmlipp
027: * Some refactoring to reduce cyclic dependencies.
028: *
029: * Revision 1.9 2006/10/13 13:59:58 drmlipp
030: * Fixed NullPointerException.
031: *
032: * Revision 1.8 2006/10/13 11:39:46 drmlipp
033: * Added new attribute suspendActivity to exception mapping
034: * and ExceptionResultProvider.
035: *
036: * Revision 1.7 2006/09/29 12:32:08 drmlipp
037: * Consistently using WfMOpen as projct name now.
038: *
039: * Revision 1.6 2006/03/08 14:46:43 drmlipp
040: * Synchronized with 1.3.3p5.
041: *
042: * Revision 1.5 2005/09/05 09:41:48 drmlipp
043: * Synchronized with 1.3.2.
044: *
045: * Revision 1.4 2005/08/25 13:24:22 drmlipp
046: * Synchronized with 1.3.1p6.
047: *
048: * Revision 1.3 2005/04/22 15:11:01 drmlipp
049: * Merged changes from 1.3 branch up to 1.3p15.
050: *
051: * Revision 1.1.1.4.6.2 2005/04/11 14:29:51 drmlipp
052: * Fixed race-condition.
053: *
054: * Revision 1.2 2005/02/04 14:25:26 drmlipp
055: * Synchronized with 1.3rc2.
056: *
057: * Revision 1.1.1.4.6.1 2005/02/03 13:02:45 drmlipp
058: * Moved warning about indexed formal parameters to process definition
059: * import.
060: *
061: * Revision 1.1.1.4 2004/08/18 15:17:38 drmlipp
062: * Update to 1.2
063: *
064: * Revision 1.74 2004/07/02 09:03:34 lipp
065: * Removed unused import.
066: *
067: * Revision 1.73 2004/06/28 10:58:26 lipp
068: * Clarified SAX buffer type usage.
069: *
070: * Revision 1.72 2004/04/13 14:31:41 lipp
071: * Added DirectInvocable support as XPDL extension.
072: *
073: * Revision 1.71 2004/04/12 19:33:52 lipp
074: * Clarified application invocation interface.
075: *
076: * Revision 1.70 2004/04/01 09:32:07 lipp
077: * Improved tool agent context implementtaion.
078: *
079: * Revision 1.69 2004/03/31 19:36:20 lipp
080: * Completed implementation of Activity.abandon(String).
081: *
082: * Revision 1.67 2004/03/29 11:45:24 lipp
083: * Made engine context available to tool agents.
084: *
085: * Revision 1.66 2004/02/19 13:10:32 lipp
086: * Clarified start-/endDocument usage in SAXEventBuffers.
087: *
088: * Revision 1.65 2003/12/08 14:08:13 lipp
089: * Execute tool termination in own transaction.
090: *
091: * Revision 1.64 2003/11/26 16:14:14 lipp
092: * Added possibility to declare tool as ResultProvider.
093: *
094: * Revision 1.63 2003/10/05 15:34:33 lipp
095: * Added tool provided execution mode.
096: *
097: * Revision 1.62 2003/07/11 14:06:33 montag
098: * if value is instance of SAXEventBufferImpl,
099: * first try to call the setter with type SAXEventBuffer.
100: *
101: * Revision 1.61 2003/07/10 14:41:33 montag
102: * Allow the parameter type of the setter to be of type
103: * SAXEventBuffer.
104: *
105: * Revision 1.60 2003/06/27 08:51:45 lipp
106: * Fixed copyright/license information.
107: *
108: * Revision 1.59 2003/06/18 15:44:53 lipp
109: * Support setting of XML argument type by tool.
110: *
111: * Revision 1.58 2003/06/17 15:47:26 lipp
112: * Prepared XML argument type control be tool implementation.
113: *
114: * Revision 1.57 2003/06/10 14:44:20 huaiyang
115: * use SAXEvent to generate DocumentFragment.
116: *
117: * Revision 1.56 2003/06/03 16:38:56 lipp
118: * Updated to jdom b9.
119: *
120: * Revision 1.55 2003/05/15 07:46:42 lipp
121: * Proper handling of JavaScript default double result.
122: *
123: * Revision 1.54 2003/05/06 13:21:30 lipp
124: * Resolved cyclic dependency.
125: *
126: * Revision 1.53 2003/05/02 08:21:54 lipp
127: * Some fixes handling tool properties specified by subtrees.
128: *
129: * Revision 1.52 2003/04/24 19:47:50 lipp
130: * Removed dependency between general util and workflow api.
131: *
132: * Revision 1.51 2003/04/24 19:25:26 lipp
133: * Storing XML properties as buffered SAX events.
134: *
135: * Revision 1.50 2003/04/24 15:08:14 lipp
136: * Reading ApplicationDefinitiosn from SAX now.
137: *
138: * Revision 1.49 2003/04/03 11:44:06 lipp
139: * Support for W3C DOM arguments.
140: *
141: * Revision 1.48 2003/03/31 16:50:28 huaiyang
142: * Logging using common-logging.
143: *
144: * Revision 1.47 2003/03/28 12:44:08 lipp
145: * Moved XPDL related constants to XPDLUtil.
146: *
147: * Revision 1.46 2003/03/28 11:58:18 huaiyang
148: * refactory the code in invoking method.
149: *
150: * Revision 1.45 2003/03/27 16:43:26 huaiyang
151: * support JDOM and DOM as param for set method.
152: *
153: * Revision 1.44 2003/03/27 13:51:37 huaiyang
154: * use JDOMSerializationWrapper to wrap JDOM element.
155: *
156: * Revision 1.43 2003/02/12 11:57:30 lipp
157: * Improved deadlock (RemoteException) handling for tools. Imroved debug
158: * information.
159: *
160: * Revision 1.42 2002/12/19 21:37:43 lipp
161: * Reorganized interfaces.
162: *
163: * Revision 1.41 2002/11/26 15:06:15 lipp
164: * Improved exception handling.
165: *
166: * Revision 1.40 2002/11/05 12:24:53 lipp
167: * Simplified access to agent.
168: *
169: * Revision 1.39 2002/10/25 14:29:41 lipp
170: * Detach interesting part of DOM tree from rest.
171: *
172: * Revision 1.38 2002/10/25 09:20:23 lipp
173: * Allow applications definition without tool agent.
174: *
175: * Revision 1.37 2002/10/24 14:25:11 lipp
176: * Added form attribute to submitter.
177: *
178: * Revision 1.36 2002/10/06 20:14:38 lipp
179: * Updated argument handling.
180: *
181: * Revision 1.35 2002/10/02 10:58:13 lipp
182: * Modifications for tool invocation.
183: *
184: * Revision 1.34 2002/09/27 15:20:53 lipp
185: * Get properties verbatim.
186: *
187: * Revision 1.33 2002/09/27 11:26:44 huaiyang
188: * Use FormalParameter.mode.fromString to construct mode object.
189: *
190: * Revision 1.32 2002/09/26 20:03:36 lipp
191: * Reorganized tool invocation.
192: *
193: * Revision 1.31 2002/09/26 15:07:37 lipp
194: * Minor fixes.
195: *
196: * Revision 1.30 2002/09/24 15:53:37 lipp
197: * Better error handling.
198: *
199: * Revision 1.29 2002/09/24 07:41:30 lipp
200: * Improved error message.
201: *
202: * Revision 1.28 2002/09/23 20:31:28 lipp
203: * Implemented async/sync invocation.
204: *
205: * Revision 1.27 2002/09/23 10:23:26 lipp
206: * Lazy instantiation of agent.
207: *
208: * Revision 1.26 2002/09/23 09:33:03 huaiyang
209: * Add formal parameter in application def.
210: *
211: * Revision 1.25 2002/09/19 20:09:26 lipp
212: * Removed methods from Application interface and reorganized
213: * asynchronous tool invocation.
214: *
215: * Revision 1.24 2002/09/19 11:21:06 huaiyang
216: * New style in defining extended attribute of application.
217: *
218: * Revision 1.23 2002/09/18 09:53:34 lipp
219: * Moved access to application data to process definition.
220: *
221: * Revision 1.22 2002/09/17 15:24:24 lipp
222: * Renamed Tool to Application and copied some functionality to
223: * ProcessDefintion.
224: *
225: * Revision 1.21 2002/09/17 13:53:14 huaiyang
226: * Invoke method using params from xpdl.
227: *
228: * Revision 1.20 2002/09/17 09:20:12 lipp
229: * Added ApplicationNotStoppedException.
230: *
231: * Revision 1.19 2002/09/15 15:13:00 lipp
232: * Moved code for asynchronous application invocation.
233: *
234: * Revision 1.18 2002/09/11 14:17:22 lipp
235: * Execptions using msgs now.
236: *
237: * Revision 1.17 2002/09/11 06:33:32 huaiyang
238: * Remove the variable of prefix.
239: *
240: * Revision 1.16 2002/09/09 13:11:46 huaiyang
241: * Cleanup the unnecessary code for old style process definition.
242: *
243: * Revision 1.15 2002/09/04 08:58:58 huaiyang
244: * Add exception handling in invoke method.
245: *
246: * Revision 1.14 2002/09/03 15:16:29 huaiyang
247: * Move the call of application class in the constructor.
248: *
249: * Revision 1.13 2002/09/03 14:51:54 huaiyang
250: * Remove unneeded code for old style of process definition spec.
251: *
252: * Revision 1.12 2002/08/30 07:58:19 huaiyang
253: * Separation of Domain class and persistent class more cleaner.
254: *
255: * Revision 1.11 2002/08/26 20:23:13 lipp
256: * Lots of method renames.
257: *
258: * Revision 1.10 2002/08/26 14:17:07 lipp
259: * JavaDoc fixes.
260: *
261: * Revision 1.9 2002/08/20 13:46:13 lipp
262: * Using xpath now to extract additional process information from xpdl.
263: *
264: * Revision 1.8 2002/07/24 08:04:42 huaiyang
265: * doccheck.
266: *
267: * Revision 1.7 2002/05/21 13:27:37 huaiyang
268: * New method of terminate.
269: *
270: * Revision 1.6 2002/05/17 12:52:34 lipp
271: * Cleaned up interface to tools.
272: *
273: * Revision 1.5 2002/05/17 08:34:21 lipp
274: * Renamed aii/Application to aii/ToolAgent.
275: *
276: * Revision 1.4 2002/05/16 19:47:48 lipp
277: * Proper usage of constructingSAXHandler.
278: *
279: * Revision 1.3 2002/02/06 18:27:44 huaiyang
280: * Add the check of application class name.
281: *
282: * Revision 1.2 2002/02/04 16:08:15 huaiyang
283: * Modified the method of runApplication.
284: *
285: * Revision 1.1 2002/01/31 15:45:08 huaiyang
286: * Initial version of the application definition.
287: *
288: *
289: */
290: package de.danet.an.workflow.domain;
291:
292: import java.io.Serializable;
293:
294: import java.rmi.RemoteException;
295: import java.util.ArrayList;
296: import java.util.HashMap;
297: import java.util.Iterator;
298: import java.util.List;
299: import java.util.Map;
300:
301: import java.lang.reflect.InvocationTargetException;
302: import java.lang.reflect.Method;
303:
304: import javax.xml.transform.TransformerConfigurationException;
305: import javax.xml.transform.TransformerFactory;
306: import javax.xml.transform.dom.DOMResult;
307: import javax.xml.transform.sax.SAXTransformerFactory;
308: import javax.xml.transform.sax.TransformerHandler;
309:
310: import org.jdom.Element;
311: import org.jdom.input.SAXHandler;
312: import org.jdom.output.DOMOutputter;
313: import org.xml.sax.Attributes;
314: import org.xml.sax.ContentHandler;
315: import org.xml.sax.SAXException;
316: import org.xml.sax.helpers.AttributesImpl;
317:
318: import de.danet.an.util.sax.BodyFilter;
319: import de.danet.an.util.sax.StackedHandler;
320:
321: import de.danet.an.workflow.util.SAXEventBufferImpl;
322: import de.danet.an.workflow.util.XPDLUtil;
323:
324: import de.danet.an.workflow.api.FormalParameter;
325: import de.danet.an.workflow.api.SAXEventBuffer;
326:
327: import de.danet.an.workflow.internalapi.ExtApplication;
328: import de.danet.an.workflow.internalapi.ToolInvocationException;
329: import de.danet.an.workflow.localapi.ActivityLocal;
330: import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
331: import de.danet.an.workflow.spis.aii.CannotExecuteException;
332: import de.danet.an.workflow.spis.aii.ContextRequester;
333: import de.danet.an.workflow.spis.aii.ExceptionMappingProvider;
334: import de.danet.an.workflow.spis.aii.ResultProvider;
335: import de.danet.an.workflow.spis.aii.ExceptionMappingProvider.ExceptionMapping;
336: import de.danet.an.workflow.spis.aii.ResultProvider.ExceptionResult;
337: import de.danet.an.workflow.spis.aii.ToolAgent;
338: import de.danet.an.workflow.spis.aii.ToolAgentContext;
339: import de.danet.an.workflow.spis.aii.XMLArgumentTypeProvider;
340: import de.danet.an.workflow.tools.util.DirectInvocable;
341:
342: /**
343: * This class defines the application.
344: */
345: public class ApplicationDefinition implements ExtApplication,
346: Serializable {
347:
348: /**
349: * logger of this class.
350: */
351: static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
352: .getLog(ApplicationDefinition.class);
353:
354: private static final String XMLNS = "http://www.w3.org/2000/xmlns/";
355:
356: /** Id of the application. */
357: private String id;
358:
359: /** Description of the application. */
360: private String description = null;
361:
362: /** Agent implementing class. */
363: private String agentClassName = null;
364:
365: /** Direct invocable? */
366: private boolean directInvocableAttr = false;
367:
368: /** Convert parameters? */
369: private int xmlParameterMode = XMLArgumentTypeProvider.XML_AS_W3C_DOM;
370:
371: /** Exception mappings? */
372: private List exceptionMappings = null;
373:
374: /** Agent configuration. */
375: private Map agentProps = new HashMap();
376:
377: /** Formal parameters of this application. */
378: private FormalParameter[] formalParameters = new FormalParameter[] {};
379:
380: /** Tool agent for this application. Tool agents are not serializable. */
381: private transient ToolAgent agentCache = null;
382:
383: /**
384: * Creates a new <code>ApplicationDefinition</code>.
385: */
386: public ApplicationDefinition() {
387: }
388:
389: /**
390: * Construct agent instance.
391: * @return agent instance
392: */
393: private ToolAgent agent() {
394: if (agentCache != null) {
395: return agentCache;
396: }
397: try {
398: ClassLoader cl = Thread.currentThread()
399: .getContextClassLoader();
400: Class appClass = cl.loadClass(agentClassName);
401: // initialize agent before putting it in cache as we do
402: // not synchronize here (and creating the agent twice
403: // doesn't really hurt)
404: ToolAgent agent = (ToolAgent) appClass.newInstance();
405: // set properties
406: for (Iterator itr = agentProps.keySet().iterator(); itr
407: .hasNext();) {
408: String param = (String) itr.next();
409: Object value = agentProps.get(param);
410: Method method = null;
411: Object[] args = new Object[] { value };
412: if (value instanceof SAXEventBufferImpl) {
413: // check for setter with type SAXEventBuffer
414: try {
415: Class[] argTypes = { SAXEventBuffer.class };
416: method = appClass.getMethod("set" + param,
417: argTypes);
418: } catch (NoSuchMethodException e) {
419: // method is null
420: }
421: }
422: if (method == null) {
423: try {
424: Class[] argTypes = { value.getClass() };
425: method = appClass.getMethod("set" + param,
426: argTypes);
427: } catch (NoSuchMethodException e) {
428: if (!(value instanceof SAXEventBufferImpl)) {
429: throw e;
430: }
431: // if value is XML, try converting to JDOM
432: try {
433: Class[] argTypes = { Element.class };
434: method = appClass.getMethod("set" + param,
435: argTypes);
436: SAXHandler sh = new SAXHandler();
437: ((SAXEventBufferImpl) value).emit(sh, sh);
438: args[0] = sh.getDocument().getRootElement();
439: } catch (NoSuchMethodException eee) {
440: // finally try converting to W3C DOM
441: Class[] argTypes = { org.w3c.dom.Element.class };
442: method = appClass.getMethod("set" + param,
443: argTypes);
444: TransformerHandler th = newTransformerHandler();
445: DOMResult out = new DOMResult();
446: th.setResult(out);
447: ((SAXEventBufferImpl) value).emit(th, th);
448: args[0] = out.getNode();
449: if (args[0] instanceof org.w3c.dom.Document) {
450: args[0] = ((org.w3c.dom.Document) args[0])
451: .getDocumentElement();
452: }
453: }
454: }
455: }
456: method.invoke(agent, args);
457: }
458: // agent may override XML parameter type setting
459: if (agent instanceof XMLArgumentTypeProvider) {
460: xmlParameterMode = ((XMLArgumentTypeProvider) agent)
461: .requestedXMLArgumentType();
462: }
463: // update exception mappings
464: if (agent instanceof ExceptionMappingProvider) {
465: if (exceptionMappings == null) {
466: exceptionMappings = new ArrayList();
467: }
468: // appending the mapping from the tool ensures that they
469: // have lower precedence
470: exceptionMappings
471: .addAll(((ExceptionMappingProvider) agent)
472: .exceptionMappings());
473: }
474: // save created agent
475: agentCache = agent;
476: } catch (ClassNotFoundException clnf) {
477: logger.error(clnf.getMessage(), clnf);
478: throw new IllegalStateException(
479: "Cannot find application class " + agentClassName
480: + " from ApplicationDefinition with Id = "
481: + id + ".");
482: } catch (IllegalAccessException ia) {
483: logger.error(ia.getMessage(), ia);
484: throw new IllegalStateException(
485: "Cannot access application class " + agentClassName
486: + " from ApplicationDefinition with Id = "
487: + id + ".");
488: } catch (InstantiationException ie) {
489: logger.error(ie.getMessage(), ie);
490: throw new IllegalStateException(
491: "Cannot instantiate application class "
492: + agentClassName
493: + " from ApplicationDefinition with Id = "
494: + id + ".");
495: } catch (NoSuchMethodException nsme) {
496: logger.error(nsme.getMessage(), nsme);
497: throw new IllegalStateException(nsme.getMessage());
498: } catch (InvocationTargetException ite) {
499: logger.error(ite.getMessage(), ite);
500: throw new IllegalArgumentException(ite.getMessage());
501: } catch (TransformerConfigurationException je) {
502: logger.error(je.getMessage(), je);
503: throw new IllegalArgumentException(je.getMessage());
504: } catch (SAXException je) {
505: logger.error(je.getMessage(), je);
506: throw new IllegalArgumentException(je.getMessage());
507: }
508: return agentCache;
509: }
510:
511: /**
512: * Return an array of the object of <code>FormalParameter</code>.
513: *
514: * @return an array of <code>FormalParameter</code> defined in this
515: * application. If no formal parameter is defined in this application, it
516: * returns an empty array.
517: */
518: public FormalParameter[] formalParameters() {
519: return formalParameters;
520: }
521:
522: /**
523: * Return id of this application definition.
524: * @return id of this application definition.
525: */
526: public String id() {
527: return id;
528: }
529:
530: /**
531: * Return description of this application definition.
532: * @return description of this application definition.
533: */
534: public String description() {
535: return description;
536: }
537:
538: /**
539: * Invokes the application for the specific activity.
540: *
541: * @param activity the activity to be executed
542: * @param params the invocation parameters
543: * @param agentContext the context to pass to the tool agent
544: * @return the invocation result if the tool agent provides one
545: * (i.e. implements <code>ResultProvider</code>), else <code>null</code>
546: * @throws ToolInvocationException if execution is not possible
547: * @throws RemoteException if a temporary problem occurs and we
548: * should retry the tool invocation. (Usually thrown when a
549: * deadlock situation occurs while accessing the activity.)
550: */
551: public InvocationResult invoke(ToolAgentContext agentContext,
552: de.danet.an.workflow.api.Activity activity, Map params)
553: throws ToolInvocationException, RemoteException {
554: ToolAgent agent = agent();
555: if (agent == null) {
556: return null;
557: }
558: // maybe convert DOM trees
559: if (xmlParameterMode == XMLArgumentTypeProvider.XML_AS_W3C_DOM) {
560: DOMOutputter domOutputter = new DOMOutputter();
561: for (Iterator i = params.keySet().iterator(); i.hasNext();) {
562: String pn = (String) i.next();
563: Object v = params.get(pn);
564: if (v instanceof SAXEventBuffer) {
565: try {
566: DOMResult domResult = new DOMResult();
567: TransformerHandler th = newTransformerHandler();
568: th.setResult(domResult);
569: convertWithTempRoot(th, (SAXEventBuffer) v);
570: org.w3c.dom.Document w3cDoc = (org.w3c.dom.Document) domResult
571: .getNode();
572: org.w3c.dom.DocumentFragment frag = w3cDoc
573: .createDocumentFragment();
574: org.w3c.dom.Element w3cTempRoot = w3cDoc
575: .getDocumentElement();
576: while (true) {
577: org.w3c.dom.Node n = w3cTempRoot
578: .getFirstChild();
579: if (n == null) {
580: break;
581: }
582: frag.appendChild(n);
583: }
584: params.put(pn, frag);
585: } catch (SAXException e) {
586: String m = "Cannot convert JDOM to W3C DOM: "
587: + e.getMessage();
588: logger.error(m, e);
589: throw new ToolInvocationException(m);
590: } catch (TransformerConfigurationException e) {
591: String m = "Cannot convert JDOM to W3C DOM: "
592: + e.getMessage();
593: logger.error(m, e);
594: throw new ToolInvocationException(m);
595: }
596: }
597: }
598: } else if (xmlParameterMode == XMLArgumentTypeProvider.XML_AS_JDOM) {
599: for (Iterator i = params.keySet().iterator(); i.hasNext();) {
600: String pn = (String) i.next();
601: Object v = params.get(pn);
602: if (v instanceof SAXEventBuffer) {
603: try {
604: SAXHandler sh = new SAXHandler();
605: convertWithTempRoot(sh, (SAXEventBuffer) v);
606: Element temporaryRoot = sh.getDocument()
607: .getRootElement();
608: params.put(pn, temporaryRoot.getChildren());
609: } catch (SAXException e) {
610: logger.error(e.getMessage(), e);
611: throw new ToolInvocationException(e
612: .getMessage());
613: }
614: }
615: }
616: }
617: // invoke
618: if (agent instanceof ContextRequester) {
619: ((ContextRequester) agent)
620: .setToolAgentContext(agentContext);
621: }
622: try {
623: agent.invoke(activity, formalParameters, params);
624: } catch (CannotExecuteException e) {
625: // try to find mapping
626: if (e.getCause() != null && exceptionMappings != null) {
627: for (Iterator i = exceptionMappings.iterator(); i
628: .hasNext();) {
629: ExceptionMapping m = (ExceptionMapping) i.next();
630: if (m.getJavaException().isInstance(e.getCause())) {
631: if (m.getProcessException() == null) {
632: break;
633: }
634: return new InvocationResult(
635: new ResultProvider.ExceptionResult(m
636: .getProcessException(), m
637: .getSuspendActivity()));
638: }
639: }
640: }
641: throw new ToolInvocationException(
642: "Cannot invoke tool, tool reports: "
643: + e.getMessage(), e);
644: }
645: // maybe get result
646: if (agent instanceof ResultProvider) {
647: Object res = ((ResultProvider) agent).result();
648: if (res != null && !(res instanceof Map)
649: && !(res instanceof ExceptionResult)) {
650: throw new ToolInvocationException(toString()
651: + " returns result that is neither"
652: + " Map nor ExceptionResult");
653: }
654: return new InvocationResult(res);
655: }
656: return null;
657: }
658:
659: // emits the SAX events in the given SAXContentBuffer in the content
660: // handler.
661: private void convertWithTempRoot(ContentHandler ch,
662: SAXEventBuffer cb) throws SAXException {
663: ch.startDocument();
664: ch.startElement("", "temporary-root", "temporary-root",
665: new AttributesImpl());
666: cb.emit(new BodyFilter(ch));
667: ch.endElement("", "temporary-root", "temporary-root");
668: ch.endDocument();
669: }
670:
671: /**
672: * Terminates the application for the specific activity.
673: *
674: * @param activity the activity to be terminated
675: * @throws ApplicationNotStoppedException if the application can not be
676: * terminated.
677: * @throws RemoteException if a temporary problem occurs and we
678: * should retry the tool invocation (usually thrown when a
679: * deadlock situation occurs while accessing the activity)
680: */
681: public void terminate(de.danet.an.workflow.api.Activity activity)
682: throws ApplicationNotStoppedException, RemoteException {
683: agent().terminate(activity);
684: }
685:
686: /* Comment copied from interface. */
687: public boolean isDirectInvocable() {
688: return (agent() instanceof DirectInvocable)
689: || directInvocableAttr;
690: }
691:
692: /**
693: * Provide a representation for debugging purposes.
694: * @return descriptive string.
695: */
696: public String toString() {
697: return "Application[Id=" + id + "]";
698: }
699:
700: /**
701: * Helper class for retrieving the applications from the process
702: * definition.
703: */
704: public class SAXInitializer extends StackedHandler {
705:
706: private List fpList = null;
707: private String fpId = null;
708: private FormalParameter.Mode fpMode = null;
709: private int fpIndex = 0;
710:
711: private String propName = null;
712: private SAXEventBufferImpl propBuffer = null;
713:
714: /**
715: * Receive notification of the beginning of an element.
716: *
717: * @param uri the Namespace URI, or the empty string if the
718: * element has no Namespace URI or if Namespace processing is not
719: * being performed.
720: * @param loc the local name (without prefix), or the empty string
721: * if Namespace processing is not being performed.
722: * @param raw the raw XML 1.0 name (with prefix), or the empty
723: * string if raw names are not available.
724: * @param a the attributes attached to the element. If there are
725: * no attributes, it shall be an empty Attributes object.
726: * @throws SAXException not thrown.
727: */
728: public void startElement(String uri, String loc, String raw,
729: Attributes a) throws SAXException {
730: if (propName != null) {
731: propBuffer = new SAXEventBufferImpl();
732: propBuffer.startDocument();
733: getStack().startAllPrefixMappings(propBuffer);
734: getStack().push(propBuffer);
735: } else if (loc.equals("Application")) {
736: id = a.getValue("Id");
737: } else if (loc.equals("FormalParameters")) {
738: fpList = new ArrayList();
739: } else if (loc.equals("FormalParameter")) {
740: fpId = a.getValue("Id");
741: fpMode = FormalParameter.Mode.fromString(a
742: .getValue("Mode"));
743: } else if (loc.equals("DataType")) {
744: getStack().push(new XPDLUtil.SAXDataTypeHandler());
745: } else if (uri.equals(XPDLUtil.XPDL_EXTN_NS)
746: && loc.equals("ToolAgent")) {
747: agentClassName = a.getValue("Class");
748: if (agentClassName == null
749: || agentClassName.length() == 0) {
750: throw new SAXException(
751: "Tool agent class must be specified in "
752: + "ApplicationDefinition with Id = "
753: + id + ".");
754: }
755: String paramMode = a.getValue("XMLParameterMode");
756: if (paramMode != null) {
757: if (paramMode.equals("USE_JDOM")) {
758: xmlParameterMode = XMLArgumentTypeProvider.XML_AS_JDOM;
759: } else if (paramMode.equals("USE_SAX")) {
760: xmlParameterMode = XMLArgumentTypeProvider.XML_AS_SAX;
761: }
762: }
763: String directInvoc = a.getValue("DirectInvocable");
764: directInvocableAttr = (directInvoc != null && (directInvoc
765: .equals("true") || directInvoc.equals("1")));
766: } else if (uri.equals(XPDLUtil.XPDL_EXTN_NS)
767: && loc.equals("ExceptionMappings")) {
768: exceptionMappings = new ArrayList();
769: } else if (uri.equals(XPDLUtil.XPDL_EXTN_NS)
770: && loc.equals("ExceptionMapping")) {
771: try {
772: Class t = Thread.currentThread()
773: .getContextClassLoader().loadClass(
774: a.getValue("JavaException"));
775: String suspAttr = a.getValue("SuspendActivity");
776: boolean suspAct = (suspAttr != null)
777: && (suspAttr.equals("true") || suspAttr
778: .equals("1"));
779: ExceptionMapping em = new ExceptionMapping(t, a
780: .getValue("ProcessException"), suspAct);
781: exceptionMappings.add(em);
782: } catch (ClassNotFoundException e) {
783: throw new SAXException(e);
784: }
785: } else if (uri.equals(XPDLUtil.XPDL_EXTN_NS)
786: && loc.equals("Property")) {
787: propName = a.getValue("Name");
788: }
789: }
790:
791: /**
792: * Receive notification of the end of an element.
793: *
794: * @param uri the Namespace URI, or the empty string if the
795: * element has no Namespace URI or if Namespace processing is not
796: * being performed.
797: * @param loc the local name (without prefix), or the empty string
798: * if Namespace processing is not being performed.
799: * @param raw the raw XML 1.0 name (with prefix), or the empty
800: * string if raw names are not available.
801: * @throws SAXException not thrown.
802: */
803: public void endElement(String uri, String loc, String raw)
804: throws SAXException {
805: if (loc.equals("Description")) {
806: description = text();
807: } else if (loc.equals("FormalParameter")) {
808: Object dtc = removeContextData("DataType");
809: String index = (new Integer(fpIndex++)).toString();
810: fpList
811: .add(new FormalParameter(fpId, index, fpMode,
812: dtc));
813: } else if (loc.equals("FormalParameters")) {
814: formalParameters = (FormalParameter[]) fpList
815: .toArray(new FormalParameter[fpList.size()]);
816: fpList = null;
817: } else if (uri.equals(XPDLUtil.XPDL_EXTN_NS)
818: && loc.equals("Property")) {
819: if (propBuffer != null) {
820: getStack().endAllPrefixMappings(propBuffer);
821: propBuffer.endDocument();
822: propBuffer.pack();
823: agentProps.put(propName, propBuffer);
824: } else {
825: agentProps.put(propName, text());
826: }
827: propName = null;
828: propBuffer = null;
829: }
830: }
831: }
832:
833: /**
834: * Return a handler that can be used to initialize an object
835: * from SAX events.
836: * @return the handler.
837: */
838: public StackedHandler saxInitializer() {
839: return new SAXInitializer();
840: }
841:
842: private TransformerHandler newTransformerHandler()
843: throws TransformerConfigurationException {
844: TransformerFactory tf = TransformerFactory.newInstance();
845: if (!tf.getFeature(SAXTransformerFactory.FEATURE)) {
846: String s = "JAXP transformer factory does not"
847: + " support a SAX transformer!";
848: logger.fatal(s);
849: throw new IllegalStateException(s);
850: }
851: TransformerHandler th = ((SAXTransformerFactory) tf)
852: .newTransformerHandler();
853: return th;
854: }
855:
856: }
|