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

Apache CXF example source code file (HandlerChainInvoker.java)

This example Apache CXF source code file (HandlerChainInvoker.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 - Apache CXF tags/keywords

arraylist, arraylist, dom, handler, handler, handlerchaininvoker, list, list, log, logging, logicalhandler, messagecontext, messagecontext, runtimeexception, soapfault, soapfaultexception, suppresswarnings, util, xml

The Apache CXF HandlerChainInvoker.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.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.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
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 javax.xml.ws.soap.SOAPFaultException;

import org.w3c.dom.Node;

import org.apache.cxf.binding.soap.SoapFault;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.jaxws.context.WebServiceContextImpl;
import org.apache.cxf.jaxws.context.WrappedMessageContext;
import org.apache.cxf.message.Message;

/**
 * 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();
    private List<LogicalHandler> logicalHandlers = new ArrayList();

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

    private boolean outbound;
    private boolean isRequestor;
    private boolean responseExpected = true;
    private boolean faultExpected;
    private boolean closed;
    private boolean messageDirectionReversed;
    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) {
        return invokeHandlerChain(logicalHandlers, context);
    }

    public boolean invokeLogicalHandlersHandleFault(boolean requestor, LogicalMessageContext context) {
        return invokeHandlerChainHandleFault(logicalHandlers, context);
    }

    public boolean invokeProtocolHandlers(boolean requestor, MessageContext context) {
        return invokeHandlerChain(protocolHandlers, context);
    }

    public boolean invokeProtocolHandlersHandleFault(boolean requestor, MessageContext context) {
        return invokeHandlerChainHandleFault(protocolHandlers, context);
    }

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

    public boolean isResponseExpected() {
        return responseExpected;
    }

    public boolean isOutbound() {
        return outbound;
    }

    public boolean isInbound() {
        return !outbound;
    }

    /**
     * We need HandlerChainInvoker behaves differently on the client and server
     * side. For the client side, as there is no inbound faultChain, we need to call
     * handleFault and close within HandlerChainInvoker directly.
     */
    public boolean isRequestor() {
        return isRequestor;
    }

    public void setRequestor(boolean requestor) {
        isRequestor = requestor;
    }

    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) {
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "closing protocol handlers - handler count:" + invokedHandlers.size());
        }

        if (isClosed()) {
            return;
        }

        invokeReversedClose();
    }

    /**
     * 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 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"));
        }

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

        boolean continueProcessing = true;
        try {
            WebServiceContextImpl.setMessageContext(ctx);
            continueProcessing = invokeHandleMessage(handlerChain, ctx);
        } finally {
            WebServiceContextImpl.clear();
        }

        return continueProcessing;
    }

    /*
     * REVISIT: the logic of current implemetation is if the exception is thrown
     * from previous handlers, we only invoke handleFault if it is
     * ProtocolException (per spec), if the exception is thrown from other
     * places other than handlers, we always invoke handleFault.
     */
    private boolean invokeHandlerChainHandleFault(List<? extends Handler> handlerChain, MessageContext ctx) {
        if (handlerChain.isEmpty()) {
            LOG.log(Level.FINEST, "no handlers registered");
            return true;
        }

        if (isClosed()) {
            return false;
        }

        //The fault is raised from previous handlers, in this case, we only invoke handleFault
        //if the fault is a ProtocolException
        if (fault != null && !(fault instanceof ProtocolException)) {
            return true;
        }

        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;
        try {
            WebServiceContextImpl.setMessageContext(ctx);
            continueProcessing = invokeHandleFault(handlerChain, ctx);
        } finally {
            WebServiceContextImpl.clear();
        }

        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;
            throw e;
        }
        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) {
                    if (responseExpected) {
                        changeMessageDirection(ctx);
                        messageDirectionReversed = true;
                    } else {
                        invokeReversedClose();                        
                    }

                    break;
                }
            }
        } catch (ProtocolException e) {
            LOG.log(Level.FINE, "handleMessage raised exception", e);

            if (responseExpected) {
                changeMessageDirection(ctx);
                messageDirectionReversed = true;
            }

            //special case for client side, this is because we do nothing in client fault
            //observer, we have to call handleFault and close here.
            if (isRequestor()) {
                if (responseExpected) {
                    setFaultMessage(ctx, e);
                    invokeReversedHandleFault(ctx);
                } else {
                    invokeReversedClose();
                }
                continueProcessing = false;
                setFault(e);
                if (responseExpected || isInbound()) {
                    //brain dead spec - if it's one way, swallow it
                    if (e instanceof SOAPFaultException) {
                        throw mapSoapFault((SOAPFaultException)e);
                    }
                    throw e;
                }
            } else {
                continueProcessing = false;
                if (responseExpected || outbound) {
                    setFault(e);
                    if (e instanceof SOAPFaultException) {
                        throw mapSoapFault((SOAPFaultException)e);
                    }
                    throw e;
                } 
                invokeReversedClose();
            }
        } catch (RuntimeException e) {
            LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION", e);

            if (responseExpected) {
                changeMessageDirection(ctx);
                messageDirectionReversed = true;
            }

            //special case for client side, this is because we do nothing in client fault
            //observer, we have to call close here.
            if (isRequestor()) {
                invokeReversedClose();
                continueProcessing = false;
                setFault(e);
                throw e;
            } else if (!responseExpected && !outbound) {
                invokeReversedClose();
                continueProcessing = false;
            } else {
                continueProcessing = false;
                setFault(e);
                throw e;
            }
        }
        return continueProcessing;
    }

    private SoapFault mapSoapFault(SOAPFaultException sfe) {
        SoapFault sf = new SoapFault(sfe.getFault().getFaultString(),
                                      sfe,
                                      sfe.getFault().getFaultCodeAsQName());
        sf.setRole(sfe.getFault().getFaultActor());
        if (sfe.getFault().hasDetail()) {
            sf.setDetail(sfe.getFault().getDetail());
        }
        
        return sf;        
    }

    /*
     * When the message direction is reversed, if the message is not already a
     * fault message then it is replaced with a fault message
     */
    private void setFaultMessage(MessageContext mc, Exception exception) {
        Message msg = ((WrappedMessageContext)mc).getWrappedMessage();
        msg.setContent(Exception.class, exception);
        msg.removeContent(XMLStreamReader.class);
        msg.removeContent(Source.class);

        try {
            SOAPMessage soapMessage = null;

            if (!(msg instanceof SoapMessage) || ((SoapMessage)msg).getVersion().getVersion() <= 1.11d) {
                soapMessage = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL).createMessage();
            } else {
                soapMessage = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL).createMessage();
            }
            msg.setContent(SOAPMessage.class, soapMessage);

            SOAPBody body = soapMessage.getSOAPBody();
            SOAPFault soapFault = body.addFault();

            if (exception instanceof SOAPFaultException) {
                SOAPFaultException sf = (SOAPFaultException)exception;
                soapFault.setFaultString(sf.getFault().getFaultString());
                soapFault.setFaultCode(sf.getFault().getFaultCode());
                soapFault.setFaultActor(sf.getFault().getFaultActor());
                if (sf.getFault().hasDetail()) {
                    Node nd = soapMessage.getSOAPPart().importNode(sf.getFault().getDetail(),
                                                                   true);
                    nd = nd.getFirstChild();
                    soapFault.addDetail();
                    while (nd != null) {
                        soapFault.getDetail().appendChild(nd);
                        nd = nd.getNextSibling();
                    }
                }
            } else if (exception instanceof Fault) {
                SoapFault sf = SoapFault.createFault((Fault)exception, ((SoapMessage)msg).getVersion());
                soapFault.setFaultString(sf.getReason());
                soapFault.setFaultCode(sf.getFaultCode());
                if (sf.hasDetails()) {
                    soapFault.addDetail();
                    Node nd = soapMessage.getSOAPPart().importNode(sf.getDetail(), true);
                    nd = nd.getFirstChild();
                    while (nd != null) {
                        soapFault.getDetail().appendChild(nd);
                        nd = nd.getNextSibling();
                    }
                }
            } else {
                soapFault.setFaultCode(new QName("http://cxf.apache.org/faultcode", "HandlerFault"));
                soapFault.setFaultString(exception.getMessage());
            }
        } catch (SOAPException e) {
            e.printStackTrace();
            // do nothing
        }
    }

    @SuppressWarnings("unchecked")
    private boolean invokeReversedHandleFault(MessageContext ctx) {
        boolean continueProcessing = true;

        try {
            int index = invokedHandlers.size() - 2;
            while (index >= 0 && continueProcessing) {
                Handler h = invokedHandlers.get(index);
                if (h instanceof LogicalHandler) {
                    continueProcessing = h.handleFault(logicalMessageContext);
                } else {
                    continueProcessing = h.handleFault(protocolMessageContext);
                }

                if (!continueProcessing) {
                    invokeReversedClose();
                    break;
                }
                index--;
            }
        } catch (RuntimeException e) {
            LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION", e);
            invokeReversedClose();
            continueProcessing = false;
            closed = true;

            throw e;
        }
        invokeReversedClose();
        return continueProcessing;
    }

    /*
     * close is called on each previously invoked handler in the chain, the
     * close method is only called on handlers that were previously invoked via
     * either handleMessage or handleFault
     */
    private void invokeReversedClose() {
        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 invoke on
        // previously invoked handlers
        //Only invoke the next handler (take the reversed direction into account)
        if (messageDirectionReversed) {
            ret = invokedHandlers.contains(h) && !isTheLastInvokedHandler(h);
        }

        if (ret && LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "invoking handler of type " + h.getClass().getName());
        }
        return ret;
    }

    private boolean isTheLastInvokedHandler(Handler h) {
        return invokedHandlers.contains(h) && invokedHandlers.indexOf(h) == (invokedHandlers.size() - 1);
    }

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

    private void changeMessageDirection(MessageContext context) {
        outbound = !outbound;
        setMessageOutboundProperty(context);
    }

    private void setMessageOutboundProperty(MessageContext context) {
        context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, this.outbound);
        if (logicalMessageContext != null) {
            logicalMessageContext.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, this.outbound);
        }
        if (protocolMessageContext != null) {
            protocolMessageContext.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, this.outbound);
        }
    }

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

    protected final void setFault(Exception ex) {
        fault = ex;
    }
}

Other Apache CXF examples (source code examples)

Here is a short list of links related to this Apache CXF HandlerChainInvoker.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.