essential problem from Issue 803:lifecycle calls such as executorService.close() not called

This commit is contained in:
Adrian Cole 2012-01-07 05:12:49 -08:00
parent 0f71ae1596
commit ef021720b1
3 changed files with 45 additions and 16 deletions

View File

@ -35,10 +35,13 @@ import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.Constants;
import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.lifecycle.Closer;
import com.google.common.util.concurrent.ExecutionList;
import com.google.inject.AbstractModule;
import com.google.inject.ProvisionException;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
@ -49,6 +52,15 @@ import com.google.inject.spi.TypeListener;
* {@link PostConstruct} after injection, and Associate {@link PreDestroy} with a global
* {@link Closer} object.
*
* <h3>Important</h3> Make sure you create your injector with {@link Stage#PRODUCTION} and execute
* the bound {@link ExecutionList} prior to using any other objects.
*
* <p/>
* Ex.
* <pre>
*
* </pre>
*
* @author Adrian Cole
*/
public class LifeCycleModule extends AbstractModule {
@ -75,10 +87,13 @@ public class LifeCycleModule extends AbstractModule {
Closer closer = new Closer();
closer.addToClose(executorCloser);
bind(Closer.class).toInstance(closer);
bindPostInjectionInvoke(closer);
ExecutionList list = new ExecutionList();
bindPostInjectionInvoke(closer, list);
bind(ExecutionList.class).toInstance(list);
}
protected void bindPostInjectionInvoke(final Closer closer) {
protected void bindPostInjectionInvoke(final Closer closer, final ExecutionList list) {
bindListener(any(), new TypeListener() {
public <I> void hear(TypeLiteral<I> injectableType, TypeEncounter<I> encounter) {
Set<Method> methods = new HashSet<Method>();
@ -93,8 +108,8 @@ public class LifeCycleModule extends AbstractModule {
}
}
private <I> void associatePreDestroyWithCloser(final Closer closer,
TypeEncounter<I> encounter, final Method method) {
private <I> void associatePreDestroyWithCloser(final Closer closer, TypeEncounter<I> encounter,
final Method method) {
PreDestroy preDestroy = method.getAnnotation(PreDestroy.class);
if (preDestroy != null) {
encounter.register(new InjectionListener<I>() {
@ -117,20 +132,23 @@ public class LifeCycleModule extends AbstractModule {
}
}
private <I> void invokePostConstructMethodAfterInjection(TypeEncounter<I> encounter,
final Method method) {
private <I> void invokePostConstructMethodAfterInjection(TypeEncounter<I> encounter, final Method method) {
PostConstruct postConstruct = method.getAnnotation(PostConstruct.class);
if (postConstruct != null) {
encounter.register(new InjectionListener<I>() {
public void afterInjection(I injectee) {
try {
method.invoke(injectee);
} catch (InvocationTargetException ie) {
Throwable e = ie.getTargetException();
throw new ProvisionException(e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new ProvisionException(e.getMessage(), e);
}
public void afterInjection(final I injectee) {
list.add(new Runnable() {
public void run() {
try {
method.invoke(injectee);
} catch (InvocationTargetException ie) {
Throwable e = ie.getTargetException();
throw new ProvisionException(e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new ProvisionException(e.getMessage(), e);
}
}
}, MoreExecutors.sameThreadExecutor());
}
});
}

View File

@ -58,6 +58,7 @@ import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.lifecycle.config.LifeCycleModule;
import org.jclouds.location.Iso3166;
import org.jclouds.location.Provider;
import org.jclouds.location.config.ProvideIso3166CodesByLocationIdViaProperties;
@ -80,12 +81,14 @@ import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.ExecutionList;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
/**
@ -194,8 +197,11 @@ public class RestContextBuilder<S, A> {
ifHttpConfigureRestOtherwiseGuiceClientFactory(modules);
addExecutorServiceIfNotPresent(modules);
addCredentialStoreIfNotPresent(modules);
modules.add(new LifeCycleModule());
modules.add(new BindPropertiesAndPrincipalContext(properties));
return Guice.createInjector(modules);
Injector returnVal = Guice.createInjector(Stage.PRODUCTION, modules);
returnVal.getInstance(ExecutionList.class).execute();
return returnVal;
}
@VisibleForTesting

View File

@ -27,6 +27,8 @@ import javax.inject.Named;
import org.jclouds.Constants;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.lifecycle.Closer;
import com.google.common.util.concurrent.ExecutionList;
import com.google.inject.name.Names;
import org.testng.annotations.Test;
@ -75,6 +77,9 @@ public class LifeCycleModuleTest {
return 1;
}
}, new ExecutorServiceModule());
// TODO: currently have to manually invoke the execution list, as otherwise it may occur
// before everything is wired up
i.getInstance(ExecutionList.class).execute();
return i;
}