/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.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.WSBinding;
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 com.sun.xml.internal.ws.binding.BindingImpl;
import com.sun.xml.internal.ws.client.HandlerConfiguration;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.Handler;
import java.util.List;
Author: WS Development team
/**
* @author WS Development team
*/
public abstract class HandlerTube extends AbstractFilterTubeImpl {
handle hold reference to other Tube for inter-tube communication
/**
* handle hold reference to other Tube for inter-tube communication
*/
HandlerTube cousinTube;
protected List<Handler> handlers;
HandlerProcessor processor;
boolean remedyActionTaken = false;
protected final @Nullable WSDLPort port;
// flag used to decide whether to call close on cousinTube
boolean requestProcessingSucessful = false;
private WSBinding binding;
private HandlerConfiguration hc;
public HandlerTube(Tube next, WSDLPort port, WSBinding binding) {
super(next);
this.port = port;
this.binding = binding;
}
public HandlerTube(Tube next, HandlerTube cousinTube, WSBinding binding) {
super(next);
this.cousinTube = cousinTube;
this.binding = binding;
if(cousinTube != null) {
this.port = cousinTube.port;
} else {
this.port = null;
}
}
Copy constructor for Tube.copy(TubeCloner)
. /**
* 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;
this.binding = that.binding;
}
protected WSBinding getBinding() {
return binding;
}
@Override
public NextAction processRequest(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, request);
}
// This is done here instead of the constructor, since User can change
// the roles and handlerchain after a stub/proxy is created.
setUpProcessorInternal();
MessageUpdatableContext context = getContext(request);
boolean isOneWay = checkOneWay(request);
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(request);
}
}
requestProcessingSucessful = true;
// Call next Tube
return doInvoke(super.next, request);
} catch (RuntimeException re) {
if(isOneWay) {
//Eat the exception, its already logged and close the transportBackChannel
if(request.transportBackChannel != null ) {
request.transportBackChannel.close();
}
request.setMessage(null);
return doReturnWith(request);
} else
throw re;
} finally {
if(!requestProcessingSucessful) {
initiateClosing(context.getMessageContext());
}
}
}
@Override
public NextAction processResponse(Packet response) {
setupExchange();
MessageUpdatableContext context = getContext(response);
try {
if (isHandleFalse() || (response.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(response);
}
setUpProcessorInternal();
boolean isFault = isHandleFault(response);
if (!isHandlerChainEmpty()) {
// Call handlers on Response
callHandlersOnResponse(context, isFault);
}
} finally {
initiateClosing(context.getMessageContext());
}
//Update Packet with user modifications
context.updatePacket();
return doReturnWith(response);
}
@Override
public NextAction processException(Throwable t) {
try {
return doThrow(t);
} finally {
Packet packet = Fiber.current().getPacket();
MessageUpdatableContext context = getContext(packet);
initiateClosing(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();
}
}
Must be overridden by HandlerTube that drives other handler tubes for processing a message.
On Client-side: ClientLogicalHandlerTube drives the Handler Processing.
On Server-side: In case SOAP Binding, ServerMessageHandlerTube drives the Handler Processing.
In case XML/HTTP Binding, ServerLogicalHandlerTube drives the Handler Processing.
If its a top HandlerTube, should override by calling #close(MessaggeContext);
/**
* Must be overridden by HandlerTube that drives other handler tubes for processing a message.
* On Client-side: ClientLogicalHandlerTube drives the Handler Processing.
* On Server-side: In case SOAP Binding, ServerMessageHandlerTube drives the Handler Processing.
* In case XML/HTTP Binding, ServerLogicalHandlerTube drives the Handler Processing.
*
*
* If its a top HandlerTube, should override by calling #close(MessaggeContext);
*
*/
protected void initiateClosing(MessageContext mc) {
// Do nothing
}
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.
On Client, SOAPHandlers are closed first and then LogicalHandlers
On Server, LogicalHandlers are closed first and then SOAPHandlers
/**
* 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.
*
* On Client, SOAPHandlers are closed first and then LogicalHandlers
* On Server, LogicalHandlers are closed first and then SOAPHandlers
*/
final public void close(MessageContext msgContext) {
//assuming cousinTube is called if requestProcessingSucessful is true
if (requestProcessingSucessful) {
if (cousinTube != null) {
cousinTube.close(msgContext);
}
}
if (processor != null)
closeHandlers(msgContext);
// Clean up the exchange for next invocation.
exchange = null;
requestProcessingSucessful = false;
}
On Client, Override by calling #closeClientHandlers(MessageContext mc)
On Server, Override by calling #closeServerHandlers(MessageContext mc)
The difference is the order in which they are closed.
Params: - mc –
/**
* On Client, Override by calling #closeClientHandlers(MessageContext mc)
* On Server, Override by calling #closeServerHandlers(MessageContext mc)
* The difference is the order in which they are closed.
* @param mc
*/
abstract void closeHandlers(MessageContext mc);
Called by close(MessageContext mc) in a Client Handlertube
/**
* Called by close(MessageContext mc) in a Client Handlertube
*/
protected void closeClientsideHandlers(MessageContext msgContext) {
if (processor == null)
return;
if (remedyActionTaken) {
//Close only invoked handlers in the chain
//CLIENT-SIDE
processor.closeHandlers(msgContext, processor.getIndex(), 0);
processor.setIndex(-1);
//reset remedyActionTaken
remedyActionTaken = false;
} else {
//Close all handlers in the chain
//CLIENT-SIDE
processor.closeHandlers(msgContext, handlers.size() - 1, 0);
}
}
Called by close(MessageContext mc) in a Server Handlertube
/**
* Called by close(MessageContext mc) in a Server Handlertube
*/
protected void closeServersideHandlers(MessageContext msgContext) {
if (processor == null)
return;
if (remedyActionTaken) {
//Close only invoked handlers in the chain
//SERVER-SIDE
processor.closeHandlers(msgContext, processor.getIndex(), handlers.size() - 1);
processor.setIndex(-1);
//reset remedyActionTaken
remedyActionTaken = false;
} else {
//Close all handlers in the chain
//SERVER-SIDE
processor.closeHandlers(msgContext, 0, handlers.size() - 1);
}
}
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 application's intention --- whether it was invokeOneway vs invoke,etc.
*/
return !(packet.expectReply != null && packet.expectReply);
}
}
private void setUpProcessorInternal() {
HandlerConfiguration hc = ((BindingImpl) binding).getHandlerConfig();
if (hc != this.hc)
resetProcessor();
this.hc = hc;
setUpProcessor();
}
abstract void setUpProcessor();
protected void resetProcessor() {
handlers = null;
}
final public boolean isHandlerChainEmpty() {
return handlers.isEmpty();
}
abstract MessageUpdatableContext getContext(Packet p);
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;
}
} else {
if(cousinTube != null) {
cousinTube.exchange = exchange;
}
}
}
private HandlerTubeExchange exchange;
This class is used primarily to exchange information or status between
LogicalHandlerTube and SOAPHandlerTube
/**
* 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;
}
}
}