Package org.apache.axis2.engine

Source Code of org.apache.axis2.engine.AxisEngine

/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* Licensed 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.engine;

import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.TransportOutDescription;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.om.OMAbstractFactory;
import org.apache.axis2.soap.*;
import org.apache.axis2.transport.TransportSender;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;

/**
* There is one engine for the Server and the Client. the send() and receive()
* Methods are the basic operations the Sync, Async messageing are build on top.
*/
public class AxisEngine {
    /**
     * Field log
     */
    private Log log = LogFactory.getLog(getClass());
    private ConfigurationContext engineContext;

    /**
     * Constructor AxisEngine
     */
    public AxisEngine(ConfigurationContext engineContext) {
        log.debug("Axis Engine Started");
        this.engineContext = engineContext;
    }

    /**
     * This methods represents the outflow of the Axis, this could be either at the server side or the client side.
     * Here the <code>ExecutionChain</code> is created using the Phases. The Handlers at the each Phases is ordered in
     * deployment time by the deployment module
     *
     * @param msgContext
     * @throws AxisFault
     * @see MessageContext
     * @see Phase
     * @see Handler
     */
    public void send(MessageContext msgContext) throws AxisFault {
        verifyContextBuilt(msgContext);

        //find and invoke the Phases
        OperationContext operationContext = msgContext.getOperationContext();
        ArrayList phases =
                operationContext.getAxisOperation().getPhasesOutFlow();
        if (msgContext.isPaused()) {
            // the message has paused, so rerun them from the position they stoped. The Handler
            //who paused the Message will be the first one to run
            //resume fixed, global precalulated phases
            resumeInvocationPhases(phases, msgContext);
            ArrayList globaleOutphase = msgContext.getConfigurationContext().
                    getAxisConfiguration().getGlobalOutPhases();
            //invoking global phase.
            invokePhases(globaleOutphase, msgContext);
        } else {
            invokePhases(phases, msgContext);
            ArrayList globaleOutphase = msgContext.getConfigurationContext().
                    getAxisConfiguration().getGlobalOutPhases();
            //invoking global phase.
            invokePhases(globaleOutphase, msgContext);
        }

        if (!msgContext.isPaused()) {
            //write the Message to the Wire
            TransportOutDescription transportOut = msgContext.getTransportOut();
            TransportSender sender = transportOut.getSender();
            sender.invoke(msgContext);
        }
    }

    /**
     * This methods represents the inflow of the Axis, this could be either at the server side or the client side.
     * Here the <code>ExecutionChain</code> is created using the Phases. The Handlers at the each Phases is ordered in
     * deployment time by the deployment module
     *
     * @throws AxisFault
     * @see MessageContext
     * @see Phase
     * @see Handler
     */
    public void receive(MessageContext msgContext) throws AxisFault {

        ConfigurationContext sysCtx = msgContext.getConfigurationContext();
        AxisOperation axisOperation;
        ArrayList preCalculatedPhases =
                sysCtx
                        .getAxisConfiguration()
                        .getInPhasesUptoAndIncludingPostDispatch();
        ArrayList operationSpecificPhases;

        if (msgContext.isPaused()) {
            // the message has paused, so rerun them from the position they stoped. The Handler
            //who paused the Message will be the first one to run
            //resume fixed, global precalulated phases
            resumeInvocationPhases(preCalculatedPhases, msgContext);
            if (msgContext.isPaused()) {
                return;
            }
            verifyContextBuilt(msgContext);
            //resume operation specific phases
            OperationContext operationContext =
                    msgContext.getOperationContext();
            axisOperation = operationContext.getAxisOperation();
            operationSpecificPhases =
                    axisOperation.getRemainingPhasesInFlow();
            resumeInvocationPhases(operationSpecificPhases, msgContext);
            if (msgContext.isPaused()) {
                return;
            }
        } else {
            invokePhases(preCalculatedPhases, msgContext);
            if (msgContext.isPaused()) {
                return;
            }

            verifyContextBuilt(msgContext);   // TODO : Chinthaka remove me. I'm redundant
            OperationContext operationContext =
                    msgContext.getOperationContext();
            axisOperation = operationContext.getAxisOperation();
            operationSpecificPhases =
                    axisOperation.getRemainingPhasesInFlow();
            invokePhases(operationSpecificPhases, msgContext);
            if (msgContext.isPaused()) {
                return;
            }
        }

        if (msgContext.isServerSide() && !msgContext.isPaused()) {
            // invoke the Message Receivers
            MessageReceiver receiver =
                    axisOperation.getMessageReceiver();
            receiver.receive(msgContext);
        }
    }

