org.chromium.sdk/src/org/chromium/sdk/CallbackSemaphore.java
changeset 2 e4420d2515f1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.chromium.sdk/src/org/chromium/sdk/CallbackSemaphore.java	Wed Dec 23 17:13:18 2009 -0800
@@ -0,0 +1,69 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.sdk;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.chromium.sdk.internal.tools.v8.MethodIsBlockingException;
+
+/**
+ * Convenient implementation of {@code SyncCallback}. Client may create one,
+ * then call asynchronous command, and finally wait on blocking method
+ * {@code #tryAcquire()}.
+ */
+public class CallbackSemaphore implements SyncCallback {
+  public static final long OPERATION_TIMEOUT_MS = 120000;
+
+  private final Semaphore sem = new Semaphore(0);
+  private Exception savedException;
+
+  /**
+   * Tries to acquire semaphore with some reasonable default timeout.
+   * @return false if {@code #OPERATION_TIMEOUT_MS} was exceeded and we gave up
+   * @throws MethodIsBlockingException if called from a callback
+   */
+  public boolean tryAcquireDefault() throws MethodIsBlockingException {
+    return tryAcquire(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+  }
+
+  /**
+   * Tries to acquire the semaphore. This method blocks until the semaphore is
+   * released; typically release call comes from a worker thread of
+   * org.chromium.sdk, the same thread that may call all other callbacks.
+   * It is vital not to call this method from any callback of org.chromium.sdk,
+   * because it's a sure deadlock.
+   * To prevent, this the method declares throwing
+   * {@code MethodIsBlockingException} which is symbolically thrown whenever
+   * someone violates this rule (i.e. invokes this method from a callback).
+   * Though currently nobody actually throws it, such declarations help to
+   * track blocking methods.
+   * @return false if {@code timeout} was exceeded and we gave up
+   * @throws MethodIsBlockingException if called from a callback
+   */
+  public boolean tryAcquire(long timeout, TimeUnit unit) throws MethodIsBlockingException {
+    boolean res;
+    try {
+      res = sem.tryAcquire(timeout, unit);
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+    if (savedException != null) {
+      throw new RuntimeException("Exception occured in callback", savedException);
+    }
+    return res;
+  }
+  /**
+   * Implementation of {@code SyncCallback#callbackDone(RuntimeException)}.
+   */
+  public void callbackDone(RuntimeException e) {
+    if (e == null) {
+      savedException = null;
+    } else {
+      savedException = new Exception("Exception saved from callback", e);
+    }
+    sem.release();
+  }
+}
\ No newline at end of file