diff --git a/projects/samskivert/src/java/com/samskivert/servlet/util/ServiceWaiter.java b/projects/samskivert/src/java/com/samskivert/servlet/util/ServiceWaiter.java new file mode 100644 index 00000000..bbc60fc4 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/servlet/util/ServiceWaiter.java @@ -0,0 +1,151 @@ +// +// $Id: ServiceWaiter.java,v 1.1 2003/08/12 23:44:33 ray Exp $ + +package com.samskivert.servlet.util; + +import com.samskivert.Log; +import com.samskivert.servlet.RedirectException; +import com.samskivert.util.ResultListener; + +/** + * A handy base class for issuing server-side service requests and + * awaiting their responses from within a servlet. + * + * Note: You might think that it would be keen to use this + * anonymously like so: + * + *
+ * ServiceWaiter waiter = new ServiceWaiter() {
+ * public void handleSuccess (int invid, ...) {
+ * // handle success
+ * }
+ * // ...
+ * };
+ *
+ *
+ * But that won't work because public methods in anonymous inner classes
+ * do not have public visibility and so the invocation manager will not be
+ * able to reflect your response methods when the time comes to deliver
+ * the response. Unfortunately, there appears to be no manner in which to
+ * instruct the Java compiler to give public scope to an anonymous inner
+ * class rather than default scope. Sigh.
+ */
+public class ServiceWaiter
+ implements ResultListener
+{
+ /**
+ * Construct a ServiceWaiter with the default (30 second) timeout.
+ */
+ public ServiceWaiter ()
+ {
+ this(DEFAULT_WAITER_TIMEOUT);
+ }
+
+ /**
+ * Construct a ServiceWaiter with the specified timeout.
+ *
+ * @param timeout the timeout, in seconds.
+ */
+ public ServiceWaiter (int timeout)
+ {
+ _timeout = timeout;
+ }
+
+ /**
+ * Marks the request as successful and posts the supplied response
+ * argument for perusal by the caller.
+ */
+ public synchronized void postSuccess (Object arg)
+ {
+ _success = 1;
+ _argument = arg;
+ notify();
+ }
+
+ /**
+ * Marks the request as failed and posts the supplied response
+ * argument for perusal by the caller.
+ */
+ public synchronized void postFailure (Object arg)
+ {
+ _success = -1;
+ _argument = arg;
+ notify();
+ }
+
+ /**
+ * Returns the argument posted by the waiter when the response
+ * arrived.
+ */
+ public Object getArgument ()
+ {
+ return _argument;
+ }
+
+ /**
+ * Blocks waiting for the response.
+ *
+ * @return true if a success response was posted, false if a failure
+ * repsonse was posted.
+ */
+ public synchronized boolean awaitResponse ()
+ throws RedirectException
+ {
+ while (_success == 0) {
+ try {
+ // wait for the response, timing out after a while
+ wait(1000L * _timeout);
+
+ // if we get here without some sort of response, then
+ // we've timed out and we should freak out
+ if (_success == 0) {
+ Log.warning("Service waiter timed out.");
+ Thread.dumpStack();
+ throw new RedirectException(getTimeoutRedirectURL());
+ }
+
+ } catch (InterruptedException ie) {
+ // fall through and wait again
+ }
+ }
+
+ return (_success > 0);
+ }
+
+ /**
+ * Get the page to which we redirect on timeout.
+ */
+ protected String getTimeoutRedirectURL ()
+ {
+ // TODO
+ return "/";
+ }
+
+ // documentation inherited from interface ResultListener
+ public void requestCompleted (Object result)
+ {
+ postSuccess(result);
+ }
+
+ // documentation inherited from interface ResultListener
+ public void requestFailed (Exception cause)
+ {
+ postFailure((cause != null) ? cause.getMessage() : null);
+ }
+
+ /** Whether or not the response succeeded; positive for success,
+ * negative for failure, zero means we haven't received the response
+ * yet. */
+ protected int _success = 0;
+
+ /** The argument posted by the waiter upon receipt of the response. */
+ protected Object _argument;
+
+ /** How many seconds to wait before giving up the ghost. */
+ protected int _timeout;
+
+ /** If a response is not received within the specified timeout, an
+ * exception is thrown which redirects the user to an internal error
+ * page. */
+ protected static final int DEFAULT_WAITER_TIMEOUT = 30;
+}