    /**
     * Sends the SOAP Fault to another SOAP node.
     *
     * @param msgContext
     * @throws AxisFault
     */
    public void sendFault(MessageContext msgContext) throws AxisFault {
        OperationContext opContext = msgContext.getOperationContext();
        //find and execute the Fault Out Flow Handlers
        if (opContext != null) {
            AxisOperation axisOperation = opContext.getAxisOperation();
            ArrayList phases = axisOperation.getPhasesOutFaultFlow();
            if (msgContext.isPaused()) {
                resumeInvocationPhases(phases, msgContext);
            } else {
                invokePhases(phases, msgContext);
            }
        }
        //it is possible that Operation Context is Null as the error occered before the
        //Dispatcher. We do not run Handlers in that case

        if (!msgContext.isPaused()) {
            //Actually send the SOAP Fault
            TransportSender sender = msgContext.getTransportOut().getSender();
            sender.invoke(msgContext);
        }
    }

    /**
     * This is invoked when a SOAP Fault is received from a Other SOAP Node
     * Receives a SOAP fault from another SOAP node.
     *
     * @param msgContext
     * @throws AxisFault
     */
    public void receiveFault(MessageContext msgContext) throws AxisFault {

        OperationContext opContext = msgContext.getOperationContext();
        if (opContext == null) {
            //If we do not have a OperationContext that means this may be a incoming
            //Dual Channel response. So try to dispatch the Service
            ConfigurationContext sysCtx = msgContext.getConfigurationContext();
            ArrayList phases =
                    sysCtx
                            .getAxisConfiguration()
                            .getInPhasesUptoAndIncludingPostDispatch();

            if (msgContext.isPaused()) {
                resumeInvocationPhases(phases, msgContext);
            } else {
                invokePhases(phases, msgContext);
            }
            verifyContextBuilt(msgContext);
        }
        opContext = msgContext.getOperationContext();
        //find and execute the Fault In Flow Handlers
        if (opContext != null) {
            AxisOperation axisOperation = opContext.getAxisOperation();
            ArrayList phases = axisOperation.getPhasesInFaultFlow();
            if (msgContext.isPaused()) {
                resumeInvocationPhases(phases, msgContext);
            } else {
                invokePhases(phases, msgContext);
            }
        }
    }

