Package org.jboss.ws.core.jaxws.client

Source Code of org.jboss.ws.core.jaxws.client.DispatchImpl$AsyncRunnable

/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt 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.ws.core.jaxws.client;

// $Id: DispatchImpl.java 8542 2008-10-22 15:00:04Z alessio.soldano@jboss.com $

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import javax.xml.bind.JAXBContext;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.Response;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.Service.Mode;
import javax.xml.ws.http.HTTPBinding;
import javax.xml.ws.soap.SOAPFaultException;

import org.jboss.logging.Logger;
import org.jboss.util.NotImplementedException;
import org.jboss.ws.core.CommonMessageContext;
import org.jboss.ws.core.MessageAbstraction;
import org.jboss.ws.core.ConfigProvider;
import org.jboss.ws.core.client.HTTPRemotingConnection;
import org.jboss.ws.core.client.RemotingConnection;
import org.jboss.ws.core.client.SOAPRemotingConnection;
import org.jboss.ws.core.jaxws.binding.BindingProviderImpl;
import org.jboss.ws.core.jaxws.handler.SOAPMessageContextJAXWS;
import org.jboss.ws.core.soap.MessageContextAssociation;
import org.jboss.ws.metadata.umdm.EndpointMetaData;
import org.jboss.ws.metadata.config.ConfigurationProvider;

/**
* The Dispatch interface provides support for the dynamic invocation of a service endpoint operations.
* The javax.xml.ws.Service interface acts as a factory for the creation of Dispatch  instances.
*
* @author Thomas.Diesler@jboss.com
* @since 04-Jul-2006
*/
public class DispatchImpl<T> implements Dispatch<T>
{
   // provide logging
   private final Logger log = Logger.getLogger(DispatchImpl.class);

   private BindingProvider bindingProvider;
   private EndpointMetaData epMetaData;
   private JAXBContext jaxbContext;
   private ExecutorService executor;
   private Class type;
   private Mode mode;

   public DispatchImpl(ExecutorService executor, EndpointMetaData epMetaData, Class<T> type, Mode mode)
   {
      this.bindingProvider = new BindingProviderImpl(epMetaData);
      this.epMetaData = epMetaData;
      this.executor = executor;
      this.type = type;
      this.mode = mode;
      initDispatch();
   }

   public DispatchImpl(ExecutorService executor, EndpointMetaData epMetaData, JAXBContext jbc, Mode mode)
   {
      this.bindingProvider = new BindingProviderImpl(epMetaData);
      this.epMetaData = epMetaData;
      this.executor = executor;
      this.type = Object.class;
      this.jaxbContext = jbc;
      this.mode = mode;
      initDispatch();
   }

   public T invoke(T obj)
   {
      T retObj = null;
      try
      {
         retObj = (T)invokeInternal(obj, getResponseContext());
      }
      catch (Exception ex)
      {
         handleInvokeException(ex);
      }
      return retObj;
   }

   private Object invokeInternal(Object obj, Map<String, Object> resContext) throws IOException
   {
      MessageAbstraction reqMsg = getRequestMessage(obj);
      String targetAddress = epMetaData.getEndpointAddress();
     
      // R2744 A HTTP request MESSAGE MUST contain a SOAPAction HTTP header field
      // with a quoted value equal to the value of the soapAction attribute of
      // soapbind:operation, if present in the corresponding WSDL description.

      // R2745 A HTTP request MESSAGE MUST contain a SOAPAction HTTP header field
      // with a quoted empty string value, if in the corresponding WSDL description,
      // the soapAction attribute of soapbind:operation is either not present, or
      // present with an empty string as its value.
      String bindingID = bindingProvider.getBinding().getBindingID();
      if (bindingID.indexOf("soap") > 0)
      {
         String soapAction = null;
         Map<String, Object> reqContext = getRequestContext();
         Boolean useSOAPAction = (Boolean)reqContext.get(BindingProvider.SOAPACTION_USE_PROPERTY);
         if (Boolean.TRUE.equals(useSOAPAction))
         {
            soapAction = (String)reqContext.get(BindingProvider.SOAPACTION_URI_PROPERTY);
            if (soapAction == null)
               throw new IllegalStateException("Cannot obtain: " + BindingProvider.SOAPACTION_URI_PROPERTY);
         }
         MimeHeaders mimeHeaders = reqMsg.getMimeHeaders();
         mimeHeaders.addHeader("SOAPAction", soapAction != null ? soapAction : "");
      }
     
      MessageAbstraction resMsg = getRemotingConnection().invoke(reqMsg, targetAddress, false);
      Object retObj = getReturnObject(resMsg);
      return retObj;
   }

