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.istack.internal.Nullable; ohair@286: import com.sun.xml.internal.ws.api.WSBinding; ohair@286: import com.sun.xml.internal.ws.api.message.Packet; ohair@286: import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; ohair@286: import com.sun.xml.internal.ws.api.pipe.*; ohair@286: import com.sun.xml.internal.ws.api.pipe.helper.AbstractFilterTubeImpl; ohair@286: import com.sun.xml.internal.ws.binding.BindingImpl; ohair@286: import com.sun.xml.internal.ws.client.HandlerConfiguration; ohair@286: ohair@286: import javax.xml.ws.handler.MessageContext; ohair@286: import javax.xml.ws.handler.Handler; ohair@286: import java.util.List; ohair@286: ohair@286: /** ohair@286: * @author WS Development team ohair@286: */ ohair@286: ohair@286: public abstract class HandlerTube extends AbstractFilterTubeImpl { ohair@286: /** ohair@286: * handle hold reference to other Tube for inter-tube communication ohair@286: */ ohair@286: HandlerTube cousinTube; ohair@286: protected List handlers; ohair@286: HandlerProcessor processor; ohair@286: boolean remedyActionTaken = false; ohair@286: protected final @Nullable WSDLPort port; ohair@286: // flag used to decide whether to call close on cousinTube ohair@286: boolean requestProcessingSucessful = false; ohair@286: private WSBinding binding; ohair@286: private HandlerConfiguration hc; ohair@286: ohair@286: public HandlerTube(Tube next, WSDLPort port, WSBinding binding) { ohair@286: super(next); ohair@286: this.port = port; ohair@286: this.binding = binding; ohair@286: } ohair@286: ohair@286: public HandlerTube(Tube next, HandlerTube cousinTube, WSBinding binding) { ohair@286: super(next); ohair@286: this.cousinTube = cousinTube; ohair@286: this.binding = binding; ohair@286: if(cousinTube != null) { ohair@286: this.port = cousinTube.port; ohair@286: } else { ohair@286: this.port = null; ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Copy constructor for {@link Tube#copy(TubeCloner)}. ohair@286: */ ohair@286: protected HandlerTube(HandlerTube that, TubeCloner cloner) { ohair@286: super(that,cloner); ohair@286: if(that.cousinTube != null) { ohair@286: this.cousinTube = cloner.copy(that.cousinTube); ohair@286: } ohair@286: this.port = that.port; ohair@286: this.binding = that.binding; ohair@286: } ohair@286: ohair@286: protected WSBinding getBinding() { ohair@286: return binding; ohair@286: } ohair@286: ohair@286: @Override ohair@286: public NextAction processRequest(Packet request) { ohair@286: setupExchange(); ohair@286: // This check is done to cover handler returning false in Oneway request ohair@286: if (isHandleFalse()) { ohair@286: // Cousin HandlerTube returned false during Oneway Request processing. ohair@286: // Don't call handlers and dispatch the message. ohair@286: remedyActionTaken = true; ohair@286: return doInvoke(super.next, request); ohair@286: } ohair@286: ohair@286: // This is done here instead of the constructor, since User can change ohair@286: // the roles and handlerchain after a stub/proxy is created. ohair@286: setUpProcessorInternal(); ohair@286: ohair@286: MessageUpdatableContext context = getContext(request); ohair@286: boolean isOneWay = checkOneWay(request); ohair@286: try { ohair@286: if (!isHandlerChainEmpty()) { ohair@286: // Call handlers on Request ohair@286: boolean handlerResult = callHandlersOnRequest(context, isOneWay); ohair@286: //Update Packet with user modifications ohair@286: context.updatePacket(); ohair@286: // two-way case where no message is sent ohair@286: if (!isOneWay && !handlerResult) { ohair@286: return doReturnWith(request); ohair@286: } ohair@286: } ohair@286: requestProcessingSucessful = true; ohair@286: // Call next Tube ohair@286: return doInvoke(super.next, request); ohair@286: } catch (RuntimeException re) { ohair@286: if(isOneWay) { ohair@286: //Eat the exception, its already logged and close the transportBackChannel ohair@286: if(request.transportBackChannel != null ) { ohair@286: request.transportBackChannel.close(); ohair@286: } ohair@286: request.setMessage(null); ohair@286: return doReturnWith(request); ohair@286: } else ohair@286: throw re; ohair@286: } finally { ohair@286: if(!requestProcessingSucessful) { ohair@286: initiateClosing(context.getMessageContext()); ohair@286: } ohair@286: } ohair@286: ohair@286: } ohair@286: ohair@286: @Override ohair@286: public NextAction processResponse(Packet response) { ohair@286: setupExchange(); ohair@286: MessageUpdatableContext context = getContext(response); ohair@286: try { ohair@286: if (isHandleFalse() || (response.getMessage() == null)) { ohair@286: // Cousin HandlerTube returned false during Response processing. ohair@286: // or it is oneway request ohair@286: // or handler chain is empty ohair@286: // Don't call handlers. ohair@286: return doReturnWith(response); ohair@286: } ohair@286: ohair@286: setUpProcessorInternal(); ohair@286: ohair@286: boolean isFault = isHandleFault(response); ohair@286: if (!isHandlerChainEmpty()) { ohair@286: // Call handlers on Response ohair@286: callHandlersOnResponse(context, isFault); ohair@286: } ohair@286: } finally { ohair@286: initiateClosing(context.getMessageContext()); ohair@286: } ohair@286: //Update Packet with user modifications ohair@286: context.updatePacket(); ohair@286: ohair@286: return doReturnWith(response); ohair@286: ohair@286: } ohair@286: ohair@286: @Override ohair@286: public NextAction processException(Throwable t) { ohair@286: try { ohair@286: return doThrow(t); ohair@286: } finally { ohair@286: Packet packet = Fiber.current().getPacket(); ohair@286: MessageUpdatableContext context = getContext(packet); ohair@286: initiateClosing(context.getMessageContext()); ohair@286: /* TODO revisit: commented this out as the modified packet is no longer used ohair@286: In future if the message is propagated even when an exception ohair@286: occurs, then uncomment context.updatePacket(); ohair@286: */ ohair@286: //Update Packet with user modifications ohair@286: //context.updatePacket(); ohair@286: ohair@286: ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Must be overridden by HandlerTube that drives other handler tubes for processing a message. ohair@286: * On Client-side: ClientLogicalHandlerTube drives the Handler Processing. ohair@286: * On Server-side: In case SOAP Binding, ServerMessageHandlerTube drives the Handler Processing. ohair@286: * In case XML/HTTP Binding, ServerLogicalHandlerTube drives the Handler Processing. ohair@286: * ohair@286: * ohair@286: * If its a top HandlerTube, should override by calling #close(MessaggeContext); ohair@286: * ohair@286: */ ohair@286: ohair@286: protected void initiateClosing(MessageContext mc) { ohair@286: // Do nothing ohair@286: ohair@286: } ohair@286: ohair@286: /** ohair@286: * Calls close on previously invoked handlers. ohair@286: * Also, Cleans up any state left over in the Tube instance from the current ohair@286: * invocation, as Tube instances can be reused after the completion of MEP. ohair@286: * ohair@286: * On Client, SOAPHandlers are closed first and then LogicalHandlers ohair@286: * On Server, LogicalHandlers are closed first and then SOAPHandlers ohair@286: */ ohair@286: final public void close(MessageContext msgContext) { ohair@286: //assuming cousinTube is called if requestProcessingSucessful is true ohair@286: if (requestProcessingSucessful) { ohair@286: if (cousinTube != null) { ohair@286: cousinTube.close(msgContext); ohair@286: } ohair@286: ohair@286: } ohair@286: if (processor != null) ohair@286: closeHandlers(msgContext); ohair@286: ohair@286: // Clean up the exchange for next invocation. ohair@286: exchange = null; ohair@286: requestProcessingSucessful = false; ohair@286: ohair@286: } ohair@286: ohair@286: /** ohair@286: * On Client, Override by calling #closeClientHandlers(MessageContext mc) ohair@286: * On Server, Override by calling #closeServerHandlers(MessageContext mc) ohair@286: * The difference is the order in which they are closed. ohair@286: * @param mc ohair@286: */ ohair@286: abstract void closeHandlers(MessageContext mc); ohair@286: ohair@286: /** ohair@286: * Called by close(MessageContext mc) in a Client Handlertube ohair@286: */ ohair@286: protected void closeClientsideHandlers(MessageContext msgContext) { ohair@286: if (processor == null) ohair@286: return; ohair@286: if (remedyActionTaken) { ohair@286: //Close only invoked handlers in the chain ohair@286: ohair@286: //CLIENT-SIDE ohair@286: processor.closeHandlers(msgContext, processor.getIndex(), 0); ohair@286: processor.setIndex(-1); ohair@286: //reset remedyActionTaken ohair@286: remedyActionTaken = false; ohair@286: } else { ohair@286: //Close all handlers in the chain ohair@286: ohair@286: //CLIENT-SIDE ohair@286: processor.closeHandlers(msgContext, handlers.size() - 1, 0); ohair@286: ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Called by close(MessageContext mc) in a Server Handlertube ohair@286: */ ohair@286: protected void closeServersideHandlers(MessageContext msgContext) { ohair@286: if (processor == null) ohair@286: return; ohair@286: if (remedyActionTaken) { ohair@286: //Close only invoked handlers in the chain ohair@286: ohair@286: //SERVER-SIDE ohair@286: processor.closeHandlers(msgContext, processor.getIndex(), handlers.size() - 1); ohair@286: processor.setIndex(-1); ohair@286: //reset remedyActionTaken ohair@286: remedyActionTaken = false; ohair@286: } else { ohair@286: //Close all handlers in the chain ohair@286: ohair@286: //SERVER-SIDE ohair@286: processor.closeHandlers(msgContext, 0, handlers.size() - 1); ohair@286: ohair@286: } ohair@286: } ohair@286: ohair@286: abstract void callHandlersOnResponse(MessageUpdatableContext context, boolean handleFault); ohair@286: ohair@286: abstract boolean callHandlersOnRequest(MessageUpdatableContext context, boolean oneWay); ohair@286: ohair@286: private boolean checkOneWay(Packet packet) { ohair@286: if (port != null) { ohair@286: /* we can determine this value from WSDL */ ohair@286: return packet.getMessage().isOneWay(port); ohair@286: } else { ohair@286: /* ohair@286: otherwise use this value as an approximation, since this carries alanb@368: the application's intention --- whether it was invokeOneway vs invoke,etc. ohair@286: */ ohair@286: return !(packet.expectReply != null && packet.expectReply); ohair@286: } ohair@286: } ohair@286: ohair@286: private void setUpProcessorInternal() { ohair@286: HandlerConfiguration hc = ((BindingImpl) binding).getHandlerConfig(); ohair@286: if (hc != this.hc) ohair@286: resetProcessor(); ohair@286: this.hc = hc; ohair@286: ohair@286: setUpProcessor(); ohair@286: } ohair@286: ohair@286: abstract void setUpProcessor(); ohair@286: ohair@286: protected void resetProcessor() { ohair@286: handlers = null; ohair@286: } ohair@286: ohair@286: final public boolean isHandlerChainEmpty() { ohair@286: return handlers.isEmpty(); ohair@286: } ohair@286: abstract MessageUpdatableContext getContext(Packet p); ohair@286: ohair@286: private boolean isHandleFault(Packet packet) { ohair@286: if (cousinTube != null) { ohair@286: return exchange.isHandleFault(); ohair@286: } else { ohair@286: boolean isFault = packet.getMessage().isFault(); ohair@286: exchange.setHandleFault(isFault); ohair@286: return isFault; ohair@286: } ohair@286: } ohair@286: ohair@286: final void setHandleFault() { ohair@286: exchange.setHandleFault(true); ohair@286: } ohair@286: ohair@286: private boolean isHandleFalse() { ohair@286: return exchange.isHandleFalse(); ohair@286: } ohair@286: ohair@286: final void setHandleFalse() { ohair@286: exchange.setHandleFalse(); ohair@286: } ohair@286: ohair@286: private void setupExchange() { ohair@286: if(exchange == null) { ohair@286: exchange = new HandlerTubeExchange(); ohair@286: if(cousinTube != null) { ohair@286: cousinTube.exchange = exchange; ohair@286: } ohair@286: } else { ohair@286: if(cousinTube != null) { ohair@286: cousinTube.exchange = exchange; ohair@286: } ohair@286: ohair@286: } ohair@286: } ohair@286: private HandlerTubeExchange exchange; ohair@286: ohair@286: /** ohair@286: * This class is used primarily to exchange information or status between ohair@286: * LogicalHandlerTube and SOAPHandlerTube ohair@286: */ ohair@286: static final class HandlerTubeExchange { ohair@286: private boolean handleFalse; ohair@286: private boolean handleFault; ohair@286: ohair@286: boolean isHandleFault() { ohair@286: return handleFault; ohair@286: } ohair@286: ohair@286: void setHandleFault(boolean isFault) { ohair@286: this.handleFault = isFault; ohair@286: } ohair@286: ohair@286: public boolean isHandleFalse() { ohair@286: return handleFalse; ohair@286: } ohair@286: ohair@286: void setHandleFalse() { ohair@286: this.handleFalse = true; ohair@286: } ohair@286: } ohair@286: ohair@286: }