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

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

/*
* 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: AbstractResponseGenerator.java 2331 2007-03-29 11:46:54Z schnelle $
*
* $Log$
* Revision 1.11  2007/03/27 21:59:42  mlipp
* Fixed lots of checkstyle warnings.
*
* Revision 1.10  2007/03/01 12:32:57  schnelle
* Enhanced Instance.SetProperties to process ContextData.
*
* Revision 1.9  2007/02/28 13:19:36  drmlipp
* Fixed charset problem.
*
* Revision 1.8  2007/02/16 21:00:21  mlipp
* Fixed some null pointer problems.
*
* Revision 1.7  2007/02/01 10:08:36  drmlipp
* Removed no longer used observer resource.
*
* Revision 1.6  2007/01/31 22:55:36  mlipp
* Some more refactoring and fixes of problems introduced by refactoring.
*
* Revision 1.5  2007/01/31 14:53:06  schnelle
* Small corrections wvaluating the resource reference.
*
* Revision 1.4  2007/01/31 13:42:02  schnelle
* Added convenient method to retrieve a boolean parameter.
*
* Revision 1.3  2007/01/31 12:24:04  drmlipp
* Design revisited.
*
* Revision 1.2  2007/01/30 11:56:14  drmlipp
* Merged Wf-XML branch.
*
* Revision 1.1.2.26  2007/01/29 15:04:20  schnelle
* Renaming of Observer to ObserverRegistry and URIDecoder to ResourceReference.
*
* Revision 1.1.2.25  2007/01/29 13:50:35  drmlipp
* Minor cleanup.
*
* Revision 1.1.2.24  2007/01/29 13:40:32  schnelle
* Storing of the sender base in the servlet context.
*
* Revision 1.1.2.23  2007/01/29 13:10:26  drmlipp
* Using utilities method for timestamp convertion.
*
* Revision 1.1.2.22  2007/01/26 15:50:28  schnelle
* Added encoding for process id and package id.
*
* Revision 1.1.2.21  2007/01/24 10:56:50  schnelle
* Prepared return of a result for aobservers.
*
* Revision 1.1.2.20  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.19  2007/01/19 07:59:35  schnelle
* Corrected return value for factory list instances.
*
* Revision 1.1.2.18  2007/01/16 11:05:42  schnelle
* Refactoring: Moved subscription handling methods to own class.
*
* Revision 1.1.2.17  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.16  2007/01/11 10:23:52  schnelle
* Creation of StateChanged notifications.
*
* Revision 1.1.2.15  2006/12/20 14:37:59  schnelle
* Implemented Factory GetDefinition.
*
* Revision 1.1.2.14  2006/12/20 13:32:25  schnelle
* Basic implementato of GetProperties for Instance and Activity.
*
* Revision 1.1.2.13  2006/12/19 14:43:29  schnelle
* Implementation of GetProperties for ServiceRegistry and Factory.
*
* Revision 1.1.2.12  2006/12/18 14:41:03  schnelle
* Preparatation for individual schema definition for each getproperties request.
*
* Revision 1.1.2.11  2006/12/18 11:56:51  schnelle
* Returning the XPDL node after a NewDefiniton to the ServiceRegistry.
*
* Revision 1.1.2.10  2006/12/14 08:50:21  schnelle
* Implemented CompleteActivity.
*
* Revision 1.1.2.9  2006/12/13 11:23:48  schnelle
* Implemented instance ListActivities.
*
* Revision 1.1.2.8  2006/12/12 13:24:38  schnelle
* Introduction of ASAPException to provide a detailed mesage.
*
* Revision 1.1.2.7  2006/12/11 11:05:34  schnelle
* Added template methods for all requests.
*
* Revision 1.1.2.6  2006/12/01 12:49:54  schnelle
* Basic import of context data for process creation.
*
* Revision 1.1.2.5  2006/11/30 12:45:08  schnelle
* Basic implementation of Factory CreateInstance.
*
* Revision 1.1.2.4  2006/11/29 14:12:37  schnelle
* Take respect to namespaces of asap requests and responses.
*
* Revision 1.1.2.3  2006/11/29 11:05:22  schnelle
* Full implementation of the request and response headers.
*
* Revision 1.1.2.2  2006/11/28 15:31:51  schnelle
* Proper selection of the response generator.
*
* 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.
*
*/
package de.danet.an.workflow.clients.wfxml;

