You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ws.apache.org by Apache Wiki <wi...@apache.org> on 2008/02/28 14:22:24 UTC

[Ws Wiki] Update of "FrontPage/Axis/AxisClientConfiguration/InterruptCalls" by RodrigoRuiz

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Ws Wiki" for change notification.

The following page has been changed by RodrigoRuiz:
http://wiki.apache.org/ws/FrontPage/Axis/AxisClientConfiguration/InterruptCalls

The comment on the change is:
First draft, comments welcome.

New page:
= How do I interrupt a thread that is blocked in a remote call in Axis 1.4? =

If you have ever tried to, you may know that a thread performing a blocking I/O operation cannot be interrupted in Java. The problem lies in the JVM itself, and comes from the ages of Java 1.1. There are several bugs open in java.sun, and it looks like this behaviour [http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4385444 is here to stay].

There are two workarounds for this issue:

 * Use the new java.nio classes, and InterruptibleChannel in particular.
 * Close the stream. This will force the blocking operation to be cancelled.

Well, porting Axis 1.4 to Java NIO does not look like the way to go so, let's take a look at the second option.

The following is a subclass of HTTPSender that will allow us to close the socket (and hence its associated streams):

{{{
package org.apache.axis.transport.http;

import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.axis.AxisFault;
import org.apache.axis.MessageContext;
import org.apache.axis.components.net.BooleanHolder;

/**
 * HTTPSender modified to allow interruption during I/O read.
 */
public class InterruptibleHttpSender extends HTTPSender {

  private static final ConcurrentMap<Thread, Socket> SOCKETS
    = new ConcurrentHashMap<Thread, Socket>();

  /**
   * Interrupts the specified thread operation by closing its associated socket.
   *
   * @param t The thread to interrupt
   */
  public static void interrupt(Thread t) {
    Socket s = SOCKETS.get(t);
    if (s != null) {
      try {
        s.close();
      } catch (IOException ignore) { }
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override public void invoke(MessageContext msgContext) throws AxisFault {
    try {
      super.invoke(msgContext);
    } catch (AxisFault fault) {
      Thread t = Thread.currentThread();
      if (fault.getCause() instanceof SocketException && t.isInterrupted()) {
        fault = AxisFault.makeFault(new InterruptedException());
      }
      throw fault;
    } finally {
      SOCKETS.remove(Thread.currentThread());
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override protected void getSocket(SocketHolder sockHolder, MessageContext msgContext,
    String protocol, String host, int port, int timeout, StringBuffer otherHeaders,
    BooleanHolder useFullURL) throws Exception {

    super.getSocket(sockHolder, msgContext, protocol, host, port,
        timeout, otherHeaders, useFullURL);

    SOCKETS.put(Thread.currentThread(), sockHolder.getSocket());
  }
}
}}}

As you can see, I am using Java 5 ConcurrentMap to handle thread-safety. If you need to compile in Java 1.4, it can be replaced by a simple Hashtable.

Now, to put this class to work we need to do two things: register it, and use it :-)

For registering the class, we just need to modify the client-config.wsdd descriptor:

{{{
 <!--transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/-->
 <transport name="http" pivot="java:org.apache.axis.transport.http.InterruptibleHttpSender"/>
}}}

If this is not an option, there are [wiki:/AxisClientConfiguration other ways] to change the configuration.

Unfortunately, this class is not magic. The interruption of the thread must be done manually by calling the {{{InterruptibleHttpSender#interrupt(Thread)}}} static method. This call should be done AFTER calling {{{Thread#interrupt()}}}, because it depends on the "isInterrupted" state of the thread to correctly handle exceptions. So, wherever you have a call to Thread.interrupt(), you should do something like:

{{{
  Thread t = ...

  t.interrupt();
  InterruptibleHttpSender.interrupt(t);
}}}

This step can be partially automated by creating a custom Thread subclass:

{{{
public abstract class AbstractAxisClientThread extends Thread {
  /**
   * {@inheritDoc}
   */
  @Override public void interrupt() {
    super.interrupt();
    InterruptibleHttpSender.interrupt(this);
  }
}
}}}

and subclassing from it.

---------------------------------------------------------------------
To unsubscribe, e-mail: general-unsubscribe@ws.apache.org
For additional commands, e-mail: general-help@ws.apache.org