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