import java.io.ByteArrayOutputStream;
import java.rmi.RemoteException;
import java.util.Iterator;

import javax.xml.soap.Name;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.Text;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.xml.sax.SAXException;

import de.danet.an.util.XMLUtil;
import de.danet.an.util.sax.HandlerStack;
import de.danet.an.util.soap.SOAPBuilder;
import de.danet.an.workflow.api.SAXEventBuffer;
import de.danet.an.workflow.api.WorkflowService;

/**
* This class provides the basic functionality of a SOAP based interface between
* the workflow engine (i.e. its processes) and any SOAP based client.
*
* @author Dirk Schnelle
*/
abstract class AbstractResponseGenerator {

    /** Connection to the workflow service. */
    private WorkflowService wfs = null;
    /** The URI decoder. */
    private ResourceReference resourceReference;
   
    public static final String RESOURCE_SERVICE_REGISTRY = "ServiceRegistry";
    public static final String RESOURCE_FACTORY = "Factory";
    public static final String RESOURCE_INSTANCE = "Instance";
    public static final String RESOURCE_ACTIVITY = "Activity";

    private final ObserverRegistry observerRegistry;
   
    /**
     * Constructs a new object.
     *
     * @param observerRegistry the observer registry
     * @param wfs Reference to the workflow engine.
     * @param resRef the resource reference.
     */
    public AbstractResponseGenerator
        (ObserverRegistry observerRegistry, WorkflowService wfs,
         ResourceReference resRef){
        this.observerRegistry = observerRegistry;
        this.wfs = wfs;
        this.resourceReference = resRef;
    }

    /**
     * Retrieves the observer registry.
     * @return the observer registry.
     */
    protected ObserverRegistry getObserverRegistry() {
        return observerRegistry;
    }
   
    /**
     * @return Returns the resourceReference.
     */
    public ResourceReference getResourceReference() {
        return resourceReference;
    }

    /**
     * @return Returns the workflow service.
     */
    public WorkflowService getWorkflowService() {
        return wfs;
    }

    /**
     * Retrieves the text content of the child node with the specified name.
     * @param message the message to inspect.
     * @param element the parent node.
     * @param prefix prefix of the searched child node.
     * @param name name of the searched child node.
     * @return text content, or <code>null</code> if there is no such child
     *          node.
     * @throws SOAPException
     *         error inspecting the SOAP message.
     */
    protected String getChildTextContent
        (SOAPMessage message, SOAPElement element, String prefix, String name)
        throws SOAPException {
        SOAPPart part = message.getSOAPPart();
        SOAPEnvelope envelope = part.getEnvelope();
        Name nm = envelope.createName(name, prefix, Consts.ASAP_NS);
        Iterator i = element.getChildElements(nm);
        if (!i.hasNext()) {
            return null;
        }
        SOAPElement child = (SOAPElement) i.next();
       
        return XMLUtil.getFirstLevelTextContent(child);
    }

