alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Axis 2 example source code file (ProviderDispatcher.java)

This example Axis 2 source code file (ProviderDispatcher.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Axis 2 tags/keywords

block, blockfactory, class, class, exception, exception, message, message, messagecontext, object, provider, provider, reflection, security, soapmessage, type, xml

The Axis 2 ProviderDispatcher.java source code

/*
 * 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.jaxws.ExceptionFactory;
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.i18n.Messages;
import org.apache.axis2.jaxws.marshaller.impl.alt.MethodMarshallerUtils;
import org.apache.axis2.jaxws.message.Block;
import org.apache.axis2.jaxws.message.Message;
import org.apache.axis2.jaxws.message.Protocol;
import org.apache.axis2.jaxws.message.XMLFault;
import org.apache.axis2.jaxws.message.factory.BlockFactory;
import org.apache.axis2.jaxws.message.factory.MessageFactory;
import org.apache.axis2.jaxws.message.factory.SOAPEnvelopeBlockFactory;
import org.apache.axis2.jaxws.message.factory.SourceBlockFactory;
import org.apache.axis2.jaxws.message.factory.XMLStringBlockFactory;
import org.apache.axis2.jaxws.registry.FactoryRegistry;
import org.apache.axis2.jaxws.server.EndpointController;
import org.apache.axis2.jaxws.utility.ClassUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.activation.DataSource;
import javax.xml.bind.JAXBContext;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.PrivilegedExceptionAction;

/**
 * The ProviderDispatcher is used to invoke instances of a target endpoint that implement the {@link
 * javax.xml.ws.Provider} interface.
 * <p/>
 * The Provider<T> is a generic class, with certain restrictions on the parameterized type T.  This
 * implementation supports the following types:
 * <p/>
 * java.lang.String javax.activation.DataSource javax.xml.soap.SOAPMessage
 * javax.xml.transform.Source
 */
public class ProviderDispatcher extends JavaDispatcher {

    private static Log log = LogFactory.getLog(ProviderDispatcher.class);

    private BlockFactory blockFactory = null;
    private Class providerType = null;
    private Provider providerInstance = null;
    private Service.Mode providerServiceMode = null;
    private Message message = null;
    private Protocol messageProtocol;


    /**
     * Constructor
     *
     * @param _class
     * @param serviceInstance
     */
    public ProviderDispatcher(Class _class, Object serviceInstance) {
        super(_class, serviceInstance);
    }

    /* (non-Javadoc)
    * @see org.apache.axis2.jaxws.server.EndpointDispatcher#execute()
    */
    public MessageContext invoke(final MessageContext mc) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Preparing to invoke javax.xml.ws.Provider based endpoint");
        }

        providerInstance = getProviderInstance();

        // First we need to know what kind of Provider instance we're going
        // to be invoking against
        providerType = getProviderType();

        // REVIEW: This assumes there is only one endpoint description on the service.  Is that always the case?
        EndpointDescription endpointDesc = mc.getEndpointDescription();

        // Now that we know what kind of Provider we have, we can create the 
        // right type of Block for the request parameter data
        Object requestParamValue = null;
        Message message = mc.getMessage();
        if (message != null) {
            
            // Enable MTOM if indicated by the binding
            String bindingType = endpointDesc.getBindingType();
            if (bindingType != null) {
                if (bindingType.equals(SOAPBinding.SOAP11HTTP_MTOM_BINDING) ||
                        bindingType.equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING)) {
                    message.setMTOMEnabled(true);
                }
            }

            // Save off the protocol info so we can use it when creating the response message.
            messageProtocol = message.getProtocol();
            // Determine what type blocks we want to create (String, Source, etc) based on Provider Type
            BlockFactory factory = createBlockFactory(providerType);


            providerServiceMode = endpointDesc.getServiceMode();

            if (providerServiceMode != null && providerServiceMode == Service.Mode.MESSAGE) {
                if (providerType.equals(SOAPMessage.class)) {
                    // We can get the SOAPMessage directly from the message itself
                    if (log.isDebugEnabled()) {
                        log.debug("Provider Type is SOAPMessage.");
                        log.debug("Number Message attachments=" + message.getAttachmentIDs().size());
                    }
                }

                requestParamValue = message.getValue(null, factory);
                if (requestParamValue == null) {
                    if (log.isDebugEnabled()) {
                        log.debug(
                                "There are no elements to unmarshal.  ProviderDispatch will pass a null as input");
                    }
                }
            } else {
                // If it is not MESSAGE, then it is PAYLOAD (which is the default); only work with the body 
                Block block = message.getBodyBlock(null, factory);
                if (block != null) {
                    requestParamValue = block.getBusinessObject(true);
                } else {
                    if (log.isDebugEnabled()) {
                        log.debug(
                                "No body blocks in SOAPMessage, Calling provider method with null input parameters");
                    }
                    requestParamValue = null;
                }
            }
        }

        if (log.isDebugEnabled())
            log.debug(
                    "Provider Type = " + providerType + "; parameter type = " + requestParamValue);

        final Object input = providerType.cast(requestParamValue);
        if (input != null && log.isDebugEnabled()) {
            log.debug("Invoking Provider<" + providerType.getName() + "> with " +
                    "parameter of type " + input.getClass().getName());
        }
        if (input == null && log.isDebugEnabled()) {
            log.debug("Invoking Provider<" + providerType.getName() + "> with " +
                    "NULL input parameter");
        }

        // Invoke the actual Provider.invoke() method
        boolean faultThrown = false;
        XMLFault fault = null;
        Object responseParamValue = null;
        Throwable t = null;
        try {
            responseParamValue = (Object)org.apache.axis2.java.security.AccessController
                    .doPrivileged(new PrivilegedExceptionAction() {
                        public Object run() throws Exception {
                            return invokeProvider(mc, providerInstance, input);
                        }
                    });
        } catch (Exception e) {
            t = ClassUtils.getRootCause(e);
            faultThrown = true;
            fault = MethodMarshallerUtils.createXMLFaultFromSystemException(t);

            if (log.isDebugEnabled()) {
                log.debug("Marshal Throwable =" + e.getClass().getName());
                log.debug("  rootCause =" + t.getClass().getName());
                log.debug("  exception=" + t.toString());
            }
        }

        // Create the response MessageContext
        MessageContext responseMsgCtx = null;
        if (!EndpointController.isOneWay(mc.getAxisMessageContext())) {
            if (faultThrown) {
                // If a fault was thrown, we need to create a slightly different
                // MessageContext, than in the response path.
                Message responseMsg = createMessageFromValue(fault);
                responseMsgCtx = MessageContextUtils.createFaultMessageContext(mc);
                responseMsgCtx.setMessage(responseMsg);
            } else {
                Message responseMsg = createMessageFromValue(responseParamValue);

                // Enable MTOM if indicated by the binding
                String bindingType = endpointDesc.getBindingType();
                if (bindingType != null) {
                    if (bindingType.equals(SOAPBinding.SOAP11HTTP_MTOM_BINDING) ||
                            bindingType.equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING)) {
                        responseMsg.setMTOMEnabled(true);
                    }
                }

                responseMsgCtx = MessageContextUtils.createResponseMessageContext(mc);
                responseMsgCtx.setMessage(responseMsg);
            }
        } else {
            // If we have a one-way operation, then we cannot create a MessageContext for the response.
            return null;
        }

        return responseMsgCtx;
    }

    protected Object invokeProvider(MessageContext ctx,
                                    Provider provider,
                                    Object input) throws Exception {
        return provider.invoke(input);
    }
    
    /**
     * Get the endpoint provider instance
     *
     * @return Provider
     * @throws Exception
     */
    public Provider getProvider() throws Exception {
        Provider p = getProviderInstance();
        setProvider(p);
        return p;
    }

    /**
     * Set the endpoint provider instance
     *
     * @param _provider
     */
    public void setProvider(Provider _provider) {
        this.providerInstance = _provider;
    }

    /**
     * Get the parameter for a given endpoint invocation
     *
     * @return
     * @throws Exception
     */
    public Message getMessage() throws Exception {
        return message;
    }

    /**
     * Set the parameter for a given endpoint invocation
     *
     * @param msg
     */
    public void setMessage(Message msg) {
        this.message = msg;
    }

    /*
    * Create a Message object out of the value object that was returned.
    */
    private Message createMessageFromValue(Object value) throws Exception {
        MessageFactory msgFactory =
                (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class);
        Message message = null;

        if (value != null) {
            BlockFactory factory = createBlockFactory(providerType);

            if (value instanceof XMLFault) {
                message = msgFactory.create(messageProtocol);
                message.setXMLFault((XMLFault)value);
            } else if (providerServiceMode != null && providerServiceMode == Service.Mode.MESSAGE) {
                // For MESSAGE mode, work with the entire message, Headers and Body
                // This is based on logic in org.apache.axis2.jaxws.client.XMLDispatch.createMessageFromBundle()
                if (value instanceof SOAPMessage) {
                    message = msgFactory.createFrom((SOAPMessage)value);
                } else {
                    Block block = factory.createFrom(value, null, null);
                    message = msgFactory.createFrom(block, null, messageProtocol);
                }
            } else {
                // PAYLOAD mode deals only with the body of the message.
                Block block = factory.createFrom(value, null, null);
                message = msgFactory.create(messageProtocol);
                message.setBodyBlock(block);
            }
        }

        if (message == null)
            // If we didn't create a message above (because there was no value), create one here
            message = msgFactory.create(messageProtocol);


        return message;
    }

    /*
      * Determine the Provider type for this instance
      */
    private Provider getProviderInstance() throws Exception {
        Class<?> clazz = getProviderType();

        if (!isValidProviderType(clazz)) {
            //TODO This will change once deployment code it in place
            throw new Exception(Messages.getMessage("InvalidProvider", clazz.getName()));
        }

        Provider provider = null;
        if (clazz == String.class) {
            provider = (Provider<String>)serviceInstance;
        } else if (clazz == Source.class) {
            provider = (Provider<Source>)serviceInstance;
        } else if (clazz == SOAPMessage.class) {
            provider = (Provider<SOAPMessage>)serviceInstance;
        } else if (clazz == JAXBContext.class) {
            provider = (Provider<JAXBContext>)serviceInstance;
        }

        if (provider == null) {
            throw ExceptionFactory.makeWebServiceException(
                    Messages.getMessage("InvalidProviderCreate", clazz.getName()));
        }

        return provider;

    }

    /*
    * Get the provider type from a given implemention class instance
    */
    private Class<?> getProviderType() throws Exception {

        Class providerType = null;

        Type[] giTypes = serviceImplClass.getGenericInterfaces();
        for (Type giType : giTypes) {
            ParameterizedType paramType = null;
            try {
                paramType = (ParameterizedType)giType;
            } catch (ClassCastException e) {
                //TODO NLS
                throw new Exception(
                        "Provider based SEI Class has to implement javax.xml.ws.Provider as javax.xml.ws.Provider<String>, javax.xml.ws.Provider, javax.xml.ws.Provider or javax.xml.ws.Provider");
            }
            Class interfaceName = (Class)paramType.getRawType();

            if (interfaceName == javax.xml.ws.Provider.class) {
                if (paramType.getActualTypeArguments().length > 1) {
                    //TODO NLS
                    throw new Exception(
                            "Provider cannot have more than one Generic Types defined as Per JAX-WS Specification");
                }
                providerType = (Class)paramType.getActualTypeArguments()[0];
            }
        }
        return providerType;
    }

    /*
    * Validate whether or not the Class passed in is a valid type of
    * javax.xml.ws.Provider<T>.  Per the JAX-WS 2.0 specification, the
    * parameterized type of a Provider can only be:
    *
    *   javax.xml.transform.Source
    *   javax.xml.soap.SOAPMessage
    *   javax.activation.DataSource
    *
    * We've also added support for String types which is NOT dictated
    * by the spec.
    */
    private boolean isValidProviderType(Class clazz) {
        boolean valid = clazz == String.class ||
                clazz == SOAPMessage.class ||
                clazz == Source.class ||
                clazz == DataSource.class;

        if (!valid) {
            if (log.isDebugEnabled()) {
                log.debug("Class " + clazz.getName() + " is not a valid Provider<T> type");
            }
        }

        return valid;
    }

    /*
    * Given a target class type for a payload, load the appropriate BlockFactory.
    */
    private BlockFactory createBlockFactory(Class type) {
        if (blockFactory != null)
            return blockFactory;

        if (type.equals(String.class)) {
            blockFactory = (XMLStringBlockFactory)FactoryRegistry.getFactory(
                    XMLStringBlockFactory.class);
        } else if (type.equals(Source.class)) {
            blockFactory = (SourceBlockFactory)FactoryRegistry.getFactory(
                    SourceBlockFactory.class);
        } else if (type.equals(SOAPMessage.class)) {
            blockFactory = (SOAPEnvelopeBlockFactory)FactoryRegistry.getFactory(
                    SOAPEnvelopeBlockFactory.class);
        } else {
            ExceptionFactory.makeWebServiceException("Unable to find BlockFactory " +
                    "for type: " + type.getClass().getName());
        }

        return blockFactory;
    }
    
}

Other Axis 2 examples (source code examples)

Here is a short list of links related to this Axis 2 ProviderDispatcher.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.