Initial Contribution

Signed-off-by: Vinay Vishal <vinay.vishal@oracle.com>
diff --git a/appserver/tests/appserv-tests/devtests/deployment/jsr88/misc/TestProgressObjectImpl.java b/appserver/tests/appserv-tests/devtests/deployment/jsr88/misc/TestProgressObjectImpl.java
new file mode 100644
index 0000000..eac4b10
--- /dev/null
+++ b/appserver/tests/appserv-tests/devtests/deployment/jsr88/misc/TestProgressObjectImpl.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017, 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
+ */
+
+/*
+ * TestProgressObjectImpl.java
+ *
+ * Created on January 15, 2004, 10:10 AM
+ */
+
+import javax.enterprise.deploy.spi.status.ProgressListener;
+import org.glassfish.deployapi.ProgressObjectImpl;
+import org.glassfish.deployapi.TargetImpl;
+import org.glassfish.deployment.client.DeploymentFacilityFactory;
+import org.glassfish.deployment.client.DeploymentFacility;
+import org.glassfish.deployment.client.AbstractDeploymentFacility;
+import javax.enterprise.deploy.shared.StateType;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+
+/**
+ *Makes sure that the ProgressObjectImpl class functions correctly.
+ *<p>
+ *In particular, bug 4977764 reported that the ProgressObjectImpl class was susceptible to 
+ *concurrent update failures in the vector that holds registered progress listeners.  The
+ *fireProgressEvent method worked with the vector of listeners itself rather than a clone of the vector.
+ *One of the listeners unregistered itself from the progress object, so when the iterator tried to
+ *get the next element it detected the concurrent update.   So, the progress object now clones the vector
+ *temporarily in fireProgressEvent and iterates through the clone.
+ *
+ * @author  tjquinn
+ */
+public class TestProgressObjectImpl {
+
+    private static final String here = "devtests/deployment/jsr88/misc";
+    
+    /**
+     *Provides a concrete implementation of the progress object for testing.  Note that the behavior being
+     *tested is actually that of the superclass ProgressObjectImpl.
+     */
+    public class MyProgressObjectImpl extends ProgressObjectImpl {
+       
+        public MyProgressObjectImpl(TargetImpl target) {
+            super(target);
+        }
+        
+        /**
+         *Required by the abstract class definition but not used during testing.
+         */
+        public void run() {}
+        
+        /**
+         *Stands in as an operation that fires an event to registered listeners.
+         */
+        public void act() {
+            fireProgressEvent(StateType.RUNNING, "starting");
+            /*
+             *This is where any real work would be done.  It's useful to test with two events just in case
+             *that would uncover any problems.
+             */
+            fireProgressEvent(StateType.COMPLETED, "done");
+        }
+    }
+    
+    /**
+     *Adds a new listener during the event handling.
+     */
+    public class MeddlingListenerAdder implements ProgressListener {
+        
+    
+        public void handleProgressEvent(javax.enterprise.deploy.spi.status.ProgressEvent progressEvent) {
+            /*
+             *Meddle in the listener list by adding a new listener to the list.  This should trigger the error
+             *in the original version of ProgressObjectImpl but should not in the fixed version.
+             */
+            TestProgressObjectImpl.this.theProgressObjectImpl.addProgressListener(new TestProgressObjectImpl.MeddlingListenerRemover());
+        }
+        
+    }
+    
+    /**
+     *Removes itself as a listener during the event handling.
+     */
+    public class MeddlingListenerRemover implements ProgressListener {
+        
+    
+        public void handleProgressEvent(javax.enterprise.deploy.spi.status.ProgressEvent progressEvent) {
+            /*
+             *Meddle in the listener list by removing itself from the list.  This should trigger the error
+             *in the original version of ProgressObjectImpl but should not in the fixed version.
+             */
+            TestProgressObjectImpl.this.theProgressObjectImpl.removeProgressListener(this);
+        }
+        
+    }
+    
+    /* Local progress object implementation to be tested. */
+    private MyProgressObjectImpl theProgressObjectImpl;
+        
+    /** Creates a new instance of TestProgressObjectImpl */
+    public TestProgressObjectImpl() {
+    }
+    
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) {
+        TestProgressObjectImpl test = new TestProgressObjectImpl();
+        try {
+            test.run(args);
+            test.pass();
+        } catch (Throwable th) {
+            th.printStackTrace(System.out);
+            test.fail();
+        }
+    }
+    
+    public void run(String[] args) {
+        addNewListenerDuringEventHandling();
+    }
+
+    /**
+     * Tamper with the listener list by adding a new listener during event handling.  
+     */
+    private void addNewListenerDuringEventHandling() {
+        /*
+         *Create a TargetImpl just to satisfy the signature of the constructor for the progress object implementation.
+         */
+        DeploymentFacility df = DeploymentFacilityFactory.getDeploymentFacility();
+        TargetImpl target = new TargetImpl((AbstractDeploymentFacility)df, "test", "test");
+        theProgressObjectImpl = new MyProgressObjectImpl(target);
+        TestProgressObjectImpl.MeddlingListenerAdder meddlingListener1 = new TestProgressObjectImpl.MeddlingListenerAdder();
+        TestProgressObjectImpl.MeddlingListenerAdder meddlingListener2 = new TestProgressObjectImpl.MeddlingListenerAdder();
+        
+        theProgressObjectImpl.addProgressListener(meddlingListener1);
+        theProgressObjectImpl.addProgressListener(meddlingListener2);
+        
+        /*
+         *Fire an event that will change the listener set.
+         */
+        theProgressObjectImpl.act();
+        
+    }
+    
+    private void log(String message) {
+        System.out.println("[TestProgressObjectImpl]:: " + message);
+    }
+
+    private void pass() {
+        log("PASSED: " + here);
+        System.exit(0);
+    }
+
+    private void fail() {
+        log("FAILED: " + here);
+        System.exit(-1);
+    }
+}