Package org.jboss.soa.bpel.runtime.ws

Source Code of org.jboss.soa.bpel.runtime.ws.WebServiceClient

/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.soa.bpel.runtime.ws;

import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.UserTransaction;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.bpel.iapi.Message;
import org.apache.ode.bpel.iapi.MessageExchange;
import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
import org.apache.ode.bpel.iapi.ProcessConf;
import org.apache.ode.bpel.iapi.Scheduler;
import org.apache.ode.utils.DOMUtils;
import org.apache.ode.utils.Properties;
import org.jboss.soa.bpel.runtime.engine.EndpointReference;
import org.jboss.soa.bpel.runtime.engine.PartnerChannel;
import org.jboss.soa.bpel.runtime.engine.ode.BPELEngineImpl;
import org.jboss.soa.bpel.runtime.engine.ode.ExecutionEnvironment;
import org.jboss.soa.bpel.runtime.engine.ode.UDDIClientFactory;
import org.jboss.soa.bpel.runtime.engine.ode.UDDIRegistration;
import org.jboss.soa.dsp.EndpointMetaData;
import org.jboss.soa.dsp.server.ServerConfig;
import org.jboss.soa.bpel.runtime.JBossDSPFactory;
import org.jboss.soa.dsp.ws.DOMWriter;
import org.jboss.soa.dsp.ws.JavaUtils;
import org.jboss.soa.dsp.ws.SOAPMessageAdapter;
import org.jboss.soa.dsp.ws.WSDLReference;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
* Represents a WS invocation.
* Delegates to a JAX-WS {@link javax.xml.ws.Dispatch} implementation.
*
* @author Heiko.Braun <heiko.braun@jboss.com>
*/
public class WebServiceClient implements PartnerChannel
{
  private static final String JAXWS_CLIENT_INITIALIZER = "jaxws.client.initializer.impl";

  protected final Log log = LogFactory.getLog(getClass());
  private boolean isInitialized=false;
  private BPELEngineImpl engine;
  private UDDIRegistration uddiRegistration = null;
  private URL wsdlUrl;

  private String id;

  private Dispatch<SOAPMessage> dispatcher = null;
  private EndpointMetaData metaData = null;
  private Definition wsdlDefinition;

  private final QName serviceName;
  private final QName port;

  private SOAPMessageAdapter messageAdapter;

  private ExecutionEnvironment executionEnvironment;
  private java.net.URI baseURI;
 
  private long timeout=Properties.DEFAULT_MEX_TIMEOUT;
 
  public WebServiceClient(EndpointMetaData metaData, ExecutionEnvironment env,
      BPELEngineImpl engine, ProcessConf pconf)
  {
  this.engine = engine;
    this.executionEnvironment = env;
    this.metaData = metaData;
    this.uddiRegistration = executionEnvironment.getUDDIRegistration();

    this.id = metaData.getEndpointId();
    this.serviceName = metaData.getServiceName();
    this.port = new QName(serviceName.getNamespaceURI(), metaData.getPortName());
   
    this.baseURI = pconf.getBaseURI();
   
    log.debug("Web Service Client: Base URI="+pconf.getBaseURI());
   
    String mextimeout = pconf.getEndpointProperties(serviceName, metaData.getPortName()).get(Properties.PROP_MEX_TIMEOUT);
   
    if (mextimeout != null) {
        try {
            this.timeout = Long.parseLong(mextimeout);
            log.debug("Web Service Client: Timeout="+timeout);
        } catch (NumberFormatException e) {
            if(log.isWarnEnabled()) log.warn("Mal-formatted Property: ["+ Properties.PROP_MEX_TIMEOUT+"="+mextimeout+"] Default value ("+Properties.DEFAULT_MEX_TIMEOUT+") will be used");
        }
    }
  }
 
  private synchronized void initialize() {
 
      WSDLReference wsdlReference = new WSDLHelper().createWSDLReference(engine,
          metaData.getProcessId(), metaData.getServiceName(), metaData.getPortName());
      wsdlDefinition = wsdlReference.getDefinition();
      wsdlUrl = wsdlReference.getWsdlURL();
   
      this.messageAdapter = new SOAPMessageAdapter(this.wsdlDefinition, serviceName, port.getLocalPart());   
    isInitialized=true;
  }

  public EndpointReference getEndpointReference()
  {
    return new ClientEndpointReference(this.id);
  }


