View Javadoc

1   /*
2   Copyright (C) 2008 Grid Systems, S.A.
3   
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2, as
6   published by the Free Software Foundation.
7   
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17  package com.gridsystems.innergrid.api;
18  
19  import java.io.IOException;
20  import java.io.InterruptedIOException;
21  import java.net.Socket;
22  import java.net.SocketException;
23  import java.net.SocketTimeoutException;
24  import java.util.concurrent.ConcurrentHashMap;
25  import java.util.concurrent.ConcurrentMap;
26  
27  import org.apache.axis.AxisFault;
28  import org.apache.axis.MessageContext;
29  import org.apache.axis.components.net.BooleanHolder;
30  import org.apache.axis.transport.http.HTTPSender;
31  import org.apache.axis.transport.http.SocketHolder;
32  
33  /**
34   * HTTPSender modified to allow interruption during I/O read.
35   *
36   * @author Rodrigo Ruiz
37   */
38  public class InterruptibleHttpSender extends HTTPSender {
39  
40    /**
41     * <code>serialVersionUID</code> attribute.
42     */
43    private static final long serialVersionUID = 6879849239456965913L;
44  
45    /**
46     * Maps threads to connection sockets.
47     */
48    private static final ConcurrentMap<Thread, Socket> SOCKETS
49      = new ConcurrentHashMap<Thread, Socket>();
50  
51    /**
52     * Interrupts the specified thread operation by closing its associated socket.
53     *
54     * @param t The thread to interrupt
55     */
56    public static void interrupt(Thread t) {
57      Socket s = SOCKETS.get(t);
58      if (s != null) {
59        try {
60          s.close();
61        } catch (IOException ignore) { }
62      }
63    }
64  
65    /**
66     * Gets if the specified thread is blocked performing a remote call to a web
67     * service.
68     * <p>
69     * A so blocked thread can can be interrupted by calling {@link #interrupt(Thread)}.
70     *
71     * @param t The thread to check
72     * @return <tt>true</tt> if t can be interrupted
73     */
74    public static boolean isBlocked(Thread t) {
75      return SOCKETS.get(t) != null;
76    }
77  
78    /**
79     * {@inheritDoc}
80     */
81    @Override public void invoke(MessageContext msgContext) throws AxisFault {
82      Thread t = Thread.currentThread();
83  
84      // Fast-fail if the thread is already in interrupted state
85      if (t.isInterrupted()) {
86        throwInterruptedFault(new InterruptedException());
87      }
88  
89      try {
90        super.invoke(msgContext);
91      } catch (AxisFault fault) {
92        Throwable cause = fault.getCause();
93        if (cause instanceof SocketTimeoutException) {
94          // Special case of InterruptedIOException
95          throw fault;
96        } else if (cause instanceof InterruptedIOException) {
97          throwInterruptedFault(cause);
98        } else if (cause instanceof SocketException && t.isInterrupted()) {
99          throwInterruptedFault(cause);
100       } else {
101         throw fault;
102       }
103     } finally {
104       SOCKETS.remove(t);
105     }
106   }
107 
108   /**
109    * Converts the specified exception in an InterruptedException with the
110    * same stack-trace, embedded into an AxisFault.
111    *
112    * @param cause  The original exception
113    * @throws AxisFault Fault containing an InterruptedException as its cause
114    */
115   private void throwInterruptedFault(Throwable cause) throws AxisFault {
116     InterruptedException ie = new InterruptedException();
117     ie.setStackTrace(cause.getStackTrace());
118     throw AxisFault.makeFault(ie);
119   }
120 
121   /**
122    * {@inheritDoc}
123    */
124   @Override
125   protected void getSocket(SocketHolder sockHolder, MessageContext msgContext,
126     String protocol, String host, int port, int timeout, StringBuffer otherHeaders,
127     BooleanHolder useFullURL) throws Exception {
128 
129     super.getSocket(sockHolder, msgContext, protocol, host, port,
130         timeout, otherHeaders, useFullURL);
131 
132     SOCKETS.put(Thread.currentThread(), sockHolder.getSocket());
133   }
134 }