    /**
     * This method is called to handle any error that occurs at inflow or outflow. But if the
     * method is called twice, it implies that sending the error handling has failed, in which case
     * the method logs the error and exists.
     *
     * @param processingContext
     * @param e
     * @throws AxisFault
     */
    public MessageContext createFaultMessageContext(
            MessageContext processingContext,
            Throwable e)
            throws AxisFault {
        if (processingContext.isProcessingFault()) {
            //We get the error file processing the fault. nothing we can do
            throw new AxisFault(
                    Messages.getMessage("errorwhileProcessingFault"));
        }

        MessageContext faultContext =
                new MessageContext(
                        engineContext,
                        processingContext.getSessionContext(),
                        processingContext.getTransportIn(),
                        processingContext.getTransportOut());

        faultContext.setProcessingFault(true);
        if (processingContext.getFaultTo() != null) {
            faultContext.setFaultTo(processingContext.getFaultTo());
        } else {
            Object writer =
                    processingContext.getProperty(MessageContext.TRANSPORT_OUT);
            if (writer != null) {
                faultContext.setProperty(MessageContext.TRANSPORT_OUT, writer);
            } else {
                throw new AxisFault(Messages.getMessage("nowhereToSendError"));
            }
        }

        faultContext.setOperationContext(processingContext.getOperationContext());
        faultContext.setProcessingFault(true);
        faultContext.setServerSide(true);
        SOAPEnvelope envelope;

        faultContext.setProperty(HTTPConstants.HTTPOutTransportInfo,
                processingContext.getProperty(HTTPConstants.HTTPOutTransportInfo));

        if (processingContext.isSOAP11()) {
            envelope =
                    OMAbstractFactory.getSOAP11Factory().getDefaultFaultEnvelope();
        } else {
            // Following will make SOAP 1.2 as the default, too.
            envelope =
                    OMAbstractFactory.getSOAP12Factory().getDefaultFaultEnvelope();
        }

        // TODO do we need to set old Headers back?

        //            body.addFault(new AxisFault(e.getMessage(), e));
        //        body.getFault().setException(new AxisFault(e));
        extractFaultInformationFromMessageContext(
                processingContext,
                envelope.getBody().getFault(),
                e);

        faultContext.setEnvelope(envelope);
        faultContext.setProperty(HTTPConstants.HTTPOutTransportInfo, processingContext.getProperty(HTTPConstants.HTTPOutTransportInfo));
        return faultContext;
    }

    /**
     * Information to create the SOAPFault can be extracted from different places.
     * 1. Those information may have been put in to the message context by some handler. When someone
     * is putting like that, he must make sure the SOAPElements he is putting must be from the
     * correct SOAP Version.
     * 2. SOAPProcessingException is flexible enough to carry information about the fault. For example
     * it has an attribute to store the fault code. The fault reason can be extracted from the
     * message of the exception. I opted to put the stacktrace under the detail element.
     * eg : <Detail>
     * <Exception> stack trace goes here </Exception>
     * <Detail>
     * <p/>
     * If those information can not be extracted from any of the above places, I default the soap
     * fault values to following.
     * <Fault>
     * <Code>
     * <Value>env:Receiver</Value>
     * </Code>
     * <Reason>
     * <Text>unknown</Text>
     * </Reason>
     * <Role/>
     * <Node/>
     * <Detail/>
     * </Fault>
     * <p/>
     * -- EC
     *
     * @param context
     * @param fault
     * @param e
     */
    private void extractFaultInformationFromMessageContext(
            MessageContext context,
            SOAPFault fault,
            Throwable e) {
        SOAPProcessingException soapException = null;
        String soapNamespaceURI;

        // get the current SOAP version
        if (!context.isSOAP11()) {
            // defaulting to SOAP 1.2
            soapNamespaceURI = SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI;
        } else {
            soapNamespaceURI = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
        }

        if (e instanceof SOAPProcessingException) {
            soapException = (SOAPProcessingException) e;
        } else if (e instanceof AxisFault) {
            if (e.getCause() instanceof SOAPProcessingException) {
                soapException = (SOAPProcessingException) e.getCause();
            }
        } else {
            // we have recd an instance of just the Exception class
        }

        Object faultCode =
                context.getProperty(SOAP12Constants.SOAP_FAULT_CODE_LOCAL_NAME);
        String soapFaultCode = "";
        if (faultCode != null) {
            fault.setCode((SOAPFaultCode) faultCode);
        } else if (soapException != null) {
            soapFaultCode = soapException.getFaultCode();
        } else if (e instanceof AxisFault) {
            //soapFaultCode = ((AxisFault) e).getFaultCode();
        }

        // defaulting to fault code Sender, if no message is available
        soapFaultCode =
                ("".equals(soapFaultCode) || soapFaultCode == null)
                        ? getSenderFaultCode(soapNamespaceURI)
                        : soapFaultCode;
        fault.getCode().getValue().setText(soapFaultCode);

        Object faultReason =
                context.getProperty(SOAP12Constants.SOAP_FAULT_REASON_LOCAL_NAME);
        String message = "";
        if (faultReason != null) {
            fault.setReason((SOAPFaultReason) faultReason);
        } else if (soapException != null) {
            message = soapException.getMessage();
        } else if (e instanceof AxisFault) {
            message = ((AxisFault) e).getMessage();
        }

        // defaulting to reason, unknown, if no reason is available
        message =
                ("".equals(message) || message == null) ? "unknown" : message;
        fault.getReason().getSOAPText().setText(message);

        Object faultRole =
                context.getProperty(SOAP12Constants.SOAP_FAULT_ROLE_LOCAL_NAME);
        if (faultRole != null) {
            fault.getRole().setText((String) faultRole);
        } else {
            // TODO : get the role of this server and assign it here
            fault.getRole().setText("http://myAxisServer/role/default");
        }

        Object faultNode =
                context.getProperty(SOAP12Constants.SOAP_FAULT_NODE_LOCAL_NAME);
        if (faultNode != null) {
            fault.getNode().setText((String) faultNode);
        } else {
            // TODO : get the node of this server and assign it here
            fault.getNode().setText("http://myAxisServer/role/default");

        }

        Object faultDetail =
                context.getProperty(SOAP12Constants.SOAP_FAULT_DETAIL_LOCAL_NAME);
        if (faultDetail != null) {
            fault.setDetail((SOAPFaultDetail) faultDetail);
        } else if (fault.getException() == null) {
            if (e instanceof Exception) {
                fault.setException((Exception) e);
            } else {
                fault.setException(new Exception(e));
            }

        }
    }

