geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kl...@apache.org
Subject [4/9] incubator-geode git commit: Dunit changes for JUnit 4 syntax. Refactoring to modernize API.
Date Fri, 21 Aug 2015 20:29:31 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java
new file mode 100755
index 0000000..a1ef782
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java
@@ -0,0 +1,142 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Invoke.invokeInEveryVM;
+
+import java.io.Serializable;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.apache.logging.log4j.Logger;
+
+import com.gemstone.gemfire.internal.logging.LogService;
+
+/**
+ * An expected exception string which is added or removed in the log to 
+ * suppress it during greplogs (grep for error strings).
+ * 
+ * Extracted from DistributedTestCase. Renamed from ExpectedException to 
+ * prevent conflict with the JUnit rule. Note that the implementation
+ * is still writing <code><ExpectedException ...></code> statements to the 
+ * log for the <code>batterytest.greplogs.LogConsumer</code>.
+ * 
+ * @author Mitch Thomas
+ * @since 5.7bugfix
+ * @see batterytest.greplogs.LogConsumer
+ */
+public class ExpectedExceptionString implements Serializable {
+  private static final long serialVersionUID = 1L;
+  private static final Logger logger = LogService.getLogger();
+  
+  // Note: if you change these prefixes and suffix then you must also change batterytest.greplogs.LogConsumer to match
+  private static final String LOG_MESSAGE_PREFIX_ADD = "<ExpectedException action=add>";
+  private static final String LOG_MESSAGE_PREFIX_REMOVE = "<ExpectedException action=remove>";
+  private static final String LOG_MESSAGE_SUFFIX = "</ExpectedException>";
+
+  private final String exceptionString;
+
+  private final transient VM vm;
+
+  // TODO: prevent memory leak here
+  private static final Queue<ExpectedExceptionString> expectedExceptionStrings = new ConcurrentLinkedQueue<ExpectedExceptionString>();
+
+  public ExpectedExceptionString(final String exceptionString) {
+    this(exceptionString, null);
+  }
+  
+  public ExpectedExceptionString(final String exceptionString, final VM vm) {
+    this.exceptionString = exceptionString;
+    this.vm = vm;
+  }
+
+  public String getAddMessage() {
+    return LOG_MESSAGE_PREFIX_ADD + this.exceptionString + LOG_MESSAGE_SUFFIX;
+  }
+
+  public String getRemoveMessage() {
+    return LOG_MESSAGE_PREFIX_REMOVE + this.exceptionString + LOG_MESSAGE_SUFFIX;
+  }
+
+  public void remove() {
+    final SerializableRunnable removeRunnable = newRemoveSerializableRunnable(getRemoveMessage());
+    
+    if (this.vm != null) {
+      this.vm.invoke(removeRunnable);
+    } else {
+      invokeInEveryVM(removeRunnable);
+    }
+    
+    logger.info(getRemoveMessage());
+  }
+
+  /**
+   * Log in all VMs the expected exception string to prevent grep logs from
+   * complaining. The expected string is used by the GrepLogs utility and so 
+   * can contain regular expression characters.
+   * 
+   * If you do not remove the expected exception, it will be removed at the
+   * end of your test case automatically.
+   * 
+   * @since 5.7bugfix
+   * @param exception the exception string to expect
+   * @return an instance that a test can use for removal
+   */
+  public static ExpectedExceptionString addExpectedExceptionString(final String exception) {
+    return addExpectedExceptionString(exception, null);
+  }
+
+  /**
+   * Log in all VMs, the
+   * expected exception string to prevent grep logs from complaining. The
+   * expected string is used by the GrepLogs utility and so can contain
+   * regular expression characters.
+   * 
+   * @since 5.7bugfix
+   * @param exceptionString the exception string to expect
+   * @param vm the VM on which to log the expected exception or null for all VMs
+   * @return an instance that a test can use for removal
+   */
+  public static ExpectedExceptionString addExpectedExceptionString(final String exceptionString, final VM vm) {
+    final ExpectedExceptionString expectedOutput;
+    if (vm != null) {
+      expectedOutput = new ExpectedExceptionString(exceptionString, vm);
+    } else {
+      expectedOutput = new ExpectedExceptionString(exceptionString);
+    }
+    
+    final String addMessage = expectedOutput.getAddMessage();
+    
+    final SerializableRunnable addRunnable = newAddSerializableRunnable(addMessage);
+    
+    if (vm != null) {
+      vm.invoke(addRunnable);
+    } else {
+      invokeInEveryVM(addRunnable);
+    }
+    
+    logger.info(addMessage);
+    expectedExceptionStrings.add(expectedOutput);
+    return expectedOutput;
+  }
+  
+  static ExpectedExceptionString poll() {
+    return expectedExceptionStrings.poll();
+  }
+  
+  @SuppressWarnings("serial")
+  private static SerializableRunnable newAddSerializableRunnable(final String addMessage) {
+    return new SerializableRunnable("addExpectedExceptionString") {
+      public void run() {
+        logger.info(addMessage);
+      }
+    };
+  }
+  
+  @SuppressWarnings("serial")
+  private static SerializableRunnable newRemoveSerializableRunnable(final String removeMessage) {
+    return new SerializableRunnable("removeExpectedExceptionString") {
+      public void run() {
+        logger.info(removeMessage);
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java
new file mode 100644
index 0000000..6d69436
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java
@@ -0,0 +1,201 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * <P>This class represents a host on which a remote method may be
+ * invoked.  It provides access to the VMs and GemFire systems that
+ * run on that host.</P>
+ *
+ * <P>Additionally, it provides access to the Java RMI registry that
+ * runs on the host.  By default, an RMI registry is only started on
+ * the host on which Hydra's Master VM runs.  RMI registries may be
+ * started on other hosts via additional Hydra configuration.</P>
+ *
+ * @author David Whitlock
+ *
+ */
+public abstract class Host implements java.io.Serializable {
+
+  /** The available hosts */
+  protected static List hosts = new ArrayList();
+
+  private static VM locator;
+
+  /** Indicates an unstarted RMI registry */
+  protected static int NO_REGISTRY = -1;
+
+  ////////////////////  Instance Fields  ////////////////////
+
+  /** The name of this host machine */
+  private String hostName;
+
+  /** The VMs that run on this host */
+  private List vms;
+
+  /** The GemFire systems that are available on this host */
+  private List systems;
+  
+  /** Key is system name, value is GemFireSystem instance */
+  private HashMap systemNames;
+  
+  ////////////////////  Static Methods  /////////////////////
+
+  /**
+   * Returns the number of known hosts
+   */
+  public static int getHostCount() {
+    return hosts.size();
+  }
+
+  /**
+   * Makes note of a new <code>Host</code>
+   */
+  protected static void addHost(Host host) {
+    hosts.add(host);
+  }
+
+  /**
+   * Returns a given host
+   *
+   * @param n
+   *        A zero-based identifier of the host
+   *
+   * @throws IllegalArgumentException
+   *         <code>n</code> is more than the number of hosts
+   */
+  public static Host getHost(int n) {
+    int size = hosts.size();
+    if (n >= size) {
+      String s = "Cannot request host " + n + ".  There are only " +
+        size + " hosts.";
+      throw new IllegalArgumentException(s);
+
+    } else {
+      return (Host) hosts.get(n);
+    }
+  }
+
+  /////////////////////  Constructors  //////////////////////
+
+  /**
+   * Creates a new <code>Host</code> with the given name
+   */
+  protected Host(String hostName) {
+    if (hostName == null) {
+      String s = "Cannot create a Host with a null name";
+      throw new NullPointerException(s);
+    }
+
+    this.hostName = hostName;
+    this.vms = new ArrayList();
+    this.systems = new ArrayList();
+    this.systemNames = new HashMap();
+  }
+
+  ////////////////////  Instance Methods  ////////////////////
+
+  /**
+   * Returns the machine name of this host
+   */
+  public String getHostName() {
+    return this.hostName;
+  }
+
+  /**
+   * Returns the number of VMs that run on this host
+   */
+  public int getVMCount() {
+    return this.vms.size();
+  }
+
+  /**
+   * Returns a VM that runs on this host
+   *
+   * @param n
+   *        A zero-based identifier of the VM
+   *
+   * @throws IllegalArgumentException
+   *         <code>n</code> is more than the number of VMs
+   */
+  public VM getVM(int n) {
+    int size = vms.size();
+    if (n >= size) {
+      String s = "Cannot request VM " + n + ".  There are only " +
+        size + " VMs on " + this;
+      throw new IllegalArgumentException(s);
+
+    } else {
+      return (VM) vms.get(n);
+    }
+  }
+
+  /**
+   * Adds a VM to this <code>Host</code> with the given process id and client record.
+   */
+  protected void addVM(int pid, RemoteDUnitVMIF client) {
+    VM vm = new VM(this, pid, client);
+    this.vms.add(vm);
+  }
+
+  public static VM getLocator() {
+    return locator;
+  }
+  
+  private static void setLocator(VM l) {
+    locator = l;
+  }
+  
+  protected void addLocator(int pid, RemoteDUnitVMIF client) {
+    setLocator(new VM(this, pid, client));
+  }
+
+  /**
+   * Returns the number of GemFire systems that run on this host
+   */
+  public int getSystemCount() {
+    return this.systems.size();
+  }
+
+  ////////////////////  Utility Methods  ////////////////////
+
+  public String toString() {
+    StringBuffer sb = new StringBuffer("Host ");
+    sb.append(this.getHostName());
+    sb.append(" with ");
+    sb.append(getVMCount());
+    sb.append(" VMs");
+    return sb.toString();
+  }
+
+  /**
+   * Two <code>Host</code>s are considered equal if they have the same
+   * name.
+   */
+  public boolean equals(Object o) {
+    if (o instanceof Host) {
+      return ((Host) o).getHostName().equals(this.getHostName());
+
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * A <code>Host</code>'s hash code is based on the hash code of its
+   * name. 
+   */
+  public int hashCode() {
+    return this.getHostName().hashCode();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
new file mode 100755
index 0000000..bd9eaf6
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
@@ -0,0 +1,146 @@
+package com.gemstone.gemfire.test.dunit;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A set of remote invocation methods useful for writing tests. 
+ * <pr/>
+ * These methods can be used directly:
+ * <code>Invoke.invokeInEveryVM(...)</code>, however, they read better if they
+ * are referenced through static import:
+ * 
+ * <pre>
+ * import static com.gemstone.gemfire.test.dunit.Invoke.*;
+ *    ...
+ *    invokeInEveryVM(...);
+ * </pre>
+ * <pr/>
+ * Extracted from DistributedTestCase
+ * 
+ * @see VM
+ * @see SerializableCallable
+ * @see SerializableRunnable
+ * @see RepeatableRunnable
+ */
+public class Invoke {
+
+  protected Invoke() {
+  }
+  
+  /**
+   * Invokes a <code>SerializableRunnable</code> in every VM that DUnit knows about.
+   *
+   * @see VM#invoke(Runnable)
+   */
+  public static void invokeInEveryVM(final SerializableRunnable work) {
+    for (int h = 0; h < Host.getHostCount(); h++) {
+      Host host = Host.getHost(h);
+
+      for (int v = 0; v < host.getVMCount(); v++) {
+        VM vm = host.getVM(v);
+        vm.invoke(work);
+      }
+    }
+  }
+
+  public static void invokeInLocator(final SerializableRunnable work) {
+    Host.getLocator().invoke(work);
+  }
+  
+  /**
+   * Invokes a <code>SerializableCallable</code> in every VM that DUnit knows about.
+   *
+   * @return a Map of results, where the key is the VM and the value is the result for that VM
+   * @see VM#invoke(java.util.concurrent.Callable)
+   */
+  public static Map<VM, Object> invokeInEveryVM(final SerializableCallable<?> work) {
+    final Map<VM, Object> results = new HashMap<VM, Object>();
+    for (int h = 0; h < Host.getHostCount(); h++) {
+      Host host = Host.getHost(h);
+      for (int v = 0; v < host.getVMCount(); v++) {
+        VM vm = host.getVM(v);
+        results.put(vm, vm.invoke(work));
+      }
+    }
+    return results;
+  }
+
+  /**
+   * Invokes a method in every remote VM that DUnit knows about.
+   *
+   * @see VM#invoke(Class, String)
+   */
+  public static void invokeInEveryVM(final Class<?> theClass, final String methodName) {
+    for (int h = 0; h < Host.getHostCount(); h++) {
+      Host host = Host.getHost(h);
+      for (int v = 0; v < host.getVMCount(); v++) {
+        VM vm = host.getVM(v);
+        vm.invoke(theClass, methodName);
+      }
+    }
+  }
+
+  /**
+   * Invokes a method in every remote VM that DUnit knows about.
+   *
+   * @see VM#invoke(Class, String)
+   */
+  public static void invokeInEveryVM(final Class<?> theClass, final String methodName, final Object[] methodArgs) {
+    for (int h = 0; h < Host.getHostCount(); h++) {
+      Host host = Host.getHost(h);
+      for (int v = 0; v < host.getVMCount(); v++) {
+        VM vm = host.getVM(v);
+        vm.invoke(theClass, methodName, methodArgs);
+      }
+    }
+  }
+  
+  public static void invokeRepeatingIfNecessary(final VM vm, final RepeatableRunnable task) {
+    vm.invokeRepeatingIfNecessary(task, 0);
+  }
+  
+  /**
+   * For ACK scopes, no repeat should be necessary.
+   * 
+   * @param vm
+   * @param task
+   * @param repeatTimeoutMs the number of milliseconds to try repeating validation code in the
+   * event that AssertionFailedError is thrown.  
+   */
+  public static void invokeRepeatingIfNecessary(final VM vm, final RepeatableRunnable task, final long repeatTimeoutMs) {
+    vm.invokeRepeatingIfNecessary(task, repeatTimeoutMs);
+  }
+  
+  /**
+   * Invokes a <code>SerializableRunnable</code> in every VM that
+   * DUnit knows about.  If work.run() throws an assertion failure, 
+   * its execution is repeated, until no assertion failure occurs or
+   * repeatTimeout milliseconds have passed.
+   *
+   * @see VM#invoke(Runnable)
+   */
+  public static void invokeInEveryVMRepeatingIfNecessary(final RepeatableRunnable work) {
+    invokeInEveryVMRepeatingIfNecessary(work, 0);
+  }
+
+  public static void invokeInEveryVMRepeatingIfNecessary(final RepeatableRunnable work, final long repeatTimeoutMs) {
+    for (int h = 0; h < Host.getHostCount(); h++) {
+      Host host = Host.getHost(h);
+      for (int v = 0; v < host.getVMCount(); v++) {
+        VM vm = host.getVM(v);
+        vm.invokeRepeatingIfNecessary(work, repeatTimeoutMs);
+      }
+    }
+  }
+  
+  /** Return the total number of VMs on all hosts */
+  public static int getVMCount() {
+    int count = 0;
+    for (int h = 0; h < Host.getHostCount(); h++) {
+      Host host = Host.getHost(h);
+      count += host.getVMCount();
+    }
+    return count;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
new file mode 100755
index 0000000..446b4bf
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
@@ -0,0 +1,70 @@
+package com.gemstone.gemfire.test.dunit;
+
+import java.util.Random;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public class Jitter {
+
+  /**
+   * If true, we randomize the amount of time we wait
+   */
+  private static final boolean USE_JITTER = true;
+  
+  private static final Random jitter = new Random();
+  
+  protected Jitter() {
+  }
+  
+  /**
+   * Returns an adjusted interval from <code>minimum()</code to 
+   * <code>intervalMillis</code> milliseconds. If jittering is disabled then 
+   * the value returned will be equal to intervalMillis.
+   * 
+   * @param intervalMillis
+   * @return adjust milliseconds to use as interval for WaitCriteria polling
+   */
+  static long jitterInterval(final long intervalMillis) {
+    if (USE_JITTER) {
+      return adjustIntervalIfJitterIsEnabled(intervalMillis);
+    } else {
+      return intervalMillis;
+    }
+  }
+  
+  static int minimum() {
+    return 10;
+  }
+  
+  static int maximum() {
+    return 5000;
+  }
+  
+  /**
+   * If jittering is enabled then returns a jittered interval up to a maximum
+   * of <code>intervalMillis</code> milliseconds, inclusive.
+   * 
+   * If jittering is disabled then returns <code>intervalMillis</code>.
+   * 
+   * The result is bounded by 50 ms as a minimum and 5000 ms as a maximum.
+   * 
+   * @param ms total amount of time to wait
+   * @return randomized interval we should wait
+   */
+  private static int adjustIntervalIfJitterIsEnabled(final long intervalMillis) {
+    final int minLegal = minimum();
+    final int maxLegal = maximum();
+    
+    if (intervalMillis <= minLegal) {
+      return (int)intervalMillis; // Don't ever jitter anything below this.
+    }
+
+    int maxValue = maxLegal;
+    if (intervalMillis < maxLegal) {
+      maxValue = (int)intervalMillis;
+    }
+
+    return minLegal + jitter.nextInt(maxValue - minLegal + 1);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java
new file mode 100644
index 0000000..d08ac25
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java
@@ -0,0 +1,161 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import com.gemstone.gemfire.GemFireException;
+
+/**
+ * This exception is thrown when an exception occurs during a remote
+ * method invocation.  This {@link RuntimeException} wraps the actual
+ * exception.  It allows distributed unit tests to verify that an
+ * exception was thrown in a different VM.
+ *
+ * <PRE>
+ *     VM vm0 = host0.getVM(0);
+ *     try {
+ *       vm.invoke(this.getClass(), "getUnknownObject");
+ *
+ *     } catch (RMIException ex) {
+ *       assertEquals(ex.getCause() instanceof ObjectException);
+ *     }
+ * </PRE>
+ *
+ * Note that special steps are taken so that the stack trace of the
+ * cause exception reflects the call stack on the remote machine.
+ * The stack trace of the exception returned by {@link #getCause()}
+ * may not be available.
+ *
+ * @see hydra.RemoteTestModuleIF
+ *
+ * @author David Whitlock
+ *
+ */
+public class RMIException extends GemFireException {
+
+  /** SHADOWED FIELD that holds the cause exception (as opposed to the
+   * HokeyException */
+  private Throwable cause;
+
+  /** The name of the method being invoked */
+  private String methodName;
+
+  /** The name of the class (or class of the object type) whose method
+   * was being invoked */
+  private String className;
+
+  /** The type of exception that was thrown in the remote VM */
+  private String exceptionClassName;
+
+  /** Stack trace for the exception that was thrown in the remote VM */
+  private String stackTrace;
+
+  /** The VM in which the method was executing */
+  private VM vm;
+
+  ////////////////////////  Constructors  ////////////////////////
+
+  /**
+   * Creates a new <code>RMIException</code> that was caused by a
+   * given <code>Throwable</code> while invoking a given method.
+   */
+  public RMIException(VM vm, String className, String methodName,
+                      Throwable cause) {
+    super("While invoking " + className + "." + methodName + " in " +
+          vm, cause);
+    this.cause = cause;
+    this.className = className;
+    this.methodName = methodName;
+    this.vm = vm;
+  }
+
+  /**
+   * Creates a new <code>RMIException</code> to indicate that an
+   * exception of a given type was thrown while invoking a given
+   * method. 
+   *
+   * @param vm
+   *        The VM in which the method was executing
+   * @param className
+   *        The name of the class whose method was being invoked
+   *        remotely 
+   * @param methodName
+   *        The name of the method that was being invoked remotely
+   * @param cause
+   *        The type of exception that was thrown in the remote VM
+   * @param stackTrace
+   *        The stack trace of the exception from the remote VM
+   */
+  public RMIException(VM vm, String className, String methodName, 
+                      Throwable cause, String stackTrace) {
+    super("While invoking " + className + "." + methodName + " in " +
+          vm, new HokeyException(cause, stackTrace));
+    this.vm = vm;
+    this.cause = cause;
+    this.className = className;
+    this.methodName = methodName;
+//    this.exceptionClassName = exceptionClassName; assignment has no effect
+    this.stackTrace = stackTrace;
+  }
+
+  /**
+   * Returns the class name of the exception that was thrown in a
+   * remote method invocation.
+   */
+  public String getExceptionClassName() {
+    return this.exceptionClassName;
+  }
+
+//   /**
+//    * Returns the stack trace for the exception that was thrown in a
+//    * remote method invocation.
+//    */
+//   public String getStackTrace() {
+//     return this.stackTrace;
+//   }
+
+  /**
+   * Returns the cause of this exception.  Note that this is not
+   * necessarily the exception that gets printed out with the stack
+   * trace.
+   */
+  public Throwable getCause() {
+    return this.cause;
+  }
+
+  /**
+   * Returns the VM in which the remote method was invoked
+   */
+  public VM getVM() {
+    return this.vm;
+  }
+
+  //////////////////////  Inner Classes  //////////////////////
+
+  /**
+   * A hokey exception class that makes it looks like we have a real
+   * cause exception.
+   */
+  private static class HokeyException extends Throwable {
+    private String stackTrace;
+    private String toString;
+
+    HokeyException(Throwable cause, String stackTrace) {
+      this.toString = cause.toString();
+      this.stackTrace = stackTrace;
+    }
+
+    public void printStackTrace(java.io.PrintWriter pw) {
+      pw.print(this.stackTrace);
+      pw.flush();
+    }
+
+    public String toString() {
+      return this.toString;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java
new file mode 100644
index 0000000..412aeac
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java
@@ -0,0 +1,18 @@
+package com.gemstone.gemfire.test.dunit;
+
+import hydra.MethExecutorResult;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+public interface RemoteDUnitVMIF extends Remote {
+
+  MethExecutorResult executeMethodOnObject(Object o, String methodName) throws RemoteException;
+
+  MethExecutorResult executeMethodOnObject(Object o, String methodName,
+      Object[] args) throws RemoteException;
+
+  MethExecutorResult executeMethodOnClass(String name, String methodName,
+      Object[] args) throws RemoteException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java
new file mode 100644
index 0000000..c8952bb
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java
@@ -0,0 +1,13 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * A RepeatableRunnable is an object that implements a method that
+ * can be invoked repeatably without causing any side affects.
+ *
+ * @author  dmonnie
+ */
+public interface RepeatableRunnable {
+  
+  public void runRepeatingIfNecessary(long repeatTimeoutMs);
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java
new file mode 100644
index 0000000..2c21284
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java
@@ -0,0 +1,61 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.io.Serializable;
+import java.util.concurrent.Callable;
+
+/**
+ * This interface provides both {@link Serializable} and {@link
+ * Callable}.  It is often used in conjunction with {@link
+ * VM#invoke(Callable)}.
+ *
+ * <PRE>
+ * public void testRepilcatedRegionPut() {
+ *   final Host host = Host.getHost(0);
+ *   VM vm0 = host.getVM(0);
+ *   VM vm1 = host.getVM(1);
+ *   final String name = this.getUniqueName();
+ *   final Object value = new Integer(42);
+ *
+ *   SerializableCallable putMethod = new SerializableCallable("Replicated put") {
+ *       public Object call() throws Exception {
+ *         ...// get replicated test region //...
+ *         return region.put(name, value);
+ *       }
+ *      });
+ *   assertNull(vm0.invoke(putMethod));
+ *   assertEquals(value, vm1.invoke(putMethod));
+ *  }
+ * </PRE>
+ * 
+ * @author Mitch Thomas
+ */
+public abstract class SerializableCallable<T> implements Callable<T>, Serializable {
+  
+  private static final long serialVersionUID = -5914706166172952484L;
+  
+  private String name;
+
+  public SerializableCallable() {
+    this.name = null;
+  }
+
+  public SerializableCallable(String name) {
+    this.name = name;
+  }
+
+  public String toString() {
+    if (this.name != null) {
+      return "\"" + this.name + "\"";
+
+    } else {
+      return super.toString();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
new file mode 100644
index 0000000..28eabc3
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
@@ -0,0 +1,83 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.io.Serializable;
+
+/**
+ * This interface provides both {@link Serializable} and {@link
+ * Runnable}.  It is often used in conjunction with {@link
+ * VM#invoke(Runnable)}.
+ *
+ * <PRE>
+ * public void testRegionPutGet() {
+ *   final Host host = Host.getHost(0);
+ *   VM vm0 = host.getVM(0);
+ *   VM vm1 = host.getVM(1);
+ *   final String name = this.getUniqueName();
+ *   final Object value = new Integer(42);
+ *
+ *   vm0.invoke(new SerializableRunnable("Put value") {
+ *       public void run() {
+ *         ...// get the region //...
+ *         region.put(name, value);
+ *       }
+ *      });
+ *   vm1.invoke(new SerializableRunnable("Get value") {
+ *       public void run() {
+ *         ...// get the region //...
+ *         assertEquals(value, region.get(name));
+ *       }
+ *     });
+ *  }
+ * </PRE>
+ */
+public abstract class SerializableRunnable
+  implements Serializable, Runnable {
+
+  private static final long serialVersionUID = 7584289978241650456L;
+  
+  private String name;
+
+  public SerializableRunnable() {
+    this.name = null;
+  }
+
+  /**
+   * This constructor lets you do the following:
+   *
+   * <PRE>
+   * vm.invoke(new SerializableRunnable("Do some work") {
+   *     public void run() {
+   *       // ...
+   *     }
+   *   });
+   * </PRE>
+   */
+  public SerializableRunnable(String name) {
+    this.name = name;
+  }
+  
+  public void setName(String newName) {
+    this.name = newName;
+  }
+  
+  public String getName() {
+    return this.name;
+  }
+
+  public String toString() {
+    if (this.name != null) {
+      return "\"" + this.name + "\"";
+
+    } else {
+      return super.toString();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java
new file mode 100755
index 0000000..b1e0d88
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java
@@ -0,0 +1,12 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public interface StoppableWaitCriterion extends WaitCriterion {
+  /**
+   * If this method returns true then quit waiting even if we are not done.
+   * This allows a wait to fail early.
+   */
+  public boolean stopWaiting();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java
new file mode 100755
index 0000000..acf43b9
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java
@@ -0,0 +1,157 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Jitter.*;
+import static org.junit.Assert.fail;
+
+import com.gemstone.gemfire.LogWriter;
+import com.gemstone.gemfire.internal.OSProcess;
+import com.gemstone.gemfire.internal.logging.LocalLogWriter;
+import com.gemstone.gemfire.internal.logging.LogWriterImpl;
+
+/**
+ * A set of thread dump methods useful for writing tests. 
+ * <pr/>
+ * These methods can be used directly:
+ * <code>ThreadDump.dumpStack(...)</code>, however, they read better if they
+ * are referenced through static import:
+ * 
+ * <pre>
+ * import static com.gemstone.gemfire.test.dunit.ThreadDump.*;
+ *    ...
+ *    dumpStack(...);
+ * </pre>
+ * <pr/>
+ * Extracted from DistributedTestCase
+ * 
+ * @see VM
+ * @see Host
+ */
+@SuppressWarnings("serial")
+public class ThreadDump {
+
+  protected ThreadDump() {
+  }
+  
+  /** 
+   * Print a stack dump for this vm
+   * 
+   * @author bruce
+   * @since 5.0
+   */
+  public static void dumpStack() {
+    com.gemstone.gemfire.internal.OSProcess.printStacks(0, false);
+  }
+  
+  /** 
+   * Print a stack dump for the given vm
+   * 
+   * @author bruce
+   * @since 5.0
+   */
+  public static void dumpStack(final VM vm) {
+    vm.invoke(dumpStackSerializableRunnable());
+  }
+  
+  /** 
+   * Print stack dumps for all vms on the given host
+   * 
+   * @author bruce
+   * @since 5.0
+   */
+  public static void dumpStack(final Host host) {
+    for (int v=0; v < host.getVMCount(); v++) {
+      host.getVM(v).invoke(dumpStackSerializableRunnable());
+    }
+  }
+  
+  /** 
+   * Print stack dumps for all vms on all hosts
+   * 
+   * @author bruce
+   * @since 5.0
+  */
+  public static void dumpAllStacks() {
+    for (int h=0; h < Host.getHostCount(); h++) {
+      dumpStack(Host.getHost(h));
+    }
+  }
+  
+  public static void dumpStackTrace(final Thread thread, final StackTraceElement[] stack, final LogWriter logWriter) { // TODO: remove LogWriter
+    StringBuilder msg = new StringBuilder();
+    msg.append("Thread=<")
+      .append(thread)
+      .append("> stackDump:\n");
+    for (int i=0; i < stack.length; i++) {
+      msg.append("\t")
+        .append(stack[i])
+        .append("\n");
+    }
+    logWriter.info(msg.toString());
+  }
+
+  /**
+   * Dump all thread stacks
+   */
+  public static void dumpMyThreads(final LogWriter logWriter) { // TODO: remove LogWriter
+    OSProcess.printStacks(0, false);
+  }
+  
+  /**
+   * Wait for a thread to join
+   * @param t thread to wait on
+   * @param ms maximum time to wait
+   * @throws AssertionFailure if the thread does not terminate
+   */
+  static public void join(Thread t, long ms, LogWriter logger) {
+    final long tilt = System.currentTimeMillis() + ms;
+    final long incrementalWait = jitterInterval(ms);
+    final long start = System.currentTimeMillis();
+    for (;;) {
+      // I really do *not* understand why this check is necessary
+      // but it is, at least with JDK 1.6.  According to the source code
+      // and the javadocs, one would think that join() would exit immediately
+      // if the thread is dead.  However, I can tell you from experimentation
+      // that this is not the case. :-(  djp 2008-12-08
+      if (!t.isAlive()) {
+        break;
+      }
+      try {
+        t.join(incrementalWait);
+      } catch (InterruptedException e) {
+        fail("interrupted");
+      }
+      if (System.currentTimeMillis() >= tilt) {
+        break;
+      }
+    } // for
+    if (logger == null) {
+      logger = new LocalLogWriter(LogWriterImpl.INFO_LEVEL, System.out);
+    }
+    if (t.isAlive()) {
+      logger.info("HUNG THREAD");
+      dumpStackTrace(t, t.getStackTrace(), logger);
+      dumpMyThreads(logger);
+      t.interrupt(); // We're in trouble!
+      fail("Thread did not terminate after " + ms + " ms: " + t);
+//      getLogWriter().warning("Thread did not terminate" 
+//          /* , new Exception()*/
+//          );
+    }
+    long elapsedMs = (System.currentTimeMillis() - start);
+    if (elapsedMs > 0) {
+      String msg = "Thread " + t + " took " 
+        + elapsedMs
+        + " ms to exit.";
+      logger.info(msg);
+    }
+  }
+
+  private static SerializableRunnable dumpStackSerializableRunnable() {
+    return new SerializableRunnable() {
+      @Override
+      public void run() {
+        dumpStack();
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java
new file mode 100644
index 0000000..f850184
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java
@@ -0,0 +1,1333 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import hydra.MethExecutorResult;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.rmi.RemoteException;
+import java.util.concurrent.Callable;
+
+/**
+ * This class represents a Java Virtual Machine that runs on a host.
+ *
+ * @author David Whitlock
+ *
+ */
+public class VM implements java.io.Serializable {
+
+  /** The host on which this VM runs */
+  private Host host;
+
+  /** The process id of this VM */
+  private int pid;
+
+  /** The hydra client for this VM */
+  private RemoteDUnitVMIF client;
+
+  /** The state of this VM */
+  private volatile boolean available;
+
+  ////////////////////  Constructors  ////////////////////
+
+  /**
+   * Creates a new <code>VM</code> that runs on a given host with a
+   * given process id.
+   */
+  public VM(Host host, int pid, RemoteDUnitVMIF client) {
+    this.host = host;
+    this.pid = pid;
+    this.client = client;
+    this.available = true;
+  }
+
+  //////////////////////  Accessors  //////////////////////
+
+  /**
+   * Returns the host on which this <code>VM</code> runs
+   */
+  public Host getHost() {
+    return this.host;
+  }
+
+  /**
+   * Returns the process id of this <code>VM</code>
+   */
+  public int getPid() {
+    return this.pid;
+  }
+
+  /////////////////  Remote Method Invocation  ///////////////
+
+  /**
+   * Invokes a static zero-arg method  with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Class c, String methodName) {
+    return invoke(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Asynchronously invokes a static zero-arg method with an {@link
+   * Object} or <code>void</code> return type in this VM.  If the
+   * return type of the method is <code>void</code>, <code>null</code>
+   * is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   */
+  public AsyncInvocation invokeAsync(Class c, String methodName) {
+    return invokeAsync(c, methodName, null);
+  }
+
+  /**
+   * Invokes a static method with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Class c, String methodName, Object[] args) {
+    if (!this.available) {
+      String s = "VM not available: " + this;
+      throw new RMIException(this, c.getName(), methodName,
+            new IllegalStateException(s));
+    }
+    MethExecutorResult result = null;
+    int retryCount = 120;
+    do {
+    try {
+      result = this.client.executeMethodOnClass(c.getName(), methodName, args);
+      break; // out of while loop
+    } catch( RemoteException e ) {
+      boolean isWindows = false;
+      String os = System.getProperty("os.name");
+      if (os != null) {
+        if (os.indexOf("Windows") != -1) {
+          isWindows = true;
+        }
+      }
+      if (isWindows && retryCount-- > 0) {
+        boolean interrupted = Thread.interrupted();
+        try { Thread.sleep(1000); } catch (InterruptedException ignore) {interrupted = true;}
+        finally {
+          if (interrupted) {
+            Thread.currentThread().interrupt();
+          }
+        }
+      } else {
+        throw new RMIException(this, c.getName(), methodName, e );
+      }
+    }
+    } while (true);
+
+    if (!result.exceptionOccurred()) {
+      return result.getResult();
+
+    } else {
+      Throwable thr = result.getException();
+      throw new RMIException(this, c.getName(), methodName, thr,
+                             result.getStackTrace()); 
+    }
+  }
+
+  /**
+   * Asynchronously invokes a static method with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   */
+  public AsyncInvocation invokeAsync(final Class c, 
+                                     final String methodName,
+                                     final Object[] args) {
+    AsyncInvocation ai =
+      new AsyncInvocation(c, methodName, new Runnable() {
+        public void run() {
+          final Object o = invoke(c, methodName, args);
+          AsyncInvocation.setReturnValue(o);
+        }
+      });
+    ai.start();
+    return ai;
+  }
+
+  /**
+   * Asynchronously invokes an instance method with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param o
+   *        The object on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   */
+  public AsyncInvocation invokeAsync(final Object o, 
+                                     final String methodName,
+                                     final Object[] args) {
+    AsyncInvocation ai =
+      new AsyncInvocation(o, methodName, new Runnable() {
+        public void run() {
+          final Object ret = invoke(o, methodName, args);
+          AsyncInvocation.setReturnValue(ret);
+        }
+      });
+    ai.start();
+    return ai;
+  }
+
+  /**
+   * Invokes the <code>run</code> method of a {@link Runnable} in this
+   * VM.  Recall that <code>run</code> takes no arguments and has no
+   * return value.
+   *
+   * @param r
+   *        The <code>Runnable</code> to be run
+   *
+   * @see SerializableRunnable
+   */
+  public AsyncInvocation invokeAsync(Runnable r) {
+    return invokeAsync(r, "run", new Object[0]);
+  }
+  
+  /**
+   * Invokes the <code>call</code> method of a {@link Runnable} in this
+   * VM.  
+   *
+   * @param c
+   *        The <code>Callable</code> to be run
+   *
+   * @see SerializableCallable
+   */
+  public AsyncInvocation invokeAsync(Callable c) {
+    return invokeAsync(c, "call", new Object[0]);
+  }
+
+  /**
+   * Invokes the <code>run</code> method of a {@link Runnable} in this
+   * VM.  Recall that <code>run</code> takes no arguments and has no
+   * return value.
+   *
+   * @param r
+   *        The <code>Runnable</code> to be run
+   *
+   * @see SerializableRunnable
+   */
+  public void invoke(Runnable r) {
+    invoke(r, "run");
+  }
+  
+  /**
+   * Invokes the <code>run</code> method of a {@link Runnable} in this
+   * VM.  Recall that <code>run</code> takes no arguments and has no
+   * return value.
+   *
+   * @param c
+   *        The <code>Callable</code> to be run
+   *
+   * @see SerializableCallable
+   */
+  public Object invoke(Callable c) {
+    return invoke(c, "call");
+  }
+  
+  /**
+   * Invokes the <code>run</code method of a {@link Runnable} in this
+   * VM.  If the invocation throws AssertionFailedError, and repeatTimeoutMs
+   * is >0, the <code>run</code> method is invoked repeatedly until it
+   * either succeeds, or repeatTimeoutMs has passed.  The AssertionFailedError
+   * is thrown back to the sender of this method if <code>run</code> has not
+   * completed successfully before repeatTimeoutMs has passed.
+   */
+  public void invokeRepeatingIfNecessary(RepeatableRunnable o, long repeatTimeoutMs) {
+    invoke(o, "runRepeatingIfNecessary", new Object[] {new Long(repeatTimeoutMs)});
+  }
+
+  /**
+   * Invokes an instance method with no arguments on an object that is
+   * serialized into this VM.  The return type of the method can be
+   * either {@link Object} or <code>void</code>.  If the return type
+   * of the method is <code>void</code>, <code>null</code> is
+   * returned.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Object o, String methodName) {
+    return invoke(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method can be either {@link
+   * Object} or <code>void</code>.  If the return type of the method
+   * is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Object o, String methodName, Object[] args) {
+    if (!this.available) {
+      String s = "VM not available: " + this;
+      throw new RMIException(this, o.getClass().getName(), methodName,
+            new IllegalStateException(s));
+    }
+    MethExecutorResult result = null;
+    int retryCount = 120;
+    do {
+    try {
+      if ( args == null )
+        result = this.client.executeMethodOnObject(o, methodName);
+      else
+        result = this.client.executeMethodOnObject(o, methodName, args);
+      break; // out of while loop
+    } catch( RemoteException e ) {
+      if (retryCount-- > 0) {
+        boolean interrupted = Thread.interrupted();
+        try { Thread.sleep(1000); } catch (InterruptedException ignore) {interrupted = true;}
+        finally {
+          if (interrupted) {
+            Thread.currentThread().interrupt();
+          }
+        }
+      } else {
+        throw new RMIException(this, o.getClass().getName(), methodName, e );
+      }
+    }
+    } while (true);
+
+    if (!result.exceptionOccurred()) {
+      return result.getResult();
+
+    } else {
+      Throwable thr = result.getException();
+      throw new RMIException(this, o.getClass().getName(), methodName, thr,
+                             result.getStackTrace()); 
+    }
+  }
+
+  /**
+   * Invokes the <code>main</code> method of a given class
+   *
+   * @param c
+   *        The class on which to invoke the <code>main</code> method
+   * @param args
+   *        The "command line" arguments to pass to the
+   *        <code>main</code> method
+   */
+  public void invokeMain(Class c, String[] args) {
+    Object[] stupid = new Object[] { args };
+    invoke(c, "main", stupid);
+  }
+
+  /**
+   * Asynchronously invokes the <code>main</code> method of a given
+   * class
+   *
+   * @param c
+   *        The class on which to invoke the <code>main</code> method
+   * @param args
+   *        The "command line" arguments to pass to the
+   *        <code>main</code> method
+   */
+  public AsyncInvocation invokeMainAsync(Class c, String[] args) {
+    Object[] stupid = new Object[] { args };
+    return invokeAsync(c, "main", stupid);
+  }
+
+  /**
+   * Invokes a static method with a <code>boolean</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Class c, String methodName) {
+    return invokeBoolean(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>boolean</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a boolean";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Boolean) {
+      return ((Boolean) result).booleanValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a boolean";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>boolean</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Object o, String methodName) {
+    return invokeBoolean(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>boolean</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a boolean";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Boolean) {
+      return ((Boolean) result).booleanValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a boolean";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>char</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Class c, String methodName) {
+    return invokeChar(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>char</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a char";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Character) {
+      return ((Character) result).charValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a char";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>char</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Object o, String methodName) {
+    return invokeChar(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>char</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a char";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Character) {
+      return ((Character) result).charValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a char";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>byte</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Class c, String methodName) {
+    return invokeByte(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>byte</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a byte";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Byte) {
+      return ((Byte) result).byteValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a byte";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>byte</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Object o, String methodName) {
+    return invokeByte(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>byte</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a byte";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Byte) {
+      return ((Byte) result).byteValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a byte";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>short</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Class c, String methodName) {
+    return invokeShort(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>short</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a short";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Short) {
+      return ((Short) result).shortValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a short";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>short</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Object o, String methodName) {
+    return invokeShort(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>short</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a short";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Short) {
+      return ((Short) result).shortValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a short";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>int</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Class c, String methodName) {
+    return invokeInt(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>int</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a int";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Integer) {
+      return ((Integer) result).intValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a int";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>int</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Object o, String methodName) {
+    return invokeInt(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>int</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a int";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Integer) {
+      return ((Integer) result).intValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a int";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>long</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Class c, String methodName) {
+    return invokeLong(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>long</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a long";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Long) {
+      return ((Long) result).longValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a long";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>long</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Object o, String methodName) {
+    return invokeLong(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>long</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a long";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Long) {
+      return ((Long) result).longValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a long";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>float</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Class c, String methodName) {
+    return invokeFloat(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>float</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a float";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Float) {
+      return ((Float) result).floatValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a float";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>float</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Object o, String methodName) {
+    return invokeFloat(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>float</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a float";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Float) {
+      return ((Float) result).floatValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a float";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>double</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Class c, String methodName) {
+    return invokeDouble(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>double</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a double";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Double) {
+      return ((Double) result).doubleValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a double";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>double</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Object o, String methodName) {
+    return invokeDouble(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>double</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a double";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Double) {
+      return ((Double) result).doubleValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a double";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Synchronously bounces (mean kills and restarts) this <code>VM</code>.
+   * Concurrent bounce attempts are synchronized but attempts to invoke
+   * methods on a bouncing VM will cause test failure.  Tests using bounce
+   * should be placed at the end of the dunit test suite, since an exception
+   * here will cause all tests using the unsuccessfully bounced VM to fail.
+   * 
+   * This method is currently not supported by the standalone dunit
+   * runner.
+   *
+   * @throws RMIException if an exception occurs while bouncing this VM, for
+   *  example a HydraTimeoutException if the VM fails to stop within {@link
+   *  hydra.Prms#maxClientShutdownWaitSec} or restart within {@link
+   *  hydra.Prms#maxClientStartupWaitSec}.
+   */
+  public synchronized void bounce() {
+    if (!this.available) {
+      String s = "VM not available: " + this;
+      throw new RMIException(this, this.getClass().getName(), "bounceVM",
+            new IllegalStateException(s));
+    }
+    this.available = false;
+    try {
+      BounceResult result = DUnitEnv.get().bounce(this.pid);
+      
+      this.pid = result.getNewPid();
+      this.client = result.getNewClient();
+      this.available = true;
+    } catch (UnsupportedOperationException e) {
+      this.available = true;
+      throw e;
+    } catch (RemoteException e) {
+      StringWriter sw = new StringWriter();
+      e.printStackTrace(new PrintWriter(sw, true));
+      RMIException rmie = new RMIException(this, this.getClass().getName(),
+        "bounceVM", e, sw.toString());
+      throw rmie;
+    }
+  }
+
+  /////////////////////  Utility Methods  ////////////////////
+
+  public String toString() {
+    return "VM " + this.getPid() + " running on " + this.getHost();
+  }
+
+  public static int getCurrentVMNum() {
+    return DUnitEnv.get().getVMID();
+  }
+  
+  public File getWorkingDirectory() {
+    return DUnitEnv.get().getWorkingDirectory(this.getPid());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
new file mode 100755
index 0000000..9653a76
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
@@ -0,0 +1,167 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Jitter.jitterInterval;
+import static org.junit.Assert.fail;
+
+import com.gemstone.gemfire.internal.cache.LocalRegion;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public class Wait {
+
+  /**
+   * Wait until given criterion is met
+   * 
+   * @param ev criterion to wait on
+   * @param ms total time to wait, in milliseconds
+   * @param interval pause interval between waits
+   * @param throwOnTimeout if false, don't generate an error
+   */
+  public static void waitForCriterion(final WaitCriterion ev, final long ms, final long interval, final boolean throwOnTimeout) {
+    long waitThisTime = jitterInterval(interval);
+    final long tilt = System.currentTimeMillis() + ms;
+    for (;;) {
+      if (ev.done()) {
+        return; // success
+      }
+      
+      if (ev instanceof StoppableWaitCriterion) {
+        StoppableWaitCriterion ev2 = (StoppableWaitCriterion)ev;
+        if (ev2.stopWaiting()) {
+          if (throwOnTimeout) {
+            fail("stopWaiting returned true: " + ev.description());
+          }
+          return;
+        }
+      }
+
+      // Calculate time left
+      long timeLeft = tilt - System.currentTimeMillis();
+      if (timeLeft <= 0) {
+        if (!throwOnTimeout) {
+          return; // not an error, but we're done
+        }
+        fail("Event never occurred after " + ms + " ms: " + ev.description());
+      }
+      
+      if (waitThisTime > timeLeft) {
+        waitThisTime = timeLeft;
+      }
+      
+      // Wait a little bit
+      Thread.yield();
+      try {
+        Thread.sleep(waitThisTime);
+      } catch (InterruptedException e) {
+        fail("interrupted");
+      }
+    }
+  }
+
+  /**
+   * Wait on a mutex.  This is done in a loop in order to address the
+   * "spurious wakeup" "feature" in Java.
+   * 
+   * @param ev condition to test
+   * @param mutex object to lock and wait on
+   * @param ms total amount of time to wait
+   * @param interval interval to pause for the wait
+   * @param throwOnTimeout if false, no error is thrown.
+   */
+  public static void waitOnMutex(final WaitCriterion ev, final Object mutex, final long ms, final long interval, final boolean throwOnTimeout) {
+    final long tilt = System.currentTimeMillis() + ms;
+    long waitThisTime = jitterInterval(interval);
+    synchronized (mutex) {
+      for (;;) {
+        if (ev.done()) {
+          break;
+        }
+        
+        long timeLeft = tilt - System.currentTimeMillis();
+        if (timeLeft <= 0) {
+          if (!throwOnTimeout) {
+            return; // not an error, but we're done
+          }
+          fail("Event never occurred after " + ms + " ms: " + ev.description());
+        }
+        
+        if (waitThisTime > timeLeft) {
+          waitThisTime = timeLeft;
+        }
+        
+        try {
+          mutex.wait(waitThisTime);
+        } catch (InterruptedException e) {
+          fail("interrupted");
+        }
+      } // for
+    } // synchronized
+  }
+
+  /** pause for a default interval */
+  public static void pause() {
+    pause(250);
+  }
+
+  /**
+   * Use of this function indicates a place in the tests tree where t
+   * he use of Thread.sleep() is
+   * highly questionable.
+   * <p>
+   * Some places in the system, especially those that test expirations and other
+   * timeouts, have a very good reason to call {@link Thread#sleep(long)}.  The
+   * <em>other</em> places are marked by the use of this method.
+   * 
+   * @param ms
+   */
+  public static final void staticPause(int ms) {
+    final long target = System.currentTimeMillis() + ms;
+    try {
+      for (;;) {
+        long msLeft = target - System.currentTimeMillis();
+        if (msLeft <= 0) {
+          break;
+        }
+        Thread.sleep(msLeft);
+      }
+    }
+    catch (InterruptedException e) {
+      throw new AssertionError("interrupted", e);
+    }
+    
+  }
+  
+  /**
+   * Blocks until the clock used for expiration on the given region changes.
+   */
+  public static final void waitForExpiryClockToChange(LocalRegion lr) {
+    long startTime = lr.cacheTimeMillis();
+    do {
+      Thread.yield();
+    } while (startTime == lr.cacheTimeMillis());
+  }
+  
+  /** pause for specified ms interval
+   * Make sure system clock has advanced by the specified number of millis before
+   * returning.
+   */
+  public static final void pause(int ms) {
+    if (ms > 50) {
+      //getLogWriter().info("Pausing for " + ms + " ms..."/*, new Exception()*/);
+    }
+    final long target = System.currentTimeMillis() + ms;
+    try {
+      for (;;) {
+        long msLeft = target - System.currentTimeMillis();
+        if (msLeft <= 0) {
+          break;
+        }
+        Thread.sleep(msLeft);
+      }
+    }
+    catch (InterruptedException e) {
+      throw new AssertionError("interrupted", e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java
new file mode 100755
index 0000000..493038e
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java
@@ -0,0 +1,11 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public interface WaitCriterion {
+
+  public boolean done();
+  
+  public String description();
+}



Mime
View raw message