[jboss-cvs] JBossRemoting/src/main/org/jboss/remoting/transport/http ...
Ron Sigal
ron_sigal at yahoo.com
Thu Feb 22 04:36:58 EST 2007
User: rsigal
Date: 07/02/22 04:36:58
Modified: src/main/org/jboss/remoting/transport/http Tag:
remoting_2_x HTTPClientInvoker.java
Log:
JBREM-657, JBREM-701: Implemented per invocation timeouts for jdk 1.4.
Revision Changes Path
No revision
No revision
1.31.2.3 +250 -50 JBossRemoting/src/main/org/jboss/remoting/transport/http/HTTPClientInvoker.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: HTTPClientInvoker.java
===================================================================
RCS file: /cvsroot/jboss/JBossRemoting/src/main/org/jboss/remoting/transport/http/HTTPClientInvoker.java,v
retrieving revision 1.31.2.2
retrieving revision 1.31.2.3
diff -u -b -r1.31.2.2 -r1.31.2.3
--- HTTPClientInvoker.java 15 Feb 2007 16:54:08 -0000 1.31.2.2
+++ HTTPClientInvoker.java 22 Feb 2007 09:36:58 -0000 1.31.2.3
@@ -24,7 +24,6 @@
import org.jboss.logging.Logger;
import org.jboss.remoting.CannotConnectException;
-import org.jboss.remoting.Client;
import org.jboss.remoting.ConnectionFailedException;
import org.jboss.remoting.InvocationRequest;
import org.jboss.remoting.InvocationResponse;
@@ -40,6 +39,11 @@
import org.jboss.remoting.serialization.ClassLoaderUtility;
import org.jboss.remoting.transport.web.WebUtil;
import org.jboss.util.Base64;
+import org.jboss.util.threadpool.BasicThreadPool;
+import org.jboss.util.threadpool.BlockingMode;
+import org.jboss.util.threadpool.RunnableTaskWrapper;
+import org.jboss.util.threadpool.Task;
+import org.jboss.util.threadpool.ThreadPool;
import java.io.IOException;
import java.io.InputStream;
@@ -51,6 +55,7 @@
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
@@ -65,9 +70,29 @@
*/
public class HTTPClientInvoker extends RemoteClientInvoker
{
+ /**
+ * Key for the configuration map that determines the threadpool size for
+ * simulated timeouts when using jdk 1.4.
+ */
+ public static final String MAX_NUM_TIMEOUT_THREADS = "maxNumTimeoutThreads";
+
+ /**
+ * Key for the configuration map that determines the queue size for simulated
+ * timeout threadpool when using jdk 1.4.
+ */
+ public static final String MAX_TIMEOUT_QUEUE_SIZE = "maxTimeoutQueueSize";
+
+ /**
+ * Specifies the default number of work threads in the thread pool for
+ * simulating timeouts when using jdk 1.4.
+ */
+ public static final int MAX_NUM_TIMEOUT_THREADS_DEFAULT = 10;
protected final Logger log = Logger.getLogger(getClass());
+ private Object timeoutThreadPoolLock = new Object();
+ private ThreadPool timeoutThreadPool;
+
public HTTPClientInvoker(InvokerLocator locator)
{
super(locator);
@@ -87,36 +112,90 @@
* @throws org.jboss.remoting.ConnectionFailedException
*
*/
- protected Object transport(String sessionId, Object invocation, Map metadata,
- Marshaller marshaller, UnMarshaller unmarshaller)
+ protected Object transport(String sessionId, final Object invocation, Map metadata,
+ final Marshaller marshaller, final UnMarshaller unmarshaller)
throws IOException, ConnectionFailedException
{
- String targetURL = getLocator().getLocatorURI();
- Object httpResponse = useHttpURLConnection(targetURL, invocation, metadata, marshaller, unmarshaller);
+ // need to check the url and make sure it compatible protocol
+ String validatedUrl = validateURL(getLocator().getLocatorURI());
- return httpResponse;
+ if (metadata == null)
+ {
+ metadata = new HashMap();
}
- private Object useHttpURLConnection(String url, Object invocation, Map metadata,
- Marshaller marshaller, UnMarshaller unmarshaller) throws WebServerError
+ final HttpURLConnection conn = createURLConnection(validatedUrl, metadata);
+
+ int simulatedTimeout = getSimulatedTimeout(configuration, metadata, conn);
+
+ if (simulatedTimeout < 0)
{
- Object result = null;
- int responseCode = -1;
+ return useHttpURLConnection(conn, invocation, metadata, marshaller, unmarshaller);
+ }
+ else
+ {
+ if (log.isTraceEnabled()) log.trace("using simulated timeout: " + simulatedTimeout);
+ class Holder {public Object value;}
+ final Holder resultHolder = new Holder();
+ final Map finalMetadata = metadata;
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
try
{
- // need to check the url and make sure it compatible protocol
- String validatedUrl = validateURL(url);
-
- if (metadata == null)
+ resultHolder.value = useHttpURLConnection(conn, invocation, finalMetadata, marshaller, unmarshaller);
+ if (log.isTraceEnabled()) log.trace("result: " + resultHolder.value);
+ }
+ catch (Exception e)
{
- metadata = new HashMap();
+ resultHolder.value = e;
+ if (log.isTraceEnabled()) log.trace("exception: " + e);
+ }
}
+ };
+
+ // BasicThreadPool timeout mechanism depends on the interrupted status of
+ // the running thread.
+ Thread.interrupted();
+
+ ThreadPool pool = getTimeoutThreadPool();
+ WaitingTaskWrapper wrapper = new WaitingTaskWrapper(r, simulatedTimeout);
+ if (log.isTraceEnabled()) log.trace("starting task in thread pool");
+ pool.runTaskWrapper(wrapper);
+ if (log.isTraceEnabled()) log.trace("task finished in thread pool");
- HttpURLConnection conn = createURLConnection(validatedUrl, metadata);
+ Object result = resultHolder.value;
+ if (result == null)
+ {
+ if (log.isDebugEnabled()) log.debug("invocation timed out");
+ throw new SocketTimeoutException("timed out");
+ }
+ else if (result instanceof IOException)
+ {
+ throw (IOException) result;
+ }
+ else if (result instanceof RuntimeException)
+ {
+ throw (RuntimeException) result;
+ }
+ else
+ {
+ if (log.isTraceEnabled()) log.trace("returning result: " + result);
+ return result;
+ }
+ }
+ }
- setTimeout(configuration, conn);
+ private Object useHttpURLConnection(HttpURLConnection conn, Object invocation, Map metadata,
+ Marshaller marshaller, UnMarshaller unmarshaller) throws WebServerError
+ {
+ Object result = null;
+ int responseCode = -1;
+ try
+ {
setChunked(configuration, conn);
// check to see if basic auth required
@@ -429,14 +508,40 @@
}
- private void setTimeout(Map metadata, HttpURLConnection conn)
+ private int getSimulatedTimeout(Map configuration, Map metadata, HttpURLConnection conn)
+ {
+ int simulatedTimeout = -1;
+ int timeout = -1;
+ String connectionTimeout = (String) configuration.get("timeout");
+ String invocationTimeout = (String) metadata.get("timeout");
+
+ if (invocationTimeout != null && invocationTimeout.length() > 0)
+ {
+ try
+ {
+ timeout = Integer.parseInt(invocationTimeout);
+ }
+ catch (NumberFormatException e)
{
- String timeoutValue = (String) metadata.get("timeout");
- if (timeoutValue != null && timeoutValue.length() > 0)
+ log.error("Could not set timeout for current invocation because value (" + invocationTimeout + ") is not a number.");
+ }
+ }
+
+ if (timeout < 0 && connectionTimeout != null && connectionTimeout.length() > 0)
{
try
{
- int timeout = Integer.parseInt(timeoutValue);
+ timeout = Integer.parseInt(connectionTimeout);
+ }
+ catch (NumberFormatException e)
+ {
+ log.error("Could not set timeout for http client connection because value (" + connectionTimeout + ") is not a number.");
+ }
+ }
+
+ if (timeout < 0)
+ return -1;
+
/**
* Since URLConnection in jdk 1.4 does NOT have a setConnectTimeout() method and
* the one in jdk 1.5 does, will have to use reflection to see if it exists before
@@ -451,24 +556,23 @@
}
catch (NoSuchMethodException e)
{
- log.warn("Could not set timeout (" + timeout + ") on http client transport as method not available with JDK 1.4 (only JDK 1.5 or higher)");
+ simulatedTimeout = timeout;
+ log.debug("Using older JDK (prior to 1.5): will simulate timeout");
}
catch (IllegalAccessException e)
{
+ simulatedTimeout = timeout;
log.error("Error setting http client connection timeout.");
log.debug(e);
}
catch (InvocationTargetException e)
{
+ simulatedTimeout = timeout;
log.error("Error setting http client connection timeout.");
log.debug(e);
}
- }
- catch (NumberFormatException e)
- {
- log.error("Could not set timeout for http client connection because value (" + timeoutValue + ") is not a number.");
- }
- }
+
+ return simulatedTimeout;
}
protected String validateURL(String url)
@@ -692,4 +796,100 @@
return HTTPMarshaller.DATATYPE;
}
+
+ /**
+ * Sets the thread pool to be used for simulating timeouts with jdk 1.4.
+ */
+ public void setTimeoutThreadPool(ThreadPool pool)
+ {
+ this.timeoutThreadPool = pool;
+ }
+
+ /**
+ * Gets the thread pool being used for simulating timeouts with jdk 1.4. If one has
+ * not be specifically set via configuration or call to set it, will always return
+ * instance of org.jboss.util.threadpool.BasicThreadPool.
+ */
+ public ThreadPool getTimeoutThreadPool()
+ {
+ synchronized (timeoutThreadPoolLock)
+ {
+ if (timeoutThreadPool == null)
+ {
+ int maxNumberThreads = MAX_NUM_TIMEOUT_THREADS_DEFAULT;
+ int maxTimeoutQueueSize = -1;
+
+ BasicThreadPool pool = new BasicThreadPool("HTTP timeout");
+ log.debug("created new thread pool: " + pool);
+ Object param = configuration.get(MAX_NUM_TIMEOUT_THREADS);
+ if (param instanceof String)
+ {
+ try
+ {
+ maxNumberThreads = Integer.parseInt((String) param);
+ }
+ catch (NumberFormatException e)
+ {
+ log.error("maxNumberThreads parameter has invalid format: " + param);
+ }
+ }
+ else if (param != null)
+ {
+ log.error("maxNumberThreads parameter must be a string in integer format: " + param);
+ }
+
+ param = configuration.get(MAX_TIMEOUT_QUEUE_SIZE);
+
+ if (param instanceof String)
+ {
+ try
+ {
+ maxTimeoutQueueSize = Integer.parseInt((String) param);
+ }
+ catch (NumberFormatException e)
+ {
+ log.error("maxTimeoutQueueSize parameter has invalid format: " + param);
+ }
+ }
+ else if (param != null)
+ {
+ log.error("maxTimeoutQueueSize parameter must be a string in integer format: " + param);
+ }
+
+ pool.setMaximumPoolSize(maxNumberThreads);
+
+ if (maxTimeoutQueueSize > 0)
+ {
+ pool.setMaximumQueueSize(maxTimeoutQueueSize);
+ }
+ pool.setBlockingMode(BlockingMode.RUN);
+ timeoutThreadPool = pool;
+ }
+ }
+ return timeoutThreadPool;
+ }
+
+
+ /**
+ * When a WaitingTaskWrapper is run in a BasicThreadPool, the calling thread
+ * will block for the designated timeout period.
+ */
+ static class WaitingTaskWrapper extends RunnableTaskWrapper
+ {
+ long completeTimeout;
+
+ public WaitingTaskWrapper(Runnable runnable, long completeTimeout)
+ {
+ super(runnable, 0, completeTimeout);
+ this.completeTimeout = completeTimeout;
+ }
+ public int getTaskWaitType()
+ {
+ return Task.WAIT_FOR_COMPLETE;
+ }
+ public String toString()
+ {
+ return "WaitingTaskWrapper[" + completeTimeout + "]";
+ }
+ }
}
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list