mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 17:05:43 +01:00
close every registered Closeable, instead of explicitly close a special set of instances
This commit is contained in:
56
scm-webapp/src/main/java/sonia/scm/CloseableModule.java
Normal file
56
scm-webapp/src/main/java/sonia/scm/CloseableModule.java
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package sonia.scm;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
import com.google.inject.spi.InjectionListener;
|
||||||
|
import com.google.inject.spi.TypeEncounter;
|
||||||
|
import com.google.inject.spi.TypeListener;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import sonia.scm.util.IOUtil;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
|
|
||||||
|
public final class CloseableModule extends AbstractModule {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CloseableModule.class);
|
||||||
|
|
||||||
|
private final Deque<WeakReference<Closeable>> closeables = new ConcurrentLinkedDeque<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindListener(MoreMatchers.isSubtypeOf(Closeable.class), new TypeListener() {
|
||||||
|
@Override
|
||||||
|
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
|
||||||
|
encounter.register((InjectionListener<I>) instance -> {
|
||||||
|
LOG.debug("register closable {}", instance.getClass());
|
||||||
|
Closeable closeable = (Closeable) instance;
|
||||||
|
closeables.push(new WeakReference<>(closeable));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bind(CloseableModule.class).toInstance(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeAll() {
|
||||||
|
LOG.debug("close all registered closeables");
|
||||||
|
WeakReference<Closeable> reference = closeables.poll();
|
||||||
|
while (reference != null) {
|
||||||
|
Closeable closeable = reference.get();
|
||||||
|
close(closeable);
|
||||||
|
reference = closeables.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close(Closeable closeable) {
|
||||||
|
if (closeable != null) {
|
||||||
|
LOG.trace("close closeable instance of {}", closeable);
|
||||||
|
IOUtil.close(closeable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
60
scm-webapp/src/main/java/sonia/scm/MoreMatchers.java
Normal file
60
scm-webapp/src/main/java/sonia/scm/MoreMatchers.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package sonia.scm;
|
||||||
|
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
import com.google.inject.matcher.AbstractMatcher;
|
||||||
|
import com.google.inject.matcher.Matcher;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper methods for Guice matchers, which are not already provided in {@link com.google.inject.matcher.Matchers}.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final class MoreMatchers {
|
||||||
|
|
||||||
|
private MoreMatchers() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a matcher which matches TypeListerals which are annotated with the given annotation.
|
||||||
|
*
|
||||||
|
* @param annotation annotation to match
|
||||||
|
*
|
||||||
|
* @return annotation matcher
|
||||||
|
*/
|
||||||
|
static Matcher<TypeLiteral> isAnnotatedWith(final Class<? extends Annotation> annotation) {
|
||||||
|
return new AbstractMatcher<TypeLiteral>() {
|
||||||
|
@Override
|
||||||
|
public boolean matches(TypeLiteral type) {
|
||||||
|
return type.getRawType().isAnnotationPresent(annotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a matcher which maches TypeLiterals which are sub types of the given class.
|
||||||
|
*
|
||||||
|
* @param supertype sub type to match
|
||||||
|
*
|
||||||
|
* @return sub type matcher
|
||||||
|
*/
|
||||||
|
static Matcher<TypeLiteral> isSubtypeOf(final Class supertype) {
|
||||||
|
return isSubtypeOf(TypeLiteral.get(supertype));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Matcher<TypeLiteral> isSubtypeOf(final TypeLiteral supertype) {
|
||||||
|
return new AbstractMatcher<TypeLiteral>() {
|
||||||
|
@Override
|
||||||
|
public boolean matches(TypeLiteral type) {
|
||||||
|
return typeIsSubtypeOf(type, supertype);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean typeIsSubtypeOf(TypeLiteral subtype, TypeLiteral supertype) {
|
||||||
|
// First check that raw types are compatible
|
||||||
|
// Then check that generic types are compatible! HOW????
|
||||||
|
return (subtype.equals(supertype)
|
||||||
|
|| (supertype.getRawType().isAssignableFrom(subtype.getRawType())
|
||||||
|
&& supertype.equals(subtype.getSupertype(supertype.getRawType()))));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -174,20 +174,7 @@ public class ScmContextListener extends GuiceResteasyBootstrapServletContextList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void closeCloseables() {
|
private void closeCloseables() {
|
||||||
// close Scheduler
|
injector.getInstance(CloseableModule.class).closeAll();
|
||||||
IOUtil.close(injector.getInstance(Scheduler.class));
|
|
||||||
|
|
||||||
// close RepositoryManager
|
|
||||||
IOUtil.close(injector.getInstance(RepositoryManager.class));
|
|
||||||
|
|
||||||
// close GroupManager
|
|
||||||
IOUtil.close(injector.getInstance(GroupManager.class));
|
|
||||||
|
|
||||||
// close UserManager
|
|
||||||
IOUtil.close(injector.getInstance(UserManager.class));
|
|
||||||
|
|
||||||
// close CacheManager
|
|
||||||
IOUtil.close(injector.getInstance(CacheManager.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void destroyServletContextListeners(ServletContextEvent event) {
|
private void destroyServletContextListeners(ServletContextEvent event) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.google.inject.Guice;
|
|||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Module;
|
import com.google.inject.Module;
|
||||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||||
|
import sonia.scm.CloseableModule;
|
||||||
import sonia.scm.EagerSingletonModule;
|
import sonia.scm.EagerSingletonModule;
|
||||||
import sonia.scm.SCMContext;
|
import sonia.scm.SCMContext;
|
||||||
import sonia.scm.ScmContextListener;
|
import sonia.scm.ScmContextListener;
|
||||||
@@ -123,6 +124,7 @@ public class BootstrapContextListener implements ServletContextListener {
|
|||||||
BootstrapModule bootstrapModule = new BootstrapModule(pluginLoader);
|
BootstrapModule bootstrapModule = new BootstrapModule(pluginLoader);
|
||||||
ScmInitializerModule scmInitializerModule = new ScmInitializerModule();
|
ScmInitializerModule scmInitializerModule = new ScmInitializerModule();
|
||||||
EagerSingletonModule eagerSingletonModule = new EagerSingletonModule();
|
EagerSingletonModule eagerSingletonModule = new EagerSingletonModule();
|
||||||
|
CloseableModule closeableModule = new CloseableModule();
|
||||||
ScmEventBusModule scmEventBusModule = new ScmEventBusModule();
|
ScmEventBusModule scmEventBusModule = new ScmEventBusModule();
|
||||||
|
|
||||||
return Guice.createInjector(
|
return Guice.createInjector(
|
||||||
@@ -130,7 +132,8 @@ public class BootstrapContextListener implements ServletContextListener {
|
|||||||
scmContextListenerModule,
|
scmContextListenerModule,
|
||||||
scmEventBusModule,
|
scmEventBusModule,
|
||||||
scmInitializerModule,
|
scmInitializerModule,
|
||||||
eagerSingletonModule
|
eagerSingletonModule,
|
||||||
|
closeableModule
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
32
scm-webapp/src/test/java/sonia/scm/CloseableModuleTest.java
Normal file
32
scm-webapp/src/test/java/sonia/scm/CloseableModuleTest.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package sonia.scm;
|
||||||
|
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class CloseableModuleTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldCloseCloseables() {
|
||||||
|
Injector injector = Guice.createInjector(new CloseableModule());
|
||||||
|
CloseMe closeMe = injector.getInstance(CloseMe.class);
|
||||||
|
|
||||||
|
injector.getInstance(CloseableModule.class).closeAll();
|
||||||
|
assertThat(closeMe.closed).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CloseMe implements Closeable {
|
||||||
|
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
scm-webapp/src/test/java/sonia/scm/MoreMatchersTest.java
Normal file
40
scm-webapp/src/test/java/sonia/scm/MoreMatchersTest.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package sonia.scm;
|
||||||
|
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
import com.google.inject.matcher.Matcher;
|
||||||
|
import org.assertj.core.api.AbstractBooleanAssert;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class MoreMatchersTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldMatchSubTypes() {
|
||||||
|
Matcher<TypeLiteral> matcher = MoreMatchers.isSubtypeOf(Serializable.class);
|
||||||
|
assertBoolean(matcher, One.class).isTrue();
|
||||||
|
assertBoolean(matcher, Two.class).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldMatchIfAnnotated() {
|
||||||
|
Matcher<TypeLiteral> matcher = MoreMatchers.isAnnotatedWith(Singleton.class);
|
||||||
|
assertBoolean(matcher, One.class).isFalse();
|
||||||
|
assertBoolean(matcher, Two.class).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractBooleanAssert<?> assertBoolean(Matcher<TypeLiteral> matcher, Class<?> clazz) {
|
||||||
|
return assertThat(matcher.matches(TypeLiteral.get(clazz)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class One implements Serializable {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public static class Two {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user