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

Axis 2 example source code file (EndpointController.java)

This example Axis 2 source code file (EndpointController.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

boolean, class, class, endpointdescription, endpointdescription, exception, incoming, io, message, messagecontext, messagecontext, object, security, soap, string, string, util

The Axis 2 EndpointController.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;

import org.apache.axiom.om.util.StAXUtils;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.WSDL2Constants;
import org.apache.axis2.java.security.AccessController;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.binding.SOAPBinding;
import org.apache.axis2.jaxws.core.InvocationContext;
import org.apache.axis2.jaxws.core.MessageContext;
import org.apache.axis2.jaxws.core.util.MessageContextUtils;
import org.apache.axis2.jaxws.description.DescriptionFactory;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.description.ServiceDescription;
import org.apache.axis2.jaxws.handler.HandlerChainProcessor;
import org.apache.axis2.jaxws.handler.HandlerInvokerUtils;
import org.apache.axis2.jaxws.handler.HandlerResolverImpl;
import org.apache.axis2.jaxws.handler.MEPContext;
import org.apache.axis2.jaxws.i18n.Messages;
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.XMLFaultCode;
import org.apache.axis2.jaxws.message.XMLFaultReason;
import org.apache.axis2.jaxws.message.factory.MessageFactory;
import org.apache.axis2.jaxws.registry.FactoryRegistry;
import org.apache.axis2.jaxws.server.dispatcher.EndpointDispatcher;
import org.apache.axis2.jaxws.server.dispatcher.factory.EndpointDispatcherFactory;
import org.apache.axis2.jaxws.server.endpoint.lifecycle.EndpointLifecycleManager;
import org.apache.axis2.jaxws.server.endpoint.lifecycle.factory.EndpointLifecycleManagerFactory;
import org.apache.axis2.jaxws.spi.Constants;
import org.apache.axis2.wsdl.WSDLConstants.WSDL20_2004_Constants;
import org.apache.axis2.wsdl.WSDLConstants.WSDL20_2006Constants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.ws.http.HTTPBinding;
import java.io.StringReader;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;

/**
 * The EndpointController is the server side equivalent to the InvocationController on the client
 * side.  It is an abstraction of the server side endpoint invocation that encapsulates all of the
 * Axis2 semantics.
 * <p/>
 * Like the InvocationController, this class is responsible for invoking the JAX-WS application
 * handler chain along with taking all of the provided information and setting up what's needed to
 * perform the actual invocation of the endpoint.
 */
public class EndpointController {

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

    private static final String PARAM_SERVICE_CLASS = "ServiceClass";

    public EndpointController() {
        //do nothing
    }

    /**
     * This method is used to start the JAX-WS invocation of a target endpoint. It takes an
     * InvocationContext, which must have a MessageContext specied for the request.  Once the
     * invocation is complete, the information will be stored
     */
    public InvocationContext invoke(InvocationContext ic) {
        MessageContext requestMsgCtx = ic.getRequestMessageContext();

        String implClassName = getServiceImplClassName(requestMsgCtx);

        Class implClass = loadServiceImplClass(implClassName,
                                               requestMsgCtx.getClassLoader());

        EndpointDescription endpointDesc = getEndpointDescription(requestMsgCtx, implClass);
        requestMsgCtx.setEndpointDescription(endpointDesc);

        /*
         * TODO: review: make sure the handlers are set on the InvocationContext
         * This implementation of the JAXWS runtime does not use Endpoint, which
         * would normally be the place to initialize and store the handler list.
         * In lieu of that, we will have to intialize and store them on the 
         * InvocationContext.  also see the InvocationContextFactory.  On the client
         * side, the binding is not yet set when we call into that factory, so the
         * handler list doesn't get set on the InvocationContext object there.  Thus
         * we gotta do it here.
         * 
         * Since we're on the server, and there apparently is no Binding object
         * anywhere to be found...
         */
        if (ic.getHandlers() == null) {
            ic.setHandlers(new HandlerResolverImpl(endpointDesc.getServiceDescription()).getHandlerChain(endpointDesc.getPortInfo()));
        }

        if (!bindingTypesMatch(requestMsgCtx, endpointDesc.getServiceDescription())) {
            Protocol protocol = requestMsgCtx.getMessage().getProtocol();
            // only if protocol is soap12 and MISmatches the endpoint do we halt processing
            if (protocol.equals(Protocol.soap12)) {
                ic.setResponseMessageContext(createMismatchFaultMsgCtx(requestMsgCtx,
                                                                       "Incoming SOAP message protocol is version 1.2, but endpoint is configured for SOAP 1.1"));
                return ic;
            } else if (protocol.equals(Protocol.soap11)) {
                // SOAP 1.1 message and SOAP 1.2 binding

                // The canSupport flag indicates that we can support this scenario.
                // Possible Examples of canSupport:  JAXB impl binding, JAXB Provider
                // Possible Example of !canSupport: Application handler usage, non-JAXB Provider
                // Initially I vote to hard code this as false.
                boolean canSupport = false;
                if (canSupport) {
                    // TODO: Okay, but we need to scrub the Message create code to make sure that the response message
                    // is always built from the receiver protocol...not the binding protocol
                } else {
                    ic.setResponseMessageContext(createMismatchFaultMsgCtx(requestMsgCtx,
                                                                           "Incoming SOAP message protocol is version 1.1, but endpoint is configured for SOAP 1.2.  This is not supported."));
                    return ic;
                }
            } else {
                ic.setResponseMessageContext(createMismatchFaultMsgCtx(requestMsgCtx,
                                                                       "Incoming message protocol does not match endpoint protocol."));
                return ic;
            }
        }

        MessageContext responseMsgContext = null;

        try {
            // Get the service instance.  This will run the @PostConstruct code.
            EndpointLifecycleManager elm = createEndpointlifecycleManager();
            Object serviceInstance = elm.createServiceInstance(requestMsgCtx, implClass);

            // The application handlers and dispatcher invoke will 
            // modify/destroy parts of the message.  Make sure to save
            // the request message if appropriate.
            saveRequestMessage(requestMsgCtx);

            // Invoke inbound application handlers.  It's safe to use the first object on the iterator because there is
            // always exactly one EndpointDescription on a server invoke
            boolean success =
                    HandlerInvokerUtils.invokeInboundHandlers(requestMsgCtx.getMEPContext(),
                                                              ic.getHandlers(),
                                                              HandlerChainProcessor.MEP.REQUEST,
                                                              isOneWay(requestMsgCtx.getAxisMessageContext()));

            if (success) {

                // Dispatch to the
                EndpointDispatcher dispatcher = getEndpointDispatcher(implClass, serviceInstance);
                try {
                    responseMsgContext = dispatcher.invoke(requestMsgCtx);
                } finally {
                    // Passed pivot point
                    requestMsgCtx.getMessage().setPostPivot();
                }

                // Invoke the outbound response handlers.
                // If the message is one way, we should not invoke the response handlers.  There is no response
                // MessageContext since a one way invocation is considered to have a "void" return.
                if (!isOneWay(requestMsgCtx.getAxisMessageContext())) {
                    responseMsgContext.setMEPContext(requestMsgCtx.getMEPContext());
                    
                    HandlerInvokerUtils.invokeOutboundHandlers(responseMsgContext.getMEPContext(),
                                                               ic.getHandlers(),
                                                               HandlerChainProcessor.MEP.RESPONSE,
                                                               false);
                }
            } else
            { // the inbound handler chain must have had a problem, and we've reversed directions
                responseMsgContext =
                        MessageContextUtils.createResponseMessageContext(requestMsgCtx);
                // since we've reversed directions, the message has "become a response message" (section 9.3.2.1, footnote superscript 2)
                responseMsgContext.setMessage(requestMsgCtx.getMessage());
            }

        } catch (Exception e) {
            // TODO for now, throw it.  We probably should try to make an XMLFault object and set it on the message
            throw ExceptionFactory.makeWebServiceException(e);
        } finally {
            restoreRequestMessage(requestMsgCtx);
        }

		// The response MessageContext should be set on the InvocationContext
		ic.setResponseMessageContext(responseMsgContext);

        return ic;
    }

    /*
      * Get the appropriate EndpointDispatcher for a given service endpoint.
      */
    protected EndpointDispatcher getEndpointDispatcher(Class serviceImplClass, Object serviceInstance)
            throws Exception {
        EndpointDispatcherFactory factory = 
            (EndpointDispatcherFactory)FactoryRegistry.getFactory(EndpointDispatcherFactory.class);        
        return factory.createEndpointDispatcher(serviceImplClass, serviceInstance);       
    }

    /*
      * Tries to load the implementation class that was specified for the
      * target endpoint
      */
    private Class loadServiceImplClass(String className, ClassLoader cl) {
        if (log.isDebugEnabled()) {
            log.debug("Attempting to load service impl class: " + className);
        }

        try {
            //TODO: What should be done if the supplied ClassLoader is null?
            Class _class = forName(className, true, cl);
            return _class;
            //Catch Throwable as ClassLoader can throw an NoClassDefFoundError that
            //does not extend Exception, so lets catch everything that extends Throwable
            //rather than just Exception.
        } catch (Throwable cnf) {
            throw ExceptionFactory.makeWebServiceException(Messages.getMessage(
                    "EndpointControllerErr4", className));
        }
    }

    /**
     * Return the class for this name
     *
     * @return Class
     */
    private static Class forName(final String className, final boolean initialize,
                                 final ClassLoader classloader) throws ClassNotFoundException {
        // NOTE: This method must remain private because it uses AccessController
        Class cl = null;
        try {
            cl = (Class)AccessController.doPrivileged(
                    new PrivilegedExceptionAction() {
                        public Object run() throws ClassNotFoundException {
                            return Class.forName(className, initialize, classloader);
                        }
                    }
            );
        } catch (PrivilegedActionException e) {
            if (log.isDebugEnabled()) {
                log.debug("Exception thrown from AccessController: " + e);
            }
            throw (ClassNotFoundException)e.getException();
        }

        return cl;
    }

    private String getServiceImplClassName(MessageContext mc) {
        // The PARAM_SERVICE_CLASS property that is set on the AxisService
        // will tell us what the service implementation class is.
        org.apache.axis2.context.MessageContext axisMsgContext = mc.getAxisMessageContext();
        AxisService as = axisMsgContext.getAxisService();
        Parameter param = as.getParameter(PARAM_SERVICE_CLASS);

        // If there was no implementation class, we should not go any further
        if (param == null) {
            throw ExceptionFactory.makeWebServiceException(Messages.getMessage(
                    "EndpointControllerErr2"));
        }

        String className = ((String)param.getValue()).trim();
        return className;
    }

    /*
    * Gets the ServiceDescription associated with the request that is currently
    * being processed.
    */
    private EndpointDescription getEndpointDescription(MessageContext mc, Class implClass) {
        AxisService axisSvc = mc.getAxisMessageContext().getAxisService();

        //Check to see if we've already created a ServiceDescription for this
        //service before trying to create a new one. 

        if (axisSvc.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER) != null) {
            Parameter param = axisSvc.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);

            EndpointDescription ed = (EndpointDescription)param.getValue();
            return ed;
        } else {
            // TODO: This is using a deprecated factory method to create the ServiceDescription.
            // The correct way to fix this is to create the ServiceDescriptions (and the AxisService
            // and associated descritpion hierahcy) at startup.  However, that is currently not done
            // in the Axis2 testing environment.  So, for testing, we create a Description hierachy
            // on the fly and attach the AxisService to it.  This should be changed to not used the
            // deprecated factory method.  HOWEVER doing so currently causes testcase failures in 
            // JAXWS and or Metadata
//            ServiceDescription sd = DescriptionFactory.createServiceDescription(implClass);
            ServiceDescription sd =
                    DescriptionFactory.createServiceDescriptionFromServiceImpl(implClass, axisSvc);
            EndpointDescription ed = sd.getEndpointDescriptions_AsCollection().iterator().next();
            return ed;
        }
    }

    private EndpointLifecycleManager createEndpointlifecycleManager() {
        EndpointLifecycleManagerFactory elmf = (EndpointLifecycleManagerFactory)FactoryRegistry
                .getFactory(EndpointLifecycleManagerFactory.class);
        return elmf.createEndpointLifecycleManager();
    }


    private boolean bindingTypesMatch(MessageContext requestMsgCtx,
                                      ServiceDescription serviceDesc) {
        // compare soap versions and respond appropriately under SOAP 1.2 Appendix 'A'
        Collection<EndpointDescription> eds = serviceDesc.getEndpointDescriptions_AsCollection();
        // dispatch endpoints do not have SEIs, so watch out for null or empty array
        if ((eds != null) && (eds.size() > 0)) {
            EndpointDescription ed = eds.iterator().next();
            Protocol protocol = requestMsgCtx.getMessage().getProtocol();
            String endpointBindingType = ed.getBindingType();
            if (protocol.equals(Protocol.soap11)) {
                return (SOAPBinding.SOAP11HTTP_BINDING.equalsIgnoreCase(endpointBindingType)) ||
                        (SOAPBinding.SOAP11HTTP_MTOM_BINDING.equalsIgnoreCase(endpointBindingType));
            } else if (protocol.equals(Protocol.soap12)) {
                return (SOAPBinding.SOAP12HTTP_BINDING.equalsIgnoreCase(endpointBindingType)) ||
                        (SOAPBinding.SOAP12HTTP_MTOM_BINDING.equalsIgnoreCase(endpointBindingType));
            } else if (protocol.equals(Protocol.rest)) {
                return HTTPBinding.HTTP_BINDING.equalsIgnoreCase(endpointBindingType);
            }
        }
        // safe to assume?
        return true;
    }

    private MessageContext createMismatchFaultMsgCtx(MessageContext requestMsgCtx,
                                                     String errorMsg) {
        try {
            XMLFault xmlfault =
                    new XMLFault(XMLFaultCode.VERSIONMISMATCH, new XMLFaultReason(errorMsg));
            Message msg = ((MessageFactory)FactoryRegistry.getFactory(MessageFactory.class))
                    .create(Protocol.soap11);  // always soap11 according to the spec
            msg.setXMLFault(xmlfault);
            MessageContext responseMsgCtx =
                    MessageContextUtils.createFaultMessageContext(requestMsgCtx);
            responseMsgCtx.setMessage(msg);
            return responseMsgCtx;
        } catch (XMLStreamException e) {
            // Need to fix this !   At least provide logging
            // TODO for now, throw it.  We probably should try to make an XMLFault object and set it on the message
            throw ExceptionFactory.makeWebServiceException(e);
        }
    }

    /**
     * Save the request message if indicated by the SAVE_REQUEST_MSG property
     *
     * @param requestMsgContext
     */
    private void saveRequestMessage(MessageContext requestMsgContext) {

        // TODO: TESTING...FORCE SAVING THE REQUEST MESSAGE
        // requestMsgContext.getAxisMessageContext().setProperty(Constants.SAVE_REQUEST_MSG, Boolean.TRUE);
        // END TESTING

        Boolean value = (Boolean)
                requestMsgContext.getAxisMessageContext().getProperty(Constants.SAVE_REQUEST_MSG);
        if (value != null && value == Boolean.TRUE) {
            // REVIEW: This does not properly account for attachments.
            Message m = requestMsgContext.getMessage();
            String savedMsg = m.getAsOMElement().toString();
            requestMsgContext.getAxisMessageContext()
                    .setProperty(Constants.SAVED_REQUEST_MSG_TEXT, savedMsg);
        }
    }

    /**
     * Restore the request message from the saved message text
     *
     * @param requestMsgContext
     */
    private void restoreRequestMessage(MessageContext requestMsgContext) {

        Boolean value = (Boolean)
                requestMsgContext.getAxisMessageContext().getProperty(Constants.SAVE_REQUEST_MSG);
        if (value != null && value == Boolean.TRUE) {
            // REVIEW: This does not properly account for attachments.
            String savedMsg = (String)requestMsgContext.getAxisMessageContext()
                    .getProperty(Constants.SAVED_REQUEST_MSG_TEXT);
            if (savedMsg != null && savedMsg.length() > 0) {
                try {
                    StringReader sr = new StringReader(savedMsg);
                    XMLStreamReader xmlreader = StAXUtils.createXMLStreamReader(sr);
                    MessageFactory mf = (MessageFactory)
                            FactoryRegistry.getFactory(MessageFactory.class);
                    Protocol protocol = requestMsgContext.getAxisMessageContext().isDoingREST() ?
                            Protocol.rest : null;
                    Message msg = mf.createFrom(xmlreader, protocol);
                    requestMsgContext.setMessage(msg);
                } catch (Throwable e) {
                    ExceptionFactory.makeWebServiceException(e);
                }
            }
        }

        // TESTING....SIMULATE A PERSIST OF THE REQUEST MESSAGE
        // String text = requestMsgContext.getMessage().getAsOMElement().toString();
        // System.out.println("Persist Message" + text);
        // END TESTING
    }

    /*
    * Determine if this is a one-way invocation or not.
    */
    public static boolean isOneWay(org.apache.axis2.context.MessageContext mc) {
        if (mc != null) {
            AxisOperation op = mc.getAxisOperation();
            String mep = op.getMessageExchangePattern();

            if (mep.equals(WSDL20_2004_Constants.MEP_URI_ROBUST_IN_ONLY) ||
                    mep.equals(WSDL20_2004_Constants.MEP_URI_IN_ONLY) ||
                    mep.equals(WSDL20_2006Constants.MEP_URI_ROBUST_IN_ONLY) ||
                    mep.equals(WSDL20_2006Constants.MEP_URI_IN_ONLY)||
                    mep.equals(WSDL2Constants.MEP_URI_ROBUST_IN_ONLY)||
                    mep.equals(WSDL2Constants.MEP_URI_IN_ONLY)) {
                return true;
            }
        }
        return false;
    }
}

Other Axis 2 examples (source code examples)

Here is a short list of links related to this Axis 2 EndpointController.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.