diff --git a/scm-core/src/main/java/sonia/scm/EagerSingleton.java b/scm-core/src/main/java/sonia/scm/EagerSingleton.java index cf68506cbe..e79d042990 100644 --- a/scm-core/src/main/java/sonia/scm/EagerSingleton.java +++ b/scm-core/src/main/java/sonia/scm/EagerSingleton.java @@ -30,12 +30,9 @@ */ + package sonia.scm; -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.ScopeAnnotation; - //~--- JDK imports ------------------------------------------------------------ import java.lang.annotation.ElementType; @@ -51,5 +48,4 @@ import java.lang.annotation.Target; */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) -@ScopeAnnotation public @interface EagerSingleton {} diff --git a/scm-webapp/src/main/java/sonia/scm/EagerSingletonModule.java b/scm-webapp/src/main/java/sonia/scm/EagerSingletonModule.java new file mode 100644 index 0000000000..29bc22ac52 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/EagerSingletonModule.java @@ -0,0 +1,132 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.collect.Sets; +import com.google.inject.AbstractModule; +import com.google.inject.Injector; +import com.google.inject.TypeLiteral; +import com.google.inject.matcher.AbstractMatcher; +import com.google.inject.matcher.Matcher; +import com.google.inject.spi.TypeEncounter; +import com.google.inject.spi.TypeListener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +//~--- JDK imports ------------------------------------------------------------ + +import java.lang.annotation.Annotation; + +import java.util.Set; + +/** + * + * @author Sebastian Sdorra + */ +public class EagerSingletonModule extends AbstractModule +{ + + /** + * the logger for EagerSingletonModule + */ + private static final Logger logger = + LoggerFactory.getLogger(EagerSingletonModule.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param injector + */ + void initialize(Injector injector) + { + for (Class clazz : eagerSingletons) + { + logger.info("initialize eager singleton {}", clazz.getName()); + injector.getInstance(clazz); + } + } + + /** + * Method description + * + */ + @Override + protected void configure() + { + bindListener(isAnnotatedWith(EagerSingleton.class), new TypeListener() + { + + @Override + public void hear(TypeLiteral type, TypeEncounter encounter) + { + eagerSingletons.add(type.getRawType()); + } + }); + + bind(EagerSingletonModule.class).toInstance(this); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * + * @param annotation + * + * @return + */ + private Matcher> isAnnotatedWith( + final Class annotation) + { + return new AbstractMatcher>() + { + @Override + public boolean matches(TypeLiteral type) + { + return type.getRawType().isAnnotationPresent(annotation); + } + }; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private final Set> eagerSingletons = Sets.newHashSet(); +} diff --git a/scm-webapp/src/main/java/sonia/scm/EagerSingletonScopeModule.java b/scm-webapp/src/main/java/sonia/scm/EagerSingletonScopeModule.java deleted file mode 100644 index 1206deaf18..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/EagerSingletonScopeModule.java +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.collect.Sets; -import com.google.inject.AbstractModule; -import com.google.inject.Binding; -import com.google.inject.Inject; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.Provider; -import com.google.inject.Scope; -import com.google.inject.Scopes; -import com.google.inject.TypeLiteral; -import com.google.inject.matcher.Matchers; -import com.google.inject.spi.BindingScopingVisitor; -import com.google.inject.spi.TypeEncounter; -import com.google.inject.spi.TypeListener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -//~--- JDK imports ------------------------------------------------------------ - -import java.lang.annotation.Annotation; - -import java.util.Set; - -/** - * - * @author Sebastian Sdorra - */ -public class EagerSingletonScopeModule extends AbstractModule -{ - - /** Field description */ - private static EagerSingletonScope EAGERSINGLETON_SCOPE = - new EagerSingletonScope(); - - /** - * the logger for EagerSingletonScopeModule - */ - private static final Logger logger = - LoggerFactory.getLogger(EagerSingletonScopeModule.class); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ - void bind() - { - for (Binding b : listener.eagerSingletons) - { - logger.info("initialize eager singleton {}", b.getKey()); - b.getProvider().get(); - } - - listener = null; - } - - /** - * Method description - * - */ - @Override - protected void configure() - { - bind(EagerSingletonScopeModule.class).toInstance(this); - bindScope(EagerSingleton.class, EAGERSINGLETON_SCOPE); - - listener = new EagerCreatingListener(); - - requestInjection(listener); - bindListener(Matchers.any(), listener); - } - - //~--- inner classes -------------------------------------------------------- - - /** - * Class description - * - * - * @version Enter version here..., 12/12/07 - * @author Enter your name here... - */ - private static class EagerCreatingListener implements TypeListener - { - - /** - * Method description - * - * - * @param type - * @param encounter - * @param - */ - @Override - public void hear(TypeLiteral type, TypeEncounter encounter) - { - if (injector != null) - { - appendIfEager(injector.getBinding(Key.get(type))); - } - } - - /** - * Method description - * - * - * @param injector - */ - @Inject - void injector(Injector injector) - { - this.injector = injector; - - for (Binding b : injector.getBindings().values()) - { - appendIfEager(b); - } - } - - /** - * Method description - * - * - * @param b - */ - private void appendIfEager(final Binding b) - { - b.acceptScopingVisitor(new BindingScopingVisitor() - { - @Override - public Void visitEagerSingleton() - { - return null; - } - - @Override - public Void visitNoScoping() - { - return null; - } - - @Override - public Void visitScope(Scope scope) - { - if (scope == EAGERSINGLETON_SCOPE) - { - eagerSingletons.add(b); - } - - return null; - } - - @Override - public Void visitScopeAnnotation( - Class scopeAnnotation) - { - return null; - } - }); - } - - //~--- fields ------------------------------------------------------------- - - /** Field description */ - private Set> eagerSingletons = Sets.newHashSet(); - - /** Field description */ - private Injector injector; - } - - - /** - * Class description - * - * - * @version Enter version here..., 12/12/07 - * @author Enter your name here... - */ - private static class EagerSingletonScope implements Scope - { - - /** - * Method description - * - * - * @param key - * @param unscoped - * @param - * - * @return - */ - @Override - public Provider scope(Key key, Provider unscoped) - { - return Scopes.SINGLETON.scope(key, unscoped); - } - } - - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private EagerCreatingListener listener; -} diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java index cf0107cd69..4fdf343e20 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java @@ -97,10 +97,11 @@ public class ScmContextListener extends GuiceServletContextListener // close CacheManager IOUtil.close(globalInjector.getInstance(CacheManager.class)); - // call destroy event - globalInjector.getInstance( - ServletContextListenerHolder.class).contextDestroyed( - servletContextEvent); + //J- + // call destroy of servlet context listeners + globalInjector.getInstance(ServletContextListenerHolder.class) + .contextDestroyed(servletContextEvent); + //J+ } super.contextDestroyed(servletContextEvent); @@ -133,12 +134,14 @@ public class ScmContextListener extends GuiceServletContextListener // call destroy event if ((globalInjector != null) &&!startupError) { - + //J- // bind eager singletons - globalInjector.getInstance(EagerSingletonScopeModule.class).bind(); - globalInjector.getInstance( - ServletContextListenerHolder.class).contextInitialized( - servletContextEvent); + globalInjector.getInstance(EagerSingletonModule.class) + .initialize(globalInjector); + // init servlet context listeners + globalInjector.getInstance(ServletContextListenerHolder.class) + .contextInitialized(servletContextEvent); + //J+ } } @@ -183,7 +186,7 @@ public class ScmContextListener extends GuiceServletContextListener moduleList.add(new ScmInitializerModule()); moduleList.add(new ScmSubscriberModule()); - moduleList.add(new EagerSingletonScopeModule()); + moduleList.add(new EagerSingletonModule()); moduleList.add(ShiroWebModule.guiceFilterModule()); moduleList.add(main); moduleList.add(new ScmSecurityModule(servletContext)); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/ext/ExtensionBinder.java b/scm-webapp/src/main/java/sonia/scm/plugin/ext/ExtensionBinder.java index 7d98f45ddf..c485db89cd 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/ext/ExtensionBinder.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/ext/ExtensionBinder.java @@ -30,6 +30,7 @@ */ + package sonia.scm.plugin.ext; //~--- non-JDK imports -------------------------------------------------------- @@ -37,12 +38,15 @@ package sonia.scm.plugin.ext; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.inject.Binder; +import com.google.inject.binder.ScopedBindingBuilder; import com.google.inject.multibindings.Multibinder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.EagerSingleton; import sonia.scm.plugin.ExtensionPoint; +import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ @@ -116,8 +120,16 @@ public class ExtensionBinder for (AnnotatedClass extension : extensionsCopy) { - logger.info("bind {}, without extensionpoint", - extension.getAnnotatedClass()); + boolean eagerSingleton = isEagerSingleton(extension.getAnnotatedClass()); + String as = Util.EMPTY_STRING; + + if (eagerSingleton) + { + as = " as eager singleton"; + } + + logger.info("bind {}{}, without extensionpoint", + extension.getAnnotatedClass(), as); binder.bind(extension.getAnnotatedClass()); } } @@ -174,14 +186,30 @@ public class ExtensionBinder if (extensionPointClass.isAssignableFrom(extensionClass)) { + boolean eagerSingleton = isEagerSingleton(extensionClass); + if (logger.isInfoEnabled()) { - logger.info("bind {} to multibinder of {}", extensionClass.getName(), - extensionPointClass.getName()); + String as = Util.EMPTY_STRING; + + if (eagerSingleton) + { + as = " as eager singleton"; + } + + logger.info("bind {} to multibinder of {}{}", + extensionClass.getName(), extensionPointClass.getName(), as); } found.add(extension); - multibinder.addBinding().to(extensionClass); + + ScopedBindingBuilder sbb = multibinder.addBinding().to(extensionClass); + + if (eagerSingleton) + { + sbb.asEagerSingleton(); + logger.info("bind {} as eager singleton"); + } } } } @@ -196,13 +224,43 @@ public class ExtensionBinder private void bindSingleInstance(Class extensionPointClass, Class extensionClass) { + boolean eagerSingleton = isEagerSingleton(extensionClass); + if (logger.isInfoEnabled()) { - logger.info("bind {} to {}", extensionClass.getName(), - extensionPointClass.getName()); + String as = Util.EMPTY_STRING; + + if (eagerSingleton) + { + as = " as eager singleton"; + } + + logger.info("bind {} to {}{}", extensionClass.getName(), + extensionPointClass.getName(), as); } - binder.bind(extensionPointClass).to(extensionClass); + ScopedBindingBuilder sbb = + binder.bind(extensionPointClass).to(extensionClass); + + if (eagerSingleton) + { + sbb.asEagerSingleton(); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param extensionClass + * + * @return + */ + private boolean isEagerSingleton(Class extensionClass) + { + return extensionClass.isAnnotationPresent(EagerSingleton.class); } //~--- fields ---------------------------------------------------------------