| /* |
| * 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.istack.internal.Nullable; |
| import com.sun.xml.internal.ws.api.message.Packet; |
| import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; |
| import com.sun.xml.internal.ws.api.pipe.*; |
| import com.sun.xml.internal.ws.api.pipe.helper.AbstractFilterTubeImpl; |
| |
| import javax.xml.ws.handler.MessageContext; |
| |
| /** |
| * @author WS Development team |
| */ |
| |
| public abstract class HandlerTube extends AbstractFilterTubeImpl { |
| |
| /** |
| * handle hold reference to other Tube for inter-tube communication |
| */ |
| HandlerTube cousinTube; |
| HandlerProcessor processor; |
| boolean remedyActionTaken = false; |
| private final @Nullable WSDLPort port; |
| // flag used to decide whether to call close on cousinTube |
| boolean requestProcessingSucessful = false; |
| |
| // TODO: For closing in Exceptions this is needed |
| // This is used for creating MessageContext in #close |
| Packet packet; |
| |
| public HandlerTube(Tube next, WSDLPort port) { |
| super(next); |
| this.port = port; |
| } |
| |
| public HandlerTube(Tube next, HandlerTube cousinTube) { |
| super(next); |
| this.cousinTube = cousinTube; |
| if(cousinTube != null) { |
| this.port = cousinTube.port; |
| } else { |
| this.port = null; |
| } |
| } |
| |
| /** |
| * Copy constructor for {@link Tube#copy(TubeCloner)}. |
| */ |
| protected HandlerTube(HandlerTube that, TubeCloner cloner) { |
| super(that,cloner); |
| if(that.cousinTube != null) { |
| this.cousinTube = cloner.copy(that.cousinTube); |
| } |
| this.port = that.port; |
| } |
| |
| @Override |
| public NextAction processRequest(Packet request) { |
| this.packet = request; |
| setupExchange(); |
| // This check is done to cover handler returning false in Oneway request |
| if (isHandleFalse()) { |
| // Cousin HandlerTube returned false during Oneway Request processing. |
| // Don't call handlers and dispatch the message. |
| remedyActionTaken = true; |
| return doInvoke(super.next, packet); |
| } |
| |
| // This is done here instead of the constructor, since User can change |
| // the roles and handlerchain after a stub/proxy is created. |
| setUpProcessor(); |
| |
| MessageUpdatableContext context = getContext(packet); |
| boolean isOneWay = checkOneWay(packet); |
| try { |
| if (!isHandlerChainEmpty()) { |
| // Call handlers on Request |
| boolean handlerResult = callHandlersOnRequest(context, isOneWay); |
| //Update Packet with user modifications |
| context.updatePacket(); |
| // two-way case where no message is sent |
| if (!isOneWay && !handlerResult) { |
| return doReturnWith(packet); |
| } |
| } |
| requestProcessingSucessful = true; |
| // Call next Tube |
| return doInvoke(super.next, packet); |
| } catch (RuntimeException re) { |
| if(isOneWay) { |
| //Eat the exception, its already logged and close the transportBackChannel |
| if(packet.transportBackChannel != null ) { |
| packet.transportBackChannel.close(); |
| } |
| packet.setMessage(null); |
| return doReturnWith(packet); |
| } else |
| throw re; |
| } finally { |
| if(!requestProcessingSucessful) { |
| cleanUpState(context.getMessageContext()); |
| } |
| } |
| |
| } |
| |
| @Override |
| public NextAction processResponse(Packet response) { |
| this.packet = response; |
| MessageUpdatableContext context = getContext(packet); |
| try { |
| if (isHandleFalse() || (packet.getMessage() == null)) { |
| // Cousin HandlerTube returned false during Response processing. |
| // or it is oneway request |
| // or handler chain is empty |
| // Don't call handlers. |
| return doReturnWith(packet); |
| } |
| boolean isFault = isHandleFault(packet); |
| if (!isHandlerChainEmpty()) { |
| // Call handlers on Response |
| callHandlersOnResponse(context, isFault); |
| } |
| } finally { |
| cleanUpState(context.getMessageContext()); |
| } |
| //Update Packet with user modifications |
| context.updatePacket(); |
| |
| return doReturnWith(packet); |
| |
| } |
| |
| @Override |
| public NextAction processException(Throwable t) { |
| try { |
| return doThrow(t); |
| } finally { |
| MessageUpdatableContext context = getContext(packet); |
| cleanUpState(context.getMessageContext()); |
| /* TODO revisit: commented this out as the modified packet is no longer used |
| In future if the message is propagated even when an exception |
| occurs, then uncomment context.updatePacket(); |
| */ |
| //Update Packet with user modifications |
| //context.updatePacket(); |
| |
| |
| } |
| } |
| |
| /** |
| * Calls close on previously invoked handlers. |
| * Also, Cleans up any state left over in the Tube instance from the current |
| * invocation, as Tube instances can be reused after the completion of MEP. |
| * |
| */ |
| private void cleanUpState(MessageContext mc) { |
| close(mc); |
| // Clean up the exchange for next invocation. |
| exchange = null; |
| requestProcessingSucessful = false; |
| } |
| |
| abstract void callHandlersOnResponse(MessageUpdatableContext context, boolean handleFault); |
| |
| abstract boolean callHandlersOnRequest(MessageUpdatableContext context, boolean oneWay); |
| |
| private boolean checkOneWay(Packet packet) { |
| if (port != null) { |
| /* we can determine this value from WSDL */ |
| return packet.getMessage().isOneWay(port); |
| } else { |
| /* |
| otherwise use this value as an approximation, since this carries |
| the appliation's intention --- whether it was invokeOneway vs invoke,etc. |
| */ |
| return (packet.expectReply != null && packet.expectReply); |
| } |
| } |
| |
| abstract void setUpProcessor(); |
| abstract boolean isHandlerChainEmpty(); |
| abstract MessageUpdatableContext getContext(Packet p); |
| |
| /** |
| * Close SOAPHandlers first and then LogicalHandlers on Client |
| * Close LogicalHandlers first and then SOAPHandlers on Server |
| */ |
| protected abstract void close(MessageContext msgContext); |
| |
| /** |
| * This is called from cousinTube. |
| * Close this Tube's handlers. |
| */ |
| protected abstract void closeCall(MessageContext msgContext); |
| |
| private boolean isHandleFault(Packet packet) { |
| if (cousinTube != null) { |
| return exchange.isHandleFault(); |
| } else { |
| boolean isFault = packet.getMessage().isFault(); |
| exchange.setHandleFault(isFault); |
| return isFault; |
| } |
| } |
| |
| final void setHandleFault() { |
| exchange.setHandleFault(true); |
| } |
| |
| private boolean isHandleFalse() { |
| return exchange.isHandleFalse(); |
| } |
| |
| final void setHandleFalse() { |
| exchange.setHandleFalse(); |
| } |
| |
| private void setupExchange() { |
| if(exchange == null) { |
| exchange = new HandlerTubeExchange(); |
| if(cousinTube != null) { |
| cousinTube.exchange = exchange; |
| } |
| } |
| } |
| private HandlerTubeExchange exchange; |
| |
| /** |
| * This class is used primarily to exchange information or status between |
| * LogicalHandlerTube and SOAPHandlerTube |
| */ |
| static final class HandlerTubeExchange { |
| private boolean handleFalse; |
| private boolean handleFault; |
| |
| boolean isHandleFault() { |
| return handleFault; |
| } |
| |
| void setHandleFault(boolean isFault) { |
| this.handleFault = isFault; |
| } |
| |
| public boolean isHandleFalse() { |
| return handleFalse; |
| } |
| |
| void setHandleFalse() { |
| this.handleFalse = true; |
| } |
| } |
| |
| } |