Package org.apache.cxf.jaxws.handler

Source Code of org.apache.cxf.jaxws.handler.HandlerChainInvoker

/**
* 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.cxf.jaxws.handler;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.ws.ProtocolException;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;

import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.jaxws.context.WebServiceContextImpl;
import org.apache.cxf.jaxws.context.WrappedMessageContext;
import org.apache.cxf.message.Message;


/**
* invoke invoke the handlers in a registered handler chain
*
*/
public class HandlerChainInvoker {

    private static final Logger LOG = LogUtils.getL7dLogger(HandlerChainInvoker.class);

    private final List<Handler> protocolHandlers = new ArrayList<Handler>();
    private List<LogicalHandler> logicalHandlers  = new ArrayList<LogicalHandler>();
    private final List<Handler> invokedHandlers  = new ArrayList<Handler>();
    private final List<Handler> closeHandlers  = new ArrayList<Handler>();

    private boolean outbound;
    private boolean responseExpected = true;
    private boolean faultExpected;
    private boolean handlerProcessingAborted;
    private boolean closed;
    private Exception fault;
    private MessageContext logicalMessageContext;
    private MessageContext protocolMessageContext;

    public HandlerChainInvoker(List<Handler> hc) {
        this(hc, true);
    }

    public HandlerChainInvoker(List<Handler> hc, boolean isOutbound) {
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "invoker for chain size: " + (hc != null ? hc.size() : 0));
        }

        if (hc != null) {
            for (Handler h : hc) {
                if (h instanceof LogicalHandler) {
                    logicalHandlers.add((LogicalHandler)h);
                } else {
                    protocolHandlers.add(h);
                }
            }
        }
        outbound = isOutbound;
    }

    public List<LogicalHandler> getLogicalHandlers() {
        return logicalHandlers;
    }

    public List<Handler> getProtocolHandlers() {
        return protocolHandlers;
    }

    public MessageContext getLogicalMessageContext() {
        return logicalMessageContext;
    }
    public void setLogicalMessageContext(MessageContext mc) {
        logicalMessageContext = mc;
    }

    public MessageContext getProtocolMessageContext() {
        return protocolMessageContext;
    }
    public void setProtocolMessageContext(MessageContext mc) {
        protocolMessageContext = mc;
    }

    public boolean invokeLogicalHandlers(boolean requestor, LogicalMessageContext context) {
        // objectCtx.setRequestorRole(requestor);
        context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, isOutbound());
        return invokeHandlerChain(logicalHandlers, context);

    }

    public boolean invokeProtocolHandlers(boolean requestor, MessageContext context) {
        // WrappedMessageContext context = new WrappedMessageContext(message);
        // bindingContext.put(ObjectMessageContext.REQUESTOR_ROLE_PROPERTY, requestor);
        context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, isOutbound());

        return invokeHandlerChain(protocolHandlers, context);
    }

    public void setResponseExpected(boolean expected) {
        responseExpected = expected;
    }

    public boolean isResponseExpected() {
        return responseExpected;
    }

    public boolean isOutbound() {
        return outbound;
    }

    public boolean isInbound() {
        return !outbound;
    }

    public void setInbound() {
        outbound = false;
    }

    public void setOutbound() {
        outbound = true;
    }


    public boolean faultRaised() {
        return null != fault  || faultExpected;
    }

    public Exception getFault() {
        return fault;
    }

    public void setFault(boolean fe) {
        faultExpected = fe;
    }

    /** Invoke handlers at the end of an MEP calling close on each.
     * The handlers must be invoked in the reverse order that they
     * appear in the handler chain.  On the server side this will not
     * be the reverse order in which they were invoked so use the
     * handler chain directly and not simply the invokedHandler list.
     */
    public void mepComplete(Message message) {
        WrappedMessageContext context = new WrappedMessageContext(message);
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "closing protocol handlers - handler count:" + invokedHandlers.size());
        }
        invokeClose(protocolHandlers, context);
        invokeClose(logicalHandlers, context);
    }


    /** Indicates that the invoker is closed.  When closed, only @see
     * #mepComplete may be called.  The invoker will become closed if
     * during a invocation of handlers, a handler throws a runtime
     * exception that is not a protocol exception and no futher
     * handler or message processing is possible.
     *
     */
    public boolean isClosed() {
        return closed;
    }

    /**
     * Allows an the logical handler chain for one invoker to be used
     * as an alternate chain for another.
     *
     * @param invoker the invoker encalsulting the alternate logical handler
     * chain
     */
    public void adoptLogicalHandlers(HandlerChainInvoker invoker) {
        logicalHandlers = invoker.getLogicalHandlers();
    }

    List getInvokedHandlers() {
        return Collections.unmodifiableList(invokedHandlers);
    }

    private <T extends Handler> void invokeClose(List<T> handlers, MessageContext context) {
        handlers = reverseHandlerChain(handlers);
        for (Handler h : handlers) {
            if (closeHandlers.contains(h)) {
                h.close(context);
            }
        }
    }

    private boolean invokeHandlerChain(List<? extends Handler> handlerChain, MessageContext ctx) {
        if (handlerChain.isEmpty()) {
            LOG.log(Level.FINEST, "no handlers registered");
            return true;
        }

        if (isClosed()) {
            return false;
        }

        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "invoking handlers, direction: " + (outbound ? "outbound" : "inbound"));
        }
        setMessageOutboundProperty(ctx);

        if (!outbound) {
            handlerChain = reverseHandlerChain(handlerChain);
        }

        boolean continueProcessing = true;

        WebServiceContextImpl.setMessageContext(ctx);

        if (!faultRaised()) {
            continueProcessing = invokeHandleMessage(handlerChain, ctx);
        } else {
            continueProcessing = invokeHandleFault(handlerChain, ctx);
        }

        if (!continueProcessing) {
            // stop processing handlers, change direction and return
            // control to the bindng.  Then the binding will invoke on
            // the next set on handlers and they will be processing in
            // the correct direction.  It would be good refactor it
            // and control all of the processing here.
            changeMessageDirection(ctx);
            handlerProcessingAborted = true;

            //TODO: reverse chain, call handlerMessage or close
        }
        return continueProcessing;
    }

    @SuppressWarnings("unchecked")
    private boolean invokeHandleFault(List<? extends Handler> handlerChain, MessageContext ctx) {

        boolean continueProcessing = true;

        try {
            for (Handler h : handlerChain) {
                if (invokeThisHandler(h)) {
                    closeHandlers.add(h);
                    markHandlerInvoked(h);
                    continueProcessing = h.handleFault(ctx);
                }
                if (!continueProcessing) {
                    break;
                }

            }
        } catch (RuntimeException e) {
            LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION", e);
            continueProcessing = false;
            closed = true;
        }
        return continueProcessing;
    }


    @SuppressWarnings("unchecked")
    private boolean invokeHandleMessage(List<? extends Handler> handlerChain, MessageContext ctx) {

        boolean continueProcessing = true;
        try {
            for (Handler h : handlerChain) {
                if (invokeThisHandler(h)) {
                    closeHandlers.add(h);
                    markHandlerInvoked(h);
                    continueProcessing = h.handleMessage(ctx);
                }
                if (!continueProcessing) {
                    callReversedHandlers(ctx);
                    break;
                }
            }
        } catch (ProtocolException e) {
            LOG.log(Level.FINE, "handleMessage raised exception", e);
            if (responseExpected) {
                if (logicalMessageContext != null) {
                    logicalMessageContext.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, !isOutbound());
                }
                if (protocolMessageContext != null) {
                    protocolMessageContext.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, !isOutbound());
                }
                callReversedHandlesFault();
            }
            continueProcessing = false;
            closeHandlers();
            setFault(e);
            throw e;
        } catch (RuntimeException e) {
            LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION", e);
            continueProcessing = false;
            closeHandlers();

            throw e;
        }
        return continueProcessing;
    }

    // REVISIT
    // handleFault() return true\false, throw Exception.
    @SuppressWarnings("unchecked")
    private boolean callReversedHandlesFault() {
        int index = invokedHandlers.size() - 2;
        while (index >= 0) {
            Handler handler = invokedHandlers.get(index);
            if (handler instanceof LogicalHandler) {
                if (Boolean.FALSE.equals(handler.
                                         handleFault(logicalMessageContext))) {
                    return false;
                }
            } else {
                if (Boolean.FALSE.equals(handler.
                                         handleFault(protocolMessageContext))) {
                    return false;
                }
            }
            index--;
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    private boolean callReversedHandlers(MessageContext ctx) {
        int index = invokedHandlers.size() - 2;
        if (responseExpected) {
            while (index >= 0) {
                Handler handler = invokedHandlers.get(index);
                if (handler instanceof LogicalHandler) {
                    if (Boolean.FALSE.equals(handler.
                                             handleMessage(logicalMessageContext))) {
                        return false;
                    }
                } else {
                    if (Boolean.FALSE.equals(handler.
                                             handleMessage(protocolMessageContext))) {
                        return false;
                    }
                }
                index--;
            }
        }
        return true;
    }

    private void closeHandlers() {
        int index = invokedHandlers.size() - 1;
        while (index >= 0) {
            Handler handler = invokedHandlers.get(index);
            if (handler instanceof LogicalHandler) {
                handler.close(logicalMessageContext);
            } else {
                handler.close(protocolMessageContext);
            }
            invokedHandlers.remove(index);
            index--;
        }
        closed = true;
    }

    private boolean invokeThisHandler(Handler h) {
        boolean ret = true;
        // when handler processing has been aborted, only invoked on
        // previously invoked handlers
        //
        if (handlerProcessingAborted) {
            ret = invokedHandlers.contains(h);
        }
        if (ret && LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "invoking handler of type " + h.getClass().getName());
        }
        return ret;
    }


    private void markHandlerInvoked(Handler h) {
        if (!invokedHandlers.contains(h)) {
            invokedHandlers.add(h);
        }
    }

    private void changeMessageDirection(MessageContext context) {
        outbound = !outbound;
        setMessageOutboundProperty(context);
        // context.put(ObjectMessageContext.MESSAGE_INPUT, Boolean.TRUE);
    }

    private void setMessageOutboundProperty(MessageContext context) {
        context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, this.outbound);
    }

    private <T extends Handler> List<T> reverseHandlerChain(List<T> handlerChain) {
        List<T> reversedHandlerChain = new ArrayList<T>();
        reversedHandlerChain.addAll(handlerChain);
        Collections.reverse(reversedHandlerChain);
        return reversedHandlerChain;
    }

    protected final void setFault(Exception ex) {
        /*
        context.put(ObjectMessageContext.METHOD_FAULT, ex);
        context.setScope(ObjectMessageContext.METHOD_FAULT, MessageContext.Scope.HANDLER);
        */
        fault = ex;
    }
}

TOP

Related Classes of org.apache.cxf.jaxws.handler.HandlerChainInvoker

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.