  public void invoke(final PartnerRoleMessageExchange mex)
  {
    if (!isInitialized) initialize();
      log.debug("Invoking dispatcher "+this.id);
   
   
    boolean isTwoWay = mex.getMessageExchangePattern()
        == org.apache.ode.bpel.iapi.MessageExchange.MessageExchangePattern.REQUEST_RESPONSE;
   
    final Callable executionCallable;
   
    if(isTwoWay)
    {
      // Defer the invoke until the transaction commits.
      Scheduler scheduler = executionEnvironment.getScheduler();
      executionCallable = new TwoWayCallable(mex.getMessageExchangeId());
      scheduler.registerSynchronizer(new Scheduler.Synchronizer() {

            public void afterCompletion(boolean success)
            {
              // If the TX is rolled back, then we don't send the request.
              if (!success) return;

              // The invocation must happen in a separate thread, holding on the afterCompletion
              // blocks other operations that could have been listed there as well.
              ExecutorService executorService = executionEnvironment.getExecutorService();
              executorService.submit(executionCallable);
            }
           
            public void beforeCompletion(){}
          }
      );

      mex.replyAsync();
    }
    else
    {
      // one-way invocation, also defer the invoke until the transaction commits.
      Scheduler scheduler = executionEnvironment.getScheduler();
      executionCallable = new OneWayCallable(mex.getMessageExchangeId());
     
      scheduler.registerSynchronizer(new Scheduler.Synchronizer() {
   
    public void beforeCompletion() {
     
    }
   
    public void afterCompletion(boolean success) {
      if (!success) return;
     
        ExecutorService executorService = executionEnvironment.getExecutorService();
        executorService.submit(executionCallable);
    }
  });
     
      mex.replyOneWayOk();
    }
  }
 
  private class TwoWayCallable implements Callable<Object> {
 
  private String mexId; 
   
    public TwoWayCallable(String mexId) {
      this.mexId = mexId;
   
   
  public Object call() throws Exception {
   
    return executionEnvironment.getScheduler().execTransaction(new Callable<Object>(){

      public Object call() throws Exception {
        //We need to get a new mex from persistence layer.
        PartnerRoleMessageExchange mex = (PartnerRoleMessageExchange) engine.getBpelServer().getEngine().getMessageExchange(mexId);
            try
            {
              // Create SOAPMessage
              SOAPMessage soapRequestMessage = MessageFactory.newInstance().createMessage();
              if(log.isDebugEnabled())
                log.debug( "ODE outbound message: \n" +DOMWriter.printNode(mex.getRequest().getMessage(), true) );
             
              String soapAction=messageAdapter.createSoapRequest(soapRequestMessage,
                      new ODEMessageAdapter(mex.getRequest()), mex.getOperation());
             
              if (log.isDebugEnabled()) {
                log.debug("Riftsaw soap request message: \n" + JavaUtils.getSoapMessageASString(soapRequestMessage));
              }
             
              org.apache.ode.bpel.iapi.EndpointReference odeepr=mex.getEndpointReference();
              javax.xml.ws.EndpointReference epr=null;
             
              if (odeepr != null) {
                if (odeepr instanceof org.apache.ode.bpel.epr.URLEndpoint) {
                  org.apache.ode.bpel.epr.URLEndpoint url=(org.apache.ode.bpel.epr.URLEndpoint)odeepr;
                 
                  javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder builder=
                        new javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder();
                 
                  epr = builder.address(url.getUrl())
                          .serviceName(serviceName)
                          .endpointName(port)
                          .build();
                 
                  if (log.isDebugEnabled()) {
                    log.debug("EPR = " + epr);
                  }
                }
               
              } else if (log.isDebugEnabled()) {
                log.debug("ODE has no EPR for this message exchange");
              }
             
              // The actual WS invocation
              Dispatch<SOAPMessage> proxy = getDispatcher(epr, port);
              setEndpointFromUDDI(proxy);
             
              try {
                // Set SOAPAction
                if (soapAction != null) {
                  // Setting soap action using both approaches, as CXF needs one and JBossWS-Native the other
                  proxy.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, soapAction);
                  MimeHeaders hd = soapRequestMessage.getMimeHeaders();
                  hd.addHeader("SOAPAction", soapAction);
                } else if (log.isDebugEnabled()) {
                  log.debug("SOAPAction not set");
                }

                // Set client side timeout for the invocation
                proxy.getRequestContext().put("javax.xml.ws.client.receiveTimeout", Long.toString(timeout));
               
                  SOAPMessage soapResponseMessage = proxy.invoke(soapRequestMessage);

                  if (log.isDebugEnabled()) {
                    log.debug("Riftsaw soap response message: \n" + JavaUtils.getSoapMessageASString(soapResponseMessage));
                  }
                 
                  // Create ODE response
                  Message odeResponse = mex.createMessage(mex.getOperation().getOutput().getMessage().getQName());
                  if(soapResponseMessage.getSOAPBody().hasFault())
                  {
                    // fault handling
                    Document odeMsg = DOMUtils.newDocument();
                    Element odeMsgEl = odeMsg.createElementNS(null, "message");
                    odeMsg.appendChild(odeMsgEl);
                   
                    Fault fault = messageAdapter.parseSoapFault(odeMsgEl, soapResponseMessage, mex.getOperation());

                    handleFault(mex, fault, soapResponseMessage.getSOAPBody().getFault(), odeMsgEl);
                   
                  }
                  else
                  {
                    messageAdapter.parseSoapResponse(new ODEMessageAdapter(odeResponse),
                            soapResponseMessage,mex.getOperation());
                    mex.reply(odeResponse);
                  }

                  if(log.isDebugEnabled())
                    log.debug( "ODE inbound message: \n" +DOMWriter.printNode(odeResponse.getMessage(), true) );
                 
              } catch(javax.xml.ws.soap.SOAPFaultException fe) {
               
                    // fault handling
                    Document odeMsg = DOMUtils.newDocument();
                    Element odeMsgEl = odeMsg.createElementNS(null, "message");
                    odeMsg.appendChild(odeMsgEl);
                   
                  if (log.isDebugEnabled()) {
                    log.debug("Riftsaw soap fault: \n" + DOMWriter.printNode(fe.getFault(), true));
                  }
                 
                    Fault fault=messageAdapter.parseSoapFault(odeMsgEl, fe.getFault(),
                                mex.getOperation());

                    handleFault(mex, fault, fe.getFault(), odeMsgEl);
              }
            }
            catch (Throwable e)
            {
              log.error("WS invocation failed", e);
              mex.replyWithFailure(MessageExchange.FailureType.COMMUNICATION_ERROR, e.getMessage(), null);
            }
            return null;
      }
           
    });
      }
  }
 
 
  private class OneWayCallable implements Callable<Object> {
 