   private RemotingConnection getRemotingConnection()
   {
      String bindingID = bindingProvider.getBinding().getBindingID();
      if (EndpointMetaData.SUPPORTED_BINDINGS.contains(bindingID) == false)
         throw new IllegalStateException("Unsupported binding: " + bindingID);

      RemotingConnection remotingConnection;
      if (HTTPBinding.HTTP_BINDING.equals(bindingID))
      {
         remotingConnection = new HTTPRemotingConnection();
      }
      else
      {
         remotingConnection = new SOAPRemotingConnection();
      }
      return remotingConnection;
   }

   public Response<T> invokeAsync(T msg)
   {
      ResponseImpl response = new ResponseImpl();
      Runnable task = new AsyncRunnable(response, null, msg);
      Future future = executor.submit(task);
      response.setFuture(future);
      return response;
   }

   public Future invokeAsync(T obj, AsyncHandler<T> handler)
   {
      ResponseImpl response = new ResponseImpl();
      Runnable task = new AsyncRunnable(response, handler, obj);
      Future future = executor.submit(task);
      response.setFuture(future);
      return response;
   }

   public void invokeOneWay(T msg)
   {
      CommonMessageContext msgContext = new SOAPMessageContextJAXWS();
      MessageContextAssociation.pushMessageContext(msgContext);
      msgContext.setEndpointMetaData(epMetaData);
      try
      {
         MessageAbstraction reqMsg = getRequestMessage(msg);
         String targetAddress = epMetaData.getEndpointAddress();
         getRemotingConnection().invoke(reqMsg, targetAddress, true);
      }
      catch (Exception ex)
      {
         handleInvokeException(ex);
      }
      finally
      {
         MessageContextAssociation.popMessageContext();
      }
   }

   // 4.17. Conformance (Failed Dispatch.invoke): When an operation is invoked using an invoke method, an
   // implementation MUST throw a WebServiceException if there is any error in the configuration of the
   // Dispatch instance or a ProtocolException if an error occurs during the remote operation invocation.
   //
   // 4.19  Conformance (Failed Dispatch.invokeOneWay): When an operation is invoked using an invoke-
   // OneWay method, an implementation MUST throw a WebServiceException if there is any error in the
   // configuration of the Dispatch instance or if an error is detected1 during the remote operation invocation.
   private void handleInvokeException(Exception ex)
   {
      if (ex instanceof WebServiceException)
      {
         throw (WebServiceException)ex;
      }

      String msg = "Cannot dispatch message";
      log.error(msg, ex);
      throw new WebServiceException(msg, ex);
   }

   public Map<String, Object> getRequestContext()
   {
      return bindingProvider.getRequestContext();
   }

   public Map<String, Object> getResponseContext()
   {
      return bindingProvider.getResponseContext();
   }

   public Binding getBinding()
   {
      return bindingProvider.getBinding();
   }

   private void initDispatch()
   {
      if (SOAPMessage.class.isAssignableFrom(type) && mode == Mode.MESSAGE)
      {
         // accepted
      }
      else if (Source.class.isAssignableFrom(type))
      {
         // accepted
      }
      else if (jaxbContext != null && mode == Mode.PAYLOAD)
      {
         // accepted
      }
      else
      {
         throw new WebServiceException("Illegal argument combination [type=" + (type != null ? type.getName() : null) + ",mode=" + mode + "]");
      }
   }

