aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.handler; aoqi@0: aoqi@0: import com.sun.xml.internal.ws.api.WSBinding; aoqi@0: aoqi@0: import javax.xml.ws.ProtocolException; aoqi@0: import javax.xml.ws.handler.Handler; aoqi@0: import javax.xml.ws.handler.MessageContext; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.List; aoqi@0: import java.util.logging.Level; aoqi@0: import java.util.logging.Logger; aoqi@0: aoqi@0: /** aoqi@0: * @author WS Development Team aoqi@0: */ aoqi@0: abstract class HandlerProcessor { aoqi@0: aoqi@0: boolean isClient; aoqi@0: static final Logger logger = Logger.getLogger( aoqi@0: com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".handler"); aoqi@0: aoqi@0: // need request or response for Handle interface aoqi@0: public enum RequestOrResponse { aoqi@0: REQUEST, RESPONSE } aoqi@0: aoqi@0: public enum Direction { aoqi@0: OUTBOUND, INBOUND } aoqi@0: aoqi@0: private List handlers; // may be logical/soap mixed aoqi@0: aoqi@0: WSBinding binding; aoqi@0: private int index = -1; aoqi@0: private HandlerTube owner; aoqi@0: aoqi@0: /** aoqi@0: * The handlers that are passed in will be sorted into aoqi@0: * logical and soap handlers. During this sorting, the aoqi@0: * understood headers are also obtained from any soap aoqi@0: * handlers. aoqi@0: * aoqi@0: * @param chain A list of handler objects, which can aoqi@0: * be protocol or logical handlers. aoqi@0: */ aoqi@0: protected HandlerProcessor(HandlerTube owner, WSBinding binding, List chain) { aoqi@0: this.owner = owner; aoqi@0: if (chain == null) { // should only happen in testing aoqi@0: chain = new ArrayList(); aoqi@0: } aoqi@0: handlers = chain; aoqi@0: this.binding = binding; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gives index of the handler in the chain to know what handlers in the chain aoqi@0: * are invoked aoqi@0: */ aoqi@0: int getIndex() { aoqi@0: return index; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This is called when a handler returns false or throws a RuntimeException aoqi@0: */ aoqi@0: void setIndex(int i) { aoqi@0: index = i; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * TODO: Just putting thoughts, aoqi@0: * Current contract: This is Called during Request Processing. aoqi@0: * return true, if all handlers in the chain return true aoqi@0: * Current Pipe can call nextPipe.process(); aoqi@0: * return false, One of the handlers has returned false or thrown a aoqi@0: * RuntimeException. Remedy Actions taken: aoqi@0: * 1) In this case, The processor will setIndex()to track what aoqi@0: * handlers are invoked until that point. aoqi@0: * 2) Previously invoked handlers are again invoked (handleMessage() aoqi@0: * or handleFault()) to take remedy action. aoqi@0: * CurrentPipe should NOT call nextPipe.process() aoqi@0: * While closing handlers, check getIndex() to get the invoked aoqi@0: * handlers. aoqi@0: * @throws RuntimeException this happens when a RuntimeException occurs during aoqi@0: * handleMessage during Request processing or aoqi@0: * during remedy action 2) aoqi@0: * CurrentPipe should NOT call nextPipe.process() and throw the aoqi@0: * exception to the previous Pipe aoqi@0: * While closing handlers, check getIndex() to get the invoked aoqi@0: * handlers. aoqi@0: */ aoqi@0: public boolean callHandlersRequest(Direction direction, aoqi@0: C context, aoqi@0: boolean responseExpected) { aoqi@0: setDirection(direction, context); aoqi@0: boolean result; aoqi@0: // call handlers aoqi@0: try { aoqi@0: if (direction == Direction.OUTBOUND) { aoqi@0: result = callHandleMessage(context, 0, handlers.size() - 1); aoqi@0: } else { aoqi@0: result = callHandleMessage(context, handlers.size() - 1, 0); aoqi@0: } aoqi@0: } catch (ProtocolException pe) { aoqi@0: logger.log(Level.FINER, "exception in handler chain", pe); aoqi@0: if (responseExpected) { aoqi@0: //insert fault message if its not a fault message aoqi@0: insertFaultMessage(context, pe); aoqi@0: // reverse direction aoqi@0: reverseDirection(direction, context); aoqi@0: //Set handleFault so that cousinTube is aware of fault aoqi@0: setHandleFaultProperty(); aoqi@0: // call handle fault aoqi@0: if (direction == Direction.OUTBOUND) { aoqi@0: callHandleFault(context, getIndex() - 1, 0); aoqi@0: } else { aoqi@0: callHandleFault(context, getIndex() + 1, handlers.size() - 1); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: throw pe; aoqi@0: } catch (RuntimeException re) { aoqi@0: logger.log(Level.FINER, "exception in handler chain", re); aoqi@0: throw re; aoqi@0: } aoqi@0: aoqi@0: if (!result) { aoqi@0: if (responseExpected) { aoqi@0: // reverse direction aoqi@0: reverseDirection(direction, context); aoqi@0: // call handle message aoqi@0: if (direction == Direction.OUTBOUND) { aoqi@0: callHandleMessageReverse(context, getIndex() - 1, 0); aoqi@0: } else { aoqi@0: callHandleMessageReverse(context, getIndex() + 1, handlers.size() - 1); aoqi@0: } aoqi@0: } else { aoqi@0: // Set handleFalse so that cousinTube is aware of false processing aoqi@0: // Oneway, dispatch the message aoqi@0: // cousinTube should n't call handleMessage() anymore. aoqi@0: setHandleFalseProperty(); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * TODO: Just putting thoughts, aoqi@0: * Current contract: This is Called during Response Processing. aoqi@0: * Runs all handlers until handle returns false or throws a RuntimeException aoqi@0: * CurrentPipe should close all the handlers in the chain. aoqi@0: * throw RuntimeException, this happens when a RuntimeException occurs during aoqi@0: * normal Response processing or remedy action 2) taken aoqi@0: * during callHandlersRequest(). aoqi@0: * CurrentPipe should close all the handlers in the chain. * aoqi@0: */ aoqi@0: public void callHandlersResponse(Direction direction, aoqi@0: C context, boolean isFault) { aoqi@0: setDirection(direction, context); aoqi@0: try { aoqi@0: if (isFault) { aoqi@0: // call handleFault on handlers aoqi@0: if (direction == Direction.OUTBOUND) { aoqi@0: callHandleFault(context, 0, handlers.size() - 1); aoqi@0: } else { aoqi@0: callHandleFault(context, handlers.size() - 1, 0); aoqi@0: } aoqi@0: } else { aoqi@0: // call handleMessage on handlers aoqi@0: if (direction == Direction.OUTBOUND) { aoqi@0: callHandleMessageReverse(context, 0, handlers.size() - 1); aoqi@0: } else { aoqi@0: callHandleMessageReverse(context, handlers.size() - 1, 0); aoqi@0: } aoqi@0: } aoqi@0: } catch (RuntimeException re) { aoqi@0: logger.log(Level.FINER, "exception in handler chain", re); aoqi@0: throw re; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Reverses the Message Direction. aoqi@0: * MessageContext.MESSAGE_OUTBOUND_PROPERTY is changed. aoqi@0: */ aoqi@0: private void reverseDirection(Direction origDirection, C context) { aoqi@0: if (origDirection == Direction.OUTBOUND) { aoqi@0: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, false); aoqi@0: } else { aoqi@0: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, true); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Sets the Message Direction. aoqi@0: * MessageContext.MESSAGE_OUTBOUND_PROPERTY is changed. aoqi@0: */ aoqi@0: private void setDirection(Direction direction, C context) { aoqi@0: if (direction == Direction.OUTBOUND) { aoqi@0: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, true); aoqi@0: } else { aoqi@0: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, false); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * When this property is set HandlerPipes can call handleFault() on the aoqi@0: * message aoqi@0: */ aoqi@0: private void setHandleFaultProperty() { aoqi@0: owner.setHandleFault(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * When this property is set HandlerPipes will not call aoqi@0: * handleMessage() during Response processing. aoqi@0: */ aoqi@0: private void setHandleFalseProperty() { aoqi@0: owner.setHandleFalse(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * When a ProtocolException is thrown, this is called. aoqi@0: * If it's XML/HTTP Binding, clear the the message aoqi@0: * If its SOAP/HTTP Binding, put right SOAP Fault version aoqi@0: */ aoqi@0: abstract void insertFaultMessage(C context, aoqi@0: ProtocolException exception); aoqi@0: aoqi@0: /* aoqi@0: * Calls handleMessage on the handlers. Indices are aoqi@0: * inclusive. Exceptions get passed up the chain, and an aoqi@0: * exception or return of 'false' ends processing. aoqi@0: */ aoqi@0: private boolean callHandleMessage(C context, int start, int end) { aoqi@0: /* Do we need this check? aoqi@0: if (handlers.isEmpty() || aoqi@0: start == -1 || aoqi@0: start == handlers.size()) { aoqi@0: return false; aoqi@0: } aoqi@0: */ aoqi@0: int i = start; aoqi@0: try { aoqi@0: if (start > end) { aoqi@0: while (i >= end) { aoqi@0: if (!handlers.get(i).handleMessage(context)) { aoqi@0: setIndex(i); aoqi@0: return false; aoqi@0: } aoqi@0: i--; aoqi@0: } aoqi@0: } else { aoqi@0: while (i <= end) { aoqi@0: if (!handlers.get(i).handleMessage(context)) { aoqi@0: setIndex(i); aoqi@0: return false; aoqi@0: } aoqi@0: i++; aoqi@0: } aoqi@0: } aoqi@0: } catch (RuntimeException e) { aoqi@0: setIndex(i); aoqi@0: throw e; aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Calls handleMessage on the handlers. Indices are aoqi@0: * inclusive. Exceptions get passed up the chain, and an aoqi@0: * exception (or) aoqi@0: * return of 'false' calls addHandleFalseProperty(context) and aoqi@0: * ends processing. aoqi@0: * setIndex() is not called. aoqi@0: * aoqi@0: */ aoqi@0: private boolean callHandleMessageReverse(C context, int start, int end) { aoqi@0: aoqi@0: if (handlers.isEmpty() || aoqi@0: start == -1 || aoqi@0: start == handlers.size()) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: int i = start; aoqi@0: aoqi@0: if (start > end) { aoqi@0: while (i >= end) { aoqi@0: if (!handlers.get(i).handleMessage(context)) { aoqi@0: // Set handleFalse so that cousinTube is aware of false processing aoqi@0: setHandleFalseProperty(); aoqi@0: return false; aoqi@0: } aoqi@0: i--; aoqi@0: } aoqi@0: } else { aoqi@0: while (i <= end) { aoqi@0: if (!handlers.get(i).handleMessage(context)) { aoqi@0: // Set handleFalse so that cousinTube is aware of false processing aoqi@0: setHandleFalseProperty(); aoqi@0: return false; aoqi@0: } aoqi@0: i++; aoqi@0: } aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Calls handleFault on the handlers. Indices are aoqi@0: * inclusive. Exceptions get passed up the chain, and an aoqi@0: * exception or return of 'false' ends processing. aoqi@0: */ aoqi@0: aoqi@0: private boolean callHandleFault(C context, int start, int end) { aoqi@0: aoqi@0: if (handlers.isEmpty() || aoqi@0: start == -1 || aoqi@0: start == handlers.size()) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: int i = start; aoqi@0: if (start > end) { aoqi@0: try { aoqi@0: while (i >= end) { aoqi@0: if (!handlers.get(i).handleFault(context)) { aoqi@0: return false; aoqi@0: } aoqi@0: i--; aoqi@0: } aoqi@0: } catch (RuntimeException re) { aoqi@0: logger.log(Level.FINER, aoqi@0: "exception in handler chain", re); aoqi@0: throw re; aoqi@0: } aoqi@0: } else { aoqi@0: try { aoqi@0: while (i <= end) { aoqi@0: if (!handlers.get(i).handleFault(context)) { aoqi@0: return false; aoqi@0: } aoqi@0: i++; aoqi@0: } aoqi@0: } catch (RuntimeException re) { aoqi@0: logger.log(Level.FINER, aoqi@0: "exception in handler chain", re); aoqi@0: throw re; aoqi@0: } aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Calls close on the handlers from the starting aoqi@0: * index through the ending index (inclusive). Made indices aoqi@0: * inclusive to allow both directions more easily. aoqi@0: */ aoqi@0: void closeHandlers(MessageContext context, int start, int end) { aoqi@0: if (handlers.isEmpty() || aoqi@0: start == -1) { aoqi@0: return; aoqi@0: } aoqi@0: if (start > end) { aoqi@0: for (int i = start; i >= end; i--) { aoqi@0: try { aoqi@0: handlers.get(i).close(context); aoqi@0: } catch (RuntimeException re) { aoqi@0: logger.log(Level.INFO, aoqi@0: "Exception ignored during close", re); aoqi@0: } aoqi@0: } aoqi@0: } else { aoqi@0: for (int i = start; i <= end; i++) { aoqi@0: try { aoqi@0: handlers.get(i).close(context); aoqi@0: } catch (RuntimeException re) { aoqi@0: logger.log(Level.INFO, aoqi@0: "Exception ignored during close", re); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: }