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);
+ }
+}