private boolean handleFault(int i) {
    Handler handler = _chain.get(i);

    boolean success = false;
    _invoked[i] = true;

    try {
      if (handler instanceof LogicalHandler) {
        _logicalContext.getMessage().setPayload(_source);
        success = handler.handleFault(_logicalContext);
        _source = _logicalContext.getMessage().getPayload();
      } else if (handler instanceof SOAPHandler) {
        try {
          _soapContext.setMessage(_source);
          success = handler.handleFault(_soapContext);
          _source = _soapContext.getMessage().getSOAPPart().getContent();
        } catch (SOAPException e) {
          throw new WebServiceException(e);
        }
      } else {
        throw new WebServiceException(
            L.l("Unsupported Handler type: {0}", handler.getClass().getName()));
      }

      _protocolException = null;
    } catch (ProtocolException e) {
      _protocolException = e;
      serializeProtocolException();
    } catch (RuntimeException e) {
      _runtimeException = e;
      serializeRuntimeException();
    }

    return success;
  }
  public boolean invokeInboundFaultHandlers() {
    for (_i++; _i < _chain.size(); _i++) {
      if (!handleFault(_i)) return false;

      if (_runtimeException != null) return false;
    }

    return true;
  }
  public InputStream invokeServerInbound(HttpServletRequest request, OutputStream os)
      throws IOException {
    Map<String, DataHandler> attachments = new HashMap<String, DataHandler>();

    Map<String, Object> httpProperties = new HashMap<String, Object>();
    httpProperties.put(HTTP_REQUEST_METHOD, request.getMethod());

    Map<String, List<String>> headers = new HashMap<String, List<String>>();

    Enumeration headerNames = request.getHeaderNames();

    while (headerNames.hasMoreElements()) {
      String name = (String) headerNames.nextElement();
      List<String> values = new ArrayList<String>();

      Enumeration headerValues = request.getHeaders(name);

      while (headerValues.hasMoreElements()) {
        String value = (String) headerValues.nextElement();
        values.add(value);
      }

      headers.put(name, values);
    }

    httpProperties.put(HTTP_REQUEST_HEADERS, headers);

    prepare(httpProperties, /*request=*/ true);

    if (!invokeInbound(request.getInputStream(), attachments)) {
      if (getProtocolException() != null) {
        reverseDirection();
        invokeInboundFaultHandlers();
      } else if (getRuntimeException() == null) uninvokeInbound();

      closeServer();
      finish(os);

      return null;
    }

    return finish();
  }
  /**
   * When a message direction is reversed within the chain, this method runs the message backwards
   * through the previous handlers. This method should only be invoked when a handler returns false,
   * but does not throw any kind of exception.
   */
  public boolean uninvokeInbound() throws WebServiceException {
    // Set the mandatory properties
    _logicalContext.put(MESSAGE_OUTBOUND_PROPERTY, Boolean.TRUE);
    _soapContext.put(MESSAGE_OUTBOUND_PROPERTY, Boolean.TRUE);

    for (_i++; _i < _chain.size(); _i++) {
      boolean success = handleMessage(_i);

      if (_protocolException != null) return false;

      if (_runtimeException != null) return false;

      if (!success) return false;
    }

    return true;
  }
  private void close(int i) {
    Handler handler = _chain.get(i);

    if (!_invoked[i]) return;

    _invoked[i] = false;

    if (handler instanceof LogicalHandler) {
      _logicalContext.getMessage().setPayload(_source);
      handler.close(_logicalContext);
      _source = _logicalContext.getMessage().getPayload();
    } else if (handler instanceof SOAPHandler) {
      try {
        _soapContext.setMessage(_source);
        handler.close(_soapContext);
        _source = _soapContext.getMessage().getSOAPPart().getContent();
      } catch (SOAPException e) {
        throw new WebServiceException(e);
      }
    }
  }
  /** Invoke the handler chain for an outbound message. */
  public boolean invokeOutbound(Source source, Map<String, DataHandler> attachments)
      throws WebServiceException {
    _source = source;

    // Set the mandatory properties
    _logicalContext.put(MESSAGE_OUTBOUND_PROPERTY, Boolean.TRUE);
    _soapContext.put(MESSAGE_OUTBOUND_PROPERTY, Boolean.TRUE);

    _logicalContext.put(OUTBOUND_MESSAGE_ATTACHMENTS, attachments);
    _soapContext.put(OUTBOUND_MESSAGE_ATTACHMENTS, attachments);

    for (_i = 0; _i < _chain.size(); _i++) {
      boolean success = handleMessage(_i);

      if (_protocolException != null) return false;

      if (_runtimeException != null) return false;

      if (!success) return false;
    }

    return true;
  }
  /** Invoke the handler chain for an inbound message. */
  public boolean invokeInbound(InputStream in, Map<String, DataHandler> attachments)
      throws WebServiceException {
    _outbound = false;
    _source = null;

    try {
      DOMResult dom = new DOMResult();
      getTransformer().transform(new StreamSource(in), dom);

      // XXX The TCK seems to assume a source that will stand up to repeated
      // reads... meaning that StreamSource and SAXSource are out, so DOM
      // must be what they want.
      _source = new DOMSource(dom.getNode());
    } catch (Exception e) {
      throw new WebServiceException(e);
    }

    // Set the mandatory properties
    _logicalContext.put(MESSAGE_OUTBOUND_PROPERTY, Boolean.FALSE);
    _soapContext.put(MESSAGE_OUTBOUND_PROPERTY, Boolean.FALSE);

    _logicalContext.put(INBOUND_MESSAGE_ATTACHMENTS, attachments);
    _soapContext.put(INBOUND_MESSAGE_ATTACHMENTS, attachments);

    // NOTE: the order is reversed for inbound messages
    for (_i = _chain.size() - 1; _i >= 0; _i--) {
      boolean success = handleMessage(_i);

      if (_protocolException != null) return false;

      if (_runtimeException != null) return false;

      if (!success) return false;
    }

    return true;
  }
 public HandlerChainInvoker(List<Handler> chain, BindingProvider bindingProvider) {
   _chain = JAXWSUtil.sortHandlerChain(chain);
   _invoked = new boolean[_chain.size()];
   _bindingProvider = bindingProvider;
 }
 public void closeClient() {
   for (int i = _chain.size() - 1; i >= 0; i--) close(i);
 }
 public void closeServer() {
   for (int i = 0; i < _chain.size(); i++) close(i);
 }