/*
* 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.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
/**
* @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.
Params: - chain – A list of handler objects, which can
be protocol or logical handlers.
/**
* 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
/**
* 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
/**
* 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.
/**
* 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. *
/**
* 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.
/**
* 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.
/**
* 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
/**
* 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.
/**
* 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
/**
* 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.
/**
* 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);
}
}
}
}
}