Refactoring how context is passed to a task

Refactoring the way context is passed to a task, so that we can add
methods to the context that are specific to a JVM.
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMFactory.java b/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMFactory.java
index 85dc64b..61f5c81 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMFactory.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMFactory.java
@@ -33,6 +33,7 @@
 import org.apache.geode.perftest.jvms.classpath.ClassPathCopier;
 import org.apache.geode.perftest.jvms.rmi.Controller;
 import org.apache.geode.perftest.jvms.rmi.ControllerFactory;
+import org.apache.geode.perftest.runner.SharedContext;
 
 /**
  * Factory for launching JVMs and a given infrastructure and setting up RMI
@@ -85,11 +86,12 @@
       throw new IllegalStateException("Too few nodes for test. Need " + numWorkers + ", have " + nodes.size());
     }
 
-    Controller controller = controllerFactory.createController(numWorkers);
+    List<JVMMapping> mapping = mapRolesToNodes(roles, nodes);
+
+    Controller controller = controllerFactory.createController(new SharedContext(mapping), numWorkers);
 
     classPathCopier.copyToNodes(infra, LIB_DIR);
 
-    List<JVMMapping> mapping = mapRolesToNodes(roles, nodes);
     CompletableFuture<Void> processesExited = jvmLauncher.launchProcesses(infra, RMI_PORT, mapping,
         LIB_DIR);
 
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMs.java b/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMs.java
index 8f47bbf..f619282 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMs.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/RemoteJVMs.java
@@ -19,9 +19,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.rmi.NoSuchObjectException;
-import java.rmi.registry.Registry;
-import java.rmi.server.UnicastRemoteObject;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -42,7 +39,6 @@
 public class RemoteJVMs implements AutoCloseable {
   private final List<JVMMapping> jvmMappings;
   private final Controller controller;
-  private final TestContext context;
   private final CompletableFuture<Void> exited;
   private final Infrastructure infra;
 
@@ -53,7 +49,6 @@
     this.infra = infra;
     this.jvmMappings = mapping;
     this.controller = controller;
-    this.context = new DefaultTestContext(jvmMappings);
     this.exited = exited;
   }
 
@@ -66,7 +61,7 @@
 
     Stream<CompletableFuture> futures = jvmMappings.stream()
         .filter(mapping -> roles.contains(mapping.getRole()))
-        .map(mapping -> controller.onWorker(mapping.getId(), task, context));
+        .map(mapping -> controller.onWorker(mapping.getId(), task));
 
     futures.forEach(CompletableFuture::join);
   }
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ChildJVM.java b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ChildJVM.java
index 7aa9b8a..d29563a 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ChildJVM.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ChildJVM.java
@@ -20,9 +20,13 @@
 import java.io.File;
 import java.io.PrintStream;
 
+import org.bouncycastle.jcajce.provider.drbg.DRBG;
+
 import org.apache.geode.perftest.jdk.RMI;
 import org.apache.geode.perftest.jdk.SystemInterface;
 import org.apache.geode.perftest.jvms.RemoteJVMFactory;
+import org.apache.geode.perftest.runner.DefaultTestContext;
+import org.apache.geode.perftest.runner.SharedContext;
 
 /**
  * Main method for a JVM running on a remote node
@@ -59,7 +63,10 @@
       ControllerRemote controller = (ControllerRemote) rmi
           .lookup("//" + RMI_HOST + ":" + RMI_PORT + "/" + RemoteJVMFactory.CONTROLLER);
 
-      Worker worker = new Worker();
+      SharedContext sharedContext = controller.getsharedContext();
+      DefaultTestContext context = new DefaultTestContext(sharedContext);
+
+      Worker worker = new Worker(context);
 
       controller.addWorker(id, worker);
 
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Controller.java b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Controller.java
index 1e20a96..e40c2fd 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Controller.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Controller.java
@@ -28,21 +28,23 @@
 import java.util.concurrent.TimeUnit;
 
 import org.apache.geode.perftest.Task;
-import org.apache.geode.perftest.TestContext;
+import org.apache.geode.perftest.runner.SharedContext;
 
 /**
  * RMI object that lives on the main controller JVM
  */
 public class Controller extends UnicastRemoteObject implements ControllerRemote {
   private final Registry registry;
-  private Map<Integer, WorkerRemote> workers = new ConcurrentHashMap<>();
+  private final SharedContext context;
+  private final Map<Integer, WorkerRemote> workers = new ConcurrentHashMap<>();
   private final CountDownLatch workersStarted;
   private volatile boolean isClosed;
 
 
-  Controller(int numWorkers, Registry registry) throws RemoteException {
+  Controller(int numWorkers, Registry registry, SharedContext context) throws RemoteException {
     this.workersStarted = new CountDownLatch(numWorkers);
     this.registry = registry;
+    this.context = context;
   }
 
   public void close() throws NoSuchObjectException {
@@ -66,7 +68,12 @@
     return !isClosed;
   }
 
-  public CompletableFuture<Void> onWorker(int id, Task task, TestContext context) {
+  @Override
+  public SharedContext getsharedContext() throws RemoteException {
+    return context;
+  }
+
+  public CompletableFuture<Void> onWorker(int id, Task task) {
     WorkerRemote worker = workers.get(id);
     if(worker == null) {
       throw new IllegalStateException("Worker number " + id + " is not set");
@@ -74,7 +81,7 @@
 
     return CompletableFuture.runAsync(() -> {
       try {
-        worker.execute(task, context);
+        worker.execute(task);
       } catch (Exception e) {
         throw new RuntimeException(e);
       }
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerFactory.java b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerFactory.java
index d580831..4aaa47f 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerFactory.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerFactory.java
@@ -25,14 +25,16 @@
 import java.rmi.registry.Registry;
 
 import org.apache.geode.perftest.jdk.RMI;
+import org.apache.geode.perftest.runner.SharedContext;
 
 public class ControllerFactory {
 
   private final RMI rmi = new RMI();
 
-  public Controller createController(int numWorkers) throws RemoteException, AlreadyBoundException {
+  public Controller createController(SharedContext sharedContext,
+                                     int numWorkers) throws RemoteException, AlreadyBoundException {
     Registry registry = rmi.createRegistry(RMI_PORT);
-    Controller controller = new Controller(numWorkers, registry);
+    Controller controller = new Controller(numWorkers, registry, sharedContext);
     registry.bind(CONTROLLER, controller);
     return controller;
   }
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerRemote.java b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerRemote.java
index 918d8d5..f29d361 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerRemote.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/ControllerRemote.java
@@ -20,9 +20,13 @@
 import java.rmi.Remote;
 import java.rmi.RemoteException;
 
+import org.apache.geode.perftest.runner.SharedContext;
+
 public interface ControllerRemote extends Remote {
 
   void addWorker(int id, WorkerRemote remote) throws RemoteException;
 
   boolean ping() throws RemoteException;
+
+  SharedContext getsharedContext() throws RemoteException;
 }
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Worker.java b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Worker.java
index a452af1..0653c0e 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Worker.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/Worker.java
@@ -21,15 +21,17 @@
 import java.rmi.server.UnicastRemoteObject;
 
 import org.apache.geode.perftest.Task;
-import org.apache.geode.perftest.TestContext;
+import org.apache.geode.perftest.runner.DefaultTestContext;
 
 public class Worker extends UnicastRemoteObject implements WorkerRemote {
 
-  public Worker() throws RemoteException {
-    super();
+  private DefaultTestContext context;
+
+  public Worker(DefaultTestContext context) throws RemoteException {
+    this.context = context;
   }
   @Override
-  public void execute(Task task, TestContext context) throws Exception {
+  public void execute(Task task) throws Exception {
     task.run(context);
   }
 }
diff --git a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/WorkerRemote.java b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/WorkerRemote.java
index a4020b8..f5f2859 100644
--- a/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/WorkerRemote.java
+++ b/harness/src/main/java/org/apache/geode/perftest/jvms/rmi/WorkerRemote.java
@@ -20,8 +20,7 @@
 import java.rmi.Remote;
 
 import org.apache.geode.perftest.Task;
-import org.apache.geode.perftest.TestContext;
 
 public interface WorkerRemote extends Remote {
-  void execute(Task task, TestContext context) throws Exception;
+  void execute(Task task) throws Exception;
 }
diff --git a/harness/src/main/java/org/apache/geode/perftest/runner/DefaultTestContext.java b/harness/src/main/java/org/apache/geode/perftest/runner/DefaultTestContext.java
index b649fa9..f54563a 100644
--- a/harness/src/main/java/org/apache/geode/perftest/runner/DefaultTestContext.java
+++ b/harness/src/main/java/org/apache/geode/perftest/runner/DefaultTestContext.java
@@ -18,26 +18,20 @@
 package org.apache.geode.perftest.runner;
 
 import java.net.InetAddress;
-import java.util.List;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 import org.apache.geode.perftest.TestContext;
-import org.apache.geode.perftest.jvms.JVMMapping;
 
 public class DefaultTestContext implements TestContext {
 
-  private List<JVMMapping> jvmMappings;
+  private SharedContext sharedContext;
 
-  public DefaultTestContext(List<JVMMapping> jvmMappings) {
-
-    this.jvmMappings = jvmMappings;
+  public DefaultTestContext(SharedContext sharedContext) {
+    this.sharedContext = sharedContext;
   }
 
-  @Override public Set<InetAddress> getHostsForRole(String role) {
-    return jvmMappings.stream()
-        .filter(mapping -> mapping.getRole().equals(role))
-        .map(mapping -> mapping.getNode().getAddress())
-        .collect(Collectors.toSet());
+  @Override
+  public Set<InetAddress> getHostsForRole(String role) {
+    return sharedContext.getHostsForRole(role);
   }
 }
diff --git a/harness/src/main/java/org/apache/geode/perftest/runner/SharedContext.java b/harness/src/main/java/org/apache/geode/perftest/runner/SharedContext.java
new file mode 100644
index 0000000..50aeadf
--- /dev/null
+++ b/harness/src/main/java/org/apache/geode/perftest/runner/SharedContext.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geode.perftest.runner;
+
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.geode.perftest.jvms.JVMMapping;
+
+/**
+ * Context for a running test that is the same for all JVMs
+ * running the test. This context is created at the beginning of the
+ * test run and passed to all JVMs.
+ */
+public class SharedContext implements Serializable {
+
+  private List<JVMMapping> jvmMappings;
+
+  public SharedContext(List<JVMMapping> jvmMappings) {
+
+    this.jvmMappings = jvmMappings;
+  }
+
+  public Set<InetAddress> getHostsForRole(String role) {
+    return jvmMappings.stream()
+        .filter(mapping -> mapping.getRole().equals(role))
+        .map(mapping -> mapping.getNode().getAddress())
+        .collect(Collectors.toSet());
+  }
+}
diff --git a/harness/src/test/java/org/apache/geode/perftest/jvms/RemoteJVMFactoryTest.java b/harness/src/test/java/org/apache/geode/perftest/jvms/RemoteJVMFactoryTest.java
index a6b5553..4d1eb2b 100644
--- a/harness/src/test/java/org/apache/geode/perftest/jvms/RemoteJVMFactoryTest.java
+++ b/harness/src/test/java/org/apache/geode/perftest/jvms/RemoteJVMFactoryTest.java
@@ -38,10 +38,10 @@
 
 import org.apache.geode.perftest.infrastructure.Infrastructure;
 import org.apache.geode.perftest.infrastructure.InfrastructureFactory;
-import org.apache.geode.perftest.jdk.RMI;
 import org.apache.geode.perftest.jvms.classpath.ClassPathCopier;
 import org.apache.geode.perftest.jvms.rmi.Controller;
 import org.apache.geode.perftest.jvms.rmi.ControllerFactory;
+import org.apache.geode.perftest.runner.SharedContext;
 
 public class RemoteJVMFactoryTest {
 
@@ -58,7 +58,7 @@
     jvmLauncher = mock(JVMLauncher.class);
     controller = mock(Controller.class);
     controllerFactory = mock(ControllerFactory.class);
-    when(controllerFactory.createController(anyInt())).thenReturn(controller);
+    when(controllerFactory.createController(any(), anyInt())).thenReturn(controller);
     infra = mock(Infrastructure.class);
     InfrastructureFactory infraFactory = nodes -> infra;
     factory = new RemoteJVMFactory(infraFactory, jvmLauncher, classPathCopier, controllerFactory);
@@ -79,7 +79,7 @@
 
     InOrder inOrder = inOrder(controller, controllerFactory, jvmLauncher, classPathCopier, infra);
 
-    inOrder.verify(controllerFactory).createController(eq(2));
+    inOrder.verify(controllerFactory).createController(any(), eq(2));
     inOrder.verify(jvmLauncher).launchProcesses(eq(infra), anyInt(), any(), any());
     inOrder.verify(controller).waitForWorkers(anyInt(), any());
 
diff --git a/harness/src/test/java/org/apache/geode/perftest/runner/DefaultTestContextTest.java b/harness/src/test/java/org/apache/geode/perftest/runner/SharedContextTest.java
similarity index 93%
rename from harness/src/test/java/org/apache/geode/perftest/runner/DefaultTestContextTest.java
rename to harness/src/test/java/org/apache/geode/perftest/runner/SharedContextTest.java
index 704374f..7784105 100644
--- a/harness/src/test/java/org/apache/geode/perftest/runner/DefaultTestContextTest.java
+++ b/harness/src/test/java/org/apache/geode/perftest/runner/SharedContextTest.java
@@ -33,7 +33,7 @@
 import org.apache.geode.perftest.infrastructure.Infrastructure;
 import org.apache.geode.perftest.jvms.JVMMapping;
 
-public class DefaultTestContextTest {
+public class SharedContextTest {
 
   @Test
   public void getHostsForRoleShouldReturnCorrectList() throws UnknownHostException {
@@ -47,7 +47,7 @@
     when(node2.getAddress()).thenReturn(host2);
     JVMMapping mapping2 = new JVMMapping(node2, "role", 2);
 
-    DefaultTestContext context = new DefaultTestContext(Arrays.asList(mapping1, mapping2));
+    SharedContext context = new SharedContext(Arrays.asList(mapping1, mapping2));
 
     Set<InetAddress> hosts = context.getHostsForRole("role");