    /**
     * Retrieves the first element of the given request body that contains the
     * requested action to perform. It is guaranteed that the element has the
     * correct namespace.
     * @param request the current request.
     * @return action element
     * @throws SOAPException
     *         error evaluating the request.
     */
    protected SOAPBodyElement getActionElement(SOAPMessage request)
        throws SOAPException {
        SOAPBody body = request.getSOAPBody();
        for (Iterator i = body.getChildElements(); i.hasNext();) {
            Node node = (Node)i.next();
            if (node instanceof SOAPBodyElement) {
                SOAPBodyElement bodyElement = (SOAPBodyElement) node;
               
                Name bodyElementName = bodyElement.getElementName();
                String headerUri = bodyElementName.getURI();
                if (headerUri.equals(Consts.ASAP_NS)
                        || headerUri.equals(Consts.WFXML_NS)) {
                    return bodyElement;
                }
            }
        }   

        throw new SOAPException("Missing body.");
    }
   
    /**
     * Handles the given request.
     * @param reqMsg the request message.
     * @param respMsg the response message.
     * @throws SOAPException
     *         Error in the underlying SOAP protocol.
     * @throws RemoteException
     *         Error accessing the workflow engine.
     */
    public abstract void evaluate(SOAPMessage reqMsg, SOAPMessage respMsg)
        throws SOAPException, RemoteException;
   
    /**
     * Retrieves the name of this resource.
     * @return Name of the sender instance.
     */
    protected abstract String getResourceName();
   
    /**
     * Retrieves the ASAP <code>key</code> from the header of the message.
     * @param message the message to inspect.
     * @param key the key to find.
     * @return value for the <code>key</code>, <code>null</code> if the key
     *         could not be found.
     * @throws SOAPException
     *         error inspecting the SOAP message.
     */
    protected String getHeaderValue(SOAPMessage message, String key)
        throws SOAPException {
        SOAPHeaderElement headerElement = null;
       
        SOAPHeader header = message.getSOAPHeader();
        for (Iterator i = header.getChildElements(); i.hasNext();) {
            Node node = (Node)i.next();
            if (node instanceof SOAPHeaderElement) {
                headerElement = (SOAPHeaderElement) node;
               
                Name headerElementName = headerElement.getElementName();
                String localName = headerElementName.getLocalName();
                if (localName.equals(Consts.REQUEST_HEADER)
                        || localName.equals(Consts.RESPONSE_HEADER)) {
                    String headerUri = headerElementName.getURI();
                    if (headerUri.equals(Consts.ASAP_NS)
                            || headerUri.equals(Consts.WFXML_NS)) {
                        break;
                    }
                }
            }
        }   

        if (headerElement == null) {
            throw new SOAPException("ASAP request header not found.");
        }
       
        return getChildsTextContent(headerElement, key);   
    }

    /**
     * Tries to find a child node with the given name. If there is such a child
     * node, the first child is returned.
     * @param element the parent element
     * @param key the name of the tag to find
     * @return first child, if the tag could be found, <code>null</code> else.
     */
    protected SOAPElement findChildNode(SOAPElement element, String key) {
        for (Iterator i = element.getChildElements(); i.hasNext();) {
            Node node = (Node)i.next();
            if (node instanceof SOAPElement) {
                SOAPElement child = (SOAPElement) node;
                String name = child.getElementName().getLocalName();
                if (name.equals(key)) {
                    return child;
                }
            }
        }
       
        return null;
    }
   
    /**
     * Retrieves the contents of the child node with the given name as text.
     * @param element the parent node.
     * @param key name of the child node.
     * @return Contents of the child node, or <code>null</code>, if the
     *         key is no child of element.
     */
    protected String getChildsTextContent(SOAPElement element, String key) {
        for (Iterator i = element.getChildElements(); i.hasNext();) {
            Node node = (Node)i.next();
            if (node instanceof SOAPElement) {
                SOAPElement child = (SOAPElement) node;
                String name = child.getElementName().getLocalName();
                if (name.equals(key)) {
                    return XMLUtil.getFirstLevelTextContent(child);
                }
            }
        }
       
        return null;
    }

