package ru.vyarus.dropwizard.guice.module.jersey.debug.service;
import com.google.common.collect.Lists;
import ru.vyarus.dropwizard.guice.module.installer.FeatureInstaller;
import ru.vyarus.dropwizard.guice.module.installer.install.JerseyInstaller;
import ru.vyarus.dropwizard.guice.module.installer.internal.ExtensionsHolder;
import ru.vyarus.dropwizard.guice.module.installer.util.JerseyBinding;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Debug service checks and collect information on jersey (and hk) related types instantiation.
* Actual bean instantiation detection by guice or hk is performed by specific listeners.
* Service only checks correctness and tracks instantiated objects.
* <p>
* Only objects installed by {@link JerseyInstaller} installers are tracked.
*
* @author Vyacheslav Rusakov
* @since 15.01.2016
*/
@Singleton
public class ContextDebugService {
private final Provider<ExtensionsHolder> holder;
private final List<Class<?>> hkManaged = Lists.newArrayList();
private final List<Class<?>> guiceManaged = Lists.newArrayList();
private final Lock lock = new ReentrantLock();
private List<Class<?>> managedTypes;
@Inject
public ContextDebugService(final Provider<ExtensionsHolder> holder) {
this.holder = holder;
}
/**
* @return list of all types that must be tracked
*/
public List<Class<?>> getManagedTypes() {
if (managedTypes == null) {
lock.lock();
try {
if (managedTypes == null) {
managedTypes = buildManagedTypes();
}
} finally {
lock.unlock();
}
}
return managedTypes;
}
/**
* Called by specific hk lifecycle listener to check if bean is properly instantiated by HK.
*
* @param type instantiated bean type
*/
public void hkManage(final Class<?> type) {
if (!JerseyBinding.isHK2Managed(type)) {
throw new WrongContextException("HK2 creates service %s which must be managed by guice.",
type.getName());
}
hkManaged.add(type);
}
/**
* Called by specific guice provision listener to check if bean is properly instantiated by guice.
*
* @param type instantiated bean type
*/
public void guiceManage(final Class<?> type) {
if (JerseyBinding.isHK2Managed(type)) {
throw new WrongContextException("Guice creates service %s which must be managed by HK2.",
type.getName());
}
guiceManaged.add(type);
}
/**
* @return classes of all tracked beans instantiated by hk (so far)
*/
public List<Class<?>> getHkManaged() {
return Lists.newArrayList(hkManaged);
}
/**
* @return classes of all tracked beans instantiated by guice (so far)
*/
public List<Class<?>> getGuiceManaged() {
return Lists.newArrayList(guiceManaged);
}
private List<Class<?>> buildManagedTypes() {
final List<Class<?>> managedTypes = Lists.newArrayList();
for (Class<? extends FeatureInstaller> installer : holder.get().getInstallerTypes()) {
if (!(JerseyInstaller.class.isAssignableFrom(installer))) {
continue;
}
final List<Class<?>> features = holder.get().getExtensions(installer);
if (features != null) {
managedTypes.addAll(features);
}
}
return managedTypes;
}
}