0001: /*
0002: * Portions Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025: package com.sun.xml.internal.ws.handler;
0026:
0027: import com.sun.xml.internal.ws.spi.runtime.WSConnection;
0028: import javax.xml.namespace.QName;
0029: import javax.xml.soap.SOAPBody;
0030: import javax.xml.soap.SOAPEnvelope;
0031: import javax.xml.soap.SOAPException;
0032: import javax.xml.soap.SOAPFault;
0033: import javax.xml.soap.SOAPMessage;
0034: import javax.xml.ws.LogicalMessage;
0035: import javax.xml.ws.ProtocolException;
0036: import javax.xml.ws.handler.Handler;
0037: import javax.xml.ws.handler.LogicalHandler;
0038: import javax.xml.ws.handler.LogicalMessageContext;
0039: import javax.xml.ws.handler.MessageContext;
0040: import javax.xml.ws.handler.soap.SOAPHandler;
0041: import javax.xml.ws.handler.soap.SOAPMessageContext;
0042: import javax.xml.ws.http.HTTPException;
0043: import javax.xml.ws.soap.SOAPFaultException;
0044:
0045: import java.util.ArrayList;
0046: import java.util.HashSet;
0047: import java.util.List;
0048: import java.util.Set;
0049: import java.util.logging.Level;
0050: import java.util.logging.Logger;
0051:
0052: import com.sun.xml.internal.ws.encoding.soap.SOAPConstants;
0053: import com.sun.xml.internal.ws.encoding.soap.SOAP12Constants;
0054: import com.sun.xml.internal.ws.encoding.soap.streaming.SOAP12NamespaceConstants;
0055:
0056: /**
0057: * The class stores the actual "chain" of handlers that is called
0058: * during a request or response. On the client side, it is created
0059: * by a {@link com.sun.xml.internal.ws.binding.BindingImpl} class when a
0060: * binding provider is created. On the server side, where a Binding
0061: * object may be passed from an outside source, the handler chain
0062: * caller may be created by the message dispatcher classes.
0063: *
0064: * <p>When created, a java.util.List of Handlers is passed in. This list
0065: * is sorted into logical and protocol handlers, so the handler order
0066: * that is returned from getHandlerChain() may be different from the
0067: * original that was passed in.
0068: *
0069: * <p>At runtime, one of the callHandlers() methods is invoked by the
0070: * soap or xml message dispatchers, passing in a {@link HandlerContext}
0071: * or {@link XMLHandlerContext} object along with other information
0072: * about the current message that is required for proper handler flow.
0073: *
0074: * <p>Exceptions are logged in many cases here before being rethrown. This
0075: * is to help primarily with server side handlers.
0076: *
0077: * <p>Currently, the handler chain caller checks for a null soap
0078: * message context to see if the binding in use is XML/HTTP.
0079: *
0080: * @see com.sun.xml.internal.ws.binding.BindingImpl
0081: * @see com.sun.xml.internal.ws.protocol.soap.client.SOAPMessageDispatcher
0082: * @see com.sun.xml.internal.ws.protocol.soap.server.SOAPMessageDispatcher
0083: * @see com.sun.xml.internal.ws.protocol.xml.server.XMLMessageDispatcher
0084: *
0085: * @author WS Development Team
0086: */
0087: public class HandlerChainCaller {
0088:
0089: public static final String HANDLER_CHAIN_CALLER = "handler_chain_caller";
0090: public static final String IGNORE_FAULT_PROPERTY = "ignore fault in message";
0091:
0092: private static final Logger logger = Logger
0093: .getLogger(com.sun.xml.internal.ws.util.Constants.LoggingDomain
0094: + ".handler");
0095:
0096: // need request or response for Handle interface
0097: public enum RequestOrResponse {
0098: REQUEST, RESPONSE
0099: }
0100:
0101: public enum Direction {
0102: OUTBOUND, INBOUND
0103: }
0104:
0105: private Set<QName> understoodHeaders;
0106: private List<Handler> handlers; // may be logical/soap mixed
0107:
0108: private List<LogicalHandler> logicalHandlers;
0109: private List<SOAPHandler> soapHandlers;
0110:
0111: private Set<String> roles;
0112:
0113: /**
0114: * The handlers that are passed in will be sorted into
0115: * logical and soap handlers. During this sorting, the
0116: * understood headers are also obtained from any soap
0117: * handlers.
0118: *
0119: * @param chain A list of handler objects, which can
0120: * be protocol or logical handlers.
0121: */
0122: public HandlerChainCaller(List<Handler> chain) {
0123: if (chain == null) { // should only happen in testing
0124: chain = new ArrayList<Handler>();
0125: }
0126: handlers = chain;
0127: logicalHandlers = new ArrayList<LogicalHandler>();
0128: soapHandlers = new ArrayList<SOAPHandler>();
0129: understoodHeaders = new HashSet<QName>();
0130: sortHandlers();
0131: }
0132:
0133: /**
0134: * This list may be different than the chain that is passed
0135: * in since the logical and protocol handlers must be separated.
0136: *
0137: * @return The list of handlers, sorted by logical and then protocol.
0138: */
0139: public List<Handler> getHandlerChain() {
0140: return handlers;
0141: }
0142:
0143: public boolean hasHandlers() {
0144: return (handlers.size() != 0);
0145: }
0146:
0147: /**
0148: * These are set by the SOAPBindingImpl when it creates the
0149: * HandlerChainCaller or when new roles are set on the binding.
0150: *
0151: * @param roles A set of roles strings.
0152: */
0153: public void setRoles(Set<String> roles) {
0154: this .roles = roles;
0155: }
0156:
0157: /**
0158: * Returns the roles that were passed in by the binding
0159: * in the case of soap binding.
0160: */
0161: public Set<String> getRoles() {
0162: return roles;
0163: }
0164:
0165: /**
0166: * Returns the headers understood by the handlers. This set
0167: * is created when the handler chain caller is instantiated and
0168: * the handlers are sorted. The set is comprised of headers
0169: * returned from SOAPHandler.getHeaders() method calls.
0170: *
0171: * @return The set of all headers that the handlers declare
0172: * that they understand.
0173: */
0174: public Set<QName> getUnderstoodHeaders() {
0175: return understoodHeaders;
0176: }
0177:
0178: /**
0179: * This method separates the logical and protocol handlers. When
0180: * this method returns, the original "handlers" List has been
0181: * resorted.
0182: */
0183: private void sortHandlers() {
0184: for (Handler handler : handlers) {
0185: if (LogicalHandler.class.isAssignableFrom(handler
0186: .getClass())) {
0187: logicalHandlers.add((LogicalHandler) handler);
0188: } else if (SOAPHandler.class.isAssignableFrom(handler
0189: .getClass())) {
0190: soapHandlers.add((SOAPHandler) handler);
0191: Set<QName> headers = ((SOAPHandler) handler)
0192: .getHeaders();
0193: if (headers != null) {
0194: understoodHeaders.addAll(headers);
0195: }
0196: } else if (Handler.class.isAssignableFrom(handler
0197: .getClass())) {
0198: throw new HandlerException(
0199: "cannot.extend.handler.directly", handler
0200: .getClass().toString());
0201: } else {
0202: throw new HandlerException("handler.not.valid.type",
0203: handler.getClass().toString());
0204: }
0205: }
0206: handlers.clear();
0207: handlers.addAll(logicalHandlers);
0208: handlers.addAll(soapHandlers);
0209: }
0210:
0211: /**
0212: * Replace the message in the given message context with a
0213: * fault message. If the context already contains a fault
0214: * message, then return without changing it.
0215: * Also sets the HTTP_RESPONSE_CODE in the context on Server-side.
0216: */
0217: private void insertFaultMessage(ContextHolder holder,
0218: ProtocolException exception) {
0219: try {
0220: SOAPMessageContext context = holder.getSMC();
0221: if (context == null) { // non-soap case
0222: LogicalMessageContext lmc = holder.getLMC();
0223: LogicalMessage msg = lmc.getMessage();
0224: if (msg != null) {
0225: msg.setPayload(null);
0226: }
0227: //Set Status Code only if it is on server
0228: if ((Boolean) lmc
0229: .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
0230: if (exception instanceof HTTPException) {
0231: lmc.put(MessageContext.HTTP_RESPONSE_CODE,
0232: ((HTTPException) exception)
0233: .getStatusCode());
0234: } else {
0235: lmc.put(MessageContext.HTTP_RESPONSE_CODE,
0236: WSConnection.INTERNAL_ERR);
0237: }
0238: }
0239: return;
0240: }
0241: //Set Status Code only if it is on server
0242: if ((Boolean) context
0243: .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
0244: context.put(MessageContext.HTTP_RESPONSE_CODE,
0245: WSConnection.INTERNAL_ERR);
0246: }
0247: SOAPMessage message = context.getMessage();
0248: SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
0249: SOAPBody body = envelope.getBody();
0250: if (body.hasFault()) {
0251: return;
0252: }
0253: if (envelope.getHeader() != null) {
0254: envelope.getHeader().detachNode();
0255: }
0256:
0257: body.removeContents();
0258: SOAPFault fault = body.addFault();
0259: String envelopeNamespace = envelope.getNamespaceURI();
0260:
0261: if (exception instanceof SOAPFaultException) {
0262: SOAPFaultException sfe = (SOAPFaultException) exception;
0263: SOAPFault userFault = sfe.getFault();
0264:
0265: QName faultCode = userFault.getFaultCodeAsQName();
0266: if (faultCode == null) {
0267: faultCode = determineFaultCode(context);
0268: }
0269: fault.setFaultCode(faultCode);
0270:
0271: String faultString = userFault.getFaultString();
0272: if (faultString == null) {
0273: if (sfe.getMessage() != null) {
0274: faultString = sfe.getMessage();
0275: } else {
0276: faultString = sfe.toString();
0277: }
0278: }
0279: fault.setFaultString(faultString);
0280:
0281: String faultActor = userFault.getFaultActor();
0282: if (faultActor == null) {
0283: faultActor = "";
0284: }
0285: fault.setFaultActor(faultActor);
0286:
0287: if (userFault.getDetail() != null) {
0288: fault.addChildElement(userFault.getDetail());
0289: }
0290: } else {
0291: fault.setFaultCode(determineFaultCode(context));
0292: if (exception.getMessage() != null) {
0293: fault.setFaultString(exception.getMessage());
0294: } else {
0295: fault.setFaultString(exception.toString());
0296: }
0297: }
0298: } catch (Exception e) {
0299: // severe since this is from runtime and not handler
0300: logger
0301: .log(
0302: Level.SEVERE,
0303: "exception while creating fault message in handler chain",
0304: e);
0305: throw new RuntimeException(e);
0306: }
0307: }
0308:
0309: /**
0310: * <p>The expectation of the rest of the code is that,
0311: * if a ProtocolException is thrown from the handler chain,
0312: * the message contents reflect the protocol exception.
0313: * However, if a new ProtocolException is thrown from
0314: * the handleFault method, then the fault should be
0315: * ignored and the new exception should be dispatched.
0316: *
0317: * <p>This method simply sets a property that is checked
0318: * by the client and server code when a ProtocolException
0319: * is caught. The property can be checked with
0320: * {@link MessageContextUtil#ignoreFaultInMessage}
0321: */
0322: private void addIgnoreFaultProperty(ContextHolder holder) {
0323: LogicalMessageContext context = holder.getLMC();
0324: context.put(IGNORE_FAULT_PROPERTY, Boolean.TRUE);
0325: }
0326:
0327: /**
0328: * <p>Figure out if the fault code local part is client,
0329: * server, sender, receiver, etc. This is called by
0330: * insertFaultMessage.
0331: *
0332: * <p>This method should only be called when there is a ProtocolException
0333: * during request. Reverse the Message direction first,
0334: * So this method can use the MESSAGE_OUTBOUND_PROPERTY
0335: * to determine whether it is being called on the client
0336: * or the server side. If this changes in the spec, then
0337: * something else will need to be passed to the method
0338: * to determine whether the fault code is client or server.
0339: *
0340: * <p>For determining soap version, start checking with the
0341: * latest version and default to soap 1.1.
0342: */
0343: private QName determineFaultCode(SOAPMessageContext context)
0344: throws SOAPException {
0345:
0346: SOAPEnvelope envelope = context.getMessage().getSOAPPart()
0347: .getEnvelope();
0348: String uri = envelope.getNamespaceURI();
0349:
0350: // client case
0351: if (!(Boolean) context
0352: .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
0353: if (uri.equals(SOAP12NamespaceConstants.ENVELOPE)) {
0354: return SOAP12Constants.FAULT_CODE_CLIENT;
0355: }
0356: return SOAPConstants.FAULT_CODE_CLIENT;
0357: }
0358:
0359: //server case
0360: if (uri.equals(SOAP12NamespaceConstants.ENVELOPE)) {
0361: return SOAP12Constants.FAULT_CODE_SERVER;
0362: }
0363: return SOAPConstants.FAULT_CODE_SERVER;
0364: }
0365:
0366: /**
0367: * <p>Method used to call handlers with a HandlerContext that
0368: * may contain logical and protocol handlers. This is the
0369: * main entry point for calling the handlers in the case
0370: * of SOAP binding. Before calling the handlers, the
0371: * handler chain caller will set the outbound property and
0372: * the roles on the message context.
0373: *
0374: * <p>Besides the context object passed in, the other information
0375: * is used to control handler execution and closing. See the
0376: * handler section of the spec for the rules concering handlers
0377: * returning false, throwing exceptions, etc.
0378: *
0379: * @param direction Inbound or outbound.
0380: * @param messageType Request or response.
0381: * @param context A soap handler context containing the message.
0382: * @param responseExpected A boolean indicating whether or not
0383: * a response is expected to the current message (should be false
0384: * for responses or one-way requests).
0385: *
0386: * @return True in the normal case, false if a handler
0387: * returned false. This normally means that the runtime
0388: * should reverse direction if called during a request.
0389: */
0390: public boolean callHandlers(Direction direction,
0391: RequestOrResponse messageType, SOAPHandlerContext context,
0392: boolean responseExpected) {
0393:
0394: return internalCallHandlers(direction, messageType,
0395: new ContextHolder(context), responseExpected);
0396: }
0397:
0398: /**
0399: * Method used to call handlers with a HandlerContext that
0400: * may contain logical handlers only. This is the
0401: * main entry point for calling the handlers in the case
0402: * of http binding. Before calling the handlers, the
0403: * handler chain caller will set the outbound property on
0404: * the message context.
0405: *
0406: * <p>Besides the context object passed in, the other information
0407: * is used to control handler execution and closing. See the
0408: * handler section of the spec for the rules concering handlers
0409: * returning false, throwing exceptions, etc.
0410: *
0411: * @param direction Inbound or outbound.
0412: * @param messageType Request or response.
0413: * @param context A soap handler context containing the message.
0414: * @param responseExpected A boolean indicating whether or not
0415: * a response is expected to the current message (should be false
0416: * for responses or one-way requests).
0417: *
0418: * @return True in the normal case, false if a handler
0419: * returned false. This normally means that the runtime
0420: * should reverse direction if called during a request.
0421: */
0422: public boolean callHandlers(Direction direction,
0423: RequestOrResponse messageType, XMLHandlerContext context,
0424: boolean responseExpected) {
0425:
0426: return internalCallHandlers(direction, messageType,
0427: new ContextHolder(context), responseExpected);
0428: }
0429:
0430: /**
0431: * Main runtime method, called internally by the callHandlers()
0432: * methods that may be called with HandlerContext or
0433: * XMLHandlerContext objects.
0434: *
0435: * The boolean passed in is whether or not a response is required
0436: * for the current message. See section 5.3.2. (todo: this section
0437: * is going to change).
0438: *
0439: * The callLogicalHandlers and callProtocolHandlers methods will
0440: * take care of execution once called and return true or false or
0441: * throw an exception.
0442: */
0443: private boolean internalCallHandlers(Direction direction,
0444: RequestOrResponse messageType, ContextHolder ch,
0445: boolean responseExpected) {
0446:
0447: // set outbound property
0448: ch.getLMC().put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0449: (direction == Direction.OUTBOUND));
0450:
0451: // if there is as soap message context, set roles
0452: if (ch.getSMC() != null) {
0453: ((SOAPMessageContextImpl) ch.getSMC()).setRoles(getRoles());
0454: }
0455:
0456: // call handlers
0457: if (direction == Direction.OUTBOUND) {
0458: if (callLogicalHandlers(ch, direction, messageType,
0459: responseExpected) == false) {
0460: return false;
0461: }
0462: if (callProtocolHandlers(ch, direction, messageType,
0463: responseExpected) == false) {
0464: return false;
0465: }
0466: } else {
0467: if (callProtocolHandlers(ch, direction, messageType,
0468: responseExpected) == false) {
0469: return false;
0470: }
0471: if (callLogicalHandlers(ch, direction, messageType,
0472: responseExpected) == false) {
0473: return false;
0474: }
0475: }
0476:
0477: /*
0478: * Close if MEP finished. Server code responsible for closing
0479: * handlers if it determines that an incoming request is a
0480: * one way message.
0481: */
0482: if (!responseExpected) {
0483: if (messageType == RequestOrResponse.REQUEST) {
0484: if (direction == Direction.INBOUND) {
0485: closeHandlersServer(ch);
0486: } else {
0487: closeHandlersClient(ch);
0488: }
0489: } else {
0490: if (direction == Direction.INBOUND) {
0491: closeHandlersClient(ch);
0492: } else {
0493: closeHandlersServer(ch);
0494: }
0495: }
0496: }
0497: return true;
0498: }
0499:
0500: /**
0501: * This method called by the server when an endpoint has thrown
0502: * an exception. This method calls handleFault on the handlers
0503: * and closes them. Because this method is called only during
0504: * a response after the endpoint has been reached, all of the
0505: * handlers have been called during the request and so all are
0506: * closed.
0507: */
0508: public boolean callHandleFault(SOAPHandlerContext context) {
0509: ContextHolder ch = new ContextHolder(context);
0510: ch.getSMC().put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, true);
0511: ((SOAPMessageContextImpl) ch.getSMC()).setRoles(getRoles());
0512:
0513: int i = 0; // counter for logical handlers
0514: int j = 0; // counter for protocol handlers
0515: try {
0516: while (i < logicalHandlers.size()) {
0517: if (logicalHandlers.get(i).handleFault(ch.getLMC()) == false) {
0518: return false;
0519: }
0520: i++;
0521: }
0522: while (j < soapHandlers.size()) {
0523: if (soapHandlers.get(j).handleFault(ch.getSMC()) == false) {
0524: return false;
0525: }
0526: j++;
0527: }
0528: } catch (RuntimeException re) {
0529: logger.log(Level.FINER, "exception in handler chain", re);
0530: throw re;
0531: } finally {
0532: closeHandlersServer(ch); // this is always called on server side
0533: }
0534: return true;
0535: }
0536:
0537: /**
0538: * This method called by the client when it sees a SOAPFault message.
0539: * This method calls handleFault on the handlers and closes them. Because
0540: * this method is called only during a response, all of the handlers have
0541: * been called during the request and so all are closed.
0542: */
0543: public boolean callHandleFaultOnClient(SOAPHandlerContext context) {
0544: ContextHolder ch = new ContextHolder(context);
0545: ch.getSMC()
0546: .put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, false);
0547: ((SOAPMessageContextImpl) ch.getSMC()).setRoles(getRoles());
0548:
0549: try {
0550: for (int i = soapHandlers.size() - 1; i >= 0; i--) {
0551: if (soapHandlers.get(i).handleFault(ch.getSMC()) == false) {
0552: return false;
0553: }
0554: }
0555: for (int i = logicalHandlers.size() - 1; i >= 0; i--) {
0556: if (logicalHandlers.get(i).handleFault(ch.getLMC()) == false) {
0557: return false;
0558: }
0559: }
0560: } catch (RuntimeException re) {
0561: logger.log(Level.FINER, "exception in handler chain", re);
0562: throw re;
0563: } finally {
0564: closeHandlersClient(ch);
0565: }
0566: return true;
0567: }
0568:
0569: /**
0570: * Called from the main callHandlers() method.
0571: * Logical message context updated before this method is called.
0572: */
0573: private boolean callLogicalHandlers(ContextHolder holder,
0574: Direction direction, RequestOrResponse type,
0575: boolean responseExpected) {
0576:
0577: if (direction == Direction.OUTBOUND) {
0578: int i = 0;
0579: try {
0580: while (i < logicalHandlers.size()) {
0581: if (logicalHandlers.get(i).handleMessage(
0582: holder.getLMC()) == false) {
0583: if (responseExpected) {
0584: // reverse and call handle message
0585: holder
0586: .getLMC()
0587: .put(
0588: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0589: false);
0590: callLogicalHandleMessage(holder, i - 1, 0);
0591: }
0592: if (type == RequestOrResponse.RESPONSE) {
0593: closeHandlersServer(holder);
0594: } else {
0595: closeLogicalHandlers(holder, i, 0);
0596: }
0597: return false;
0598: }
0599: i++;
0600: }
0601: } catch (RuntimeException re) {
0602: logger.log(Level.FINER, "exception in handler chain",
0603: re);
0604: if (responseExpected && re instanceof ProtocolException) {
0605: // reverse direction and handle fault
0606: holder.getLMC().put(
0607: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0608: false);
0609: insertFaultMessage(holder, (ProtocolException) re);
0610: if (i > 0) {
0611: try {
0612: callLogicalHandleFault(holder, i - 1, 0);
0613: } catch (ProtocolException re1) {
0614: addIgnoreFaultProperty(holder);
0615: re = re1;
0616: } catch (RuntimeException re2) {
0617: re = re2;
0618: }
0619: }
0620: }
0621: if (type == RequestOrResponse.RESPONSE) {
0622: closeHandlersServer(holder);
0623: } else {
0624: closeLogicalHandlers(holder, i, 0);
0625: }
0626: throw re;
0627: }
0628: } else { // inbound case, H(x) -> H(x-1) -> ... H(1) -> H(0)
0629: int i = logicalHandlers.size() - 1;
0630: try {
0631: while (i >= 0) {
0632: if (logicalHandlers.get(i).handleMessage(
0633: holder.getLMC()) == false) {
0634:
0635: if (responseExpected) {
0636: // reverse and call handle message/response
0637: holder
0638: .getLMC()
0639: .put(
0640: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0641: true);
0642: callLogicalHandleMessage(holder, i + 1,
0643: logicalHandlers.size() - 1);
0644: callProtocolHandleMessage(holder, 0,
0645: soapHandlers.size() - 1);
0646: }
0647: if (type == RequestOrResponse.RESPONSE) {
0648: closeHandlersClient(holder);
0649: } else {
0650: closeLogicalHandlers(holder, i,
0651: logicalHandlers.size() - 1);
0652: closeProtocolHandlers(holder, 0,
0653: soapHandlers.size() - 1);
0654: }
0655: return false;
0656: }
0657: i--;
0658: }
0659: } catch (RuntimeException re) {
0660: logger.log(Level.FINER, "exception in handler chain",
0661: re);
0662: if (responseExpected && re instanceof ProtocolException) {
0663: // reverse direction and handle fault
0664: holder.getLMC().put(
0665: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0666: true);
0667: insertFaultMessage(holder, (ProtocolException) re);
0668:
0669: try {
0670: // if i==size-1, no more logical handlers to call
0671: if (i == logicalHandlers.size() - 1
0672: || callLogicalHandleFault(holder,
0673: i + 1,
0674: logicalHandlers.size() - 1)) {
0675: callProtocolHandleFault(holder, 0,
0676: soapHandlers.size() - 1);
0677: }
0678: } catch (ProtocolException re1) {
0679: addIgnoreFaultProperty(holder);
0680: re = re1;
0681: } catch (RuntimeException re2) {
0682: re = re2;
0683: }
0684: }
0685: if (type == RequestOrResponse.RESPONSE) {
0686: closeHandlersClient(holder);
0687: } else {
0688: closeLogicalHandlers(holder, i, logicalHandlers
0689: .size() - 1);
0690: closeProtocolHandlers(holder, 0, soapHandlers
0691: .size() - 1);
0692: }
0693: throw re;
0694: }
0695: }
0696:
0697: return true;
0698: }
0699:
0700: /**
0701: * Called from the main callHandlers() method.
0702: * SOAP message context updated before this method is called.
0703: */
0704: private boolean callProtocolHandlers(ContextHolder holder,
0705: Direction direction, RequestOrResponse type,
0706: boolean responseExpected) {
0707:
0708: if (direction == Direction.OUTBOUND) {
0709: int i = 0;
0710: try {
0711: while (i < soapHandlers.size()) {
0712: if (soapHandlers.get(i).handleMessage(
0713: holder.getSMC()) == false) {
0714:
0715: if (responseExpected) {
0716: // reverse and call handle message/response
0717: holder
0718: .getSMC()
0719: .put(
0720: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0721: false);
0722: if (i > 0) {
0723: callProtocolHandleMessage(holder,
0724: i - 1, 0);
0725: }
0726: callLogicalHandleMessage(holder,
0727: logicalHandlers.size() - 1, 0);
0728: }
0729: if (type == RequestOrResponse.RESPONSE) {
0730: closeHandlersServer(holder);
0731: } else {
0732: closeProtocolHandlers(holder, i, 0);
0733: closeLogicalHandlers(holder,
0734: logicalHandlers.size() - 1, 0);
0735: }
0736: return false;
0737: }
0738: i++;
0739: }
0740: } catch (RuntimeException re) {
0741: logger.log(Level.FINER, "exception in handler chain",
0742: re);
0743: if (responseExpected && re instanceof ProtocolException) {
0744: // reverse direction and handle fault
0745: holder.getSMC().put(
0746: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0747: false);
0748: insertFaultMessage(holder, (ProtocolException) re);
0749: try {
0750: if (i == 0 || // still on first handler
0751: callProtocolHandleFault(holder, i - 1,
0752: 0)) {
0753: callLogicalHandleFault(holder,
0754: logicalHandlers.size() - 1, 0);
0755: }
0756: } catch (ProtocolException re1) {
0757: addIgnoreFaultProperty(holder);
0758: re = re1;
0759: } catch (RuntimeException re2) {
0760: re = re2;
0761: }
0762: }
0763: if (type == RequestOrResponse.RESPONSE) {
0764: closeHandlersServer(holder);
0765: } else {
0766: closeProtocolHandlers(holder, i, 0);
0767: closeLogicalHandlers(holder,
0768: logicalHandlers.size() - 1, 0);
0769: }
0770: throw re;
0771: }
0772: } else { // inbound case, H(x) -> H(x-1) -> ... H(1) -> H(0)
0773: int i = soapHandlers.size() - 1;
0774: try {
0775: while (i >= 0) {
0776: if (soapHandlers.get(i).handleMessage(
0777: holder.getSMC()) == false) {
0778:
0779: // reverse and call handle message/response
0780: holder
0781: .getSMC()
0782: .put(
0783: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0784: true);
0785: if (responseExpected
0786: && i != soapHandlers.size() - 1) {
0787: callProtocolHandleMessage(holder, i + 1,
0788: soapHandlers.size() - 1);
0789: }
0790: if (type == RequestOrResponse.RESPONSE) {
0791: closeHandlersClient(holder);
0792: } else {
0793: closeProtocolHandlers(holder, i,
0794: soapHandlers.size() - 1);
0795: }
0796: return false;
0797: }
0798: i--;
0799: }
0800: } catch (RuntimeException re) {
0801: logger.log(Level.FINER, "exception in handler chain",
0802: re);
0803: if (responseExpected && re instanceof ProtocolException) {
0804: // reverse direction and handle fault
0805: holder.getSMC().put(
0806: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
0807: true);
0808: insertFaultMessage(holder, (ProtocolException) re);
0809: try {
0810: if (i < soapHandlers.size() - 1) {
0811: callProtocolHandleFault(holder, i + 1,
0812: soapHandlers.size() - 1);
0813: }
0814: } catch (ProtocolException re1) {
0815: addIgnoreFaultProperty(holder);
0816: re = re1;
0817: } catch (RuntimeException re2) {
0818: re = re2;
0819: }
0820: }
0821: if (type == RequestOrResponse.RESPONSE) {
0822: closeHandlersClient(holder);
0823: } else {
0824: closeProtocolHandlers(holder, i, soapHandlers
0825: .size() - 1);
0826: }
0827: throw re;
0828: }
0829: }
0830: return true;
0831: }
0832:
0833: /**
0834: * Method called for abnormal processing (for instance, as the
0835: * result of a handler returning false during normal processing).
0836: * Start and end indices are inclusive.
0837: */
0838: private void callLogicalHandleMessage(ContextHolder holder,
0839: int start, int end) {
0840:
0841: if (logicalHandlers.isEmpty() || start == -1
0842: || start == logicalHandlers.size()) {
0843: return;
0844: }
0845: callGenericHandleMessage(logicalHandlers, holder.getLMC(),
0846: start, end);
0847:
0848: }
0849:
0850: /**
0851: * Method called for abnormal processing (for instance, as the
0852: * result of a handler returning false during normal processing).
0853: * Start and end indices are inclusive.
0854: */
0855: private void callProtocolHandleMessage(ContextHolder holder,
0856: int start, int end) {
0857:
0858: if (soapHandlers.isEmpty()) {
0859: return;
0860: }
0861: callGenericHandleMessage(soapHandlers, holder.getSMC(), start,
0862: end);
0863: }
0864:
0865: /**
0866: * Utility method for calling handleMessage during abnormal processing(for
0867: * instance, as the result of a handler returning false during normal
0868: * processing). Start and end indices are inclusive.
0869: */
0870:
0871: private <C extends MessageContext> void callGenericHandleMessage(
0872: List<? extends Handler> handlerList, C context, int start,
0873: int end) {
0874: if (handlerList.isEmpty()) {
0875: return;
0876: }
0877: int i = start;
0878: if (start > end) {
0879: try {
0880: while (i >= end) {
0881: if (handlerList.get(i).handleMessage(context) == false)
0882: return;
0883: i--;
0884: }
0885: } catch (RuntimeException re) {
0886: logger.log(Level.FINER, "exception in handler chain",
0887: re);
0888: throw re;
0889: }
0890: } else {
0891: try {
0892: while (i <= end) {
0893: if (handlerList.get(i).handleMessage(context) == false)
0894: return;
0895: i++;
0896: }
0897: } catch (RuntimeException re) {
0898: logger.log(Level.FINER, "exception in handler chain",
0899: re);
0900: throw re;
0901: }
0902: }
0903: return;
0904: }
0905:
0906: /*
0907: * Calls handleFault on the logical handlers. Indices are
0908: * inclusive. Exceptions get passed up the chain, and an
0909: * exception or return of 'false' ends processing.
0910: */
0911: private boolean callLogicalHandleFault(ContextHolder holder,
0912: int start, int end) {
0913:
0914: return callGenericHandleFault(logicalHandlers, holder.getLMC(),
0915: start, end);
0916: }
0917:
0918: /**
0919: * Calls handleFault on the protocol handlers. Indices are
0920: * inclusive. Exceptions get passed up the chain, and an
0921: * exception or return of 'false' ends processing.
0922: */
0923: private boolean callProtocolHandleFault(ContextHolder holder,
0924: int start, int end) {
0925:
0926: return callGenericHandleFault(soapHandlers, holder.getSMC(),
0927: start, end);
0928: }
0929:
0930: /*
0931: * Used by callLogicalHandleFault and callProtocolHandleFault.
0932: */
0933: private <C extends MessageContext> boolean callGenericHandleFault(
0934: List<? extends Handler> handlerList, C context, int start,
0935: int end) {
0936:
0937: if (handlerList.isEmpty()) {
0938: return true;
0939: }
0940: int i = start;
0941: if (start > end) {
0942: try {
0943: while (i >= end) {
0944: if (handlerList.get(i).handleFault(context) == false) {
0945:
0946: return false;
0947: }
0948: i--;
0949: }
0950: } catch (RuntimeException re) {
0951: logger.log(Level.FINER, "exception in handler chain",
0952: re);
0953: throw re;
0954: }
0955: } else {
0956: try {
0957: while (i <= end) {
0958: if (handlerList.get(i).handleFault(context) == false) {
0959:
0960: return false;
0961: }
0962: i++;
0963: }
0964: } catch (RuntimeException re) {
0965: logger.log(Level.FINER, "exception in handler chain",
0966: re);
0967: throw re;
0968: }
0969: }
0970: return true;
0971: }
0972:
0973: /**
0974: * Method that closes protocol handlers and then
0975: * logical handlers.
0976: */
0977: private void closeHandlersClient(ContextHolder holder) {
0978: closeProtocolHandlers(holder, soapHandlers.size() - 1, 0);
0979: closeLogicalHandlers(holder, logicalHandlers.size() - 1, 0);
0980: }
0981:
0982: /**
0983: * Method that closes logical handlers and then
0984: * protocol handlers.
0985: */
0986: private void closeHandlersServer(ContextHolder holder) {
0987: closeLogicalHandlers(holder, 0, logicalHandlers.size() - 1);
0988: closeProtocolHandlers(holder, 0, soapHandlers.size() - 1);
0989: }
0990:
0991: /**
0992: * This version is called by the server code once it determines
0993: * that an incoming message is a one-way request.
0994: */
0995: public void forceCloseHandlersOnServer(SOAPHandlerContext context) {
0996: ContextHolder ch = new ContextHolder(context);
0997: // only called after an inbound request
0998: ch.getSMC()
0999: .put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, false);
1000: ((SOAPMessageContextImpl) ch.getSMC()).setRoles(getRoles());
1001: closeHandlersServer(ch);
1002: }
1003:
1004: /**
1005: * It is called by the client when an MU fault occurs since the handlerchain
1006: * never gets invoked. The direction is an inbound message.
1007: */
1008: public void forceCloseHandlersOnClient(SOAPHandlerContext context) {
1009: ContextHolder ch = new ContextHolder(context);
1010:
1011: // only called after an inbound request
1012: ch.getSMC()
1013: .put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, false);
1014: ((SOAPMessageContextImpl) ch.getSMC()).setRoles(getRoles());
1015: closeHandlersClient(ch);
1016: }
1017:
1018: /**
1019: * Version of forceCloseHandlers(HandlerContext) that is used
1020: * by XML binding.
1021: */
1022: public void forceCloseHandlersOnServer(XMLHandlerContext context) {
1023: ContextHolder ch = new ContextHolder(context);
1024: // only called after an inbound request
1025: ch.getLMC()
1026: .put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, false);
1027: closeHandlersServer(ch);
1028: }
1029:
1030: /**
1031: * Version of forceCloseHandlers(HandlerContext) that is used
1032: * by XML binding.
1033: */
1034: public void forceCloseHandlersOnClient(XMLHandlerContext context) {
1035: ContextHolder ch = new ContextHolder(context);
1036: // only called after an inbound request
1037: ch.getLMC()
1038: .put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, false);
1039: closeHandlersClient(ch);
1040: }
1041:
1042: private void closeProtocolHandlers(ContextHolder holder, int start,
1043: int end) {
1044:
1045: closeGenericHandlers(soapHandlers, holder.getSMC(), start, end);
1046: }
1047:
1048: private void closeLogicalHandlers(ContextHolder holder, int start,
1049: int end) {
1050:
1051: closeGenericHandlers(logicalHandlers, holder.getLMC(), start,
1052: end);
1053: }
1054:
1055: /**
1056: * Calls close on the handlers from the starting
1057: * index through the ending index (inclusive). Made indices
1058: * inclusive to allow both directions more easily.
1059: */
1060: private void closeGenericHandlers(
1061: List<? extends Handler> handlerList,
1062: MessageContext context, int start, int end) {
1063:
1064: if (handlerList.isEmpty()) {
1065: return;
1066: }
1067: if (start > end) {
1068: for (int i = start; i >= end; i--) {
1069: try {
1070: handlerList.get(i).close(context);
1071: } catch (RuntimeException re) {
1072: logger.log(Level.INFO,
1073: "Exception ignored during close", re);
1074: }
1075: }
1076: } else {
1077: for (int i = start; i <= end; i++) {
1078: try {
1079: handlerList.get(i).close(context);
1080: } catch (RuntimeException re) {
1081: logger.log(Level.INFO,
1082: "Exception ignored during close", re);
1083: }
1084: }
1085: }
1086: }
1087:
1088: /**
1089: * Used to hold the context objects that are used to get
1090: * and set the current message.
1091: *
1092: * If a HandlerContext is passed in, both logical and soap
1093: * handlers are used. If XMLHandlerContext is passed in,
1094: * only logical handlers are assumed to be present.
1095: */
1096: static class ContextHolder {
1097:
1098: boolean logicalOnly;
1099: SOAPHandlerContext context;
1100: XMLHandlerContext xmlContext;
1101:
1102: ContextHolder(SOAPHandlerContext context) {
1103: this .context = context;
1104: logicalOnly = false;
1105: }
1106:
1107: ContextHolder(XMLHandlerContext xmlContext) {
1108: this .xmlContext = xmlContext;
1109: logicalOnly = true;
1110: }
1111:
1112: LogicalMessageContext getLMC() {
1113: return (logicalOnly ? xmlContext.getLogicalMessageContext()
1114: : context.getLogicalMessageContext());
1115: }
1116:
1117: SOAPMessageContext getSMC() {
1118: return (logicalOnly ? null : context
1119: .getSOAPMessageContext());
1120: }
1121: }
1122:
1123: }
|