Skip to content

Instantly share code, notes, and snippets.

@jdcasey
Created January 25, 2018 05:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdcasey/191d8a53dbbbd06e44799c5e5aef1e9a to your computer and use it in GitHub Desktop.
Save jdcasey/191d8a53dbbbd06e44799c5e5aef1e9a to your computer and use it in GitHub Desktop.
test that demonstrates resources escaping control of weft ThreadContext
package org.commonjava.cdi.util.weft;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Created by jdcasey on 1/24/18.
*/
public class ThreadContext_EscapingResourceTest
{
@Test
public void resourcesEscapingContextAreNotSafe()
throws InterruptedException
{
Resource res = new Resource();
ExecutorService external = Executors.newFixedThreadPool( 1, new NamedThreadFactory( "external", true, 10 ) );
NamedThreadFactory fac = new NamedThreadFactory( "internal", true, 10 );
ContextSensitiveExecutorService internal =
new ContextSensitiveExecutorService( Executors.newFixedThreadPool( 1, fac ) );
ThreadContext ctx = ThreadContext.getContext( true );
ctx.put( Resource.class.getSimpleName(), res );
CountDownLatch waitInternalClose = new CountDownLatch( 1 );
CountDownLatch waitExternalClose = new CountDownLatch( 1 );
CountDownLatch waitInternalEnd = new CountDownLatch( 1 );
CountDownLatch waitAll = new CountDownLatch( 2 );
Logger logger = LoggerFactory.getLogger( getClass() );
AtomicBoolean externalClosed = new AtomicBoolean( false );
external.execute( ()->{
try
{
logger.info("Waiting for external proceed signal");
waitExternalClose.await();
logger.info("Proceeding with external close()");
externalClosed.set( res.close() );
logger.info("External close called.");
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
logger.info( "Counting down all-latch" );
waitAll.countDown();
}
} );
AtomicBoolean internalHasResource = new AtomicBoolean( false );
internal.execute( ()->{
try
{
logger.info("Waiting for internal proceed signal");
waitInternalClose.await();
logger.info( "Retrieving context" );
ThreadContext context = ThreadContext.getContext( false );
Object resource = context.get( Resource.class.getSimpleName() );
logger.info( "Internal user has resource: {}", resource );
internalHasResource.set( resource != null );
logger.info( "Waiting for internal end signal" );
waitInternalEnd.await();
logger.info( "Ending internal processor" );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
logger.info( "Counting down all-latch" );
waitAll.countDown();
}
} );
AtomicBoolean finalizerClosed = new AtomicBoolean( false );
logger.info( "Registering finalizer in context" );
ctx.registerFinalizer( (c)->{
logger.info( "Finalizer retrieving resource" );
Resource r = (Resource) c.get( Resource.class.getSimpleName() );
boolean closed = r != null && r.close();
logger.info( "Finalizer closed resource? {}", closed );
finalizerClosed.set( closed );
logger.info( "Signaling external proceed from finalizer" );
waitExternalClose.countDown();
} );
logger.info( "Signaling internal proceed from main thread" );
waitInternalClose.countDown();
logger.info( "Clearing context from main thread" );
ThreadContext.clearContext();
logger.info( "Signaling internal end" );
waitInternalEnd.countDown();
logger.info( "Waiting for all handlers to complete" );
waitAll.await();
assertThat( externalClosed.get(), equalTo( false ) );
assertThat( finalizerClosed.get(), equalTo( true ) );
assertThat( internalHasResource.get(), equalTo( true ) );
}
public static final class Resource
{
private boolean closed;
public synchronized boolean close()
{
if ( closed )
{
return false;
}
closed = true;
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment