|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
import javax.xml.transform.TransformerFactory;
|
|
|
|
import net.sf.saxon.Configuration;
|
|
|
|
import org.testng.Assert;
|
|
import org.testng.annotations.Test;
|
|
|
|
import com.saxonica.config.EnterpriseConfiguration;
|
|
|
|
public class TestSaxonConfigurationInstantiation {
|
|
|
|
private static class TestForSaxonBug2327 {
|
|
|
|
protected static void testForDeadlock(Thread thread1, Thread thread2) throws InterruptedException {
|
|
thread1.start();
|
|
thread2.start();
|
|
|
|
// allow 5 seconds for threads to complete
|
|
long timeout = 5000;
|
|
long timestamp = System.currentTimeMillis();
|
|
thread1.join(timeout);
|
|
thread2.join(Math.max(1, timestamp + timeout - System.currentTimeMillis()));
|
|
|
|
System.out.println(thread1.isAlive() && thread2.isAlive() ? Result.SUSPECTED_DEADLOCK : Result.NORMAL_COMPLETION);
|
|
}
|
|
}
|
|
|
|
private static class UseWorkaroundForSaxonBug2327 extends TestForSaxonBug2327 {
|
|
|
|
@SuppressWarnings("unused")
|
|
public static void main(String[] args) throws InterruptedException {
|
|
testForDeadlock(
|
|
new Thread() {
|
|
public void run() {
|
|
new Configuration();
|
|
new EnterpriseConfiguration();
|
|
}
|
|
},
|
|
new Thread() {
|
|
public void run() {
|
|
new Configuration();
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
private static class UseFixForSaxonBug2327 extends TestForSaxonBug2327 {
|
|
|
|
@SuppressWarnings("unused")
|
|
public static void main(String[] args) throws InterruptedException {
|
|
testForDeadlock(
|
|
new Thread() {
|
|
public void run() {
|
|
new EnterpriseConfiguration();
|
|
}
|
|
},
|
|
new Thread() {
|
|
public void run() {
|
|
new Configuration();
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
private static enum Result {
|
|
SUSPECTED_DEADLOCK,
|
|
NORMAL_COMPLETION
|
|
};
|
|
|
|
@Test(invocationCount = 10)
|
|
public static void testWorkaroundForSaxonBug2327() throws IOException {
|
|
Process process = execute(UseWorkaroundForSaxonBug2327.class);
|
|
Assert.assertEquals(Result.valueOf(waitForNextOutputLine(process, 10000)), Result.NORMAL_COMPLETION, "The workaround did not prevent the deadlock during class loading.");
|
|
}
|
|
|
|
@Test(invocationCount = 10)
|
|
public static void testFixForSaxonBug2327() throws IOException {
|
|
Process process = execute(UseFixForSaxonBug2327.class);
|
|
Assert.assertEquals(Result.valueOf(waitForNextOutputLine(process, 10000)), Result.NORMAL_COMPLETION, "The fix did not prevent the deadlock during class loading.");
|
|
}
|
|
|
|
private static Process execute(Class<?> clazz) throws IOException {
|
|
List<String> args = new ArrayList<>();
|
|
args.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");
|
|
args.add("-cp");
|
|
args.add(System.getProperty("java.class.path"));
|
|
args.add(clazz.getName());
|
|
return Runtime.getRuntime().exec(args.toArray(new String[args.size()]));
|
|
}
|
|
|
|
private static String waitForNextOutputLine(Process process, long waitTime) throws IOException {
|
|
final AtomicReference<String> result = new AtomicReference<>();
|
|
final AtomicBoolean gotResult = new AtomicBoolean(false);
|
|
final AtomicReference<IOException> exception = new AtomicReference<>();
|
|
Thread reader = new Thread("result reader") {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
result.set(nextOutputLine(process));
|
|
gotResult.set(true);
|
|
}
|
|
catch (IOException e) {
|
|
exception.set(e);
|
|
}
|
|
}
|
|
};
|
|
reader.start();
|
|
try {
|
|
reader.join(waitTime);
|
|
}
|
|
catch (InterruptedException e) {}
|
|
if (exception.get() != null)
|
|
throw exception.get();
|
|
if (! gotResult.get())
|
|
throw new RuntimeException("waitForNextOutputLine timed out after " + waitTime +"ms");
|
|
return result.get();
|
|
}
|
|
|
|
public static String nextOutputLine(Process process) throws IOException {
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
|
return reader.readLine();
|
|
}
|
|
}
|