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) { }
    }
  }

  /**
   * [EMAIL PROTECTED]
   */
  @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());
    }
  }

  /**
   * [EMAIL PROTECTED]
   */
  @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 {
  /**
   * [EMAIL PROTECTED]
   */
  @Override public void interrupt() {
    super.interrupt();
    InterruptibleHttpSender.interrupt(this);
  }
}
}}}

and subclassing from it.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to