    private void verifyContextBuilt(MessageContext msgctx) throws AxisFault {
        if (msgctx.getConfigurationContext() == null) {
            throw new AxisFault(
                    Messages.getMessage("cannotBeNullConfigurationContext"));
        }
        if (msgctx.getOperationContext() == null) {
            throw new AxisFault(
                    Messages.getMessage("cannotBeNullOperationContext"));
        }
        if (msgctx.getServiceContext() == null) {
            throw new AxisFault(
                    Messages.getMessage("cannotBeNullServiceContext"));
        }
    }

    private void invokePhases(ArrayList phases, MessageContext msgctx)
            throws AxisFault {
        int count = phases.size();
        for (int i = 0; (i < count && !msgctx.isPaused()); i++) {
            Phase phase = (Phase) phases.get(i);
            phase.invoke(msgctx);
        }
    }

    public void resumeInvocationPhases(ArrayList phases, MessageContext msgctx)
            throws AxisFault {
        msgctx.setPausedFalse();
        int count = phases.size();
        boolean foundMatch = false;

        for (int i = 0; i < count && !msgctx.isPaused(); i++) {
            Phase phase = (Phase) phases.get(i);
            if (phase.getPhaseName().equals(msgctx.getPausedPhaseName())) {
                foundMatch = true;
                phase.invokeStartFromHandler(
                        msgctx.getPausedHandlerName(),
                        msgctx);
            } else {
                if (foundMatch) {
                    phase.invoke(msgctx);
                }

            }
        }
    }

    private String getSenderFaultCode(String soapNamespace) {
        return SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(
                soapNamespace)
                ? SOAP12Constants.FAULT_CODE_SENDER
                : SOAP11Constants.FAULT_CODE_SENDER;
    }

    private String getReceiverFaultCode(String soapNamespace) {
        return SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(
                soapNamespace)
                ? SOAP12Constants.FAULT_CODE_RECEIVER
                : SOAP11Constants.FAULT_CODE_RECEIVER;
    }
}
TOP

Related Classes of org.apache.axis2.engine.AxisEngine

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.