Package de.danet.an.workflow.clients.wfxml

Source Code of de.danet.an.workflow.clients.wfxml.FactoryResponseGenerator

/*
* 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);
    }
}
TOP

Related Classes of de.danet.an.workflow.clients.wfxml.FactoryResponseGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.