  private String mexId; 
   
    public OneWayCallable(String mexId) {
      this.mexId = mexId;
    }   
   
  public Object call() throws Exception {
    return executionEnvironment.getScheduler().execTransaction(new Callable<Object>(){

      public Object call() throws Exception {
        //We need to get a new mex from persistence layer.
        PartnerRoleMessageExchange mex = (PartnerRoleMessageExchange) engine.getBpelServer().getEngine().getMessageExchange(mexId);
                try
                {
                  // Create SOAPMessage
                  SOAPMessage soapRequestMessage = MessageFactory.newInstance().createMessage();
                  if(log.isDebugEnabled())
                    log.debug( "ODE outbound message: \n" +DOMWriter.printNode(mex.getRequest().getMessage(), true) );
                 
              String soapAction=messageAdapter.createSoapRequest(soapRequestMessage,
                          new ODEMessageAdapter(mex.getRequest()), mex.getOperation());

                  if (log.isDebugEnabled()) {
                    log.debug("Riftsaw soap request message: \n" + JavaUtils.getSoapMessageASString(soapRequestMessage));
                  }
                 
                org.apache.ode.bpel.iapi.EndpointReference odeepr=mex.getEndpointReference();
                javax.xml.ws.EndpointReference epr=null;
               
                if (odeepr != null) {
                  if (odeepr instanceof org.apache.ode.bpel.epr.URLEndpoint) {
                    org.apache.ode.bpel.epr.URLEndpoint url=(org.apache.ode.bpel.epr.URLEndpoint)odeepr;
                   
                    javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder builder=
                          new javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder();
                   
                    epr = builder.address(url.getUrl())
                            .serviceName(serviceName)
                            .endpointName(port)
                            .build();
                   
                    if (log.isDebugEnabled()) {
                      log.debug("EPR = " + epr);
                    }
                  }
                 
                } else if (log.isDebugEnabled()) {
                  log.debug("ODE has no EPR for this message exchange");
                }
               
                  // The actual WS invocation
                  Dispatch<SOAPMessage> proxy = getDispatcher(epr, port);
                  setEndpointFromUDDI(proxy);
                 
                  // Set SOAPAction
                  if (soapAction != null) {
                    // Setting soap action using both approaches, as CXF needs one and JBossWS-Native the other
                    proxy.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, soapAction);
                    MimeHeaders hd = soapRequestMessage.getMimeHeaders();
                    hd.addHeader("SOAPAction", soapAction);
                  } else if (log.isDebugEnabled()) {
                    log.debug("SOAPAction not set");
                  }
                 
                  proxy.invokeOneWay(soapRequestMessage);

                }
                catch (Throwable e)
                {
                  log.error("WS invocation failed", e);
                  mex.replyWithFailure(MessageExchange.FailureType.COMMUNICATION_ERROR, e.getMessage(), null);
                }

                return null;
      }     
     
    });
  }
   
  }

 
  private void handleFault(PartnerRoleMessageExchange mex, Fault fault, SOAPFault soapFault,
                    Element odeMsgEl) {
      if (fault != null)
      {
        if (log.isWarnEnabled())
          log.warn("Fault response: faultName="
              + fault.getName() + " faultType=" + fault.getMessage().getQName()
              + "\n" + DOMWriter.printNode(odeMsgEl, true));

        QName faultType = fault.getMessage().getQName();
        QName faultName = new QName(wsdlDefinition.getTargetNamespace(), fault.getName());
        Message response = mex.createMessage(faultType);
        response.setMessage(odeMsgEl);

        mex.replyWithFault(faultName, response);
      }
      else
      {
        if (log.isWarnEnabled())
          log.warn("Fault response: faultType=(unknown)");

        mex.replyWithFailure(MessageExchange.FailureType.OTHER, "Unspecified", soapFault.getDetail());
      }
  }

  private UserTransaction getUserTransaction()
      throws NamingException
  {
    InitialContext ctx = new InitialContext();
    UserTransaction tx = (UserTransaction)ctx.lookup("UserTransaction");
    return tx;
  }

  public Element invoke(String operation, Element mesg) throws Exception
  {
    throw new RuntimeException("Not implemented. Should be removed form interface");
  }

  private synchronized Dispatch<SOAPMessage> getDispatcher(javax.xml.ws.EndpointReference epr, QName portName)
  {
  
   if(null==dispatcher) {
     
      log.debug("Creating Dispatcher ("+this.id+") on " + wsdlUrl + ": "+serviceName);
      JAXWSInitializer initializer=initializeStack(portName);

      Service service = Service.create(this.wsdlUrl, serviceName);
     
      if (epr != null) {
          dispatcher = service.createDispatch(
                  epr,
                  SOAPMessage.class,
                  Service.Mode.MESSAGE,
                  new javax.xml.ws.soap.AddressingFeature()
              );
      } else {
          dispatcher = service.createDispatch(
                  portName,
                  SOAPMessage.class,
                  Service.Mode.MESSAGE
              );
      }
     
      if (initializer != null) {
        initializer.serviceCreated();
      }
    }
    return dispatcher;
  }
 
  private synchronized JAXWSInitializer initializeStack(QName portName) {
    JAXWSInitializer initializer=null;
    String impl=this.executionEnvironment.getOdeConfig().getProperty(JAXWS_CLIENT_INITIALIZER);

    if (impl != null && impl.trim().length() > 0) {
     
      try {
        Class<?> cls=Class.forName(impl);
       
        initializer = (JAXWSInitializer)cls.newInstance();
       
      } catch(Exception e) {
        log.error("Unable to obtain JAXWS Initializer class '"+impl+"'", e);
      }
     
      if (initializer != null) {
        initializer.initializeStack(this.serviceName, portName, this.baseURI);
      }
    } else {
      log.debug("JAXWS Client Initializer not defined");
    }
   
    return(initializer);
  }
 
  private void setEndpointFromUDDI(Dispatch<SOAPMessage> proxy) {
    if (uddiRegistration!=null) {
        String endpoint = uddiRegistration.lookupEndpoint(serviceName, port.getLocalPart());
        if (endpoint!=null) {
          proxy.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint);
        } else {
          log.debug("Could not find endpoint in UDDI registry for service " + serviceName.getLocalPart());
        }
      }
  }

  public String toString()
  {
    return "WebServiceClient {service="+serviceName+",port="+port+"}";
  }
 

}
TOP

Related Classes of org.jboss.soa.bpel.runtime.ws.WebServiceClient

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.