Package org.jboss.soa.esb.actions.bpel

Source Code of org.jboss.soa.esb.actions.bpel.BPELInvoke

/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*
* (C) 2005-2006,
* @author JBoss Inc.
*/
package org.jboss.soa.esb.actions.bpel;

import java.security.AccessController;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.internal.soa.esb.actions.bpel.ESBInvocationAdapter;
import org.jboss.soa.esb.actions.AbstractActionLifecycle;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.MessagePayloadProxy;
import org.jboss.soa.esb.message.format.MessageFactory;

import javax.naming.*;
import javax.security.auth.Subject;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.jboss.soa.bpel.runtime.engine.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class BPELInvoke extends AbstractActionLifecycle {
   
  private static final String TOP_LEVEL_ELEMENT_NAME = "message";
  protected static final String REQUEST_PART_NAME = "requestPartName";
  protected static final String REQUEST_SAML_PART_NAME = "requestSAMLPartName";
  protected static final String RESPONSE_PART_NAME = "responsePartName";
  protected static final String SERVICE = "service";
  protected static final String PORT = "port";
  protected static final String OPERATION = "operation";
  protected static final String ABORT_ON_FAULT = "abortOnFault";
 
  protected static final String BODY_FAULT_CODE = "org.jboss.soa.esb.message.fault.detail.code";
  protected static final String BODY_BPEL_FAULT_CODE = "org.jboss.soa.bpel.message.fault.detail.code";
 
  protected ConfigTree  _config;
  private static BPELEngine  _bpelEngine;
   
  public BPELInvoke(ConfigTree config) {
    _config = config;
  }
 
  /**
   * This method returns a reference to the BPEL Engine.
   *
   * @return The BPEL engine
   * @throws Exception Failed to obtain a reference to the
   *           BPEL engine
   */
  protected static BPELEngine getBPELEngine() throws Exception {

    // If BPEL engine not set, then locate from JNDI
    if (_bpelEngine == null) {
      InitialContext context=new InitialContext();
      _bpelEngine = (BPELEngine)context.lookup(BPELEngine.Service);
    }
   
    return(_bpelEngine);
  }
 
  /**
   * This method sets the reference to the BPEL engine.
   *
   * @param engine The BPEL engine
   */
  protected void setBPELEngine(BPELEngine engine) {
    _bpelEngine = engine;
  }
 
  /**
   * This method processes the supplied message, and optionally
   * returns a response message.
   *
   * @param message The request message
   * @return The optional response message
   * @throws Exception Failed to process the message
   */
  public Message process(Message message) throws Exception {
    Message ret=null;
   
    // Check the operation and service details are available
    if (_config.getAttribute(OPERATION) == null) {
      throw new RuntimeException("Property '"+OPERATION+"' has not been specified");
    }
   
    if (_config.getAttribute(SERVICE) == null) {
      throw new RuntimeException("Property '"+SERVICE+"' has not been specified");
    }
 
    BPELEngine engine=getBPELEngine();
   
    if (engine == null) {
      throw new RuntimeException("Failed to locate BPEL engine");
    }
   
    // Create MessagePayloadProxy
    MessagePayloadProxy proxy=new MessagePayloadProxy(_config);
   
    logger.debug("Request: "+message);

    // Get default body value
    Object value=proxy.getPayload(message);
   
    boolean f_toText=(value instanceof String);
   
    org.w3c.dom.Element mesgElem=createMessageElement(value);
   
    // Invoke the service
    String serviceName=_config.getAttribute(SERVICE);
   
    javax.xml.namespace.QName qname=javax.xml.namespace.QName.valueOf(serviceName);
   
    logger.debug("Invoking service: "+qname);

    // Create invocationContext
    ESBInvocationAdapter invocationContext =
      new ESBInvocationAdapter(_config.getAttribute(OPERATION), qname, _config.getAttribute(PORT));
    invocationContext.setRequestXML(mesgElem);
   
    establishHeaderParts(invocationContext);
   
    // invoke ODE
    try {
      engine.invoke(invocationContext);
    } catch(Throwable t) {
      // RIFTSAW-177 - prevent ODE specific exceptions being returned to ESB client where
      // a ClassNotFoundException would be thrown
      throw new Exception("BPEL invoke failed: "+t);
    }
   
    ret = handleResponse(invocationContext.getInvocationResult(),
              invocationContext.getFaultName(), serviceName, proxy, f_toText);

    return(ret);  
  }
 
  protected Element createMessageElement(Object value) throws Exception {
   
    String requestPartName=_config.getAttribute(REQUEST_PART_NAME);
   
    org.w3c.dom.Element mesgElem=null;
    Node node=null;
     
    if (value instanceof String) {

      // Convert to element
      node = getNode((String)value);

    } else if (value instanceof Node) {
      node = (Node)value;
    }

    if (node == null) {
      throw new RuntimeException("Failed to obtain DOM representation of message value");
    }
   
    logger.debug("Node type is: "+node.getNodeType()+" requestPartName="+requestPartName);
   
    // If value is an element, and no request part name has been provided,
    // then pass the DOM element through as is.
    if (node.getNodeType() == Node.ELEMENT_NODE &&
              requestPartName == null) {
      mesgElem = (org.w3c.dom.Element)node;
     
    } else if (requestPartName == null) {
      // Not possible to pass anything other than an Element
      // if the request partname is not defined
      throw new RuntimeException("Non-element value can only be used in request if part name specified");
     
    } else {
     
      // Need to construct DOM element for message
      mesgElem = createMessage();
     
      // Transfer value into this message element
      node = (Node)node.cloneNode(true);
     
      Element partElem=mesgElem.getOwnerDocument().createElement(requestPartName);
      mesgElem.appendChild(partElem);
     
      node = (Node)mesgElem.getOwnerDocument().adoptNode(node);
     
      partElem.appendChild(node);
    }
       
    return(mesgElem);
  }
 
  protected void establishHeaderParts(ESBInvocationAdapter invocationContext) {
    String requestSAMLAssertionPartName=_config.getAttribute(REQUEST_SAML_PART_NAME);

    if (requestSAMLAssertionPartName != null) {
     
      // Check if PicketLink SAML creditial is available
      Subject subject = Subject.getSubject(AccessController.getContext());
     
      if (subject != null) {
        org.picketlink.identity.federation.core.wstrust.SamlCredential samlCred=null;
       
        for (Object cred : subject.getPublicCredentials()) {
          if (cred instanceof org.picketlink.identity.federation.core.wstrust.SamlCredential) {
            samlCred = (org.picketlink.identity.federation.core.wstrust.SamlCredential)cred;
            break;
          }
        }
       
        if (samlCred != null) {
          try {
            java.util.Map<String,Element> headerParts=
              new java.util.HashMap<String, Element>();
           
            // Wrap assertion element in a wsse:Security element
            org.w3c.dom.Element assertion=samlCred.getAssertionAsElement();
            org.w3c.dom.Document doc=assertion.getOwnerDocument();
           
            org.w3c.dom.Element security=doc.createElementNS(
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
                        "Security");
           
            security.appendChild(assertion.cloneNode(true));
           
            //doc.appendChild(security);

            headerParts.put(requestSAMLAssertionPartName, security);
           
            invocationContext.setRequestHeaderParts(headerParts);
          } catch(Throwable t) {
            logger.error("Failed to add header parts", t);
          }
        }
      }
    }
  }
 
  protected Message handleResponse(org.w3c.dom.Element resp, javax.xml.namespace.QName faultName,
            String serviceName, MessagePayloadProxy proxy, boolean f_toText)
                      throws Exception {
    Message ret=null;

    if (resp != null) {
      ret = MessageFactory.getInstance().getMessage();
     
      try {
        String defpart=_config.getAttribute(RESPONSE_PART_NAME);
       
        org.w3c.dom.Node respNode=null;
       
        if (defpart != null) {
          org.w3c.dom.NodeList nl=resp.getChildNodes();
         
          // Find content in named part
          for (int i=0; respNode == null && i < nl.getLength(); i++) {
            if (nl.item(i).getNodeType() == Node.ELEMENT_NODE &&
                nl.item(i).getNodeName().equals(defpart)) {
             
              // Find element
              org.w3c.dom.NodeList subnl=
                ((org.w3c.dom.Element)nl.item(i)).getChildNodes();
              if (subnl.getLength() == 1) {
                respNode = subnl.item(0);
              } else {
                // Scan for element
                for (int j=0; respNode != null && j < subnl.getLength(); j++) {
                  if (subnl.item(j).getNodeType() == Node.ELEMENT_NODE) {
                    respNode = subnl.item(j);
                  }
                }
              }
            }
          }
        } else {
          respNode = resp;
        }
       
        Object respValue=respNode;
       
        // Check if node needs to be converted to text
        if ((f_toText || faultName != null) && respNode != null) {
          respValue = getText(respNode);
        }
                 
        if (respValue == null) {
          logger.error("Unable to convert message part '"+(defpart==null?"<undefined>":defpart)+
                    "' into a response document");
        } else {
          //ret.getBody().add(respValue);
         
          // Set the payload in the returned message
          proxy.setPayload(ret, respValue);
         
          // Check if fault name should be set
          if (faultName != null) {
            logger.debug("Fault '"+faultName+"' detected, throwing exception");
           
            org.jboss.soa.esb.actions.ActionProcessingDetailFaultException faultException=
              new org.jboss.soa.esb.actions.ActionProcessingDetailFaultException(faultName,
                  "Fault '"+faultName+"' occurred when calling service '"+serviceName+"'",
                      respValue.toString());
           
            // In case we wanted to return the fault message as the message body
            //faultException.getFaultMessage().getBody().add(respValue.toString());
           
            // Record string representation of faultName, as currently if the client
            // does not include the stax-api.jar in its list of endorsed libs (as the
            // JBoss AS server does, then it will result in a class version issue when
            // it tries to retrieve the ESB fault code (which is transferred as a QName).
            // See RIFTSAW-110 for more details.
            faultException.getFaultMessage().getBody().add(BODY_BPEL_FAULT_CODE, faultName.toString());
           
            throw faultException;
          }
        }
      } catch(org.jboss.soa.esb.actions.ActionProcessingDetailFaultException fault) {
       
        // Determine whether to abort action pipeline with exception or return
        // fault message for continued processing
        if (_config.getAttribute(ABORT_ON_FAULT, "true").equalsIgnoreCase("true")) {
          logger.debug("Rethrowing BPEL fault: "+fault);
         
          throw fault;
        } else {
          ret = fault.getFaultMessage();
         
          logger.debug("Returning fault as message: "+ret);
        }
       
      } catch(Exception e) {
        logger.error("Failed to parse response '"+resp+"'", e);
      }
    }
   
    logger.debug("Response: "+ret);
   
    return(ret);
  }
 
  /**
   * This class converts a DOM representation node to
   * text.
   *
   * @param node The DOM node
   * @return The text
   * @throws Exception Failed to convert
   */
  protected static String getText(Node node) throws Exception {
    String ret=null;
     
    try {
      // Transform the DOM represent to text
      java.io.ByteArrayOutputStream xmlstr=
          new java.io.ByteArrayOutputStream();
       
      DOMSource source=new DOMSource();
      source.setNode(node);
     
      StreamResult result=new StreamResult(xmlstr);
     
      Transformer trans=
          TransformerFactory.newInstance().newTransformer();
      trans.transform(source, result);
     
      xmlstr.close();
     
      ret = new String(xmlstr.toByteArray());
     
      if ((node instanceof org.w3c.dom.Document) == false) {
       
        // Strip off any <?xml> header
        int index=ret.indexOf("<?xml");
        if (index != -1) {
          index = ret.indexOf("<", 1);
         
          if (index != -1) {
            ret = ret.substring(index);
          } else {
            index = ret.indexOf("?>");
           
            if (index != -1) {
              index += 2;
             
              // Remove any trailing whitespaces
              // after XML header
              while (index < ret.length() &&
                  Character.isWhitespace(ret.charAt(index))) {
                index++;
              }
             
              ret = ret.substring(index);
            }
          }
        }
      }

    } catch(Exception e) {
      throw new Exception("Failed to transform " +
          "DOM representation into text", e);
    }
   
    return(ret);
  }
 
  /**
   * Create an empty message element.
   *
   * @return The new message
   */
  protected org.w3c.dom.Element createMessage() {
    org.w3c.dom.Element ret=null;
   
    try {
      DocumentBuilder builder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
     
      Document doc=builder.newDocument();
     
      ret = doc.createElement(TOP_LEVEL_ELEMENT_NAME);
     
    } catch(Exception e) {
      logger.error("Failed to create message", e);
    }

    return(ret);
  }
 
  /**
   * This method converts the supplied text representation
   * of an XML document into a DOM Node.
   *
   * @param text The text
   * @return The node
   * @throws Exception Failed to convert the text
   */
  protected static Node getNode(String text) throws Exception {
    Node ret=null;
   
    try {
      // Transform the text representation to DOM
      DocumentBuilderFactory fact=DocumentBuilderFactory.newInstance();
      fact.setNamespaceAware(true);
     
      DocumentBuilder builder=fact.newDocumentBuilder();
     
      // Check if XML document, and if not return as text node
      if (text.trim().length() == 0 || text.charAt(0) != '<') {
        org.w3c.dom.Document doc=builder.newDocument();
       
        // Assume is text node
        ret = doc.createTextNode(text);
      } else {
        java.io.InputStream xmlstr=
          new java.io.ByteArrayInputStream(text.getBytes());

        org.w3c.dom.Document doc=builder.parse(xmlstr);
       
        xmlstr.close();
     
        ret = doc.getDocumentElement();
      }
     
    } catch(Exception e) {
      throw new Exception("Failed to transform text " +
          "into DOM representation", e);
    }

    return(ret);
  }

    private final Log logger = LogFactory.getLog(getClass());
}
TOP

Related Classes of org.jboss.soa.esb.actions.bpel.BPELInvoke

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.