    /**
     * Fills the response header.
     * @param reqMsg the request message.
     * @param respMsg the response message.
     * @exception SOAPException
     *            Error in the SOAP message.
     */
    void fillResponseHeader(SOAPMessage reqMsg, SOAPMessage respMsg)
        throws SOAPException {
               
        SOAPEnvelope respEnv = respMsg.getSOAPPart().getEnvelope();
        SOAPHeader respHeader = respEnv.getHeader();
        SOAPHeaderElement respNode
            = respHeader.addHeaderElement
            (respEnv.createName(Consts.RESPONSE_HEADER, Consts.ASAP_PREFIX,
                    Consts.ASAP_NS));
       
        // Set the sender to me. This might differ from the value, given in
        // the request as ReceiverKey. We set it to the URL under which we were
        // called.
        SOAPElement skNode = respNode.addChildElement(Consts.SENDER_KEY,
                Consts.ASAP_PREFIX);
        skNode.addTextNode(resourceReference.getResourceKey());

        // Set the receiver if it was specified in the request.
        String receiver = getHeaderValue(reqMsg, Consts.SENDER_KEY);
        if (receiver != null) {
            SOAPElement node = respNode.addChildElement(Consts.RECEIVER_KEY,
                    Consts.ASAP_PREFIX, Consts.ASAP_NS);
            node.addTextNode(receiver);
        }
       
        // Retain the RequestId if given.
        String requestId = getHeaderValue(reqMsg, Consts.REQUEST_ID);
        if (requestId != null) {
            SOAPElement node = respNode.addChildElement(Consts.REQUEST_ID,
                    Consts.ASAP_PREFIX, Consts.ASAP_NS);
            node.addTextNode(requestId);
        }
    }

    /**
     * Adds the text as a child node, if it is neither <code>null</code> nor
     * empty.
     * @param element the parent node.
     * @param text the text to add.
     * @throws SOAPException
     *         error appending the text node.
     */
    protected void maybeAddTextNode(SOAPElement element, String text)
        throws SOAPException {
        if ((text == null) || (text.length() == 0)) {
            return;
        }

        element.addTextNode(text);
    }

    /**
     * Convenience method to create response node for WfXML requests.
     * @param respMsg the response message.
     * @param nodeName name of the response node.
     * @return created response node.
     * @throws SOAPException
     *         error creating the SOAP nodes.
     */
    protected SOAPBodyElement createWfxmlResponseNode(SOAPMessage respMsg,
            String nodeName)
        throws SOAPException {
        SOAPEnvelope respEnv = respMsg.getSOAPPart().getEnvelope();
        SOAPBody respBody = respEnv.getBody();
        Name respName = respEnv.createName(nodeName, Consts.WFXML_PREFIX,
                Consts.WFXML_NS);
       
        SOAPBodyElement node = respBody.addBodyElement(respName);
        node.addNamespaceDeclaration(Consts.ASAP_PREFIX, Consts.ASAP_NS);
       
        return node;
    }

    /**
     * Convenience method to create response node for WfXML requests.
     * @param respMsg the repsonse message.
     * @param nodeName name of the response node.
     * @return created response node.
     * @throws SOAPException
     *         error creating the SOAP nodes.
     */
    protected SOAPBodyElement createAsapResponseNode(SOAPMessage respMsg,
            String nodeName)
        throws SOAPException {
        SOAPEnvelope respEnv = respMsg.getSOAPPart().getEnvelope();
        SOAPBody respBody = respEnv.getBody();
        Name respName = respEnv.createName(nodeName, Consts.ASAP_PREFIX,
                Consts.ASAP_NS);

        SOAPBodyElement node = respBody.addBodyElement(respName);

        return node;
    }

    /**
     * Creates a byte array representation for the given SOAP element.
     * @param node the node to transform
     * @return bytes for the given SOAP element.
     * @throws TransformerException
     *         error transforming the node into a string.
     */
    protected byte[] nodeToBytes(SOAPElement node) throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();

        DOMSource source = new DOMSource(node);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        StreamResult result = new StreamResult(out);

        transformer.transform(source, result);

        return out.toByteArray();
    }
   
    /**
     * Imports a SOAP node as a child of another node in another document.
     *
     * <p>
     * Note that this might be not namespace aware. make sure to have all
     * namespaces resolved before calling this method.
     * </p>
     *
     * @param parent the parent node
     * @param imported the node to import
     * @return the imported node
     * @throws SOAPException
     *         error navigating through the SOAP stack.
     */
    protected SOAPElement importAsChild(SOAPElement parent,
            SOAPElement imported) throws SOAPException {
        SOAPFactory factory = SOAPFactory.newInstance();
       
        Name name = imported.getElementName();
       
        SOAPElement newChild = parent.addChildElement(name.getLocalName(),
                name.getPrefix(), name.getURI());
       
        Iterator attributes = imported.getAllAttributes();
        while (attributes.hasNext()) {
            Name attribute = (Name) attributes.next();
            String value = imported.getAttributeValue(attribute);
            Name newName = factory.createName(attribute.getLocalName(),
                    attribute.getPrefix(), attribute.getURI());
            newChild.addAttribute(newName, value);
        }
       
        Iterator children = imported.getChildElements();
        while (children.hasNext()) {
            Object o = children.next();
            if (o instanceof Text) {
                String text = imported.getNodeValue();
                if (text != null) {
                    newChild.addTextNode(text);
                }
            } else {
                importAsChild(newChild, (SOAPElement) o);
            }
        }
       
        return newChild;
    }

    /**
     * Imports a SOAP node as a child of another node in another document.
     *
     * <p>
     * Note that this might be not namespace aware. make sure to have all
     * namespaces resolved before calling this method.
     * </p>
     *
     * @param parent the parent node
     * @param imported the node to import
     * @return the imported node
     * @throws SOAPException
     *         error navigating through the SOAP stack.
     */
    protected static SOAPElement importW3CNodeAsChild(SOAPElement parent,
            org.w3c.dom.Node imported) throws SOAPException {
        SOAPFactory factory = SOAPFactory.newInstance();
       
        SOAPElement newChild = parent.addChildElement(imported.getLocalName(),
                imported.getPrefix(), imported.getNamespaceURI());
       
        org.w3c.dom.NamedNodeMap attributes = imported.getAttributes();
        for(int i=0; i<attributes.getLength(); i++) {
            org.w3c.dom.Node attribute = attributes.item(i);
            Name newName = factory.createName(attribute.getLocalName(),
                    attribute.getPrefix(), attribute.getNamespaceURI());
            newChild.addAttribute(newName, attribute.getNodeValue());
        }
       
        org.w3c.dom.NodeList children = imported.getChildNodes();
        for(int i=0; i<children.getLength(); i++) {
            Object o = children.item(i);
            if (o instanceof org.w3c.dom.Text) {
                String text = imported.getNodeValue();
                newChild.addTextNode(text);
            } else {
                importW3CNodeAsChild(newChild, (org.w3c.dom.Node) o);
            }
        }
       
        return newChild;
    }

    /**
     * Append the given SAX event buffer as a child to the parent SOAP element.
     * @param message the message containing the parent
     * @param parent the parent SOAP element
     * @param sax the sax buffer to import.
     * @throws TransformerException
     * @throws SOAPException
     *         Error in the SOAP message.
     */
    protected static void importSAXAsChild
        (SOAPMessage message, SOAPElement parent, SAXEventBuffer sax)
        throws SOAPException {
        SOAPEnvelope env = message.getSOAPPart().getEnvelope();

        HandlerStack hs = new HandlerStack (new SOAPBuilder(parent));
        hs.setContextData ("envelope", env);
        try {
            sax.emit(hs.contentHandler());
        } catch (SAXException e) {
            throw (IllegalArgumentException)
                (new IllegalArgumentException(e.getMessage()).initCause(e));
        }
    }
}
TOP

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

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.