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