New setting "hibernate.classloader.tccl_lookup" to allow the configuration of the thread context classloader lookup.
The bootstrap classloader context is not stored anymore in the ClassLoaderService because on Glassfish 4.1.1, the former will be closed after bootstrap, causing huge warning and stacktraces occurs in the log each time a HQL query has to be compiled. See ticket HHH-11245 for details.
This commit is contained in:
parent
b0fad884f0
commit
726305f33e
|
@ -14,6 +14,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
|
import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService.TCCLLookupBehavior;
|
||||||
import org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl;
|
import org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl;
|
||||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||||
|
@ -39,6 +40,7 @@ public class BootstrapServiceRegistryBuilder {
|
||||||
private List<ClassLoader> providedClassLoaders;
|
private List<ClassLoader> providedClassLoaders;
|
||||||
private ClassLoaderService providedClassLoaderService;
|
private ClassLoaderService providedClassLoaderService;
|
||||||
private StrategySelectorBuilder strategySelectorBuilder = new StrategySelectorBuilder();
|
private StrategySelectorBuilder strategySelectorBuilder = new StrategySelectorBuilder();
|
||||||
|
private TCCLLookupBehavior tcclLookupBehaviour = TCCLLookupBehavior.AFTER;
|
||||||
|
|
||||||
private boolean autoCloseRegistry = true;
|
private boolean autoCloseRegistry = true;
|
||||||
|
|
||||||
|
@ -85,6 +87,15 @@ public class BootstrapServiceRegistryBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines when the lookup in the thread context {@code ClassLoader} is done.
|
||||||
|
*
|
||||||
|
* @param behavior The behavior.
|
||||||
|
*/
|
||||||
|
public void applyTCCLBehavior(TCCLLookupBehavior behavior) {
|
||||||
|
tcclLookupBehaviour = behavior;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #applyClassLoaderService} instead
|
* @deprecated Use {@link #applyClassLoaderService} instead
|
||||||
*/
|
*/
|
||||||
|
@ -205,6 +216,7 @@ public class BootstrapServiceRegistryBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
classLoaderService = new ClassLoaderServiceImpl( classLoaders );
|
classLoaderService = new ClassLoaderServiceImpl( classLoaders );
|
||||||
|
classLoaderService.setTCCLLookupBehavior( tcclLookupBehaviour );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
classLoaderService = providedClassLoaderService;
|
classLoaderService = providedClassLoaderService;
|
||||||
|
@ -215,7 +227,6 @@ public class BootstrapServiceRegistryBuilder {
|
||||||
classLoaderService
|
classLoaderService
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return new BootstrapServiceRegistryImpl(
|
return new BootstrapServiceRegistryImpl(
|
||||||
autoCloseRegistry,
|
autoCloseRegistry,
|
||||||
classLoaderService,
|
classLoaderService,
|
||||||
|
|
|
@ -79,17 +79,6 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
|
||||||
// then the Hibernate class loader
|
// then the Hibernate class loader
|
||||||
orderedClassLoaderSet.add( ClassLoaderServiceImpl.class.getClassLoader() );
|
orderedClassLoaderSet.add( ClassLoaderServiceImpl.class.getClassLoader() );
|
||||||
|
|
||||||
// then the TCCL, if one...
|
|
||||||
final ClassLoader tccl = locateTCCL();
|
|
||||||
if ( tccl != null ) {
|
|
||||||
orderedClassLoaderSet.add( tccl );
|
|
||||||
}
|
|
||||||
// finally the system classloader
|
|
||||||
final ClassLoader sysClassLoader = locateSystemClassLoader();
|
|
||||||
if ( sysClassLoader != null ) {
|
|
||||||
orderedClassLoaderSet.add( sysClassLoader );
|
|
||||||
}
|
|
||||||
|
|
||||||
// now build the aggregated class loader...
|
// now build the aggregated class loader...
|
||||||
this.aggregatedClassLoader = new AggregatedClassLoader( orderedClassLoaderSet );
|
this.aggregatedClassLoader = new AggregatedClassLoader( orderedClassLoaderSet );
|
||||||
}
|
}
|
||||||
|
@ -120,15 +109,6 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
|
||||||
addIfSet( providedClassLoaders, AvailableSettings.HIBERNATE_CLASSLOADER, configValues );
|
addIfSet( providedClassLoaders, AvailableSettings.HIBERNATE_CLASSLOADER, configValues );
|
||||||
addIfSet( providedClassLoaders, AvailableSettings.ENVIRONMENT_CLASSLOADER, configValues );
|
addIfSet( providedClassLoaders, AvailableSettings.ENVIRONMENT_CLASSLOADER, configValues );
|
||||||
|
|
||||||
if ( providedClassLoaders.isEmpty() ) {
|
|
||||||
log.debugf( "Incoming config yielded no classloaders; adding standard SE ones" );
|
|
||||||
final ClassLoader tccl = locateTCCL();
|
|
||||||
if ( tccl != null ) {
|
|
||||||
providedClassLoaders.add( tccl );
|
|
||||||
}
|
|
||||||
providedClassLoaders.add( ClassLoaderServiceImpl.class.getClassLoader() );
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ClassLoaderServiceImpl( providedClassLoaders );
|
return new ClassLoaderServiceImpl( providedClassLoaders );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,19 +137,96 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TCCLLookupBehavior getTTCLLookupBehavior() {
|
||||||
|
return getAggregatedClassLoader().tcclLookupBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTCCLLookupBehavior(TCCLLookupBehavior behavior) {
|
||||||
|
getAggregatedClassLoader().tcclLookupBehavior = behavior;
|
||||||
|
}
|
||||||
|
|
||||||
private static class AggregatedClassLoader extends ClassLoader {
|
private static class AggregatedClassLoader extends ClassLoader {
|
||||||
private final ClassLoader[] individualClassLoaders;
|
private final ClassLoader[] individualClassLoaders;
|
||||||
|
private volatile TCCLLookupBehavior tcclLookupBehavior = TCCLLookupBehavior.AFTER;
|
||||||
|
|
||||||
private AggregatedClassLoader(final LinkedHashSet<ClassLoader> orderedClassLoaderSet) {
|
private AggregatedClassLoader(final LinkedHashSet<ClassLoader> orderedClassLoaderSet) {
|
||||||
super( null );
|
super( null );
|
||||||
individualClassLoaders = orderedClassLoaderSet.toArray( new ClassLoader[orderedClassLoaderSet.size()] );
|
individualClassLoaders = orderedClassLoaderSet.toArray( new ClassLoader[orderedClassLoaderSet.size()] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Iterator<ClassLoader> newClassLoaderIterator() {
|
||||||
|
final ClassLoader sysClassLoader = locateSystemClassLoader();
|
||||||
|
final ClassLoader threadClassLoader = locateTCCL();
|
||||||
|
|
||||||
|
final TCCLLookupBehavior behavior;
|
||||||
|
if ( threadClassLoader == null ) {
|
||||||
|
behavior = TCCLLookupBehavior.NEVER;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
behavior = tcclLookupBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Iterator<ClassLoader>() {
|
||||||
|
private boolean tcclReturned = false;
|
||||||
|
private boolean sysclReturned = false;
|
||||||
|
private int currentIndex = 0;
|
||||||
|
|
||||||
|
private ClassLoader nextClassLoader;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
if ( nextClassLoader != null ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( currentIndex == 0 && behavior == TCCLLookupBehavior.BEFORE && !tcclReturned ) {
|
||||||
|
tcclReturned = true;
|
||||||
|
nextClassLoader = threadClassLoader;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( currentIndex < individualClassLoaders.length ) {
|
||||||
|
nextClassLoader = individualClassLoaders[ currentIndex ];
|
||||||
|
++currentIndex;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( behavior == TCCLLookupBehavior.AFTER && !tcclReturned ) {
|
||||||
|
tcclReturned = true;
|
||||||
|
nextClassLoader = threadClassLoader;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !sysclReturned ) {
|
||||||
|
sysclReturned = true;
|
||||||
|
nextClassLoader = sysClassLoader;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader next() {
|
||||||
|
if ( nextClassLoader == null ) {
|
||||||
|
throw new IllegalStateException( "No more ClassLoader to return" );
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoader result = nextClassLoader;
|
||||||
|
nextClassLoader = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Enumeration<URL> getResources(String name) throws IOException {
|
public Enumeration<URL> getResources(String name) throws IOException {
|
||||||
final LinkedHashSet<URL> resourceUrls = new LinkedHashSet<URL>();
|
final LinkedHashSet<URL> resourceUrls = new LinkedHashSet<URL>();
|
||||||
|
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||||
for ( ClassLoader classLoader : individualClassLoaders ) {
|
while ( clIterator.hasNext() ) {
|
||||||
|
final ClassLoader classLoader = clIterator.next();
|
||||||
final Enumeration<URL> urls = classLoader.getResources( name );
|
final Enumeration<URL> urls = classLoader.getResources( name );
|
||||||
while ( urls.hasMoreElements() ) {
|
while ( urls.hasMoreElements() ) {
|
||||||
resourceUrls.add( urls.nextElement() );
|
resourceUrls.add( urls.nextElement() );
|
||||||
|
@ -193,7 +250,9 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected URL findResource(String name) {
|
protected URL findResource(String name) {
|
||||||
for ( ClassLoader classLoader : individualClassLoaders ) {
|
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||||
|
while ( clIterator.hasNext() ) {
|
||||||
|
final ClassLoader classLoader = clIterator.next();
|
||||||
final URL resource = classLoader.getResource( name );
|
final URL resource = classLoader.getResource( name );
|
||||||
if ( resource != null ) {
|
if ( resource != null ) {
|
||||||
return resource;
|
return resource;
|
||||||
|
@ -204,7 +263,9 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
for ( ClassLoader classLoader : individualClassLoaders ) {
|
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||||
|
while ( clIterator.hasNext() ) {
|
||||||
|
final ClassLoader classLoader = clIterator.next();
|
||||||
try {
|
try {
|
||||||
return classLoader.loadClass( name );
|
return classLoader.loadClass( name );
|
||||||
}
|
}
|
||||||
|
@ -358,8 +419,8 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
|
||||||
return work.doWork( getAggregatedClassLoader() );
|
return work.doWork( getAggregatedClassLoader() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClassLoader getAggregatedClassLoader() {
|
private AggregatedClassLoader getAggregatedClassLoader() {
|
||||||
final ClassLoader aggregated = this.aggregatedClassLoader;
|
final AggregatedClassLoader aggregated = this.aggregatedClassLoader;
|
||||||
if ( aggregated == null ) {
|
if ( aggregated == null ) {
|
||||||
throw log.usingStoppedClassLoaderService();
|
throw log.usingStoppedClassLoaderService();
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,4 +80,33 @@ public interface ClassLoaderService extends Service, Stoppable {
|
||||||
}
|
}
|
||||||
|
|
||||||
<T> T workWithClassLoader(Work<T> work);
|
<T> T workWithClassLoader(Work<T> work);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines of the lookup in the current thread context {@link ClassLoader} should be
|
||||||
|
* used.
|
||||||
|
*/
|
||||||
|
enum TCCLLookupBehavior {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current thread context {@link ClassLoader} will never be used during
|
||||||
|
* the class lookup.
|
||||||
|
*/
|
||||||
|
NEVER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class lookup will be done in the thread context {@link ClassLoader} prior
|
||||||
|
* to the other {@code ClassLoader}s.
|
||||||
|
*/
|
||||||
|
BEFORE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class lookup will be done in the thread context {@link ClassLoader} if
|
||||||
|
* the former hasn't been found in the other {@code ClassLoader}s.
|
||||||
|
* This is the default value.
|
||||||
|
*/
|
||||||
|
AFTER
|
||||||
|
}
|
||||||
|
|
||||||
|
TCCLLookupBehavior getTTCLLookupBehavior();
|
||||||
|
void setTCCLLookupBehavior(TCCLLookupBehavior behavior);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.cfg;
|
package org.hibernate.cfg;
|
||||||
|
|
||||||
import org.hibernate.boot.MetadataBuilder;
|
import org.hibernate.boot.MetadataBuilder;
|
||||||
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
||||||
|
@ -190,6 +191,14 @@ public interface AvailableSettings {
|
||||||
*/
|
*/
|
||||||
String CLASSLOADERS = "hibernate.classLoaders";
|
String CLASSLOADERS = "hibernate.classLoaders";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to define how the current thread context {@link ClassLoader} must be used
|
||||||
|
* for class lookup.
|
||||||
|
*
|
||||||
|
* @see ClassLoaderService#TCCLLookupBehavior
|
||||||
|
*/
|
||||||
|
String TC_CLASSLOADER = "hibernate.classloader.tccl_lookup";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Names the {@link ClassLoader} used to load user application classes.
|
* Names the {@link ClassLoader} used to load user application classes.
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import javax.persistence.AttributeConverter;
|
import javax.persistence.AttributeConverter;
|
||||||
|
@ -44,6 +45,7 @@ import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
|
||||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService.TCCLLookupBehavior;
|
||||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||||
import org.hibernate.boot.spi.MetadataBuilderImplementor;
|
import org.hibernate.boot.spi.MetadataBuilderImplementor;
|
||||||
|
@ -390,6 +392,15 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
|
||||||
bsrBuilder.applyClassLoader( (ClassLoader) classLoadersSetting );
|
bsrBuilder.applyClassLoader( (ClassLoader) classLoadersSetting );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//configurationValues not assigned yet, using directly the properties of the PU
|
||||||
|
Properties puProperties = persistenceUnit.getProperties();
|
||||||
|
if( puProperties != null ) {
|
||||||
|
final String tcclBehavior = puProperties.getProperty( org.hibernate.cfg.AvailableSettings.TC_CLASSLOADER );
|
||||||
|
if( tcclBehavior != null ) {
|
||||||
|
bsrBuilder.applyTCCLBehavior( TCCLLookupBehavior.valueOf( tcclBehavior.toUpperCase() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bsrBuilder.build();
|
return bsrBuilder.build();
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.boot.registry.classloading.internal;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Cedric Tabin
|
||||||
|
*/
|
||||||
|
public class ClassLoaderServiceImplTest {
|
||||||
|
@Test
|
||||||
|
public void testNullTCCL() {
|
||||||
|
ClassLoaderServiceImpl csi = new ClassLoaderServiceImpl();
|
||||||
|
Thread.currentThread().setContextClassLoader(null);
|
||||||
|
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.BEFORE);
|
||||||
|
Class<ClassLoaderServiceImplTest> clazz1 = csi.classForName(ClassLoaderServiceImplTest.class.getName());
|
||||||
|
assertEquals(ClassLoaderServiceImplTest.class, clazz1);
|
||||||
|
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.AFTER);
|
||||||
|
Class<ClassLoaderServiceImplTest> clazz2 = csi.classForName(ClassLoaderServiceImplTest.class.getName());
|
||||||
|
assertEquals(ClassLoaderServiceImplTest.class, clazz2);
|
||||||
|
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.NEVER);
|
||||||
|
Class<ClassLoaderServiceImplTest> clazz3 = csi.classForName(ClassLoaderServiceImplTest.class.getName());
|
||||||
|
assertEquals(ClassLoaderServiceImplTest.class, clazz3);
|
||||||
|
|
||||||
|
csi.stop();
|
||||||
|
try { csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.BEFORE); assertTrue(false); } catch (Exception e) { }
|
||||||
|
try { csi.getTTCLLookupBehavior(); assertTrue(false); } catch (Exception e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLookupBefore() {
|
||||||
|
InternalClassLoader icl = new InternalClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(icl);
|
||||||
|
|
||||||
|
ClassLoaderServiceImpl csi = new ClassLoaderServiceImpl();
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.BEFORE);
|
||||||
|
Class<ClassLoaderServiceImplTest> clazz = csi.classForName(ClassLoaderServiceImplTest.class.getName());
|
||||||
|
assertEquals(ClassLoaderServiceImplTest.class, clazz);
|
||||||
|
assertEquals(1, icl.accessCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLookupAfterAvoided() {
|
||||||
|
InternalClassLoader icl = new InternalClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(icl);
|
||||||
|
|
||||||
|
ClassLoaderServiceImpl csi = new ClassLoaderServiceImpl();
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.AFTER);
|
||||||
|
Class<ClassLoaderServiceImplTest> clazz = csi.classForName(ClassLoaderServiceImplTest.class.getName());
|
||||||
|
assertEquals(ClassLoaderServiceImplTest.class, clazz);
|
||||||
|
assertEquals(0, icl.accessCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLookupAfter() {
|
||||||
|
InternalClassLoader icl = new InternalClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(icl);
|
||||||
|
|
||||||
|
ClassLoaderServiceImpl csi = new ClassLoaderServiceImpl();
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.AFTER);
|
||||||
|
try { csi.classForName("test.class.name"); assertTrue(false); }
|
||||||
|
catch (Exception e) {}
|
||||||
|
assertEquals(1, icl.accessCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLookupAfterNotFound() {
|
||||||
|
InternalClassLoader icl = new InternalClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(icl);
|
||||||
|
|
||||||
|
ClassLoaderServiceImpl csi = new ClassLoaderServiceImpl();
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.AFTER);
|
||||||
|
try { csi.classForName("test.class.not.found"); assertTrue(false); }
|
||||||
|
catch (Exception e) { }
|
||||||
|
assertEquals(1, icl.accessCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLookupNever() {
|
||||||
|
InternalClassLoader icl = new InternalClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(icl);
|
||||||
|
|
||||||
|
ClassLoaderServiceImpl csi = new ClassLoaderServiceImpl();
|
||||||
|
csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.NEVER);
|
||||||
|
try { csi.classForName("test.class.name"); assertTrue(false); }
|
||||||
|
catch (Exception e) { }
|
||||||
|
assertEquals(0, icl.accessCount);
|
||||||
|
|
||||||
|
csi.stop();
|
||||||
|
try { csi.setTCCLLookupBehavior(ClassLoaderService.TCCLLookupBehavior.BEFORE); assertTrue(false); } catch (Exception e) { }
|
||||||
|
try { csi.getTTCLLookupBehavior(); assertTrue(false); } catch (Exception e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class InternalClassLoader extends ClassLoader {
|
||||||
|
private int accessCount = 0;
|
||||||
|
|
||||||
|
public InternalClassLoader() { super(null); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
++accessCount;
|
||||||
|
return super.loadClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URL findResource(String name) {
|
||||||
|
++accessCount;
|
||||||
|
return super.findResource(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue