/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2006 Danet GmbH (www.danet.de), BU BTS.
* 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: FactoryResponseGenerator.java 2414 2007-06-20 13:37:03Z schnelle $
*
* $Log$
* Revision 1.16 2007/03/29 11:46:54 schnelle
* Reactivated ASAPException to propagate ASAP error messages in cases of an invalid key, a missing resource or an invalid factory.
*
* Revision 1.15 2007/03/27 21:59:42 mlipp
* Fixed lots of checkstyle warnings.
*
* Revision 1.14 2007/03/22 13:47:51 schnelle
* Removed unused retrieval of the receiver key.
*
* Revision 1.13 2007/03/01 12:32:57 schnelle
* Enhanced Instance.SetProperties to process ContextData.
*
* Revision 1.12 2007/02/06 08:35:34 schnelle
* Started automatic generation of wsdl description.
*
* Revision 1.11 2007/02/01 13:44:44 schnelle
* Using namespace for factory schemas that do not contain '&'.
*
* Revision 1.10 2007/02/01 12:38:36 schnelle
* Use of encoded key for properties.
*
* Revision 1.9 2007/01/31 22:55:36 mlipp
* Some more refactoring and fixes of problems introduced by refactoring.
*
* Revision 1.8 2007/01/31 14:53:06 schnelle
* Small corrections wvaluating the resource reference.
*
* Revision 1.7 2007/01/31 13:42:02 schnelle
* Added convenient method to retrieve a boolean parameter.
*
* Revision 1.6 2007/01/31 12:24:06 drmlipp
* Design revisited.
*
* Revision 1.5 2007/01/31 10:55:31 schnelle
* Fixed typo in constants.
*
* Revision 1.4 2007/01/30 22:55:02 mlipp
* Fixed generated schemata.
*
* Revision 1.3 2007/01/30 15:07:37 schnelle
* Filtering of all instances for the current factory in a list instances request.
*
* Revision 1.2 2007/01/30 11:56:14 drmlipp
* Merged Wf-XML branch.
*
* Revision 1.1.2.26 2007/01/29 15:04:22 schnelle
* Renaming of Observer to ObserverRegistry and URIDecoder to ResourceReference.
*
* Revision 1.1.2.25 2007/01/29 13:40:30 schnelle
* Storing of the sender base in the servlet context.
*
* Revision 1.1.2.24 2007/01/24 09:28:53 schnelle
* Returning result data for the instance.
*
* Revision 1.1.2.23 2007/01/19 15:01:59 schnelle
* Returning context data at instance getproperties.
*
* Revision 1.1.2.22 2007/01/19 12:34:56 schnelle
* Moved generation and decoding of the URI that is used as the receiver key to new class URIDecoder.
*
* Revision 1.1.2.21 2007/01/19 07:59:35 schnelle
* Corrected return value for factory list instances.
*
* Revision 1.1.2.20 2007/01/16 11:05:42 schnelle
* Refactoring: Moved subscription handling methods to own class.
*
* Revision 1.1.2.19 2007/01/11 11:37:10 schnelle
* Added subscription if an oberver key is given in the creation of a process.
*
* Revision 1.1.2.18 2007/01/10 09:03:43 schnelle
* Implemented set properties methods.
*
* Revision 1.1.2.17 2007/01/09 15:53:36 schnelle
* Added implementation of activity set properties.
*
* Revision 1.1.2.16 2006/12/20 14:37:59 schnelle
* Implemented Factory GetDefinition.
*
* Revision 1.1.2.15 2006/12/20 13:32:24 schnelle
* Basic implementato of GetProperties for Instance and Activity.
*
* Revision 1.1.2.14 2006/12/19 14:43:29 schnelle
* Implementation of GetProperties for ServiceRegistry and Factory.
*
* Revision 1.1.2.13 2006/12/18 14:41:02 schnelle
* Preparatation for individual schema definition for each getproperties request.
*
* Revision 1.1.2.12 2006/12/18 11:56:51 schnelle
* Returning the XPDL node after a NewDefiniton to the ServiceRegistry.
*
* Revision 1.1.2.11 2006/12/14 08:50:21 schnelle
* Implemented CompleteActivity.
*
* Revision 1.1.2.10 2006/12/13 11:23:48 schnelle
* Implemented instance ListActivities.
*
* Revision 1.1.2.9 2006/12/12 13:24:38 schnelle
* Introduction of ASAPException to provide a detailed mesage.
*
* Revision 1.1.2.8 2006/12/12 09:34:35 schnelle
* Implemented ChangeState for Instance.
*
* Revision 1.1.2.7 2006/12/11 12:21:40 schnelle
* Support of process creation with a later start.
*
* Revision 1.1.2.6 2006/12/11 11:05:34 schnelle
* Added template methods for all requests.
*
* Revision 1.1.2.5 2006/12/01 14:17:45 schnelle
* Added support for schema type for data in create process
*
* Revision 1.1.2.4 2006/12/01 12:49:54 schnelle
* Basic import of context data for process creation.
*
* Revision 1.1.2.3 2006/11/30 12:45:09 schnelle
* Basic implementation of Factory CreateInstance.
*
* Revision 1.1.2.2 2006/11/30 10:38:08 schnelle
* Implementation of Factory ListInstance.
*
* Revision 1.1.2.1 2006/11/28 12:20:09 schnelle
* Creation of a separate class to handle the issues for a specific resource.
*
* Revision 1.1.2.2 2006/11/27 15:41:55 schnelle
* Introducing some constants for request and response identification.
*
* Revision 1.1.2.1 2006/11/24 12:19:13 schnelle
* Separtion of response generation into ResponseGenerator class.
*
*/
package de.danet.an.workflow.clients.wfxml;
import java.rmi.RemoteException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.NoSuchElementException;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import de.danet.an.util.XMLUtil;
import de.danet.an.workflow.api.DefaultProcessData;
import de.danet.an.workflow.api.DefaultRequester;
import de.danet.an.workflow.api.InvalidKeyException;
import de.danet.an.workflow.api.Process;
import de.danet.an.workflow.api.ProcessDefinition;
import de.danet.an.workflow.api.ProcessDefinitionDirectory;
import de.danet.an.workflow.api.ProcessMgr;
import de.danet.an.workflow.api.SAXEventBuffer;
import de.danet.an.workflow.api.WorkflowService;
import de.danet.an.workflow.omgcore.AlreadyRunningException;
import de.danet.an.workflow.omgcore.CannotStartException;
import de.danet.an.workflow.omgcore.InvalidDataException;
import de.danet.an.workflow.omgcore.InvalidRequesterException;
import de.danet.an.workflow.omgcore.NotEnabledException;
import de.danet.an.workflow.omgcore.ProcessData;
import de.danet.an.workflow.omgcore.ProcessDataInfo;
import de.danet.an.workflow.omgcore.RequesterRequiredException;
import de.danet.an.workflow.omgcore.UpdateNotAllowedException;
/**
* This class provides the methods of an {@link AbstractResponseGenerator} that
* are relevant for the factory.
*
* <p>
* The <em>Factory</em> resource represents a "way of doing some work". For a
* process engine, this is also known as a process definition resource. Once a
* process definition is created (that is a description of process to be
* performed), the process engine exposes this as a factory resource.
* </p>
*
* @author Dirk Schnelle
*
*/
class FactoryResponseGenerator extends AbstractResponseGenerator {
/** Logger instance. */
private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
.getLog(FactoryResponseGenerator.class);
/**
* Constructs a new object.
*
* @param observerRegistry
* the observer registry.
* @param wfs
* Reference to the workflow engine.
* @param decoder
* the URI decoder.
*/
public FactoryResponseGenerator(ObserverRegistry observerRegistry,
WorkflowService wfs, ResourceReference decoder) {
super(observerRegistry, wfs, decoder);
}
/**
* Requests the factory context data schemas.
*
* @return the factory context data schema.
* @throws RemoteException
* @throws SOAPException
*/
private void addContextDataSchema(SOAPMessage message, String ns,
ProcessDefinition pd, SOAPElement cds) throws RemoteException,
SOAPException {
SOAPEnvelope env = message.getSOAPPart().getEnvelope();
SOAPElement schema = cds.addChildElement("schema", "xsd",
"http://www.w3.org/2001/XMLSchema");
Name nsAttribute = env.createName("targetNamespace");
schema.addAttribute(nsAttribute, ns);
Name attdefAttribute = env.createName("attributeFormDefault");
schema.addAttribute(attdefAttribute, "unqualified");
Name elemdefAttribute = env.createName("elementFormDefault");
schema.addAttribute(elemdefAttribute, "qualified");
SOAPElement complexType = schema.addChildElement("complexType", "xsd");
Name nameAttribute = env.createName("name");
complexType.addAttribute(nameAttribute, "ContextDataType");
Name mixedAttribute = env.createName("mixed");
complexType.addAttribute(mixedAttribute, "true");
ProcessDataInfo context = pd.contextSignature();
if (context.isEmpty()) {
return;
}
SOAPElement sequence = complexType.addChildElement("sequence", "xsd");
appendProcessDataInfoSchema(env, sequence, context);
}
/**
* Requests the factory context data schemas.
*
* @return the factory context data schema.
* @throws RemoteException
* @throws SOAPException
*/
private void addResultDataSchema(SOAPMessage message, String ns,
ProcessDefinition pd, SOAPElement cds) throws RemoteException,
SOAPException {
SOAPEnvelope env = message.getSOAPPart().getEnvelope();
SOAPElement schema = cds.addChildElement("schema", "xsd",
"http://www.w3.org/2001/XMLSchema");
Name nsAttribute = env.createName("targetNamespace");
schema.addAttribute(nsAttribute, ns);
Name attdefAttribute = env.createName("attributeFormDefault");
schema.addAttribute(attdefAttribute, "unqualified");
Name elemdefAttribute = env.createName("elementFormDefault");
schema.addAttribute(elemdefAttribute, "qualified");
SOAPElement complexType = schema.addChildElement("complexType", "xsd");
Name nameAttribute = env.createName("name");
complexType.addAttribute(nameAttribute, "ResultDataType");
Name mixedAttribute = env.createName("mixed");
complexType.addAttribute(mixedAttribute, "true");
ProcessDataInfo result = pd.resultSignature();
if (result.isEmpty()) {
return;
}
SOAPElement sequence = complexType.addChildElement("sequence", "xsd");
appendProcessDataInfoSchema(env, sequence, result);
}
/**
* Appends the schema for the given {@link ProcessDataInfo}.
*
* @param env
* message envelope
* @param sequence
* parent element.
* @param context
* process data info.
* @throws SOAPException
* error creating the schema.
*/
private void appendProcessDataInfoSchema(SOAPEnvelope env,
SOAPElement sequence, ProcessDataInfo context) throws SOAPException {
Iterator contextItarator = context.keySet().iterator();
while (contextItarator.hasNext()) {
String name = (String) contextItarator.next();
Object type = context.get(name);
String prefix = "xsd";
String xsdtype;
// TODO: Check other values for schema type.
if (type.equals(org.w3c.dom.Element.class)) {
SOAPElement var = sequence.addChildElement("any", "xsd");
Name namespaceAttribute = env.createName("namespace");
var.addAttribute(namespaceAttribute, "##other");
} else {
if (type.equals(String.class)) {
prefix = "xsd";
xsdtype = "string";
} else if (type.equals(Long.class)) {
prefix = "xsd";
xsdtype = "long";
} else if (type.equals(Double.class)) {
prefix = "xsd";
xsdtype = "double";
} else if (type.equals(Boolean.class)) {
prefix = "xsd";
xsdtype = "boolean";
} else if (type.equals(Date.class)) {
prefix = "xsd";
xsdtype = "dateTime";
} else {
// cannot resolve the type. leave it as a string and pray.
prefix = "xsd";
xsdtype = "string";
}
SOAPElement var = sequence.addChildElement("element", "xsd");
Name nameAttribute = env.createName("name");
var.addAttribute(nameAttribute, name);
Name typeAttribute = env.createName("type");
var.addAttribute(typeAttribute, prefix + ":" + xsdtype);
Name minAttribute = env.createName("minOccurs");
var.addAttribute(minAttribute, "0");
Name maxAttribute = env.createName("maxOccurs");
var.addAttribute(maxAttribute, "1");
}
}
}
/*
* (non-Javadoc)
*
* @see de.danet.an.workflow.clients.wfxml.AbstractResponseGenerator#evaluate(javax.xml.soap.SOAPMessage,
* javax.xml.soap.SOAPMessage)
*/
public void evaluate(SOAPMessage reqMsg, SOAPMessage respMsg)
throws SOAPException {
SOAPBodyElement actionElement = getActionElement(reqMsg);
String actName = actionElement.getElementName().getLocalName();
try {
if (actName.equals(Consts.GET_DEFINITION_REQUEST)) {
getDefinition(actionElement, reqMsg, respMsg);
} else if (actName.equals(Consts.SET_DEFINITION_REQUEST)) {
setDefinition(actionElement, reqMsg, respMsg);
} else if (actName.equals(Consts.LIST_INSTANCES_REQUEST)) {
listInstances(reqMsg, respMsg);
} else if (actName.equals(Consts.CREATE_INSTANCE_REQUEST)) {
createInstance(actionElement, reqMsg, respMsg);
} else if (actName.equals(Consts.GET_PROPERTIES_REQUEST)) {
getFactoryProperties(reqMsg, respMsg);
} else if (actName.equals(Consts.SET_PROPERTIES_REQUEST)) {
setFactoryProperties(actionElement, reqMsg, respMsg);
} else {
if (logger.isDebugEnabled()) {
logger.debug("unknown action '" + actName + "'");
}
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_OPERATION_SPECIFICATION,
getResourceName() + ": Unknown action \"" + actName
+ "\".");
}
} catch (RemoteException re) {
FaultUtils.setFault(respMsg, re);
}
}
/*
* (non-Javadoc)
*
* @see de.danet.an.workflow.clients.wfxml.AbstractResponseGenerator#getSender()
*/
protected String getResourceName() {
return RESOURCE_FACTORY;
}
/**
* Creates a response that contains the XPDL process definition of the
* specified process.
*
* @param action
* the action element.
* @param reqMsg
* the request message.
* @param respMsg
* the response message.
* @throws SOAPException
* error evaluating the request or constructing the response.
* @throws RemoteException
* error accessing the workflow engine.
*/
private void getDefinition(SOAPElement action, SOAPMessage reqMsg,
SOAPMessage respMsg) throws SOAPException, RemoteException {
String language = getChildsTextContent(action, "ProcessLanguage");
if ((language != null) && !language.equalsIgnoreCase("XPDL")) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_CONTEXT_DATA,
"Allowed value for process language is XPDL only!");
return;
}
ProcessDefinition pd;
try {
pd = getProcessDefinition();
} catch (InvalidKeyException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
} catch (NoSuchElementException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
}
SOAPBodyElement defNode = createWfxmlResponseNode(respMsg,
Consts.GET_DEFINITION_RESPONSE);
SAXEventBuffer sax = pd.toSAX();
importSAXAsChild(respMsg, defNode, sax);
}
/**
* Sets the XPDL process definition.
*
* <p>
* This method is currently not implemented. Use <code>NEW_DEFINITION</code>
* of <code>ServiceRegistry</code> instead.
* </p>
*
* @param action
* the request element.
* @param reqMsg
* the request message.
* @param respMsg
* the response message.
* @throws SOAPException
* error evaluating the request or constructing the response.
* @throws RemoteException
* error accessing the workflow engine.
*/
private void setDefinition(SOAPElement action, SOAPMessage reqMsg,
SOAPMessage respMsg) throws SOAPException, RemoteException {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED,
Consts.SET_DEFINITION_REQUEST + " is not implemented, yet!");
}
/**
* Creates a response that contains the known process instances.
*
* @param reqMsg
* the request message.
* @param respMsg
* the response message.
* @throws SOAPException
* error evaluating the request or constructing the response.
* @throws RemoteException
* error accessing the workflow engine.
*/
private void listInstances(SOAPMessage reqMsg, SOAPMessage respMsg)
throws SOAPException, RemoteException {
if (logger.isDebugEnabled()) {
logger.debug("list all processes");
}
ProcessMgr procMgr = null;
try {
procMgr = getProcessMgr();
} catch (InvalidKeyException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
} catch (NoSuchElementException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
}
SOAPBodyElement instancesNode = createAsapResponseNode(respMsg,
Consts.LIST_INSTANCES_RESPONSE);
Collection procs = procMgr.processes();
for (Iterator i = procs.iterator(); i.hasNext();) {
Process proc = (Process) i.next();
SOAPElement instance = instancesNode.addChildElement("Instance",
Consts.ASAP_PREFIX);
SOAPElement instanceKey = instance.addChildElement("InstanceKey",
Consts.ASAP_PREFIX);
ResourceReference procResRef = new ResourceReference(
getResourceReference().getBaseUrl(), proc);
instanceKey.addTextNode(procResRef.getResourceKey());
SOAPElement name = instance.addChildElement("Name",
Consts.ASAP_PREFIX);
String val = proc.name();
maybeAddTextNode(name, val);
SOAPElement subject = instance.addChildElement("Subject",
Consts.ASAP_PREFIX);
val = proc.description();
maybeAddTextNode(subject, val);
SOAPElement priority = instance.addChildElement("Priority",
Consts.ASAP_PREFIX);
val = Integer.toString(proc.priority());
priority.addTextNode(val);
}
}
/**
* Creates a new process instance.
*
* @param action
* the element containing the request.
* @param reqMsg
* the request message.
* @param respMsg
* the response message.
* @throws SOAPException
* error evaluating the request or constructing the response.
* @throws RemoteException
* error accessing the workflow engine.
*/
private void createInstance(SOAPElement action, SOAPMessage reqMsg,
SOAPMessage respMsg) throws SOAPException, RemoteException {
ProcessMgr procMgr = null;
try {
procMgr = getProcessMgr();
} catch (InvalidKeyException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
} catch (NoSuchElementException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
}
boolean startImmediately = true;
String textStartImmediately = getChildsTextContent(action,
"StartImmediately");
if ((textStartImmediately != null)
&& (textStartImmediately.equalsIgnoreCase("NO") || textStartImmediately
.equalsIgnoreCase("FALSE"))) {
startImmediately = false;
}
// TODO: Check, if it should be possible to start processes in debug
// mode. In that case, we have to enhance the WfXML schema.
// boolean debug = getChildsBooleanContent(action, "Debug");
String name = getChildsTextContent(action, "Name");
String subject = getChildsTextContent(action, "Subject");
// TODO clarify the difference between subject and description
// String description = getChildsTextContent(action, "Description");
SOAPElement contextData = findChildNode(action, "ContextData");
if (logger.isDebugEnabled()) {
logger.debug("creating new process instance (" + name + ", "
+ subject + ", " + startImmediately + ")");
}
Process proc;
try {
proc = (Process) procMgr.createProcess(new DefaultRequester(
getWorkflowService()));
if (name != null) {
proc.setName(name);
}
if (subject != null) {
proc.setDescription(subject);
}
if (contextData != null) {
ProcessDefinition procdef = proc.processDefinition();
ProcessData procData = getProcessData(procdef, contextData);
proc.setProcessContext(procData);
}
if (startImmediately) {
proc.start();
// proc.setDebugEnabled(debug);
}
} catch (NotEnabledException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED, e
.getMessage());
return;
} catch (InvalidRequesterException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED, e
.getMessage());
return;
} catch (RequesterRequiredException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED, e
.getMessage());
return;
} catch (CannotStartException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED, e
.getMessage());
return;
} catch (AlreadyRunningException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED, e
.getMessage());
return;
} catch (InvalidDataException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED, e
.getMessage());
return;
} catch (UpdateNotAllowedException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_OPERATION_FAILED, e
.getMessage());
return;
} catch (ParseException e) {
FaultUtils.setFault(respMsg, ASAPException.ASAP_PARSING_ERROR, e
.getMessage());
return;
}
String observer = getChildsTextContent(action, "ObserverKey");
if (observer != null) {
try {
ProcessDefinition procdef = proc.processDefinition();
ObserverRegistry obs = getObserverRegistry();
obs.subscribe(observer, procdef.packageId(), procdef
.processId(), proc.key(), getResourceReference()
.getBaseUrl());
} catch (SQLException e) {
FaultUtils.setFault(respMsg, e);
return;
}
}
SOAPBodyElement instance = createAsapResponseNode(respMsg,
Consts.CREATE_INSTANCE_RESPONSE);
SOAPElement instanceKey = instance.addChildElement("InstanceKey",
Consts.ASAP_PREFIX);
ResourceReference procResRef = new ResourceReference(
getResourceReference().getBaseUrl(), proc);
instanceKey.addTextNode(procResRef.getResourceKey());
}
/**
* Creates a response that contains properties of the process definition.
*
* @param reqMsg
* the request message.
* @param respMsg
* the response message
* @throws SOAPException
* error evaluating the request or constructing the response.
* @throws RemoteException
* error accessing the workflow engine.
*/
private void getFactoryProperties(SOAPMessage reqMsg, SOAPMessage respMsg)
throws SOAPException, RemoteException {
if (logger.isDebugEnabled()) {
logger.debug("get factory properties...");
}
String receiverKey = getHeaderValue(reqMsg, Consts.RECEIVER_KEY);
ProcessDefinition pd;
try {
pd = getProcessDefinition();
} catch (InvalidKeyException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
} catch (NoSuchElementException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
}
SOAPBodyElement propsNode = createAsapResponseNode(respMsg,
Consts.GET_PROPERTIES_RESPONSE);
appendFactoryProperties(respMsg, receiverKey, pd, propsNode);
}
/**
* Reads the properties from the process definition and appends them to the
* parent.
*
* @param respMsg
* the response message.
* @param receiverKey
* this activity instance
* @param parent
* the parent node of the response message.
* @param procMgr
* the process manager.
* @throws SOAPException
* error appending to the parent node
* @throws RemoteException
* error accessing the process
*/
private void appendFactoryProperties(SOAPMessage respMsg,
String receiverKey, ProcessDefinition pd, SOAPBodyElement propsNode)
throws SOAPException, RemoteException {
SOAPElement keyNode = propsNode.addChildElement("Key",
Consts.ASAP_PREFIX);
keyNode.addTextNode(getResourceReference().getResourceKey());
SOAPElement nameNode = propsNode.addChildElement("Name",
Consts.ASAP_PREFIX);
nameNode.addTextNode(pd.processName());
SOAPElement subjectNode = propsNode.addChildElement("Subject",
Consts.ASAP_PREFIX);
subjectNode.addTextNode("");
SOAPElement descNode = propsNode.addChildElement("Description",
Consts.ASAP_PREFIX);
descNode.addTextNode("");
SOAPElement cdsNode = propsNode.addChildElement("ContextDataSchema",
Consts.ASAP_PREFIX);
addContextDataSchema(respMsg, getResourceReference().getNamespace(),
pd, cdsNode);
SOAPElement rdsNode = propsNode.addChildElement("ResultDataSchema",
Consts.ASAP_PREFIX);
addResultDataSchema(respMsg, getResourceReference().getNamespace(), pd,
rdsNode);
SOAPElement expNode = propsNode.addChildElement("Expiration",
Consts.ASAP_PREFIX);
expNode.addTextNode("P1D");
}
/**
* Sets properties of the process manager.
*
* @param action
* the action element.
* @param reqMsg
* the request message.
* @param respMsg
* the response message
* @throws SOAPException
* error evaluating the request or constructing the response.
* @throws RemoteException
* error accessing the workflow engine.
*/
private void setFactoryProperties(SOAPElement action, SOAPMessage reqMsg,
SOAPMessage respMsg) throws SOAPException, RemoteException {
if (logger.isDebugEnabled()) {
logger.debug("set factory properties...");
}
String receiverKey = getHeaderValue(reqMsg, Consts.RECEIVER_KEY);
ProcessDefinition pd;
try {
pd = getProcessDefinition();
} catch (InvalidKeyException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
} catch (NoSuchElementException e) {
FaultUtils.setFault(respMsg,
ASAPException.ASAP_INVALID_INSTANCE_KEY, e.getMessage());
return;
}
SOAPBodyElement propsNode = createAsapResponseNode(respMsg,
Consts.SET_PROPERTIES_RESPONSE);
appendFactoryProperties(respMsg, receiverKey, pd, propsNode);
}
/**
* Extracts the process data from the given context data.
*
* @param contextData
* the context data.
* @return process data to set in the the process.
* @throws RemoteException
* @throws SOAPException
* @throws ParseException
*/
private ProcessData getProcessData(ProcessDefinition procdef,
SOAPElement contextData) throws RemoteException, SOAPException,
ParseException {
ProcessDataInfo info = procdef.contextSignature();
ProcessData procData = new DefaultProcessData();
for (Iterator pdi = contextData.getChildElements(); pdi.hasNext();) {
SOAPElement current = (SOAPElement) pdi.next();
String pdname = current.getLocalName();
Object type = info.get(pdname);
if (type == null) {
throw new SOAPException("process does not contain a variable "
+ "with name " + pdname);
}
String pdvalue = XMLUtil.getFirstLevelTextContent(current);
Object value;
if (type.equals(String.class)) {
value = pdvalue;
} else if (type.equals(Long.class)) {
value = new Long(pdvalue);
} else if (type.equals(Double.class)) {
value = new Double(XMLUtil.parseXsdDouble(pdvalue));
} else if (type.equals(Boolean.class)) {
value = new Boolean(XMLUtil.parseXsdBoolean(pdvalue));
} else if (type.equals(Date.class)) {
value = XMLUtil.parseXsdDateTime(pdvalue);
} else if (type.equals(org.w3c.dom.Element.class)) {
// TODO: Check other values for schema types.
value = current.getFirstChild();
} else {
// cannot resolve the type. leave it as a string and pray.
value = pdvalue;
}
procData.put(pdname, value);
}
return procData;
}
/**
* Find the process manager that that can handle the package id and the
* process id that are encoded in the given URI.
*
* @param uri
* the URI with package and process id.
* @return process manager.
* @throws RemoteException
* error accessing the workflow engine
* @throws InvalidKeyException
* process manager does not exist
*/
private ProcessMgr getProcessMgr() throws RemoteException,
InvalidKeyException {
String packageId = getResourceReference().getPackageId();
String processId = getResourceReference().getProcessId();
if (logger.isDebugEnabled()) {
logger.debug("getting process manager for " + packageId + "/"
+ processId);
}
ProcessDefinitionDirectory pdd = getWorkflowService()
.processDefinitionDirectory();
ProcessMgr procmgr = pdd.processMgr(packageId, processId);
return procmgr;
}
/**
* Gets the process definition that that can handle the package id and the
* process id that are encoded in the given URI.
*
* @param uri
* the URI with package and process id.
* @return process manager.
* @throws RemoteException
* error accessing the workflow engine
* @throws InvalidKeyException
* process manager does not exist
*/
private ProcessDefinition getProcessDefinition() throws RemoteException,
InvalidKeyException {
String packageId = getResourceReference().getPackageId();
String processId = getResourceReference().getProcessId();
if (logger.isDebugEnabled()) {
logger.debug("finding process definition'" + packageId + "/"
+ processId + "'...");
}
ProcessDefinitionDirectory pdd = getWorkflowService()
.processDefinitionDirectory();
return pdd.lookupProcessDefinition(packageId, processId);
}
}