| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.axis2.jaxws.server.dispatcher; |
| |
| |
| import org.apache.axis2.AxisFault; |
| import org.apache.axis2.jaxws.ExceptionFactory; |
| import org.apache.axis2.jaxws.binding.BindingUtils; |
| import org.apache.axis2.jaxws.context.utils.ContextUtils; |
| import org.apache.axis2.jaxws.core.MessageContext; |
| import org.apache.axis2.jaxws.core.util.MessageContextUtils; |
| import org.apache.axis2.jaxws.description.EndpointDescription; |
| import org.apache.axis2.jaxws.description.OperationDescription; |
| import org.apache.axis2.jaxws.i18n.Messages; |
| import org.apache.axis2.jaxws.marshaller.MethodMarshaller; |
| import org.apache.axis2.jaxws.marshaller.factory.MethodMarshallerFactory; |
| import org.apache.axis2.jaxws.message.Message; |
| import org.apache.axis2.jaxws.message.Protocol; |
| import org.apache.axis2.jaxws.registry.FactoryRegistry; |
| import org.apache.axis2.jaxws.server.EndpointCallback; |
| import org.apache.axis2.jaxws.server.EndpointInvocationContext; |
| import org.apache.axis2.jaxws.server.InvocationHelper; |
| import org.apache.axis2.jaxws.server.ServerConstants; |
| import org.apache.axis2.jaxws.server.endpoint.Utils; |
| import org.apache.axis2.jaxws.spi.Constants; |
| import org.apache.axis2.jaxws.utility.ExecutorFactory; |
| import org.apache.axis2.jaxws.utility.SingleThreadedExecutor; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import java.lang.reflect.Method; |
| import java.util.concurrent.Executor; |
| import java.util.concurrent.FutureTask; |
| |
| /** |
| * The JavaBeanDispatcher is used to manage creating an instance of a JAX-WS service implementation |
| * bean and dispatching the inbound request to that instance. |
| */ |
| public class JavaBeanDispatcher extends JavaDispatcher { |
| |
| private static final Log log = LogFactory.getLog(JavaBeanDispatcher.class); |
| |
| private EndpointDescription endpointDesc = null; |
| |
| public JavaBeanDispatcher(Class implClass, Object serviceInstance) { |
| super(implClass, serviceInstance); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.apache.axis2.jaxws.server.EndpointDispatcher#invoke(org.apache.axis2.jaxws.core.MessageContext) |
| */ |
| public MessageContext invoke(MessageContext mc) throws Exception { |
| if (log.isDebugEnabled()) { |
| log.debug("Invoking service endpoint: " + serviceImplClass.getName()); |
| log.debug("Invocation pattern: two way, sync"); |
| } |
| |
| initialize(mc); |
| |
| OperationDescription operationDesc = Utils.getOperationDescription(mc); |
| |
| Object[] methodInputParams = createRequestParameters(mc); |
| |
| Method target = getJavaMethod(mc, serviceImplClass); |
| if (log.isDebugEnabled()) { |
| // At this point, the OpDesc includes everything we know, including the actual method |
| // on the service impl we will delegate to; it was set by getJavaMethod(...) above. |
| log.debug("JavaBeanDispatcher about to invoke using OperationDesc: " + |
| operationDesc.toString()); |
| } |
| |
| // We have the method that is going to be invoked and the parameter data to invoke it |
| // with, so just invoke the operation. |
| boolean faultThrown = false; |
| Throwable fault = null; |
| Object output = null; |
| try { |
| output = invokeTargetOperation(target, methodInputParams); |
| } |
| catch (Throwable e) { |
| faultThrown = true; |
| fault = e; |
| } |
| |
| MessageContext response = null; |
| if (operationDesc.isOneWay()) { |
| // If the operation is one-way, then we can just return null because |
| // we cannot create a MessageContext for one-way responses. |
| return null; |
| } else if (faultThrown) { |
| response = createFaultResponse(mc, mc.getMessage().getProtocol(), fault); |
| setExceptionProperties(response, target, fault); |
| } else { |
| response = createResponse(mc, mc.getMessage().getProtocol(), methodInputParams, output); |
| } |
| |
| return response; |
| } |
| |
| public void invokeOneWay(MessageContext request) { |
| if (log.isDebugEnabled()) { |
| log.debug("Invoking service endpoint: " + serviceImplClass.getName()); |
| log.debug("Invocation pattern: one way"); |
| } |
| |
| initialize(request); |
| |
| OperationDescription operationDesc = Utils.getOperationDescription(request); |
| |
| Object[] methodInputParams = createRequestParameters(request); |
| |
| Method target = getJavaMethod(request, serviceImplClass); |
| if (log.isDebugEnabled()) { |
| // At this point, the OpDesc includes everything we know, including the actual method |
| // on the service impl we will delegate to; it was set by getJavaMethod(...) above. |
| log.debug("JavaBeanDispatcher about to invoke using OperationDesc: " |
| + operationDesc.toString()); |
| } |
| |
| EndpointInvocationContext eic = (EndpointInvocationContext) request.getInvocationContext(); |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| |
| AsyncInvocationWorker worker = new AsyncInvocationWorker(target, |
| methodInputParams, |
| cl, eic); |
| FutureTask task = new FutureTask<AsyncInvocationWorker>(worker); |
| |
| ExecutorFactory ef = (ExecutorFactory) FactoryRegistry.getFactory(ExecutorFactory.class); |
| Executor executor = ef.getExecutorInstance(ExecutorFactory.SERVER_EXECUTOR); |
| |
| // If the property has been set to disable thread switching, then we can |
| // do so by using a SingleThreadedExecutor instance to continue processing |
| // work on the existing thread. |
| Boolean disable = (Boolean) |
| request.getProperty(ServerConstants.SERVER_DISABLE_THREAD_SWITCH); |
| if (disable != null && disable.booleanValue()) { |
| if (log.isDebugEnabled()) { |
| log.debug("Server side thread switch disabled. " + |
| "Setting Executor to the SingleThreadedExecutor."); |
| } |
| executor = new SingleThreadedExecutor(); |
| } |
| |
| executor.execute(task); |
| return; |
| } |
| |
| public void invokeAsync(MessageContext request, EndpointCallback callback) { |
| if (log.isDebugEnabled()) { |
| log.debug("Invoking service endpoint: " + serviceImplClass.getName()); |
| log.debug("Invocation pattern: two way, async"); |
| } |
| |
| initialize(request); |
| |
| OperationDescription operationDesc = Utils.getOperationDescription(request); |
| |
| Object[] methodInputParams = createRequestParameters(request); |
| |
| Method target = getJavaMethod(request, serviceImplClass); |
| if (log.isDebugEnabled()) { |
| // At this point, the OpDesc includes everything we know, including the actual method |
| // on the service impl we will delegate to; it was set by getJavaMethod(...) above. |
| log.debug("JavaBeanDispatcher about to invoke using OperationDesc: " |
| + operationDesc.toString()); |
| } |
| |
| EndpointInvocationContext eic = (EndpointInvocationContext) request.getInvocationContext(); |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| |
| AsyncInvocationWorker worker = new AsyncInvocationWorker(target, methodInputParams, cl, eic); |
| FutureTask task = new FutureTask<AsyncInvocationWorker>(worker); |
| |
| ExecutorFactory ef = (ExecutorFactory) FactoryRegistry.getFactory(ExecutorFactory.class); |
| Executor executor = ef.getExecutorInstance(ExecutorFactory.SERVER_EXECUTOR); |
| // If the property has been set to disable thread switching, then we can |
| // do so by using a SingleThreadedExecutor instance to continue processing |
| // work on the existing thread. |
| Boolean disable = (Boolean) request.getProperty(ServerConstants.SERVER_DISABLE_THREAD_SWITCH); |
| if (disable != null && disable.booleanValue()) { |
| if (log.isDebugEnabled()) { |
| log.debug("Server side thread switch disabled. Setting Executor to the SingleThreadedExecutor."); |
| } |
| executor = new SingleThreadedExecutor(); |
| } |
| executor.execute(task); |
| |
| return; |
| } |
| |
| protected void initialize(MessageContext mc) { |
| mc.setOperationName(mc.getAxisMessageContext().getAxisOperation().getName()); |
| mc.setOperationDescription(Utils.getOperationDescription(mc)); |
| endpointDesc = mc.getEndpointDescription(); |
| if (endpointDesc.isMTOMEnabled()) { |
| mc.getMessage().setMTOMEnabled(true); |
| } |
| |
| |
| //Set SOAP Operation Related properties in SOAPMessageContext. |
| ContextUtils.addWSDLProperties(mc); |
| } |
| |
| private MethodMarshaller getMethodMarshaller(Protocol protocol, |
| OperationDescription operationDesc, |
| MessageContext mc) { |
| javax.jws.soap.SOAPBinding.Style styleOnSEI = |
| endpointDesc.getEndpointInterfaceDescription().getSoapBindingStyle(); |
| javax.jws.soap.SOAPBinding.Style styleOnMethod = operationDesc.getSoapBindingStyle(); |
| if (styleOnMethod != null && styleOnSEI != styleOnMethod) { |
| throw ExceptionFactory.makeWebServiceException(Messages.getMessage("proxyErr2")); |
| } |
| |
| // check for a stored classloader to be used as the cache key |
| ClassLoader cl = null; |
| if(mc != null) { |
| cl = (ClassLoader) mc.getProperty(Constants.CACHE_CLASSLOADER); |
| } |
| return MethodMarshallerFactory.getMarshaller(operationDesc, false, cl); |
| } |
| |
| protected Method getJavaMethod(MessageContext mc, Class serviceImplClass) { |
| |
| OperationDescription opDesc = mc.getOperationDescription(); |
| if (opDesc == null) { |
| throw ExceptionFactory.makeWebServiceException(Messages.getMessage("proxyErr3")); |
| } |
| |
| Method returnMethod = opDesc.getMethodFromServiceImpl(serviceImplClass); |
| if (returnMethod == null) { |
| throw ExceptionFactory |
| .makeWebServiceException(Messages.getMessage("JavaBeanDispatcherErr1")); |
| } |
| |
| return returnMethod; |
| } |
| |
| private Object[] createRequestParameters(MessageContext request) { |
| // Get the appropriate MethodMarshaller for the WSDL type. This will reflect |
| // the "style" and "use" of the WSDL. |
| Protocol requestProtocol = request.getMessage().getProtocol(); |
| MethodMarshaller methodMarshaller = |
| getMethodMarshaller(requestProtocol, request.getOperationDescription(), |
| request); |
| |
| // The MethodMarshaller will return the input parameters that are needed to |
| // invoke the target method. |
| Object[] methodInputParams = |
| methodMarshaller.demarshalRequest(request.getMessage(), request.getOperationDescription()); |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Unmarshalled parameters for request"); |
| if (methodInputParams != null) { |
| log.debug(methodInputParams.length + " parameters were found."); |
| } |
| } |
| |
| return methodInputParams; |
| } |
| |
| public MessageContext createResponse(MessageContext request, Object[] input, Object output) { |
| return createResponse(request, request.getMessage().getProtocol(), input, output); |
| } |
| |
| public MessageContext createResponse(MessageContext request, Protocol p, Object[] params, Object output) { |
| OperationDescription operationDesc = request.getOperationDescription(); |
| Method method = operationDesc.getMethodFromServiceImpl(serviceImplClass); |
| |
| // Create the appropriate response message, using the protocol from the |
| // request message. |
| MethodMarshaller marshaller = getMethodMarshaller(p, request.getOperationDescription(), |
| request); |
| Message m = null; |
| if (method.getReturnType().getName().equals("void")) { |
| m = marshaller.marshalResponse(null, params, operationDesc, p); |
| } else { |
| m = marshaller.marshalResponse(output, params, operationDesc, p); |
| } |
| |
| // We'll need a MessageContext configured based on the response. |
| MessageContext response = MessageContextUtils.createResponseMessageContext(request); |
| response.setMessage(m); |
| |
| // Enable MTOM for the response if necessary. |
| // (MTOM is not enabled it this operation has SWA parameters |
| |
| EndpointDescription epDesc = request.getEndpointDescription(); |
| String bindingType = epDesc.getBindingType(); |
| boolean isMTOMBinding = epDesc.isMTOMEnabled(); |
| boolean isDoingSWA = m.isDoingSWA(); |
| if (log.isDebugEnabled()) { |
| log.debug("EndpointDescription = " + epDesc.toString()); |
| log.debug("BindingType = " + bindingType); |
| log.debug("isMTOMBinding = " + isMTOMBinding); |
| log.debug("isDoingSWA = " + isDoingSWA); |
| } |
| if (!m.isDoingSWA() && isMTOMBinding) { |
| if (log.isDebugEnabled()) { |
| log.debug("MTOM enabled for the response message."); |
| } |
| m.setMTOMEnabled(true); |
| } |
| |
| return response; |
| } |
| |
| public MessageContext createFaultResponse(MessageContext request, Throwable t) { |
| return createFaultResponse(request, request.getMessage().getProtocol(), t); |
| } |
| |
| public MessageContext createFaultResponse(MessageContext request, Protocol p, Throwable t) { |
| |
| // call the InvocationListener instances before marshalling |
| // the fault into a message |
| // call the InvocationListener instances before marshalling |
| // the fault into a message |
| Throwable faultMessage = InvocationHelper.determineMappedException(t, request); |
| if(faultMessage != null) { |
| t = faultMessage; |
| } |
| |
| MethodMarshaller marshaller = getMethodMarshaller(p, request.getOperationDescription(), |
| request); |
| |
| Message m = marshaller.marshalFaultResponse(t, request.getOperationDescription(), p); |
| |
| MessageContext response = MessageContextUtils.createFaultMessageContext(request); |
| response.setMessage(m); |
| |
| AxisFault axisFault = new AxisFault("The endpoint returned a fault when invoking the target operation.", |
| response.getAxisMessageContext(), |
| t); |
| |
| response.setCausedByException(axisFault); |
| |
| setFaultResponseAction(t, request, response); |
| |
| return response; |
| } |
| |
| } |