blob: 20178cfb0ea7ef4f6a27d7b43fa8ef128c7e0aaf [file] [log] [blame]
/*
* 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);
}
}