   private MessageAbstraction getRequestMessage(Object obj)
   {
      // jaxws/api/javax_xml_ws/Dispatch/Client.java#invokeTestJAXBNull
      if (obj == null)
         throw new SOAPFaultException("Request object cannot be null");

      String bindingID = bindingProvider.getBinding().getBindingID();
      if (EndpointMetaData.SUPPORTED_BINDINGS.contains(bindingID) == false)
         throw new IllegalStateException("Unsupported binding: " + bindingID);

      MessageAbstraction message;
      if (HTTPBinding.HTTP_BINDING.equals(bindingID))
      {
         DispatchHTTPBinding helper = new DispatchHTTPBinding(mode, type, jaxbContext);
         ((ConfigurationProvider)epMetaData).configure(helper);
         message = helper.getRequestMessage(obj);
      }
      else
      {
         DispatchSOAPBinding helper = new DispatchSOAPBinding(mode, type, jaxbContext);
         ((ConfigurationProvider)epMetaData).configure(helper);
         message = helper.getRequestMessage(obj);
      }
      return message;
   }

   private Object getReturnObject(MessageAbstraction resMsg)
   {
      String bindingID = bindingProvider.getBinding().getBindingID();
      if (EndpointMetaData.SUPPORTED_BINDINGS.contains(bindingID) == false)
         throw new IllegalStateException("Unsupported binding: " + bindingID);

      Object retObj = null;
      if (HTTPBinding.HTTP_BINDING.equals(bindingID))
      {
         DispatchHTTPBinding helper = new DispatchHTTPBinding(mode, type, jaxbContext);
         retObj = helper.getReturnObject(resMsg);
      }
      else
      {
         DispatchSOAPBinding helper = new DispatchSOAPBinding(mode, type, jaxbContext);
         retObj = helper.getReturnObject(resMsg);
      }
      return retObj;
   }

   class AsyncRunnable implements Runnable
   {
      private ResponseImpl response;
      private AsyncHandler handler;
      private Object payload;

      public AsyncRunnable(ResponseImpl response, AsyncHandler handler, Object payload)
      {
         if (response == null)
            throw new IllegalArgumentException("Async response cannot be null");
         if (payload == null)
            throw new IllegalArgumentException("Async payload cannot be null");
        
         this.response = response;
         this.handler = handler;
         this.payload = payload;
      }

      public void run()
      {
         try
         {
            Map<String, Object> resContext = response.getContext();
            Object result = invokeInternal(payload, resContext);
            response.set(result);
         }
         catch (Exception ex)
         {
            handleAsynInvokeException(ex);
         }
         finally
         {
            // Call the handler if available
            if (handler != null)
               handler.handleResponse(response);
         }
      }

      // 4.18 Conformance (Failed Dispatch.invokeAsync): When an operation is invoked using an invokeAsync
      // method, an implementation MUST throw a WebServiceException if there is any error in the configuration
      // of the Dispatch instance. Errors that occur during the invocation are reported when the client
      // attempts to retrieve the results of the operation.
      private void handleAsynInvokeException(Exception ex)
      {
         String msg = "Cannot dispatch message";
         log.error(msg, ex);

         WebServiceException wsex;
         if (ex instanceof WebServiceException)
         {
            wsex = (WebServiceException)ex;
         }
         else
         {
            wsex = new WebServiceException(msg, ex);
         }
         response.setException(wsex);
      }
   }

   public EndpointReference getEndpointReference()
   {
      throw new NotImplementedException();
   }

   public <T extends EndpointReference> T getEndpointReference(Class<T> clazz)
   {
      throw new NotImplementedException();
   }
}
TOP

Related Classes of org.jboss.ws.core.jaxws.client.DispatchImpl$AsyncRunnable

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.