package ameba.container.internal;
import com.google.common.collect.Iterables;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.inject.Providers;
import org.glassfish.jersey.server.ApplicationHandler;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spi.AbstractContainerLifecycleListener;
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.ContainerLifecycleListener;
import javax.ws.rs.core.Application;
import java.util.LinkedList;
/**
* <p>ConfigHelper class.</p>
*
* @author icode
*
*/
public class ConfigHelper {
/**
* Prevents instantiation.
*/
private ConfigHelper() {
}
/**
* Provides a single ContainerLifecycleListener instance based on the {@link ApplicationHandler application} configuration.
* This method looks for providers implementing {@link org.glassfish.jersey.server.spi.ContainerLifecycleListener} interface and aggregates them into
* a single umbrella listener instance that is returned.
*
* @param applicationHandler actual application from where to get the listener.
* @return a single instance of a ContainerLifecycleListener, can not be null.
*/
public static LifecycleListener getContainerLifecycleListener(final ApplicationHandler applicationHandler) {
final Iterable<ContainerLifecycleListener> listeners = Iterables.concat(
Providers.getAllProviders(applicationHandler.getInjectionManager(), ContainerLifecycleListener.class),
new LinkedList<ContainerLifecycleListener>() {{
add(new ServiceLocatorShutdownListener());
}});
return new LifecycleListener() {
@Override
public void onReloadShutdown(Container container, Runnable tryScope) {
for (final ContainerLifecycleListener listener : listeners) {
if (listener instanceof ServiceLocatorShutdownListener) {
container = new ContainerDelegate(container);
tryScope.run();
}
listener.onShutdown(container);
}
}
@Override
public void onStartup(final Container container) {
for (final ContainerLifecycleListener listener : listeners) {
listener.onStartup(container);
}
}
@Override
public void onReload(final Container container) {
for (final ContainerLifecycleListener listener : listeners) {
listener.onReload(container);
}
}
@Override
public void onShutdown(final Container container) {
for (final ContainerLifecycleListener listener : listeners) {
listener.onShutdown(container);
}
}
};
}
/**
* Gets the most internal wrapped {@link Application application} class. This method is similar to
* {@link org.glassfish.jersey.server.ResourceConfig#getApplication()} except if provided application was created by wrapping multiple
* {@link org.glassfish.jersey.server.ResourceConfig} instances this method returns the original application and not a resource config wrapper.
*
* @param app jax-rs application
* @return the original {@link javax.ws.rs.core.Application} subclass.
*/
public static Application getWrappedApplication(Application app) {
while (app instanceof ResourceConfig) {
final Application wrappedApplication = ((ResourceConfig) app).getApplication();
if (wrappedApplication == app) {
break;
}
app = wrappedApplication;
}
return app;
}
public static class ServiceLocatorShutdownListener extends AbstractContainerLifecycleListener {
@Override
public void onShutdown(final Container container) {
final ApplicationHandler handler = container.getApplicationHandler();
final InjectionManager injectionManager = handler.getInjectionManager();
// Call @PreDestroy method on Application.
injectionManager.preDestroy(getWrappedApplication(handler.getConfiguration()));
// Shutdown ServiceLocator.
injectionManager.shutdown();
}
}
private static class ContainerDelegate implements Container {
private Container container;
private ResourceConfig config;
private ApplicationHandler handler;
public ContainerDelegate(Container container) {
this.container = container;
this.config = container.getConfiguration();
this.handler = container.getApplicationHandler();
}
@Override
public ResourceConfig getConfiguration() {
return config;
}
@Override
public ApplicationHandler getApplicationHandler() {
return handler;
}
@Override
public void reload() {
container.reload();
}
@Override
public void reload(ResourceConfig configuration) {
container.reload(configuration);
}
}
public static abstract class LifecycleListener implements ContainerLifecycleListener {
/**
* use for reload Container.
* <p>
* the tryScope must run success then shutdown ServiceLocator
* <p>
* otherwise not shut down ServiceLocator
*
* @param container {@link Container}
* @param tryScope try scope
*/
public abstract void onReloadShutdown(final Container container, Runnable tryScope);
}
}