/*
* 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: ApplicationDefinition.java 2942 2009-02-18 23:12:12Z mlipp $
*
* $Log$
* Revision 1.10 2007/02/27 14:34:12 drmlipp
* Some refactoring to reduce cyclic dependencies.
*
* Revision 1.9 2006/10/13 13:59:58 drmlipp
* Fixed NullPointerException.
*
* Revision 1.8 2006/10/13 11:39:46 drmlipp
* Added new attribute suspendActivity to exception mapping
* and ExceptionResultProvider.
*
* Revision 1.7 2006/09/29 12:32:08 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.6 2006/03/08 14:46:43 drmlipp
* Synchronized with 1.3.3p5.
*
* Revision 1.5 2005/09/05 09:41:48 drmlipp
* Synchronized with 1.3.2.
*
* Revision 1.4 2005/08/25 13:24:22 drmlipp
* Synchronized with 1.3.1p6.
*
* Revision 1.3 2005/04/22 15:11:01 drmlipp
* Merged changes from 1.3 branch up to 1.3p15.
*
* Revision 1.1.1.4.6.2 2005/04/11 14:29:51 drmlipp
* Fixed race-condition.
*
* Revision 1.2 2005/02/04 14:25:26 drmlipp
* Synchronized with 1.3rc2.
*
* Revision 1.1.1.4.6.1 2005/02/03 13:02:45 drmlipp
* Moved warning about indexed formal parameters to process definition
* import.
*
* Revision 1.1.1.4 2004/08/18 15:17:38 drmlipp
* Update to 1.2
*
* Revision 1.74 2004/07/02 09:03:34 lipp
* Removed unused import.
*
* Revision 1.73 2004/06/28 10:58:26 lipp
* Clarified SAX buffer type usage.
*
* Revision 1.72 2004/04/13 14:31:41 lipp
* Added DirectInvocable support as XPDL extension.
*
* Revision 1.71 2004/04/12 19:33:52 lipp
* Clarified application invocation interface.
*
* Revision 1.70 2004/04/01 09:32:07 lipp
* Improved tool agent context implementtaion.
*
* Revision 1.69 2004/03/31 19:36:20 lipp
* Completed implementation of Activity.abandon(String).
*
* Revision 1.67 2004/03/29 11:45:24 lipp
* Made engine context available to tool agents.
*
* Revision 1.66 2004/02/19 13:10:32 lipp
* Clarified start-/endDocument usage in SAXEventBuffers.
*
* Revision 1.65 2003/12/08 14:08:13 lipp
* Execute tool termination in own transaction.
*
* Revision 1.64 2003/11/26 16:14:14 lipp
* Added possibility to declare tool as ResultProvider.
*
* Revision 1.63 2003/10/05 15:34:33 lipp
* Added tool provided execution mode.
*
* Revision 1.62 2003/07/11 14:06:33 montag
* if value is instance of SAXEventBufferImpl,
* first try to call the setter with type SAXEventBuffer.
*
* Revision 1.61 2003/07/10 14:41:33 montag
* Allow the parameter type of the setter to be of type
* SAXEventBuffer.
*
* Revision 1.60 2003/06/27 08:51:45 lipp
* Fixed copyright/license information.
*
* Revision 1.59 2003/06/18 15:44:53 lipp
* Support setting of XML argument type by tool.
*
* Revision 1.58 2003/06/17 15:47:26 lipp
* Prepared XML argument type control be tool implementation.
*
* Revision 1.57 2003/06/10 14:44:20 huaiyang
* use SAXEvent to generate DocumentFragment.
*
* Revision 1.56 2003/06/03 16:38:56 lipp
* Updated to jdom b9.
*
* Revision 1.55 2003/05/15 07:46:42 lipp
* Proper handling of JavaScript default double result.
*
* Revision 1.54 2003/05/06 13:21:30 lipp
* Resolved cyclic dependency.
*
* Revision 1.53 2003/05/02 08:21:54 lipp
* Some fixes handling tool properties specified by subtrees.
*
* Revision 1.52 2003/04/24 19:47:50 lipp
* Removed dependency between general util and workflow api.
*
* Revision 1.51 2003/04/24 19:25:26 lipp
* Storing XML properties as buffered SAX events.
*
* Revision 1.50 2003/04/24 15:08:14 lipp
* Reading ApplicationDefinitiosn from SAX now.
*
* Revision 1.49 2003/04/03 11:44:06 lipp
* Support for W3C DOM arguments.
*
* Revision 1.48 2003/03/31 16:50:28 huaiyang
* Logging using common-logging.
*
* Revision 1.47 2003/03/28 12:44:08 lipp
* Moved XPDL related constants to XPDLUtil.
*
* Revision 1.46 2003/03/28 11:58:18 huaiyang
* refactory the code in invoking method.
*
* Revision 1.45 2003/03/27 16:43:26 huaiyang
* support JDOM and DOM as param for set method.
*
* Revision 1.44 2003/03/27 13:51:37 huaiyang
* use JDOMSerializationWrapper to wrap JDOM element.
*
* Revision 1.43 2003/02/12 11:57:30 lipp
* Improved deadlock (RemoteException) handling for tools. Imroved debug
* information.
*
* Revision 1.42 2002/12/19 21:37:43 lipp
* Reorganized interfaces.
*
* Revision 1.41 2002/11/26 15:06:15 lipp
* Improved exception handling.
*
* Revision 1.40 2002/11/05 12:24:53 lipp
* Simplified access to agent.
*
* Revision 1.39 2002/10/25 14:29:41 lipp
* Detach interesting part of DOM tree from rest.
*
* Revision 1.38 2002/10/25 09:20:23 lipp
* Allow applications definition without tool agent.
*
* Revision 1.37 2002/10/24 14:25:11 lipp
* Added form attribute to submitter.
*
* Revision 1.36 2002/10/06 20:14:38 lipp
* Updated argument handling.
*
* Revision 1.35 2002/10/02 10:58:13 lipp
* Modifications for tool invocation.
*
* Revision 1.34 2002/09/27 15:20:53 lipp
* Get properties verbatim.
*
* Revision 1.33 2002/09/27 11:26:44 huaiyang
* Use FormalParameter.mode.fromString to construct mode object.
*
* Revision 1.32 2002/09/26 20:03:36 lipp
* Reorganized tool invocation.
*
* Revision 1.31 2002/09/26 15:07:37 lipp
* Minor fixes.
*
* Revision 1.30 2002/09/24 15:53:37 lipp
* Better error handling.
*
* Revision 1.29 2002/09/24 07:41:30 lipp
* Improved error message.
*
* Revision 1.28 2002/09/23 20:31:28 lipp
* Implemented async/sync invocation.
*
* Revision 1.27 2002/09/23 10:23:26 lipp
* Lazy instantiation of agent.
*
* Revision 1.26 2002/09/23 09:33:03 huaiyang
* Add formal parameter in application def.
*
* Revision 1.25 2002/09/19 20:09:26 lipp
* Removed methods from Application interface and reorganized
* asynchronous tool invocation.
*
* Revision 1.24 2002/09/19 11:21:06 huaiyang
* New style in defining extended attribute of application.
*
* Revision 1.23 2002/09/18 09:53:34 lipp
* Moved access to application data to process definition.
*
* Revision 1.22 2002/09/17 15:24:24 lipp
* Renamed Tool to Application and copied some functionality to
* ProcessDefintion.
*
* Revision 1.21 2002/09/17 13:53:14 huaiyang
* Invoke method using params from xpdl.
*
* Revision 1.20 2002/09/17 09:20:12 lipp
* Added ApplicationNotStoppedException.
*
* Revision 1.19 2002/09/15 15:13:00 lipp
* Moved code for asynchronous application invocation.
*
* Revision 1.18 2002/09/11 14:17:22 lipp
* Execptions using msgs now.
*
* Revision 1.17 2002/09/11 06:33:32 huaiyang
* Remove the variable of prefix.
*
* Revision 1.16 2002/09/09 13:11:46 huaiyang
* Cleanup the unnecessary code for old style process definition.
*
* Revision 1.15 2002/09/04 08:58:58 huaiyang
* Add exception handling in invoke method.
*
* Revision 1.14 2002/09/03 15:16:29 huaiyang
* Move the call of application class in the constructor.
*
* Revision 1.13 2002/09/03 14:51:54 huaiyang
* Remove unneeded code for old style of process definition spec.
*
* Revision 1.12 2002/08/30 07:58:19 huaiyang
* Separation of Domain class and persistent class more cleaner.
*
* Revision 1.11 2002/08/26 20:23:13 lipp
* Lots of method renames.
*
* Revision 1.10 2002/08/26 14:17:07 lipp
* JavaDoc fixes.
*
* Revision 1.9 2002/08/20 13:46:13 lipp
* Using xpath now to extract additional process information from xpdl.
*
* Revision 1.8 2002/07/24 08:04:42 huaiyang
* doccheck.
*
* Revision 1.7 2002/05/21 13:27:37 huaiyang
* New method of terminate.
*
* Revision 1.6 2002/05/17 12:52:34 lipp
* Cleaned up interface to tools.
*
* Revision 1.5 2002/05/17 08:34:21 lipp
* Renamed aii/Application to aii/ToolAgent.
*
* Revision 1.4 2002/05/16 19:47:48 lipp
* Proper usage of constructingSAXHandler.
*
* Revision 1.3 2002/02/06 18:27:44 huaiyang
* Add the check of application class name.
*
* Revision 1.2 2002/02/04 16:08:15 huaiyang
* Modified the method of runApplication.
*
* Revision 1.1 2002/01/31 15:45:08 huaiyang
* Initial version of the application definition.
*
*
*/
package de.danet.an.workflow.domain;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import org.jdom.Element;
import org.jdom.input.SAXHandler;
import org.jdom.output.DOMOutputter;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import de.danet.an.util.sax.BodyFilter;
import de.danet.an.util.sax.StackedHandler;
import de.danet.an.workflow.util.SAXEventBufferImpl;
import de.danet.an.workflow.util.XPDLUtil;
import de.danet.an.workflow.api.Activity;
import de.danet.an.workflow.api.FormalParameter;
import de.danet.an.workflow.api.SAXEventBuffer;
import de.danet.an.workflow.internalapi.ExtApplication;
import de.danet.an.workflow.internalapi.ToolInvocationException;
import de.danet.an.workflow.localapi.ActivityLocal;
import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
import de.danet.an.workflow.spis.aii.CannotExecuteException;
import de.danet.an.workflow.spis.aii.ContextRequester;
import de.danet.an.workflow.spis.aii.ExceptionMappingProvider;
import de.danet.an.workflow.spis.aii.ResultProvider;
import de.danet.an.workflow.spis.aii.ExceptionMappingProvider.ExceptionMapping;
import de.danet.an.workflow.spis.aii.ResultProvider.ExceptionResult;
import de.danet.an.workflow.spis.aii.ToolAgent;
import de.danet.an.workflow.spis.aii.ToolAgentContext;
import de.danet.an.workflow.spis.aii.XMLArgumentTypeProvider;
import de.danet.an.workflow.tools.util.DirectInvocable;
/**
* This class defines the application. Setting the log level to debug
* will generate additional messages about the tool invocation.
*/
public class ApplicationDefinition implements ExtApplication, Serializable {
/**
* logger of this class.
*/
static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory
.getLog(ApplicationDefinition.class);
private static final String XMLNS = "http://www.w3.org/2000/xmlns/";
/** Id of the application. */
private String id;
/** Description of the application. */
private String description = null;
/** Agent implementing class. */
private String agentClassName = null;
/** Handler */
private String invocationHandler = null;
/** Direct invocable? */
private boolean directInvocableAttr = false;
/** Convert parameters? */
private int xmlParameterMode = XMLArgumentTypeProvider.XML_AS_W3C_DOM;
/** Exception mappings? */
private List exceptionMappings = null;
/** Agent configuration. */
private Map agentProps = new HashMap();
/** Formal parameters of this application. */
private FormalParameter[] formalParameters = new FormalParameter[] {};
/** Tool agent for this application. Tool agents are not serializable. */
private transient ToolAgent agentCache = null;
/**
* Creates a new <code>ApplicationDefinition</code>.
*/
public ApplicationDefinition () {
}
/**
* Construct agent instance.
* @return agent instance
*/
private ToolAgent agent() {
if (agentCache != null) {
return agentCache;
}
Class appClass = null;
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
appClass = cl.loadClass(agentClassName);
} catch (ClassNotFoundException e) {
if (invocationHandler == null) {
logger.error (e.getMessage(), e);
throw new IllegalStateException
("Cannot find application class " + agentClassName
+ " from ApplicationDefinition with Id = " + id + ".");
}
agentCache = new ToolAgent () {
public void invoke
(Activity activity,
FormalParameter[] formalParameters, Map actualParameters)
throws RemoteException, CannotExecuteException {
throw new IllegalStateException
("Application class " + agentClassName
+ " from ApplicationDefinition with Id = " + id
+ " is not locally available.");
}
public void terminate(Activity activity)
throws ApplicationNotStoppedException, RemoteException {
throw new ApplicationNotStoppedException
("Cannot stop tool agent in other deployment unit.");
}
};
return agentCache;
}
try {
// initialize agent before putting it in cache as we do
// not synchronize here (and creating the agent twice
// doesn't really hurt)
ToolAgent agent = (ToolAgent)appClass.newInstance();
// set properties
for (Iterator itr = agentProps.keySet().iterator();
itr.hasNext();) {
String param = (String)itr.next();
Object value = agentProps.get(param);
Method method = null;
Object[] args = new Object[] { value };
if (value instanceof SAXEventBufferImpl) {
// check for setter with type SAXEventBuffer
try {
Class[] argTypes = { SAXEventBuffer.class };
method = appClass.getMethod ("set" + param, argTypes);
} catch (NoSuchMethodException e) {
// method is null
}
}
if (method == null) {
try {
Class[] argTypes = { value.getClass() };
method = appClass.getMethod ("set" + param, argTypes);
} catch (NoSuchMethodException e) {
if (!(value instanceof SAXEventBufferImpl)) {
throw e;
}
// if value is XML, try converting to JDOM
try {
Class[] argTypes = { Element.class };
method = appClass.getMethod
("set" + param, argTypes);
SAXHandler sh = new SAXHandler ();
((SAXEventBufferImpl)value).emit(sh, sh);
args[0] = sh.getDocument().getRootElement();
} catch (NoSuchMethodException eee) {
// finally try converting to W3C DOM
Class[] argTypes
= { org.w3c.dom.Element.class };
method = appClass.getMethod
("set" + param, argTypes);
TransformerHandler th = newTransformerHandler ();
DOMResult out = new DOMResult ();
th.setResult (out);
((SAXEventBufferImpl)value).emit(th, th);
args[0] = out.getNode();
if (args[0] instanceof org.w3c.dom.Document) {
args[0] = ((org.w3c.dom.Document)args[0])
.getDocumentElement();
}
}
}
}
method.invoke(agent, args);
}
// agent may override XML parameter type setting
if (agent instanceof XMLArgumentTypeProvider) {
xmlParameterMode = ((XMLArgumentTypeProvider)agent)
.requestedXMLArgumentType ();
}
// update exception mappings
if (agent instanceof ExceptionMappingProvider) {
if (exceptionMappings == null) {
exceptionMappings = new ArrayList ();
}
// appending the mapping from the tool ensures that they
// have lower precedence
exceptionMappings.addAll
(((ExceptionMappingProvider)agent).exceptionMappings());
}
// save created agent
agentCache = agent;
} catch (IllegalAccessException ia) {
logger.error (ia.getMessage(), ia);
throw new IllegalStateException
("Cannot access application class " + agentClassName
+ " from ApplicationDefinition with Id = " + id + ".");
} catch (InstantiationException ie) {
logger.error (ie.getMessage(), ie);
throw new IllegalStateException
("Cannot instantiate application class " + agentClassName
+ " from ApplicationDefinition with Id = " + id + ".");
} catch (NoSuchMethodException nsme) {
logger.error (nsme.getMessage(), nsme);
throw new IllegalStateException (nsme.getMessage());
} catch (InvocationTargetException ite) {
logger.error (ite.getMessage(), ite);
throw new IllegalArgumentException (ite.getMessage());
} catch (TransformerConfigurationException je) {
logger.error (je.getMessage(), je);
throw new IllegalArgumentException (je.getMessage());
} catch (SAXException je) {
logger.error (je.getMessage(), je);
throw new IllegalArgumentException (je.getMessage());
}
return agentCache;
}
/**
* Return an array of the object of <code>FormalParameter</code>.
*
* @return an array of <code>FormalParameter</code> defined in this
* application. If no formal parameter is defined in this application, it
* returns an empty array.
*/
public FormalParameter[] formalParameters() {
return formalParameters;
}
/**
* Return id of this application definition.
* @return id of this application definition.
*/
public String id() {
return id;
}
/**
* Return description of this application definition.
* @return description of this application definition.
*/
public String description() {
return description;
}
/**
* Invokes the application for the specific activity.
*
* @param activity the activity to be executed
* @param params the invocation parameters
* @param agentContext the context to pass to the tool agent
* @return the invocation result if the tool agent provides one
* (i.e. implements <code>ResultProvider</code>), else <code>null</code>
* @throws ToolInvocationException if execution is not possible
* @throws RemoteException if a temporary problem occurs and we
* should retry the tool invocation. (Usually thrown when a
* deadlock situation occurs while accessing the activity.)
*/
public InvocationResult invoke
(ToolAgentContext agentContext,
de.danet.an.workflow.api.Activity activity, Map params)
throws ToolInvocationException, RemoteException {
ToolAgent agent = agent();
if (agent == null) {
return null;
}
// maybe convert DOM trees
if (xmlParameterMode == XMLArgumentTypeProvider.XML_AS_W3C_DOM) {
DOMOutputter domOutputter = new DOMOutputter();
for (Iterator i = params.keySet().iterator(); i.hasNext();) {
String pn = (String)i.next();
Object v = params.get (pn);
if (v instanceof SAXEventBuffer) {
try {
DOMResult domResult = new DOMResult();
TransformerHandler th = newTransformerHandler();
th.setResult(domResult);
convertWithTempRoot(th, (SAXEventBuffer)v);
org.w3c.dom.Document w3cDoc
= (org.w3c.dom.Document)domResult.getNode();
org.w3c.dom.DocumentFragment frag
= w3cDoc.createDocumentFragment();
org.w3c.dom.Element w3cTempRoot
= w3cDoc.getDocumentElement();
while (true) {
org.w3c.dom.Node n = w3cTempRoot.getFirstChild();
if (n == null) {
break;
}
frag.appendChild(n);
}
params.put (pn, frag);
} catch (SAXException e) {
String m = "Cannot convert JDOM to W3C DOM: "
+ e.getMessage ();
logger.error (m, e);
throw new ToolInvocationException (m);
} catch (TransformerConfigurationException e) {
String m = "Cannot convert JDOM to W3C DOM: "
+ e.getMessage ();
logger.error (m, e);
throw new ToolInvocationException (m);
}
}
}
} else if (xmlParameterMode == XMLArgumentTypeProvider.XML_AS_JDOM) {
for (Iterator i = params.keySet().iterator(); i.hasNext();) {
String pn = (String)i.next();
Object v = params.get (pn);
if (v instanceof SAXEventBuffer) {
try {
SAXHandler sh = new SAXHandler ();
convertWithTempRoot(sh, (SAXEventBuffer)v);
Element temporaryRoot
= sh.getDocument().getRootElement();
params.put (pn, temporaryRoot.getChildren());
} catch (SAXException e) {
logger.error (e.getMessage(), e);
throw new ToolInvocationException (e.getMessage());
}
}
}
}
// invoke
if (agent instanceof ContextRequester) {
((ContextRequester)agent).setToolAgentContext (agentContext);
}
if (logger.isDebugEnabled()) {
logger.debug ("Invoking " + this.toString()
+ " with " + formalParameters
+ " and " + params);
}
try {
agent.invoke(activity, formalParameters, params);
} catch (CannotExecuteException e) {
if (logger.isDebugEnabled()) {
logger.debug ("Invocation resulted in: " + e.toString());
}
// try to find mapping
if (e.getCause() != null && exceptionMappings != null) {
for (Iterator i = exceptionMappings.iterator(); i.hasNext();) {
ExceptionMapping m = (ExceptionMapping)i.next ();
if (m.getJavaException().isInstance(e.getCause())) {
if (m.getProcessException() == null) {
break;
}
ResultProvider.ExceptionResult eres
= new ResultProvider.ExceptionResult
(m.getProcessException(), m.getSuspendActivity());
if (logger.isDebugEnabled()) {
logger.debug
("Exception mapped to: " + eres.toString());
}
return new InvocationResult (eres);
}
}
}
throw new ToolInvocationException
("Cannot invoke tool, tool reports: " + e.getMessage(), e);
}
// maybe get result
if (agent instanceof ResultProvider) {
Object res = ((ResultProvider)agent).result ();
if (res != null
&& !(res instanceof Map)
&& !(res instanceof ExceptionResult)) {
throw new ToolInvocationException
(toString() + " returns result that is neither"
+ " Map nor ExceptionResult");
}
if (logger.isDebugEnabled()) {
logger.debug("Invocation result is: " + res);
}
return new InvocationResult (res);
}
return null;
}
// emits the SAX events in the given SAXContentBuffer in the content
// handler.
private void convertWithTempRoot (ContentHandler ch, SAXEventBuffer cb)
throws SAXException {
ch.startDocument();
ch.startElement
("", "temporary-root", "temporary-root", new AttributesImpl());
cb.emit(new BodyFilter (ch));
ch.endElement ("", "temporary-root", "temporary-root");
ch.endDocument();
}
/**
* Terminates the application for the specific activity.
*
* @param activity the activity to be terminated
* @throws ApplicationNotStoppedException if the application can not be
* terminated.
* @throws RemoteException if a temporary problem occurs and we
* should retry the tool invocation (usually thrown when a
* deadlock situation occurs while accessing the activity)
*/
public void terminate (de.danet.an.workflow.api.Activity activity)
throws ApplicationNotStoppedException, RemoteException {
agent().terminate(activity);
}
/* Comment copied from interface. */
public boolean isDirectInvocable () {
return (agent() instanceof DirectInvocable) || directInvocableAttr;
}
/* (non-Javadoc)
* Comment copied from interface or superclass.
*/
public String handler() {
return invocationHandler;
}
/**
* Update the invocation handler.
*
* @param handler the new handler
*/
public void updateHandler (String handler) {
invocationHandler = handler;
}
/**
* @return Returns the agentClassName.
*/
public String agentClassName() {
return agentClassName;
}
/**
* Update the agent's class.
*
* @param className the new class name
*/
public void updateAgentClassName (String className) {
agentClassName = className;
}
/**
* Provide a representation for debugging purposes.
* @return descriptive string.
*/
public String toString() {
return "Application[Id=" + id + "]";
}
/**
* Helper class for retrieving the applications from the process
* definition.
*/
public class SAXInitializer extends StackedHandler {
private List fpList = null;
private String fpId = null;
private FormalParameter.Mode fpMode = null;
private int fpIndex = 0;
private String propName = null;
private SAXEventBufferImpl propBuffer = null;
/**
* Receive notification of the beginning of an element.
*
* @param uri the Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace processing is not
* being performed.
* @param loc the local name (without prefix), or the empty string
* if Namespace processing is not being performed.
* @param raw the raw XML 1.0 name (with prefix), or the empty
* string if raw names are not available.
* @param a the attributes attached to the element. If there are
* no attributes, it shall be an empty Attributes object.
* @throws SAXException not thrown.
*/
public void startElement
(String uri, String loc, String raw, Attributes a)
throws SAXException {
if (propName != null) {
propBuffer = new SAXEventBufferImpl ();
propBuffer.startDocument ();
getStack().startAllPrefixMappings (propBuffer);
getStack().push (propBuffer);
} else if (loc.equals ("Application")) {
id = a.getValue("Id");
} else if (loc.equals ("FormalParameters")) {
fpList = new ArrayList ();
} else if (loc.equals ("FormalParameter")) {
fpId = a.getValue("Id");
fpMode = FormalParameter.Mode.fromString(a.getValue("Mode"));
} else if (loc.equals ("DataType")) {
getStack().push (new XPDLUtil.SAXDataTypeHandler());
} else if (XPDLUtil.isXpdlExtNs(uri)
&& loc.equals ("ToolAgent")) {
agentClassName = a.getValue("Class");
if (agentClassName == null || agentClassName.length() == 0) {
throw new SAXException
("Tool agent class must be specified in "
+ "ApplicationDefinition with Id = " + id + ".");
}
invocationHandler = a.getValue("Handler");
String paramMode = a.getValue("XMLParameterMode");
if (paramMode != null) {
if (paramMode.equals ("USE_JDOM")) {
xmlParameterMode = XMLArgumentTypeProvider.XML_AS_JDOM;
} else if (paramMode.equals ("USE_SAX")) {
xmlParameterMode = XMLArgumentTypeProvider.XML_AS_SAX;
}
}
String directInvoc = a.getValue("DirectInvocable");
directInvocableAttr = (directInvoc != null
&& (directInvoc.equals ("true")
|| directInvoc.equals("1")));
} else if (uri.equals (XPDLUtil.XPDL_EXTN_NS)
&& loc.equals ("ExceptionMappings")) {
exceptionMappings = new ArrayList ();
} else if (XPDLUtil.isXpdlExtNs(uri)
&& loc.equals ("ExceptionMapping")) {
try {
Class t = Thread.currentThread().getContextClassLoader()
.loadClass(a.getValue("JavaException"));
String suspAttr = a.getValue("SuspendActivity");
boolean suspAct = (suspAttr != null)
&& (suspAttr.equals("true") || suspAttr.equals("1"));
ExceptionMapping em = new ExceptionMapping
(t, a.getValue("ProcessException"), suspAct);
exceptionMappings.add (em);
} catch (ClassNotFoundException e) {
throw new SAXException (e);
}
} else if (XPDLUtil.isXpdlExtNs(uri)
&& loc.equals ("Property")) {
propName = a.getValue ("Name");
}
}
/**
* Receive notification of the end of an element.
*
* @param uri the Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace processing is not
* being performed.
* @param loc the local name (without prefix), or the empty string
* if Namespace processing is not being performed.
* @param raw the raw XML 1.0 name (with prefix), or the empty
* string if raw names are not available.
* @throws SAXException not thrown.
*/
public void endElement(String uri, String loc, String raw)
throws SAXException {
if (loc.equals ("Description")) {
description = text();
} else if (loc.equals ("FormalParameter")) {
Object dtc = removeContextData ("DataType");
String index = (new Integer(fpIndex++)).toString();
fpList.add (new FormalParameter(fpId, index, fpMode, dtc));
} else if (loc.equals ("FormalParameters")) {
formalParameters = (FormalParameter[])fpList
.toArray(new FormalParameter[fpList.size()]);
fpList = null;
} else if (XPDLUtil.isXpdlExtNs(uri)
&& loc.equals ("Property")) {
if (propBuffer != null) {
getStack().endAllPrefixMappings (propBuffer);
propBuffer.endDocument ();
propBuffer.pack ();
agentProps.put (propName, propBuffer);
} else {
agentProps.put (propName, text());
}
propName = null;
propBuffer = null;
}
}
}
/**
* Return a handler that can be used to initialize an object
* from SAX events.
* @return the handler.
*/
public StackedHandler saxInitializer () {
return new SAXInitializer ();
}
private TransformerHandler newTransformerHandler()
throws TransformerConfigurationException {
TransformerFactory tf = TransformerFactory.newInstance();
if (!tf.getFeature(SAXTransformerFactory.FEATURE)) {
String s = "JAXP transformer factory does not"
+ " support a SAX transformer!";
logger.fatal (s);
throw new IllegalStateException (s);
}
TransformerHandler th = ((SAXTransformerFactory)tf)
.newTransformerHandler ();
return th;
}
}