You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2020/06/17 03:03:17 UTC

[tomee-tck] 02/05: Copy JSR-88 deploy code deleted from EE 9 TCK

This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch jakartaee9-tck
in repository https://gitbox.apache.org/repos/asf/tomee-tck.git

commit b1fd6923e4d3e05ac3279616ce1361b3576ad19a
Author: David Blevins <da...@gmail.com>
AuthorDate: Tue Jun 16 18:52:56 2020 -0700

    Copy JSR-88 deploy code deleted from EE 9 TCK
---
 .../org/apache/openejb/cts/DeploymentImpl.java     |    3 +-
 .../org/apache/openejb/cts/deploy/DMProps.java     |   79 ++
 .../apache/openejb/cts/deploy/DeployTestUtil.java  | 1036 ++++++++++++++++++++
 .../apache/openejb/cts/deploy/OperationStatus.java |  147 +++
 .../openejb/cts/deploy/StandardDeployment14.java   |  869 ++++++++++++++++
 .../apache/openejb/cts/deploy/TSDeployment2.java   |   57 ++
 .../openejb/cts/deploy/TSDeploymentInterface2.java |   38 +
 7 files changed, 2227 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/openejb/cts/DeploymentImpl.java b/src/main/java/org/apache/openejb/cts/DeploymentImpl.java
index 3a572b3..778201e 100644
--- a/src/main/java/org/apache/openejb/cts/DeploymentImpl.java
+++ b/src/main/java/org/apache/openejb/cts/DeploymentImpl.java
@@ -24,9 +24,8 @@ import com.sun.ts.lib.deliverable.PropertyManagerInterface;
 import com.sun.ts.lib.deliverable.PropertyNotSetException;
 import com.sun.ts.lib.porting.DeploymentInfo;
 import com.sun.ts.lib.porting.TSDeploymentException;
-import com.sun.ts.lib.porting.TSDeploymentInterface2;
 import org.apache.openejb.config.RemoteServer;
-import org.apache.openejb.testng.PropertiesBuilder;
+import org.apache.openejb.cts.deploy.TSDeploymentInterface2;
 
 import javax.enterprise.deploy.spi.DeploymentManager;
 import javax.enterprise.deploy.spi.Target;
