package org.drools.integrationtests;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import org.drools.compiler.DroolsError;
import org.drools.compiler.PackageBuilderConfiguration;
import org.drools.compiler.PackageBuilderErrors;
import org.drools.lang.descr.FunctionDescr;
import org.drools.lang.descr.ImportDescr;
import org.drools.lang.descr.PackageDescr;
import org.drools.rule.builder.dialect.java.JavaDialectConfiguration;
public class PackageBuilderThreadSafetyTest {
private static final int _NUMBER_OF_THREADS = 100;
private static final int _SLEEP_TIME_MS = 100;
@Test
public void testThreadSafetyEclipse() {
execute( JavaDialectConfiguration.ECLIPSE );
}
@Test
public void testThreadSafetyJanino() {
execute( JavaDialectConfiguration.JANINO );
}
public void execute(int compiler) {
final PackageBuilderConfiguration packageBuilderConfig = new PackageBuilderConfiguration();
((JavaDialectConfiguration) packageBuilderConfig.getDialectConfiguration( "java" )).setCompiler( compiler );
final List<PackageBuilderErrors> errors = new ArrayList<PackageBuilderErrors>();
final List<Exception> exceptions = new ArrayList<Exception>();
Thread[] threads = new Thread[_NUMBER_OF_THREADS];
for ( int i = 0; i < _NUMBER_OF_THREADS; i++ ) {
final int ID = i;
Thread testThread = new Thread() {
public void run() {
try {
this.setName( "Thread[" + ID + "]" );
org.drools.compiler.PackageBuilder builder = null;
try {
builder = new org.drools.compiler.PackageBuilder( packageBuilderConfig );
} catch ( Throwable t ) {
t.printStackTrace();
throw new RuntimeException( t );
}
PackageDescr packageDescr = new PackageDescr( "MyRulebase" );
addImports( packageDescr );
addFunctions( packageDescr );
// added some arbitrary sleep statements to encourage
// context switching and hope this provokes exceptions
sleep( _SLEEP_TIME_MS );
builder.addPackage( packageDescr );
sleep( _SLEEP_TIME_MS );
builder.getPackage();
sleep( _SLEEP_TIME_MS );
if ( builder.hasErrors() ) {
System.out.println( "ERROR in thread: " + ID );
System.out.println( builder.getErrors().toString() );
errors.add( builder.getErrors() );
}
} catch ( Exception e ) {
e.printStackTrace();
exceptions.add( e );
}
}
};
threads[i] = testThread;
try {
testThread.start();
} catch ( Exception e ) {
assertTrue( false );
}
}
for ( int i = 0; i < _NUMBER_OF_THREADS; i++ ) {
try {
threads[i].join();
} catch ( InterruptedException e ) {
threads[i].interrupt();
}
}
StringBuilder exceptionBuf = new StringBuilder();
if (!exceptions.isEmpty()) {
System.err.println("------->EXCEPTION(s) DURING THREAD TEST : <-------------------");
for (Iterator<Exception> iterator = exceptions.iterator(); iterator.hasNext();) {
Exception name = iterator.next();
exceptionBuf.append(name + name.getMessage() + "\n");
}
}
StringBuilder errorBuf = new StringBuilder();
if (!errors.isEmpty()) {
System.err.println("------->ERROR(s) DURING THREAD TEST : <-------------------");
for (Iterator<PackageBuilderErrors> iterator = errors.iterator(); iterator.hasNext();) {
PackageBuilderErrors e = iterator.next();
for (int i = 0; i < e.getErrors().length; i++) {
DroolsError de = e.getErrors()[i];
errorBuf.append(de.getMessage() + "\n");
}
}
}
assertTrue( "Exceptions during package compilation : \n" + exceptionBuf.toString(),
exceptions.isEmpty() );
assertTrue( "PackageBuilderErrors during package compilation : \n" + errorBuf.toString(),
errors.isEmpty() );
}
private static void addImports(PackageDescr packageDescr) {
packageDescr.addImport( new ImportDescr( "java.util.List" ) );
packageDescr.addImport( new ImportDescr( "java.util.ArrayList" ) );
packageDescr.addImport( new ImportDescr( "java.util.LinkedList" ) );
packageDescr.addImport( new ImportDescr( "java.util.Set" ) );
packageDescr.addImport( new ImportDescr( "java.util.HashSet" ) );
packageDescr.addImport( new ImportDescr( "java.util.SortedSet" ) );
packageDescr.addImport( new ImportDescr( "java.util.TreeSet" ) );
}
private static void addFunctions(PackageDescr packageDescr) {
FunctionDescr functionDescr = new FunctionDescr( "foo",
"void" );
functionDescr.addParameter( "String",
"arg1" );
String body = "Set myHashSet = new HashSet();" + "myHashSet.add(arg1);" + "List myArrayList = new ArrayList();" + "myArrayList.add(arg1);" + "List myLinkedList = new LinkedList();" + "myLinkedList.add(arg1);"
+ "Set myTreeSet = new TreeSet();" + "myTreeSet.add(arg1);";
functionDescr.setText( body );
packageDescr.addFunction( functionDescr );
}
}