diff --git a/src/main/java/org/apache/openejb/cts/deploy/DMProps.java b/src/main/java/org/apache/openejb/cts/deploy/DMProps.java
new file mode 100644
index 0000000..d78c576
--- /dev/null
+++ b/src/main/java/org/apache/openejb/cts/deploy/DMProps.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.apache.openejb.cts.deploy;
+
+import java.lang.String;
+import java.util.Properties;
+
+// Harness imports
+import com.sun.ts.lib.util.TestUtil;
+
+public class DMProps {
+
+  private String jarfile;
+
+  private String uri;
+
+  private String uname;
+
+  private String passwd;
+
+  public DMProps(String jarfile, String uri, String uname, String passwd) {
+    this.jarfile = jarfile;
+    this.uri = uri;
+    this.uname = uname;
+    this.passwd = passwd;
+  }
+
+  public boolean equals(DMProps dm2) {
+    return (this.jarfile.equals(dm2.jarfile) && this.uri.equals(dm2.uri)
+        && this.uname.equals(dm2.uname) && this.passwd.equals(dm2.passwd));
+  }
+
+  public void setJarFile(String jarfile) {
+    this.jarfile = jarfile;
+  }
+
+  public void setURI(String uri) {
+    this.uri = uri;
+  }
+
+  public void setUname(String uname) {
+    this.uname = uname;
+  }
+
+  public void setPasswd(String passwd) {
+    this.passwd = passwd;
+  }
+
+  public String getJarFile() {
+    return (jarfile);
+  }
+
+  public String getURI() {
+    return (uri);
+  }
+
+  public String getUname() {
+    return (uname);
+  }
+
+  public String getPasswd() {
+    return (passwd);
+  }
+
+}
diff --git a/src/main/java/org/apache/openejb/cts/deploy/DeployTestUtil.java b/src/main/java/org/apache/openejb/cts/deploy/DeployTestUtil.java
new file mode 100644
index 0000000..13ad65e
--- /dev/null
+++ b/src/main/java/org/apache/openejb/cts/deploy/DeployTestUtil.java
@@ -0,0 +1,1036 @@
+
+/*
+ * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.apache.openejb.cts.deploy;
+
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Hashtable;
+
+import java.io.*;
+import java.util.jar.Manifest;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+// Harness imports
+import com.sun.ts.lib.util.TestUtil;
+
+// J2EE Deployment imports
+import javax.enterprise.deploy.spi.*;
+import javax.enterprise.deploy.spi.status.*;
+import javax.enterprise.deploy.spi.exceptions.*;
+import javax.enterprise.deploy.model.*;
+import javax.enterprise.deploy.shared.*;
+import javax.enterprise.deploy.model.*;
+
+import java.io.*;
+import java.util.*;
+
+import javax.enterprise.deploy.shared.factories.*;
+import javax.enterprise.deploy.spi.*;
+import javax.enterprise.deploy.spi.exceptions.*;
+import javax.enterprise.deploy.spi.factories.*;
+
+public class DeployTestUtil {
+
+  public static final String DEPLOYMENT_MANIFEST_ENTRY_NAME = "J2EE-DeploymentFactory-Implementation-Class";
+
+  public static final String FILE_ARCHIVE = "FILE";
+
+  public static final String STREAM_ARCHIVE = "STREAM";
+
+  public static final String APPLICATION_ARCHIVE = "APPLICATION";
+
+  public static final String STAND_ALONE_ARCHIVE = "STAND_ALONE";
+
+  private DeploymentManager dm = null;
+
+  private DMProps dmp;
+
+  private DeploymentManager disconnectedDM;
+
+  /**
+   *
+   * Construct a DeployTestUtil object. Load the DeploymentFactories from the
+   * provided jarfile, and get a DeploymentManager instance.
+   *
+   */
+  public DeployTestUtil(DMProps dmprops) throws Exception {
+    dmp = dmprops;
+    loadDMFactories();
+  }
+
+  public DeploymentManager getDeploymentManager()
+      throws DeploymentManagerCreationException {
+    if (dm == null) {
+      DeploymentFactoryManager dfmanager = DeploymentFactoryManager
+          .getInstance();
+      dm = dfmanager.getDeploymentManager(dmp.getURI(), dmp.getUname(),
+          dmp.getPasswd());
+      TestUtil.logHarnessDebug(
+          "$$$$$$$$$$$$$$$[" + dmp.getUname() + ", " + dmp.getPasswd() + "]");
+      TestUtil.logHarness("amd Obtained FRESH DeploymentManager");
+    } else {
+      TestUtil.logHarness("amd Obtained CACHED DeploymentManager");
+    }
+    System.out.println(dm);
+    return dm;
+  }
+
+  public DeploymentManager getDisconnectedDeploymentManager()
+      throws DeploymentManagerCreationException {
+    if (disconnectedDM == null) {
+
+      TestUtil.logHarness("DeployTestUtil.getDeploymentManager called");
+      DeploymentFactoryManager dfmanager = DeploymentFactoryManager
+          .getInstance();
+      disconnectedDM = dfmanager.getDisconnectedDeploymentManager(dmp.getURI());
+    }
+    return (disconnectedDM);
+  }
+
+  public Vector getDeploymentFactoryClassNames() throws Exception {
+    File deployPlatformJarFile;
+
+    try {
+      deployPlatformJarFile = new File(dmp.getJarFile());
+    } catch (Exception e) {
+      throw new Exception(
+          "Could not contruct file object: " + dmp.getJarFile());
+    }
+
+    // Obtain DeploymentFactory names from manifest and load those entries
+    TestUtil.logHarness("loadDeploymentFactories loading factories from file:"
+        + deployPlatformJarFile.getName());
+
+    Manifest mf = new java.util.jar.JarFile(deployPlatformJarFile)
+        .getManifest();
+
+    // This should be rewritten to get multiple class names from the manifest
+    String dfClassNames = mf.getMainAttributes()
+        .getValue(DEPLOYMENT_MANIFEST_ENTRY_NAME);
+    if (dfClassNames == null) {
+      throw new Exception(
+          "Invalid Jar File: Jar file does not have entry for Deployment factories");
+    }
+
+    // Parse class names, assuming that class names are separated by space
+    java.util.StringTokenizer st = new java.util.StringTokenizer(dfClassNames,
+        " ");
+    Vector classNames = new Vector();
+    while (st.hasMoreTokens()) {
+      classNames.add(st.nextToken());
+    }
+
+    return (classNames);
+
+  }
+
+  private void loadDMFactories() throws Exception {
+    TestUtil.logHarness("DeployTestUtil.loadDMFactories called");
+    TestUtil.logHarness(
+        "DeployTestUtil.loadDMFactories using jarfile: " + dmp.getJarFile());
+    loadDeploymentFactories();
+  }
+
+  private void loadDeploymentFactories() throws Exception {
+
+    File deployPlatformJarFile;
+
+    try {
+      deployPlatformJarFile = new File(dmp.getJarFile());
+    } catch (Exception e) {
+      throw new Exception(
+          "Could not contruct file object: " + dmp.getJarFile());
+    }
+
+    // Obtain DeploymentFactory names from manifest and load those entries
+    TestUtil.logHarness("loadDeploymentFactories loading factories from file:"
+        + deployPlatformJarFile.getName());
+
+    Manifest mf = new java.util.jar.JarFile(deployPlatformJarFile)
+        .getManifest();
+
+    // This should be rewritten to get multiple class names from the manifest
+    TestUtil.logHarness(
+        "Looking for manifest entry: " + DEPLOYMENT_MANIFEST_ENTRY_NAME);
+    String dfClassNames = mf.getMainAttributes()
+        .getValue(DEPLOYMENT_MANIFEST_ENTRY_NAME);
+
+    if (dfClassNames == null) {
+      throw new Exception("Invalid Jar File: No manifest entry.");
+    }
+
+    // Parse class names, assuming that class names are separated by space
+    java.util.StringTokenizer st = new java.util.StringTokenizer(dfClassNames,
+        " ");
+    Vector classNames = new Vector();
+    while (st.hasMoreTokens())
+      classNames.add(st.nextToken());
+
+    // Load classes
+    try {
+      URL[] urls = new URL[] { deployPlatformJarFile.toURL() };
+      URLClassLoader urlClassLoader = new URLClassLoader(urls,
+          this.getClass().getClassLoader());
+
+      // Do i need to set the contect class loader ?
+      TestUtil.logHarness(
+          "loadDeploymentFactories about to load classes :" + dfClassNames);
+      Thread.currentThread().setContextClassLoader(urlClassLoader);
+
+      // Load all classes
+      for (int classNameIndex = 0; classNameIndex < classNames
+          .size(); classNameIndex++) {
+
+        Class factory = null;
+        DeploymentFactory df = null;
+
+        try {
+          factory = urlClassLoader
+              .loadClass((String) classNames.elementAt(classNameIndex));
+          df = (DeploymentFactory) factory.newInstance();
+        } catch (Exception e) {
+          e.printStackTrace();
+        }
+
+        if (df instanceof DeploymentFactory) {
+          DeploymentFactoryManager.getInstance()
+              .registerDeploymentFactory((DeploymentFactory) df);
+          TestUtil
+              .logMsg("Registered DeploymentFactory: " + df.getDisplayName());
+        } else {
+          throw new Exception("Does not implement DeploymentFactory");
+        }
+
+        // Class.forName((String)classNames.elementAt(classNameIndex),
+        // true, urlClassLoader);
+
+        // Register DeploymentFactory with DeploymentFactoryManager
+        // DeploymentFactory df = (DeploymentFactory)classNames.elementAt
+        // (classNameIndex);
+      }
+
+    } catch (Exception ex) {
+      ex.printStackTrace();
+      throw new Exception(
+          "Could not load DeploymentFactory class: " + ex.getMessage());
+    }
+
+  }
+
+  public void releaseDeploymentManager() {
+
+    if (dm != null) {
+      TestUtil.logHarness("amd Releasing DeploymentManager amd");
+      this.dm.release();
+    }
+    if (disconnectedDM != null) {
+      TestUtil.logHarness("amd Releasing DISCONNECTED DeploymentManager amd");
+      this.disconnectedDM.release();
+    }
+
+    TestUtil.logHarness(" amd Released DeploymentManager amd ");
+  }
+
+  public boolean checkIfModuleExists(TargetModuleID moduleToCheck,
+      TargetModuleID[] modulesList) {
+    boolean exists = false;
+    if (moduleToCheck == null) {
+      return exists;
+    }
+    int numMods = (modulesList == null) ? 0 : modulesList.length;
+    for (int modIndex = 0; modIndex < numMods; modIndex++) {
+      if (moduleToCheck.getModuleID()
+          .equals(modulesList[modIndex].getModuleID())) {
+        // Also check for same targets.
+        if (moduleToCheck.getTarget().getName()
+            .equals(modulesList[modIndex].getTarget().getName())) {
+          exists = true;
+          break;
+        }
+      }
+    }
+    return exists;
+  }
+
+  /*
+   * If the operation is successful then TargetModuleID is a valid module id.
+   * Else it will be null
+   **/
+  public TargetModuleID distributeModuleArchive(Target[] targets,
+      File moduleArchive, File deploymentPlan) throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    ProgressHandler progressHandler = new ProgressHandler();
+    ProgressObject progress = dm.distribute(targets, moduleArchive,
+        deploymentPlan);
+    progress.addProgressListener(progressHandler);
+    progressHandler.start();
+    // Wait for the progress handler to complete its job
+    progressHandler.join();
+    StateType completionState = progressHandler.getCompletionState();
+    if (completionState.getValue() != StateType.COMPLETED.getValue()) {
+      // The state must be either FAILED, or RELEASED
+      return null;
+    }
+    TargetModuleID[] resultModuleIDs = progress.getResultTargetModuleIDs();
+    if (resultModuleIDs.length < 1) {
+      // There should be atleast one target module id if progress is
+      // successfully complete
+      return null;
+    }
+    return resultModuleIDs[0];
+  }
+
+  /*
+   * If the operation is successful then TargetModuleID is a valid module id.
+   * Else it will be null
+   **/
+  public TargetModuleID distributeModuleStream(Target[] targets,
+      ModuleType moduleType, InputStream moduleArchive,
+      InputStream deploymentPlan, boolean oneDotFiveApi) throws Exception {
+    String apiType = (oneDotFiveApi == true) ? "1.5 API" : "deprecated API";
+    TestUtil.logMsg("Calling distribute(): Using " + apiType);
+    DeploymentManager dm = getDeploymentManager();
+    ProgressHandler progressHandler = new ProgressHandler();
+    ProgressObject progress = dm.distribute(targets, moduleArchive, deploymentPlan);
+    progress.addProgressListener(progressHandler);
+    progressHandler.start();
+    // Wait for the progress handler to complete its job
+    progressHandler.join();
+    StateType completionState = progressHandler.getCompletionState();
+    if (completionState.getValue() != StateType.COMPLETED.getValue()) {
+      // The state must be either FAILED, or RELEASED
+      return null;
+    }
+    TargetModuleID[] resultModuleIDs = progress.getResultTargetModuleIDs();
+    if (resultModuleIDs.length < 1) {
+      // There should be atleast one target module id if progress is
+      // successfully complete
+      return null;
+    }
+    return resultModuleIDs[0];
+  }
+
+  /*
+   * If the operation is successful then TargetModuleID is a valid module id.
+   * Else it will be null
+   **/
+  public TargetModuleID startModule(TargetModuleID moduleToStart)
+      throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    ProgressHandler progressHandler = new ProgressHandler();
+    ProgressObject progress = dm.start(new TargetModuleID[] { moduleToStart });
+    progress.addProgressListener(progressHandler);
+    progressHandler.start();
+    // Wait for the progress handler to complete its job
+    progressHandler.join();
+    StateType completionState = progressHandler.getCompletionState();
+    if (completionState.getValue() != StateType.COMPLETED.getValue()) {
+      // The state must be either FAILED, or RELEASED
+      return null;
+    }
+    TargetModuleID[] resultModuleIDs = progress.getResultTargetModuleIDs();
+    if (resultModuleIDs.length < 1) {
+      // There should be atleast one target module id if progress is
+      // successfully complete
+      return null;
+    }
+    return resultModuleIDs[0];
+  }
+
+  /*
+   * If the operation is successful then TargetModuleID is a valid module id.
+   * Else it will be null
+   **/
+  public TargetModuleID stopModule(TargetModuleID moduleToStop)
+      throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    ProgressHandler progressHandler = new ProgressHandler();
+    ProgressObject progress = dm.stop(new TargetModuleID[] { moduleToStop });
+    progress.addProgressListener(progressHandler);
+    progressHandler.start();
+    // Wait for the progress handler to complete its job
+    progressHandler.join();
+    StateType completionState = progressHandler.getCompletionState();
+    if (completionState.getValue() != StateType.COMPLETED.getValue()) {
+      // The state must be either FAILED, or RELEASED
+      return null;
+    }
+    TargetModuleID[] resultModuleIDs = progress.getResultTargetModuleIDs();
+    if (resultModuleIDs.length < 1) {
+      // There should be atleast one target module id if progress is
+      // successfully complete
+      return null;
+    }
+    return resultModuleIDs[0];
+  }
+
+  /*
+   * If the operation is successful then TargetModuleID is a valid module id.
+   * Else it will be null
+   **/
+  public TargetModuleID undeployModule(TargetModuleID moduleToUndeploy)
+      throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    ProgressHandler progressHandler = new ProgressHandler();
+    ProgressObject progress = dm
+        .undeploy(new TargetModuleID[] { moduleToUndeploy });
+    progress.addProgressListener(progressHandler);
+    progressHandler.start();
+    // Wait for the progress handler to complete its job
+    progressHandler.join();
+    StateType completionState = progressHandler.getCompletionState();
+    if (completionState.getValue() != StateType.COMPLETED.getValue()) {
+      // The state must be either FAILED, or RELEASED
+      return null;
+    }
+    TargetModuleID[] resultModuleIDs = progress.getResultTargetModuleIDs();
+    if (resultModuleIDs.length < 1) {
+      // There should be atleast one target module id if progress is
+      // successfully complete
+      return null;
+    }
+    return resultModuleIDs[0];
+  }
+
+  /*
+   * If the operation is successful then TargetModuleID is a valid module id.
+   * Else it will be null
+   **/
+  public TargetModuleID redeployModuleArchive(TargetModuleID[] targetModuleIds,
+      File moduleArchive, File deploymentPlan) throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    ProgressHandler progressHandler = new ProgressHandler();
+    ProgressObject progress = dm.redeploy(targetModuleIds, moduleArchive,
+        deploymentPlan);
+    progress.addProgressListener(progressHandler);
+    progressHandler.start();
+    // Wait for the progress handler to complete its job
+    progressHandler.join();
+    StateType completionState = progressHandler.getCompletionState();
+    if (completionState.getValue() != StateType.COMPLETED.getValue()) {
+      // The state must be either FAILED, or RELEASED
+      return null;
+    }
+    TargetModuleID[] resultModuleIDs = progress.getResultTargetModuleIDs();
+    if (resultModuleIDs.length < 1) {
+      // There should be atleast one target module id if progress is
+      // successfully complete
+      return null;
+    }
+    return resultModuleIDs[0];
+  }
+
+  /*
+   * If the operation is successful then TargetModuleID is a valid module id.
+   * Else it will be null
+   **/
+  public TargetModuleID redeployModuleStream(TargetModuleID[] targetModuleIds,
+      InputStream moduleArchive, InputStream deploymentPlan) throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    ProgressHandler progressHandler = new ProgressHandler();
+    ProgressObject progress = dm.redeploy(targetModuleIds, moduleArchive,
+        deploymentPlan);
+    progress.addProgressListener(progressHandler);
+    progressHandler.start();
+    // Wait for the progress handler to complete its job
+    progressHandler.join();
+    StateType completionState = progressHandler.getCompletionState();
+    if (completionState.getValue() != StateType.COMPLETED.getValue()) {
+      // The state must be either FAILED, or RELEASED
+      return null;
+    }
+    TargetModuleID[] resultModuleIDs = progress.getResultTargetModuleIDs();
+    if (resultModuleIDs.length < 1) {
+      // There should be atleast one target module id if progress is
+      // successfully complete
+      return null;
+    }
+    return resultModuleIDs[0];
+  }
+
+  public boolean testDistributeModule(ModuleType moduleType, File moduleArchive,
+      File deploymentPlan, String archiveType, boolean oneDotFiveApi)
+      throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    Target[] targets = dm.getTargets();
+    if (targets.length == 0)
+      return false;
+    Target targetToDeploy = targets[0];
+    TargetModuleID distributedModuleID = null;
+    TargetModuleID[] moduleIDsBeforeDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    if (archiveType.equals(FILE_ARCHIVE)) {
+      distributedModuleID = distributeModuleArchive(
+          new Target[] { targetToDeploy }, moduleArchive, deploymentPlan);
+    } else {
+      FileInputStream moduleStream = (moduleArchive == null) ? null
+          : new FileInputStream(moduleArchive);
+      FileInputStream planStream = (deploymentPlan == null) ? null
+          : new FileInputStream(deploymentPlan);
+      distributedModuleID = distributeModuleStream(
+          new Target[] { targetToDeploy }, moduleType, moduleStream, planStream,
+          oneDotFiveApi);
+    }
+    // If the distributedModuleID == null, the test is failed
+    if (distributedModuleID == null)
+      return false;
+    // Check if distriburtedModuleID has the same target as deployed target
+    if (!distributedModuleID.getTarget().getName()
+        .equals(targetToDeploy.getName()))
+      return false;
+    TargetModuleID[] moduleIDsAfterDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    boolean moduleExistsBeforeDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsBeforeDistribute);
+    boolean moduleExistsAfterDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsAfterDistribute);
+
+    // Clean up....
+    // undeploy the module
+    undeployModule(distributedModuleID);
+
+    if ((!moduleExistsBeforeDistribute) && moduleExistsAfterDistribute)
+      return true;
+    else
+      return false;
+  }
+
+  public boolean testStartModule(ModuleType moduleType, File moduleArchive,
+      File deploymentPlan, String archiveType) throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    Target[] targets = dm.getTargets();
+    if (targets.length == 0)
+      return false;
+    Target targetToDeploy = targets[0];
+    TargetModuleID distributedModuleID = null;
+    TargetModuleID[] moduleIDsBeforeDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    if (archiveType.equals(FILE_ARCHIVE)) {
+      distributedModuleID = distributeModuleArchive(
+          new Target[] { targetToDeploy }, moduleArchive, deploymentPlan);
+    } else {
+      distributedModuleID = distributeModuleStream(
+          new Target[] { targetToDeploy }, moduleType,
+          new FileInputStream(moduleArchive),
+          new FileInputStream(deploymentPlan), true);
+    }
+    // If the distributedModuleID == null, the test is failed
+    if (distributedModuleID == null)
+      return false;
+    // Check if distriburtedModuleID has the same target as deployed target
+    if (!distributedModuleID.getTarget().getName()
+        .equals(targetToDeploy.getName()))
+      return false;
+    TargetModuleID[] moduleIDsAfterDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    boolean moduleExistsBeforeDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsBeforeDistribute);
+    boolean moduleExistsAfterDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsAfterDistribute);
+    if (!((!moduleExistsBeforeDistribute) && moduleExistsAfterDistribute))
+      return false;
+
+    // start the module
+    TargetModuleID startedModuleID = null;
+    startedModuleID = startModule(distributedModuleID);
+    if (startedModuleID == null)
+      return false;
+    // Check that the startedModuleID is same as deployed module id
+    if (!startedModuleID.getModuleID()
+        .equals(distributedModuleID.getModuleID()))
+      return false;
+    TargetModuleID[] runningModules = dm.getRunningModules(moduleType,
+        new Target[] { targetToDeploy });
+    boolean result = false;
+    if (checkIfModuleExists(startedModuleID, runningModules))
+      result = true;
+    // Clean up....
+    // undeploy the module
+    stopModule(startedModuleID);
+    undeployModule(startedModuleID);
+
+    return result;
+
+  }
+
+  public boolean testStopModule(ModuleType moduleType, File moduleArchive,
+      File deploymentPlan, String archiveType) throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    Target[] targets = dm.getTargets();
+    if (targets.length == 0)
+      return false;
+    Target targetToDeploy = targets[0];
+    TargetModuleID distributedModuleID = null;
+    TargetModuleID[] moduleIDsBeforeDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    if (archiveType.equals(FILE_ARCHIVE)) {
+      distributedModuleID = distributeModuleArchive(
+          new Target[] { targetToDeploy }, moduleArchive, deploymentPlan);
+    } else {
+      distributedModuleID = distributeModuleStream(
+          new Target[] { targetToDeploy }, moduleType,
+          new FileInputStream(moduleArchive),
+          new FileInputStream(deploymentPlan), true);
+    }
+    // If the distributedModuleID == null, the test is failed
+    if (distributedModuleID == null)
+      return false;
+    // Check if distriburtedModuleID has the same target as deployed target
+    if (!distributedModuleID.getTarget().getName()
+        .equals(targetToDeploy.getName()))
+      return false;
+    TargetModuleID[] moduleIDsAfterDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    boolean moduleExistsBeforeDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsBeforeDistribute);
+    boolean moduleExistsAfterDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsAfterDistribute);
+    if (!((!moduleExistsBeforeDistribute) && moduleExistsAfterDistribute))
+      return false;
+
+    // start the module
+    TargetModuleID startedModuleID = null;
+    startedModuleID = startModule(distributedModuleID);
+    if (startedModuleID == null)
+      return false;
+    // Check that the startedModuleID is same as deployed module id
+    if (!startedModuleID.getModuleID()
+        .equals(distributedModuleID.getModuleID()))
+      return false;
+    TargetModuleID[] runningModules = dm.getRunningModules(moduleType,
+        new Target[] { targetToDeploy });
+    if (!checkIfModuleExists(startedModuleID, runningModules))
+      return false;
+
+    // stop the module
+    TargetModuleID stoppedModuleID = null;
+    stoppedModuleID = stopModule(startedModuleID);
+    if (stoppedModuleID == null)
+      return false;
+    // Check that the startedModuleID is same as redeployed module id
+    if (!startedModuleID.getModuleID().equals(stoppedModuleID.getModuleID()))
+      return false;
+    boolean modExistsInRunningMods = checkIfModuleExists(stoppedModuleID,
+        dm.getRunningModules(moduleType, new Target[] { targetToDeploy }));
+    boolean modExistsInNonRunningMods = checkIfModuleExists(stoppedModuleID,
+        dm.getNonRunningModules(moduleType, new Target[] { targetToDeploy }));
+
+    // Clean up....
+    // undeploy the module
+    undeployModule(stoppedModuleID);
+
+    if ((!modExistsInRunningMods) && modExistsInNonRunningMods)
+      return true;
+    else
+      return false;
+  }
+
+  public boolean testRedeployModule(ModuleType moduleType, File moduleArchive,
+      File deploymentPlan, String archiveType) throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    Target[] targets = dm.getTargets();
+    if (targets.length == 0)
+      return false;
+    Target targetToDeploy = targets[0];
+    TargetModuleID distributedModuleID = null;
+    TargetModuleID[] moduleIDsBeforeDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    if (archiveType.equals(FILE_ARCHIVE)) {
+      distributedModuleID = distributeModuleArchive(
+          new Target[] { targetToDeploy }, moduleArchive, deploymentPlan);
+    } else {
+      distributedModuleID = distributeModuleStream(
+          new Target[] { targetToDeploy }, moduleType,
+          new FileInputStream(moduleArchive),
+          new FileInputStream(deploymentPlan), true);
+    }
+    // If the distributedModuleID == null, the test is failed
+    if (distributedModuleID == null)
+      return false;
+    // Check if distriburtedModuleID has the same target as deployed target
+    if (!distributedModuleID.getTarget().getName()
+        .equals(targetToDeploy.getName()))
+      return false;
+    TargetModuleID[] moduleIDsAfterDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    boolean moduleExistsBeforeDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsBeforeDistribute);
+    boolean moduleExistsAfterDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsAfterDistribute);
+    if (!((!moduleExistsBeforeDistribute) && moduleExistsAfterDistribute))
+      return false;
+
+    // start the module
+    TargetModuleID startedModuleID = null;
+    startedModuleID = startModule(distributedModuleID);
+    if (startedModuleID == null)
+      return false;
+    // Check that the startedModuleID is same as deployed module id
+    if (!startedModuleID.getModuleID()
+        .equals(distributedModuleID.getModuleID()))
+      return false;
+    TargetModuleID[] runningModules = dm.getRunningModules(moduleType,
+        new Target[] { targetToDeploy });
+    if (!checkIfModuleExists(startedModuleID, runningModules))
+      return false;
+
+    // redeploy the module
+    TargetModuleID redeployedModuleID = null;
+    if (archiveType.equals(FILE_ARCHIVE)) {
+      redeployedModuleID = redeployModuleArchive(
+          new TargetModuleID[] { startedModuleID }, moduleArchive,
+          deploymentPlan);
+    } else {
+      redeployedModuleID = redeployModuleStream(
+          new TargetModuleID[] { startedModuleID },
+          new FileInputStream(moduleArchive),
+          new FileInputStream(deploymentPlan));
+    }
+    if (redeployedModuleID == null)
+      return false;
+    // Check that the startedModuleID is same as redeployed module id
+    if (!startedModuleID.getModuleID().equals(redeployedModuleID.getModuleID()))
+      return false;
+    TargetModuleID[] runningModulesAfterRedeploy = dm
+        .getRunningModules(moduleType, new Target[] { targetToDeploy });
+    boolean result = false;
+    if (checkIfModuleExists(redeployedModuleID, runningModulesAfterRedeploy))
+      result = true;
+
+    // Clean up....
+    // undeploy the module
+    stopModule(redeployedModuleID);
+    undeployModule(redeployedModuleID);
+
+    return result;
+  }
+
+  public boolean testUndeployModule(ModuleType moduleType, File moduleArchive,
+      File deploymentPlan, String archiveType) throws Exception {
+    DeploymentManager dm = getDeploymentManager();
+    Target[] targets = dm.getTargets();
+    if (targets.length == 0)
+      return false;
+    Target targetToDeploy = targets[0];
+    TargetModuleID distributedModuleID = null;
+    TargetModuleID[] moduleIDsBeforeDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    if (archiveType.equals(FILE_ARCHIVE)) {
+      distributedModuleID = distributeModuleArchive(
+          new Target[] { targetToDeploy }, moduleArchive, deploymentPlan);
+    } else {
+      distributedModuleID = distributeModuleStream(
+          new Target[] { targetToDeploy }, moduleType,
+          new FileInputStream(moduleArchive),
+          new FileInputStream(deploymentPlan), true);
+    }
+    // If the distributedModuleID == null, the test is failed
+    if (distributedModuleID == null)
+      return false;
+    // Check if distriburtedModuleID has the same target as deployed target
+    if (!distributedModuleID.getTarget().getName()
+        .equals(targetToDeploy.getName()))
+      return false;
+    TargetModuleID[] moduleIDsAfterDistribute = dm
+        .getAvailableModules(moduleType, new Target[] { targetToDeploy });
+    boolean moduleExistsBeforeDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsBeforeDistribute);
+    boolean moduleExistsAfterDistribute = checkIfModuleExists(
+        distributedModuleID, moduleIDsAfterDistribute);
+    if (!((!moduleExistsBeforeDistribute) && moduleExistsAfterDistribute))
+      return false;
+
+    // start the module
+    TargetModuleID undeployedModuleID = null;
+    undeployedModuleID = undeployModule(distributedModuleID);
+    if (undeployedModuleID == null)
+      return false;
+    // Check that the startedModuleID is same as deployed module id
+    if (!undeployedModuleID.getModuleID()
+        .equals(distributedModuleID.getModuleID()))
+      return false;
+    if (checkIfModuleExists(undeployedModuleID,
+        dm.getAvailableModules(moduleType, new Target[] { targetToDeploy })))
+      return false;
+    else
+      return true;
+  }
+
+  // To test TargetModuleID
+  // Test TargetModuleID
+  public boolean testTargetModuleID(File moduleArchive, File deploymentPlan,
+      String archiveType) {
+    try {
+      DeploymentManager dm = getDeploymentManager();
+      Target[] targets = dm.getTargets();
+      if (targets.length == 0)
+        return false;
+      Target targetToDeploy = targets[0];
+      TargetModuleID distributedModuleID = null;
+      distributedModuleID = distributeModuleArchive(
+          new Target[] { targetToDeploy }, moduleArchive, deploymentPlan);
+      // If the distributedModuleID == null, the test is failed
+      if (distributedModuleID == null)
+        return false;
+      // Check if distriburtedModuleID has the same target as deployed target
+      if (!distributedModuleID.getTarget().getName()
+          .equals(targetToDeploy.getName()))
+        return false;
+
+      // Clean up....
+      // undeploy the module
+      undeployModule(distributedModuleID);
+
+      return true;
+    } catch (Exception ex) {
+      ex.printStackTrace();
+      return false;
+    }
+  }
+
+  //////
+  // Porting package 1.4 additions
+  //////
+
+  /*
+   * Why are we polling on the progress object's state to determine when the
+   * executed command is actually finished? First, Prakash mentioned that there
+   * is a case where it is possible for an executed command to finish before the
+   * user is even returned the progress object. In this case if we register a
+   * ProgressListener with the ProgressObject and handle events within the
+   * ProgressListener's handleProgressEvent() we may miss the event that told us
+   * the executed command had finished. Second, again according to Prakash, the
+   * spec does not specify how many events are generated when executing a
+   * command. For instance, if we call stop and pass 4 TargetModuleID objects,
+   * there is no place in the spec that tells us how many events we should
+   * expect. There could be a set of one or more events for each target or a
+   * single event for all the targets. Since the spec doesn't define this, we
+   * shouldn't assume.
+   *
+   * Having said that we decided to simply poll the progress object and ask it
+   * when it thinks it is finished. This will be denoted by a COMPLETED or
+   * FAILED state. If the state is FAILED we can use the
+   * getResultTargetModuleIds method to determine the failed targets. We can
+   * determine the failed targets by comparing the targets we issued the command
+   * for against the targets returned by getResultTargetModuleIds. The doc for
+   * getResultTargetModuleIds says it only returns the IDs of the targets that
+   * successfully completed the specified command. See the OperationStatus class
+   * for details on determining the failed targets.
+   */
+  private OperationStatus commandStatus(Target[] targets,
+      ProgressObject progress) {
+    OperationStatus status = null;
+    int sleepCount = 0;
+    int deployWaitMinutes = getDeployDelay();
+    final int MAX_SLEEP_COUNT = deployWaitMinutes * 60; // minutes to delay
+    while (!(progress.getDeploymentStatus().isCompleted()
+        || progress.getDeploymentStatus().isFailed())) {
+      try {
+        Thread.sleep(1 * 1000); // 1 second
+        if (++sleepCount >= MAX_SLEEP_COUNT) {
+          TestUtil.logErr("Error: DeployTestUtil.commandStatus() timed out"
+              + " waiting for operation to complete");
+          status = new OperationStatus(progress, targets, true);
+          break;
+        }
+      } catch (InterruptedException ie) {
+        break;
+      }
+    }
+    if (status == null) {
+      status = new OperationStatus(progress, targets);
+    }
+
+    return status;
+  }
+
+  private int getDeployDelay() {
+    int result = 5;
+    String delayStr = System.getProperty("DEPLOY_DELAY_IN_MINUTES", "5");
+    try {
+      result = Integer.parseInt(delayStr);
+    } catch (NumberFormatException nfe) {
+    }
+    TestUtil.logTrace(
+        "Maximum wait time for deployment is " + result + " minutes.");
+    return result;
+  }
+
+  private void writeFile(File aFile) {
+    FileInputStream in = null;
+    FileOutputStream out = null;
+    try {
+      in = new FileInputStream(aFile);
+      out = new FileOutputStream("/tmp/" + aFile.getName());
+      byte[] buf = new byte[2048];
+      int start = 0;
+      int i = 0;
+      while ((i = in.read(buf)) != -1) {
+        out.write(buf, 0, i);
+        start += i;
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      try {
+        in.close();
+      } catch (Exception e) {
+      }
+      try {
+        out.close();
+      } catch (Exception e) {
+      }
+    }
+  }
+
+  public OperationStatus distributeModuleStreams(Target[] targets,
+      InputStream moduleArchive, InputStream deploymentPlan) throws Exception {
+    ProgressObject progress = null;
+    try {
+      progress = getDeploymentManager().distribute(targets, moduleArchive,
+          deploymentPlan);
+    } catch (Exception e) {
+      e.printStackTrace();
+      if (progress.isCancelSupported()) {
+        progress.cancel();
+      }
+      throw e;
+    }
+    OperationStatus result = commandStatus(targets, progress);
+    delay();
+    return result;
+  }
+
+  public OperationStatus distributeModuleFiles(Target[] targets,
+      File moduleArchive, File deploymentPlan) throws Exception {
+    ProgressObject progress = null;
+    try {
+      progress = getDeploymentManager().distribute(targets, moduleArchive,
+          deploymentPlan);
+    } catch (Exception e) {
+      e.printStackTrace();
+      if (progress.isCancelSupported()) {
+        progress.cancel();
+      }
+      throw e;
+    }
+    OperationStatus result = commandStatus(targets, progress);
+    delay();
+    return result;
+  }
+
+  public Target[] getTargets() throws Exception {
+    Target[] result = null;
+    result = getDeploymentManager().getTargets();
+    return result;
+  }
+
+  public OperationStatus stopModule(TargetModuleID[] modulesIDsToStop)
+      throws Exception {
+    ProgressObject progress = null;
+    try {
+      progress = getDeploymentManager().stop(modulesIDsToStop);
+    } catch (Exception e) {
+      e.printStackTrace();
+      // throw e;
+    }
+    return commandStatus(convertTargets(modulesIDsToStop), progress);
+  }
+
+  public OperationStatus startModule(TargetModuleID[] modulesIDsToStart)
+      throws Exception {
+    ProgressObject progress = null;
+    try {
+      progress = getDeploymentManager().start(modulesIDsToStart);
+    } catch (Exception e) {
+      e.printStackTrace();
+      // throw e;
+    }
+    return commandStatus(convertTargets(modulesIDsToStart), progress);
+  }
+
+  public OperationStatus undeployModule(TargetModuleID[] modulesIDsToUndeploy)
+      throws Exception {
+    ProgressObject progress = null;
+    try {
+      progress = getDeploymentManager().undeploy(modulesIDsToUndeploy);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+    OperationStatus result = commandStatus(convertTargets(modulesIDsToUndeploy),
+        progress);
+    delay();
+    return result;
+  }
+
+  private void delay() {
+    try {
+      int delayTime = Integer
+          .parseInt(System.getProperty("delay.after.deploy", "0"));
+      if (delayTime != 0) {
+        System.err.println("%%%%%%%%% SLEEPING FOR " + delayTime + " SECONDS");
+        Thread.sleep(delayTime * 1000);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  private Target[] convertTargets(TargetModuleID[] targets) {
+    if (targets == null) {
+      return null;
+    }
+    Target[] result = new Target[targets.length];
+    for (int i = 0; i < targets.length; i++) {
+      result[i] = targets[i].getTarget();
+    }
+    return result;
+  }
+
+  //////
+  // Porting package 1.4 additions
+  //////
+
+}
+
+class ProgressHandler extends Thread implements ProgressListener {
+  volatile StateType finalState = null;
+
+  public void run() {
+    while (finalState == null) {
+      Thread.currentThread().yield();
+    }
+  }
+
+  public void handleProgressEvent(ProgressEvent event) {
+    DeploymentStatus ds = event.getDeploymentStatus();
+    System.out.println(ds.getMessage() + "\n");
+    if (ds.getState().getValue() != StateType.RUNNING.getValue()) {
+      finalState = ds.getState();
+    }
+  }
+
+  public StateType getCompletionState() {
+    return finalState;
+  }
+}
diff --git a/src/main/java/org/apache/openejb/cts/deploy/OperationStatus.java b/src/main/java/org/apache/openejb/cts/deploy/OperationStatus.java
new file mode 100644
index 0000000..efdb3b8
--- /dev/null
+++ b/src/main/java/org/apache/openejb/cts/deploy/OperationStatus.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.apache.openejb.cts.deploy;
+
+import javax.enterprise.deploy.spi.Target;
+import javax.enterprise.deploy.spi.status.ProgressObject;
+import javax.enterprise.deploy.spi.TargetModuleID;
+import java.util.List;
+import java.util.ArrayList;
+import com.sun.ts.lib.util.TestUtil;
+
+public class OperationStatus {
+  private boolean failed;
+
+  private String progressMessage;
+
+  private Target[] failedTargets;
+
+  private TargetModuleID[] deployedTargetIDs;
+
+  private ProgressObject progress;
+
+  public OperationStatus(ProgressObject progress, Target[] failedTargets) {
+    this(progress, failedTargets, progress.getDeploymentStatus().isFailed());
+  }
+
+  public OperationStatus(ProgressObject progress, Target[] failedTargets,
+      boolean failed) {
+    this.progress = progress;
+    this.failed = failed;
+    this.progressMessage = progress.getDeploymentStatus().getMessage();
+    this.failedTargets = failedTargets;
+    this.deployedTargetIDs = filterNonRootTargetModuleIDs(
+        progress.getResultTargetModuleIDs());
+  }
+
+  public boolean isFailed() {
+    return failed;
+  }
+
+  public String getProgressMessage() {
+    return progressMessage;
+  }
+
+  public Target[] getFailedTargets() {
+    return findErrors();
+  }
+
+  public TargetModuleID[] getDeployedTargetIDs() {
+    return deployedTargetIDs;
+  }
+
+  public ProgressObject getProgressObject() {
+    return progress;
+  }
+
+  /*
+   * Filter out the non-root target module IDs from the specified list. The JSR
+   * 88 spec is ambiguous as to what the ProgressObject.getResultTargetModuleIDs
+   * method returns. The list of target module IDs may be root target module IDs
+   * (those corresponding to an application or standalone module) only or root
+   * plus non-root target module IDs (those corresponding to modules that are
+   * part of a larger application). Since the harness is only interested in
+   * stopping, starting and undeploying applications or standalone components we
+   * filter out the non-root target module IDs since we don't do anything with
+   * them anyway. We also need to filter the non-root target module IDs because
+   * the spec is ambiguous as to what will happen if we pass a list of target
+   * module IDs that contain non-root IDs to the start, stop and undeploy
+   * methods (in the JSR 88 API). The spec does not state if these methods
+   * should throw an error, ignore the non-root target module IDs or take some
+   * other action. Since this is implementation specific we can not assume
+   * anything except for the fact that the start, stop and undeploy methods
+   * should have no affect on non-root modules since they can NOT be started,
+   * stopped or undeployed according to the spec. See section 4.1 in the JSR 88
+   * spec for details.
+   */
+  private TargetModuleID[] filterNonRootTargetModuleIDs(TargetModuleID[] ids) {
+    List result = new ArrayList();
+    for (int i = 0; i < ids.length; i++) {
+      TargetModuleID id = ids[i];
+      if (id.getParentTargetModuleID() == null) {
+        result.add(id);
+      }
+    }
+    return (TargetModuleID[]) (result
+        .toArray(new TargetModuleID[result.size()]));
+  }
+
+  private boolean targetInList(Target target, TargetModuleID[] list) {
+    boolean result = false;
+    for (int i = 0; i < list.length; i++) {
+      Target t = list[i].getTarget();
+      if (t.getName().equals(target.getName())) {
+        result = true;
+        break;
+      }
+    }
+    return result;
+  }
+
+  private Target[] findErrors() {
+    List failed = new ArrayList();
+    for (int i = 0; i < failedTargets.length; i++) {
+      if (!targetInList(failedTargets[i], deployedTargetIDs)) {
+        failed.add(failedTargets[i]);
+      }
+    }
+    return (Target[]) failed.toArray(new Target[failed.size()]);
+  }
+
+  public String errMessage() {
+    StringBuffer buf = new StringBuffer("Failed targets: ");
+    int numFailures = (failedTargets == null) ? 0 : failedTargets.length;
+    for (int i = 0; i < numFailures; i++) {
+      buf.append(failedTargets[i].getName() + "  ");
+    }
+
+    buf.append(TestUtil.NEW_LINE + "DeploymentStatus...");
+    buf.append(TestUtil.NEW_LINE + "Message             = "
+        + progress.getDeploymentStatus().getMessage());
+    buf.append(TestUtil.NEW_LINE + "State               = "
+        + progress.getDeploymentStatus().getState());
+    buf.append(TestUtil.NEW_LINE + "Command             = "
+        + progress.getDeploymentStatus().getCommand());
+    buf.append(TestUtil.NEW_LINE + "Action              = "
+        + progress.getDeploymentStatus().getAction());
+    buf.append(TestUtil.NEW_LINE + "Additional info     = "
+        + progress.getDeploymentStatus().toString() + TestUtil.NEW_LINE);
+
+    return buf.toString();
+  }
+
+}
diff --git a/src/main/java/org/apache/openejb/cts/deploy/StandardDeployment14.java b/src/main/java/org/apache/openejb/cts/deploy/StandardDeployment14.java
new file mode 100644
index 0000000..8145bca
--- /dev/null
+++ b/src/main/java/org/apache/openejb/cts/deploy/StandardDeployment14.java
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.apache.openejb.cts.deploy;
+
+import javax.enterprise.deploy.spi.*;
+import javax.enterprise.deploy.shared.*;
+
+import java.io.*;
+import java.util.*;
+import com.sun.ts.lib.implementation.sun.javaee.runtime.SunRIDeploymentInfo;
+import com.sun.ts.lib.porting.*;
+import com.sun.ts.lib.util.*;
+import com.sun.ts.lib.deliverable.*;
+import com.sun.ts.lib.harness.ExecutionMode;
+
+/**
+ *
+ * This class implements the TSDeploymentInterface. It does so by using the 88
+ * API's. As of J2EE 1.4, this class should be the standard implementation of
+ * TSDeploymentInterface. There will be no need of alternative implentations.
+ * All implementation specific code now exists in TSDeploymentInterface2.
+ *
+ * @author Kyle Grucci
+ * @author Anand Dhingra
+ *
+ */
+public class StandardDeployment14 implements TSDeploymentInterface {
+
+  protected static final String DEPLOYED_MODULES_FILE = "ts-deployed-modules";
+
+  protected static String TEMP_DIR;
+
+  protected PrintWriter log; // Log to harness
+
+  protected int iPortingSet = 1; // Porting set using this impl
+                                 // of TSDeploymentInterface
+
+  private String url = "deployer:???:???:999"; // URI for DM
+
+  private DeploymentManager depMgr; // for Deployment to manager 1
+
+  private DeployTestUtil dtu; // for Deployment to manager 1
+
+  private DMProps dmProps; // get these from Propmgr
+
+  protected TSDeploymentInterface2 dep2; // our impl of
+  // TSDeploymentInterface2
+
+  protected Hashtable htDeployedModules = // Map ear files to IDs so we
+      new Hashtable(); // can later undeploy
+
+  protected PropertyManagerInterface propMgr; // Properties from ts.jte
+
+  protected String sDepNumber = null; // Module ID
+
+  protected String deployStateFile;
+
+  /**
+   *
+   * Static initialization of this class
+   *
+   */
+  static {
+    TestUtil.initJavaTest();
+    TEMP_DIR = System.getProperty("java.io.tmpdir");
+    if (TEMP_DIR != null && TEMP_DIR.endsWith(File.separator)) {
+      TEMP_DIR = TEMP_DIR.substring(0, TEMP_DIR.length() - 1);
+    }
+  }
+
+  /**
+   *
+   * Initializes logging output, gets the Deliverable instance
+   *
+   * @param writer - PrintWriter for harness tracing
+   *
+   */
+  public void init(PrintWriter writer) {
+
+    this.log = writer;
+    TestUtil.logHarness("StandardDeployment14.init()");
+
+    iPortingSet = TSDeployment.iPortingSet;
+    TestUtil
+        .logHarness("StandardDeployment14:  Using porting set #" + iPortingSet);
+
+    try {
+      propMgr = DeliverableFactory.getDeliverableInstance()
+          .getPropertyManager();
+
+      try {
+        String portingString = String.valueOf(iPortingSet);
+        initDeployTestUtils(portingString);
+        deployStateFile = TEMP_DIR + File.separator + DEPLOYED_MODULES_FILE
+            + "_" + portingString + ".ser";
+      } catch (TSDeploymentException e) {
+        TestUtil.logHarness("Unable to initialize the deployment utilities.");
+      }
+      htDeployedModules = getDeployedModules();
+      dumpDeployedMods(htDeployedModules);
+
+      TestUtil.logHarnessDebug("Adding shutdown hook for state serialization");
+
+      // Handle shutdown gracefully.
+      Runtime.getRuntime().addShutdownHook(new Thread() {
+
+        // When the VM shuts down this method is invoked to undeploy
+        // all currently deployed applications. Note, this method is
+        // invoked when a user issues a ctrl-c or the VM shuts down
+        // normally. No matter which way the VM shuts down, this
+        // method will honor the harness execute mode specified by
+        // the user in the ts.jte file (harness.executeMode property).
+        public void run() {
+
+          int harnessExecMode = ExecutionMode.getExecutionMode(propMgr);
+
+          // immediately return if we are running in a mode
+          // where undeploy is not required.
+          if (harnessExecMode == ExecutionMode.DEPLOY
+              || harnessExecMode == ExecutionMode.DEPLOY_RUN) {
+            try {
+              TestUtil.logHarness("IN SHUTDOWN HOOK BEFORE WRITE");
+              dumpDeployedMods(htDeployedModules);
+              writeMap(htDeployedModules);
+            } catch (IOException ioe) {
+              ioe.printStackTrace();
+            }
+            return;
+          } else if (harnessExecMode == ExecutionMode.RUN) {
+            return;
+          }
+          TestUtil.logHarness(
+              "IN SHUTDOWNHOOK state file is : \"" + deployStateFile + "\"");
+          dumpDeployedMods(htDeployedModules);
+          Map deployedModules = (Map) htDeployedModules.clone();
+          if (deployedModules.size() != 0) {
+            TestUtil.logHarness("Shutdown requested during test run."
+                + "  Undeploying previously deployed applications...");
+
+            try {
+              initDeployTestUtils(sDepNumber);
+            } catch (TSDeploymentException e) {
+              TestUtil.logHarness("Unable to initialize the deployment"
+                  + " utilities.  Applications will not be undeployed.");
+            }
+
+            for (Iterator i = deployedModules.keySet().iterator(); i
+                .hasNext();) {
+
+              try {
+                undeploy((String) i.next());
+              } catch (TSDeploymentException tde) {
+                TestUtil.logHarness("Unexpected exception while"
+                    + " undeploying application during shutdown. " + "Cause: "
+                    + tde.getMessage());
+              }
+
+            }
+            // Release deployment manager in case we get killed
+            // We'll also do this with the deploy and undeploy methods
+            // since this will only be called if a shutdown is received
+            dtu.releaseDeploymentManager();
+            deleteDeployedModulesState(); // remove deployed module state
+          }
+        }
+      });
+      String portClass = "porting.ts.deploy2.class." + iPortingSet;
+      TestUtil.logHarness("Using " + portClass);
+      dep2 = TSDeployment2.getDeploymentInstance(log, portClass);
+    } catch (Exception e) {
+      e.printStackTrace();
+      TestUtil.logHarness(
+          "Creation of TSDeployment2 implementation instance failed."
+              + " Please check the values of 'porting.ts.deploy2.class.1' and"
+              + " 'porting.ts.deploy2.class.2'");
+    }
+  }
+
+  public String deploy(DeploymentInfo info) throws TSDeploymentException {
+    try {
+      String sArchive = info.getEarFile();
+      // we need to pass the deployinfo to the new porting package to get the
+      // plan. For now just use the runtime file
+      String[] sRunTimeFileArray = info.getRuntimeFiles();
+
+      TestUtil.logHarness("StandardDeployment14.deploy()");
+      sDepNumber = info.getProperty("deployment.props.number");
+      initDeployTestUtils(sDepNumber);
+
+      // start distribute here
+      TestUtil.logHarness("Starting to distribute:  " + sArchive);
+
+      File earfile = new File(sArchive);
+      Object plan = dep2.getDeploymentPlan(info);
+
+      TestUtil.logHarness("file: " + earfile.toString());
+
+      if (plan != null)
+        TestUtil.logHarness("plan: " + plan.toString());
+      else
+        TestUtil.logHarness("No deployment plan for this archive.");
+
+      Target[] targets = dep2.getTargetsToUse(dtu.getTargets(), info);
+      if (targets == null || targets.length == 0)
+        throw new TSDeploymentException("Empty Target List: ");
+
+      OperationStatus status;
+
+      if (plan instanceof InputStream) {
+        // distribute the module
+        status = dtu.distributeModuleStreams(targets,
+            new FileInputStream(earfile), (InputStream) plan);
+      } else if ((plan instanceof File) || (plan == null)) {
+        // distribute the module
+        status = dtu.distributeModuleFiles(targets, earfile, (File) plan);
+      } else {
+        throw new TSDeploymentException(
+            "Object returned from getDeploymentPlan must return either an InputStream or a File."
+                + "  May also be null in some cases like connectors.");
+      }
+
+      if (status.isFailed()) {
+        throw new TSDeploymentException(
+            "Distribute to one or more targets failed " + status.errMessage());
+      }
+
+      TestUtil.logHarness(
+          "$$$$$$$$$$ Deployment SUCCEEDED for \"" + earfile + "\"");
+
+      // Allow the licensee an opportunity to examine the returned
+      // ProgressObject and
+      // take any vendor specifc actions that may be necessary.
+      dep2.postDistribute(status.getProgressObject());
+
+      status = dtu.startModule(status.getDeployedTargetIDs());
+      if (status.isFailed()) {
+        throw new TSDeploymentException(
+            "Starting of module failed on one or more targets "
+                + status.errMessage());
+      }
+
+      // Allow the licensee an opportunity to examine the returned
+      // ProgressObject and
+      // take any vendor specifc actions that may be necessary.
+      dep2.postStart(status.getProgressObject());
+
+      // keep track of filename to TargetmoduleIDs mapping
+      htDeployedModules.put(getAppName(sArchive),
+          status.getDeployedTargetIDs());
+
+      // Check to see if we're in a test directory that contains
+      // embedded rars
+      if (sArchive.indexOf("connector" + File.separator + "deployment"
+          + File.separator + "ejb_Deployment.ear") != -1) {
+
+        Properties p = new Properties();
+        p.setProperty("rar_file", sArchive);
+        dep2.createConnectionFactory(status.getDeployedTargetIDs(), p);
+      }
+
+      if (sArchive.indexOf("xa" + File.separator + "ee" + File.separator + "tsr"
+          + File.separator + "ejb_Tsr.ear") != -1) {
+
+        Properties p = new Properties();
+        p.setProperty("rar_file", sArchive);
+        dep2.createConnectionFactory(status.getDeployedTargetIDs(), p);
+      }
+
+      // if we have a rar file embedded in the ear, then we need to create
+      // connection factories - needsome naming we can rely on - don't want
+      // to open every ear file to check
+      String javaeeLevel = propMgr.getProperty("javaee.level", "full");
+
+      if (javaeeLevel.contains("full") && !sArchive.endsWith(".rar")) {
+        return dep2.getClientClassPath(status.getDeployedTargetIDs(), info,
+            dtu.getDeploymentManager());
+      } else {
+        return "";
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw (TSDeploymentException) new TSDeploymentException(
+          "Deployment Failed.").initCause(e);
+    }
+  }
+
+  public void undeploy(String moduleId) throws TSDeploymentException {
+    ModuleType moduleType = getModuleType(moduleId);
+    TargetModuleID[] idsToUndeploy = (TargetModuleID[]) htDeployedModules
+        .get(getAppName(moduleId));
+
+    TestUtil.logHarnessDebug(
+        "$$$$$$$$$$$$$ idsToUndeploy.length = " + idsToUndeploy.length);
+    TestUtil.logHarnessDebug("$$$$$$$$$$$$$ Undeploying Module ID \""
+        + idsToUndeploy[0].getModuleID() + "\"");
+
+    if (idsToUndeploy == null) {
+      TestUtil.logHarness(
+          "idToUndeploy is null.  Assuming that the module is not currently deployed");
+      return;
+    } else {
+      TestUtil.logHarness("Undeploying module \"" + moduleId + "\"");
+    }
+
+    OperationStatus status = null;
+    try {
+      status = dtu.stopModule(idsToUndeploy);
+      if (status.isFailed()) {
+        // log a message but still try to undeploy all the modules
+        TestUtil.logHarness(
+            "Stop failed for one or more targets while undeploying module \""
+                + moduleId + "\"");
+      }
+
+      // Allow the licensee an opportunity to examine the returned
+      // ProgressObject and
+      // take any vendor specifc actions that may be necessary.
+      dep2.postStop(status.getProgressObject());
+
+      status = dtu.undeployModule(idsToUndeploy);
+      if (status.isFailed()) {
+        TestUtil.logHarness("Undeploy failed for one or more targets \""
+            + status.errMessage() + "\"");
+      }
+
+      // Allow the licensee an opportunity to examine the returned
+      // ProgressObject and
+      // take any vendor specifc actions that may be necessary.
+      dep2.postUndeploy(status.getProgressObject());
+
+      htDeployedModules.remove(getAppName(moduleId));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw new TSDeploymentException("Error while undeploying");
+    }
+    if (status.isFailed()) {
+      throw new TSDeploymentException(
+          "Undeploy failed for one or more targets \"" + status.errMessage()
+              + "\"");
+    }
+  }
+
+  public void undeploy(Properties p) throws TSDeploymentException {
+    String sArchive = p.getProperty("ear_file");
+    TestUtil.logHarness("StandardDeployment14.undeploy()");
+    initDeployTestUtils(p.getProperty("deployment.props.number"));
+
+    // Check to see if we're in a test directory that contains
+    // embedded rars
+    if (sArchive
+        .indexOf("connector" + File.separator + "deployment" + File.separator
+            + "ejb_Deployment.ear") != -1
+        || sArchive.indexOf("xa" + File.separator + "ee" + File.separator
+            + "tsr" + File.separator + "ejb_Tsr.ear") != -1) {
+      // we must have an embedded ra file in this ear
+      // we need to remove the connection factory
+      p.setProperty("rar_file", sArchive);
+      // call into new porting package to remove connection factories
+      TargetModuleID[] modulesToUndeploy = (TargetModuleID[]) (htDeployedModules
+          .get(getAppName(sArchive)));
+      if (modulesToUndeploy.length == 0) {
+        TestUtil
+            .logHarness("undeploy failed for application \"" + sArchive + "\"");
+        throw new TSDeploymentException(
+            "undeploy failed for application \"" + sArchive + "\"");
+      }
+      dep2.removeConnectionFactory(modulesToUndeploy, p);
+    }
+    this.undeploy(sArchive);
+  }
+
+  public boolean isDeployed(Properties p) throws TSDeploymentException {
+    TestUtil.logHarness("StandardDeployment14.isDeployed()");
+    String sArchive = p.getProperty("ear_file");
+    String sAppName = getAppName(sArchive);
+    // For now just assume that we started with clean servers
+    // and check our internal state hashtable
+    if (htDeployedModules == null) {
+      return false;
+    }
+
+    // resync the list of deployed modules with what the targets actually report
+    try {
+      normalizeMap(getTargets());
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    TargetModuleID[] id = (TargetModuleID[]) htDeployedModules.get(sAppName);
+    if (id != null && id.length > 0) {
+      TestUtil.logHarnessDebug("StandardDeployment14.isDeployed():  "
+          + "After checking hashtable, id = " + sAppName);
+      return true;
+    } else {
+      TestUtil.logHarnessDebug("StandardDeployment14.isDeployed():  "
+          + "After checking hashtable, id = null");
+      return false;
+    }
+  }
+
+  public void deployConnector(Properties p) throws TSDeploymentException {
+    TestUtil.logHarness("StandardDeployment14.deployConnector()");
+    String sRarFileName = p.getProperty("rar_file");
+    DeploymentInfo info = null;
+    try {
+      info = new SunRIDeploymentInfo(sRarFileName, new String[] {});
+      info.setProperty("deployment.props.number",
+          p.getProperty("deployment.props.number"));
+      deploy(info); // adds deployed targets IDs to htDeployedModules
+      TargetModuleID[] targets = (TargetModuleID[]) (htDeployedModules
+          .get(getAppName(sRarFileName)));
+      dep2.createConnectionFactory(targets, p);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw new TSDeploymentException("Error while deploying Connector");
+    }
+
+    // call into new porting package to create connection factories
+    // If rar files now have runtime info, we will have to change the harness
+    // code
+    // to call deploy if we are using the StandardDeployment class. Our deploy
+    // method in here can check for rars and handle the connection factory
+    // logic.
+    // If old porting impls are used, then the harness wil still call these
+    // connector methods.
+  }
+
+  public void undeployConnector(Properties p) throws TSDeploymentException {
+    TestUtil.logHarness("StandardDeployment14.undeployConnector()");
+
+    if (isConnectorDeployed(p)) {
+      String rarFile = p.getProperty("rar_file");
+      // targets must have a non-empty list of TargetModuleIDs since
+      // isConnectorDeployed just checked it.
+      TargetModuleID[] targets = (TargetModuleID[]) (htDeployedModules
+          .get(getAppName(rarFile)));
+      dep2.removeConnectionFactory(targets, p);
+      p.setProperty("ear_file", rarFile);
+      undeploy(p);
+    } else {
+      TestUtil.logHarness(
+          "StandardDeployment14.undeployConnector() - " + "not undeploying.");
+    }
+  }
+
+  public boolean isConnectorDeployed(Properties p)
+      throws TSDeploymentException {
+    TestUtil.logHarness("StandardDeployment14.isConnectorDeployed()");
+    p.setProperty("ear_file", p.getProperty("rar_file"));
+    return isDeployed(p);
+  }
+
+  protected void initDeployTestUtils(String sPropNum)
+      throws TSDeploymentException {
+    try {
+      if (dtu != null) {
+        return;
+      }
+      String sJar = propMgr.getProperty("deployManagerJarFile." + sPropNum);
+      String sUri = propMgr.getProperty("deployManageruri." + sPropNum);
+      String sUname = propMgr.getProperty("deployManageruname." + sPropNum);
+      String sPassword = propMgr.getProperty("deployManagerpasswd." + sPropNum);
+
+      TestUtil.logHarnessDebug(
+          "StandardDeployment14.initDeployTestUtils() + sPropNum = "
+              + sPropNum);
+      TestUtil.logHarnessDebug("deployManagerJarFile:  " + sJar);
+      TestUtil.logHarnessDebug("deployManageruri:  " + sUri);
+      TestUtil.logHarnessDebug("deployManageruname:  " + sUname);
+      TestUtil.logHarnessDebug("deployManagerpasswd:  " + sPassword);
+
+      // Construct properties object for DM
+      dmProps = new DMProps(sJar, sUri, sUname, sPassword);
+
+      // Utility object for getting depMgr's
+      // dtu = DeployTestUtil.getDeployTestUtil(dmProps);
+      dtu = new DeployTestUtil(dmProps);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw new TSDeploymentException(
+          "Failed to get DeployTestUtil: " + e.getMessage());
+    }
+
+    // Construct the DM
+    // always initialize these in case props change in same VM of JavaTest
+    try {
+      depMgr = dtu.getDeploymentManager();
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      TestUtil.logHarness(
+          "Exception loading DeploymentFactoryManager factories: " + e);
+      throw new TSDeploymentException(
+          "Unable to get DeploymentManager: " + e.getMessage());
+    }
+  }
+
+  public String getAppClientArgs(Properties p) {
+    return dep2.getAppClientArgs(p);
+  }
+
+  public Hashtable getInteropJNDINames(DeploymentInfo[] infoArray) {
+    return dep2.getDependentValues(infoArray);
+  }
+
+  private static ModuleType getModuleType(String sArchive) {
+    String sExtension = sArchive.substring(sArchive.lastIndexOf(".") + 1);
+    ModuleType mt;
+
+    if (sExtension.equalsIgnoreCase("ear"))
+      mt = ModuleType.EAR;
+    else if (sExtension.equalsIgnoreCase("rar"))
+      mt = ModuleType.RAR;
+    else if (sExtension.equalsIgnoreCase("jar")) {
+      if (sArchive.indexOf("component") != -1)
+        mt = ModuleType.EJB;
+      else
+        mt = ModuleType.EJB; // Should this be CAR ?
+    } else if (sExtension.equalsIgnoreCase("war"))
+      mt = ModuleType.WAR;
+    else
+      mt = ModuleType.EAR;
+
+    return mt;
+  }
+
+  protected static String getAppName(String path) {
+    return path.substring(path.lastIndexOf(File.separator) + 1);
+  }
+
+  protected void dumpDeployedMods(Hashtable map) {
+    StringBuffer message = new StringBuffer("Deployed Modules: \n");
+    if (map == null || map.keySet() == null) {
+      TestUtil.logHarness("There are no deployed modules, returning");
+      return;
+    }
+    Iterator iter = map.keySet().iterator();
+    while (iter.hasNext()) {
+      String modName = (String) iter.next();
+      message.append("\t" + modName + "\n");
+    }
+    TestUtil.logHarness(message.toString());
+  }
+
+  protected boolean isValidTargetID(TargetModuleID targModID,
+      SerializableTargetID[] serTargModIDs) {
+    boolean result = false;
+    SerializableTargetID test = new SerializableTargetID(targModID);
+    for (int i = 0; i < serTargModIDs.length; i++) {
+      if (serTargModIDs[i].equals(test)) {
+        result = true;
+        break;
+      }
+    }
+    return result;
+  }
+
+  protected boolean isValidTargetID(TargetModuleID targModID,
+      TargetModuleID[] serTargModIDs) {
+    boolean result = false;
+    for (int i = 0; i < serTargModIDs.length; i++) {
+      if (serTargModIDs[i].equals(targModID)) {
+        result = true;
+        break;
+      }
+    }
+    return result;
+  }
+
+  protected TargetModuleID[] getRunningTargetModuleIDs(String sModuleName,
+      Target[] targets) throws Exception {
+    return depMgr.getRunningModules(getModuleType(sModuleName), targets);
+  }
+
+  /*
+   * This method is used to update our local hashtable (htDeployedModules) of
+   * deployed modules with the latest information from the targets that we've
+   * deployed them to.
+   */
+  protected void normalizeMap(Target[] targets) throws Exception {
+    List targModIDsList = null;
+
+    TestUtil.logHarnessDebug("Target[]");
+    for (int i = 0; i < targets.length; i++) {
+      TestUtil.logHarnessDebug("[" + targets[i].getDescription() + ", "
+          + targets[i].getName() + "]");
+    }
+
+    Hashtable result = new Hashtable();
+    Iterator iter = htDeployedModules.keySet().iterator();
+    while (iter.hasNext()) {
+      String modName = (String) iter.next();
+      TargetModuleID[] targModIDs = getRunningTargetModuleIDs(modName, targets);
+      if (targModIDs == null || targModIDs.length == 0) {
+        continue;
+      }
+      TestUtil.logHarnessDebug("****** Module name = \"" + modName + "\"");
+      TestUtil
+          .logHarnessDebug("****** targModIDs.length = " + targModIDs.length);
+      TestUtil.logHarnessDebug("TargetModuleID[]");
+      for (int i = 0; i < targModIDs.length; i++) {
+        TestUtil.logHarnessDebug("[" + targModIDs[i].getModuleID() + ", "
+            + targModIDs[i].getTarget().getDescription() + ", "
+            + targModIDs[i].getTarget().getName() + "]");
+      }
+
+      TargetModuleID[] savedIDs = (TargetModuleID[]) htDeployedModules
+          .get(modName);
+
+      TestUtil.logHarnessDebug("****** savedIDs.length = " + savedIDs.length);
+      TestUtil.logHarnessDebug("TargetModuleID[]");
+      for (int i = 0; i < savedIDs.length; i++) {
+        TestUtil.logHarnessDebug("[" + savedIDs[i].getModuleID() + "]");
+      }
+
+      targModIDsList = new ArrayList();
+      for (int i = 0; i < targModIDs.length; i++) {
+        if (isValidTargetID(targModIDs[i], savedIDs)) {
+          TestUtil.logHarnessDebug(
+              "&&&&&&&& Adding = " + targModIDs[i].getModuleID());
+          targModIDsList.add(targModIDs[i]);
+          TestUtil.logHarnessDebug(
+              "&&&&&&&& targModIDsList.size() is " + targModIDsList.size());
+          break;
+        }
+      }
+      if (targModIDsList.size() > 0) {
+        TargetModuleID[] validSavedIDs = (TargetModuleID[]) (targModIDsList
+            .toArray(new TargetModuleID[targModIDsList.size()]));
+        result.put(modName, validSavedIDs);
+      } else {
+        TestUtil.logHarnessDebug(
+            "$$$$$ We did not find any valid IDs :  " + modName);
+      }
+    }
+    TestUtil.logHarnessDebug("DUMP OF RESULT");
+    dumpDeployedMods(result);
+    TestUtil.logHarnessDebug("END DUMP OF RESULT END");
+    htDeployedModules = result;
+  }
+
+  // Read
+  protected Hashtable normalizeMap(Hashtable map, Target[] targets)
+      throws Exception {
+    List targModIDsList = null;
+
+    TestUtil.logHarnessDebug("Target[]");
+    for (int i = 0; i < targets.length; i++) {
+      TestUtil.logHarnessDebug("[" + targets[i].getDescription() + ", "
+          + targets[i].getName() + "]");
+    }
+
+    Hashtable result = new Hashtable();
+    Iterator iter = map.keySet().iterator();
+    while (iter.hasNext()) {
+      String modName = (String) iter.next();
+      TargetModuleID[] targModIDs = getRunningTargetModuleIDs(modName, targets);
+      if (targModIDs == null || targModIDs.length == 0) {
+        continue;
+      }
+      TestUtil.logHarnessDebug("****** Module name = \"" + modName + "\"");
+      TestUtil
+          .logHarnessDebug("****** targModIDs.length = " + targModIDs.length);
+      TestUtil.logHarnessDebug("TargetModuleID[]");
+      for (int i = 0; i < targModIDs.length; i++) {
+        TestUtil.logHarnessDebug("[" + targModIDs[i].getModuleID() + ", "
+            + targModIDs[i].getTarget().getDescription() + ", "
+            + targModIDs[i].getTarget().getName() + "]");
+      }
+
+      SerializableTargetID[] serIDs = (SerializableTargetID[]) map.get(modName);
+
+      TestUtil.logHarnessDebug("****** serIDs.length = " + serIDs.length);
+      TestUtil.logHarnessDebug("SerializableTargetModuleID[]");
+      for (int i = 0; i < serIDs.length; i++) {
+        TestUtil.logHarnessDebug("[" + serIDs[i].getModuleID() + "]");
+      }
+
+      targModIDsList = new ArrayList();
+      for (int i = 0; i < targModIDs.length; i++) {
+        if (isValidTargetID(targModIDs[i], serIDs)) {
+          TestUtil.logHarnessDebug(
+              "&&&&&&&& Adding = " + targModIDs[i].getModuleID());
+          targModIDsList.add(targModIDs[i]);
+          TestUtil.logHarnessDebug(
+              "&&&&&&&& targModIDsList.size() is " + targModIDsList.size());
+          break;
+        }
+      }
+      if (targModIDsList.size() > 0) {
+        TargetModuleID[] validSerIDs = (TargetModuleID[]) (targModIDsList
+            .toArray(new TargetModuleID[targModIDsList.size()]));
+        result.put(modName, validSerIDs);
+      }
+    }
+    TestUtil.logHarnessDebug("DUMP OF RESULT");
+    dumpDeployedMods(result);
+    TestUtil.logHarnessDebug("END DUMP OF RESULT END");
+    return result;
+  }
+
+  // Write
+  protected Hashtable normalizeMap(Hashtable map) {
+    Hashtable result = new Hashtable();
+    Iterator iter = map.keySet().iterator();
+    while (iter.hasNext()) {
+      String key = (String) iter.next();
+      TargetModuleID[] tmid = (TargetModuleID[]) map.get(key);
+      SerializableTargetID[] serIDs = new SerializableTargetID[tmid.length];
+      for (int i = 0; i < tmid.length; i++) {
+        serIDs[i] = new SerializableTargetID(tmid[i]);
+      }
+      result.put(key, serIDs);
+    }
+    return result;
+  }
+
+  protected void writeMap(Hashtable map) throws IOException {
+    deleteDeployedModulesState();
+    ObjectOutputStream oout = null;
+    Hashtable newMap = normalizeMap(map);
+    try {
+      oout = new ObjectOutputStream(new FileOutputStream(deployStateFile));
+      oout.writeObject(newMap);
+    } catch (IOException e) {
+      throw e;
+    } finally {
+      try {
+        oout.close();
+      } catch (Exception ee) {
+      }
+    }
+  }
+
+  protected Hashtable readMap() throws IOException {
+    Hashtable result = null;
+    File inFile = new File(deployStateFile);
+    if (inFile.isFile()) {
+      ObjectInputStream oin = null;
+      try {
+        oin = new ObjectInputStream(new FileInputStream(deployStateFile));
+        result = (Hashtable) (oin.readObject());
+      } catch (IOException e) {
+        throw e;
+      } catch (ClassNotFoundException cnfe) {
+        cnfe.printStackTrace();
+      } finally {
+        try {
+          oin.close();
+        } catch (Exception ee) {
+        }
+      }
+    }
+    return result;
+  }
+
+  protected Hashtable getDeployedModules() {
+    Hashtable result = null;
+    Hashtable serMap = null;
+    try {
+      serMap = readMap();
+    } catch (IOException e) {
+    }
+    if (serMap == null) {
+      result = new Hashtable();
+    } else {
+      try {
+        result = normalizeMap(serMap, getTargets());
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return result;
+  }
+
+  protected void deleteDeployedModulesState() {
+    try {
+      File removeMe = new File(
+          TEMP_DIR + File.separator + DEPLOYED_MODULES_FILE);
+      removeMe.delete();
+    } catch (Exception e) {
+    }
+  }
+
+  protected Target[] getTargets() {
+    // get the targets
+    return depMgr.getTargets();
+  }
+
+  protected static class SerializableTarget implements Serializable {
+    private String description;
+
+    private String name;
+
+    public SerializableTarget(Target target) {
+      this.description = target.getDescription();
+      this.name = target.getName();
+    }
+
+    public String getDescription() {
+      return description;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public boolean equals(Object obj) {
+      SerializableTarget that = null;
+      boolean result = false;
+      if (this instanceof SerializableTarget) {
+        that = (SerializableTarget) obj;
+        result = (description == null) ? that.getDescription() == null
+            : description.equals(that.getDescription());
+        result = result && ((name == null) ? that.getName() == null
+            : name.equals(that.getName()));
+      }
+      return result;
+    }
+  }
+
+  protected static class SerializableTargetID implements Serializable {
+    private SerializableTarget target;
+
+    private String moduleID;
+
+    public SerializableTargetID(TargetModuleID id) {
+      this.moduleID = id.getModuleID();
+      this.target = new SerializableTarget(id.getTarget());
+    }
+
+    public SerializableTarget getTarget() {
+      return target;
+    }
+
+    public String getModuleID() {
+      return moduleID;
+    }
+
+    public boolean equals(Object obj) {
+      boolean result = false;
+      SerializableTargetID that = null;
+      if (obj instanceof SerializableTargetID) {
+        that = (SerializableTargetID) obj;
+        result = (moduleID == null) ? that.getModuleID() == null
+            : moduleID.equals(that.getModuleID());
+        result = result && ((target == null) ? that.getTarget() == null
+            : target.equals(that.getTarget()));
+      }
+      return result;
+    }
+  }
+
+}
diff --git a/src/main/java/org/apache/openejb/cts/deploy/TSDeployment2.java b/src/main/java/org/apache/openejb/cts/deploy/TSDeployment2.java
new file mode 100644
index 0000000..7148b1d
--- /dev/null
+++ b/src/main/java/org/apache/openejb/cts/deploy/TSDeployment2.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package org.apache.openejb.cts.deploy;
+
+import java.io.*;
+import com.sun.ts.lib.deliverable.*;
+
+/**
+ * This is a factory class for creating instances of TSDeploymentInterface2. The
+ * implementation classes used are determined by the values of the porting
+ * package properties in TS_HOME/bin/ts.jte.
+ * 
+ * @author Kyle Grucci
+ */
+public class TSDeployment2 {
+  private static PropertyManagerInterface propMgr = null;
+
+  public static TSDeploymentInterface2 getDeploymentInstance(PrintWriter writer,
+      String sClassName) throws Exception {
+    return createInstance(sClassName, writer);
+  }
+
+  private static TSDeploymentInterface2 createInstance(String sClassName,
+      PrintWriter writer) throws Exception {
+    try {
+      propMgr = DeliverableFactory.getDeliverableInstance()
+          .getPropertyManager();
+
+      // create and initialize a new instance of the Deployment class
+      Class c = Class.forName(propMgr.getProperty(sClassName));
+      TSDeploymentInterface2 ctsDep1 = (TSDeploymentInterface2) c.newInstance();
+      ctsDep1.init(writer);
+      return ctsDep1;
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+}
diff --git a/src/main/java/org/apache/openejb/cts/deploy/TSDeploymentInterface2.java b/src/main/java/org/apache/openejb/cts/deploy/TSDeploymentInterface2.java
new file mode 100644
index 0000000..c901c77
--- /dev/null
+++ b/src/main/java/org/apache/openejb/cts/deploy/TSDeploymentInterface2.java
@@ -0,0 +1,38 @@
+package org.apache.openejb.cts.deploy;
+
+import com.sun.ts.lib.porting.DeploymentInfo;
+import com.sun.ts.lib.porting.TSDeploymentException;
+
+import java.io.PrintWriter;
+import java.util.Hashtable;
+import java.util.Properties;
+import javax.enterprise.deploy.spi.DeploymentManager;
+import javax.enterprise.deploy.spi.Target;
+import javax.enterprise.deploy.spi.TargetModuleID;
+import javax.enterprise.deploy.spi.status.ProgressObject;
+
+public interface TSDeploymentInterface2 {
+    void init(PrintWriter var1);
+
+    String getClientClassPath(TargetModuleID[] var1, DeploymentInfo var2, DeploymentManager var3) throws TSDeploymentException;
+
+    Object getDeploymentPlan(DeploymentInfo var1) throws TSDeploymentException;
+
+    void createConnectionFactory(TargetModuleID[] var1, Properties var2) throws TSDeploymentException;
+
+    void removeConnectionFactory(TargetModuleID[] var1, Properties var2) throws TSDeploymentException;
+
+    String getAppClientArgs(Properties var1);
+
+    Hashtable getDependentValues(DeploymentInfo[] var1);
+
+    Target[] getTargetsToUse(Target[] var1, DeploymentInfo var2);
+
+    void postDistribute(ProgressObject var1);
+
+    void postStart(ProgressObject var1);
+
+    void postStop(ProgressObject var1);
+
+    void postUndeploy(ProgressObject var1);
+}