added modules, classloading and view packages to sonia.scm.lifecycle

This commit is contained in:
Sebastian Sdorra
2019-06-25 09:49:52 +02:00
parent 6efa6ff29f
commit 80febf9424
47 changed files with 105 additions and 107 deletions

View File

@@ -0,0 +1,74 @@
package sonia.scm.lifecycle.modules;
import com.google.common.base.Throwables;
import com.google.inject.Module;
import org.apache.shiro.guice.web.ShiroWebModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext;
import sonia.scm.Stage;
import sonia.scm.api.v2.resources.MapperModule;
import sonia.scm.debug.DebugModule;
import sonia.scm.filter.WebElementModule;
import sonia.scm.plugin.ExtensionProcessor;
import sonia.scm.plugin.PluginLoader;
import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.List;
public class ApplicationModuleProvider implements ModuleProvider {
private static final Logger LOG = LoggerFactory.getLogger(ApplicationModuleProvider.class);
private final ServletContext servletContext;
private final PluginLoader pluginLoader;
public ApplicationModuleProvider(ServletContext servletContext, PluginLoader pluginLoader) {
this.servletContext = servletContext;
this.pluginLoader = pluginLoader;
}
@Override
public List<Module> createModules() {
ClassOverrides overrides = createClassOverrides();
return createModules(overrides);
}
private List<Module> createModules(ClassOverrides overrides) {
List<Module> moduleList = new ArrayList<>();
moduleList.add(new ResteasyModule());
moduleList.add(ShiroWebModule.guiceFilterModule());
moduleList.add(new WebElementModule(pluginLoader));
moduleList.add(new ScmServletModule(pluginLoader, overrides));
moduleList.add(
new ScmSecurityModule(servletContext, pluginLoader.getExtensionProcessor())
);
appendModules(pluginLoader.getExtensionProcessor(), moduleList);
moduleList.addAll(overrides.getModules());
if (SCMContext.getContext().getStage() == Stage.DEVELOPMENT){
moduleList.add(new DebugModule());
}
moduleList.add(new MapperModule());
return moduleList;
}
private ClassOverrides createClassOverrides() {
ClassLoader uberClassLoader = pluginLoader.getUberClassLoader();
return ClassOverrides.findOverrides(uberClassLoader);
}
private void appendModules(ExtensionProcessor ep, List<Module> moduleList) {
for (Class<? extends Module> module : ep.byExtensionPoint(Module.class)) {
try {
LOG.info("add module {}", module);
moduleList.add(module.newInstance());
} catch (IllegalAccessException | InstantiationException ex) {
throw Throwables.propagate(ex);
}
}
}
}

View File

@@ -0,0 +1,85 @@
package sonia.scm.lifecycle.modules;
import com.google.inject.AbstractModule;
import com.google.inject.throwingproviders.ThrowingProviderBinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext;
import sonia.scm.SCMContextProvider;
import sonia.scm.io.DefaultFileSystem;
import sonia.scm.io.FileSystem;
import sonia.scm.plugin.PluginLoader;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.repository.xml.PathBasedRepositoryLocationResolver;
import sonia.scm.security.CipherHandler;
import sonia.scm.security.CipherUtil;
import sonia.scm.security.DefaultKeyGenerator;
import sonia.scm.security.KeyGenerator;
import sonia.scm.store.BlobStoreFactory;
import sonia.scm.store.ConfigurationEntryStoreFactory;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.store.DataStoreFactory;
import sonia.scm.store.FileBlobStoreFactory;
import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
import sonia.scm.store.JAXBConfigurationStoreFactory;
import sonia.scm.store.JAXBDataStoreFactory;
public class BootstrapModule extends AbstractModule {
private static final Logger LOG = LoggerFactory.getLogger(BootstrapModule.class);
private final ClassOverrides overrides;
private final PluginLoader pluginLoader;
public BootstrapModule(PluginLoader pluginLoader) {
this.overrides = ClassOverrides.findOverrides(pluginLoader.getUberClassLoader());
this.pluginLoader = pluginLoader;
}
@Override
protected void configure() {
install(ThrowingProviderBinder.forModule(this));
SCMContextProvider context = SCMContext.getContext();
bind(SCMContextProvider.class).toInstance(context);
bind(KeyGenerator.class).to(DefaultKeyGenerator.class);
bind(RepositoryLocationResolver.class).to(PathBasedRepositoryLocationResolver.class);
bind(FileSystem.class, DefaultFileSystem.class);
// note CipherUtil uses an other generator
bind(CipherHandler.class).toInstance(CipherUtil.getInstance().getCipherHandler());
// bind core
bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class);
bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class);
bind(DataStoreFactory.class, JAXBDataStoreFactory.class);
bind(BlobStoreFactory.class, FileBlobStoreFactory.class);
bind(PluginLoader.class).toInstance(pluginLoader);
}
private <T> void bind(Class<T> clazz, Class<? extends T> defaultImplementation) {
Class<? extends T> implementation = find(clazz, defaultImplementation);
LOG.debug("bind {} to {}", clazz, implementation);
bind(clazz).to(implementation);
}
private <T> Class<? extends T> find(Class<T> clazz, Class<? extends T> defaultImplementation) {
Class<? extends T> implementation = overrides.getOverride(clazz);
if (implementation != null) {
LOG.info("found override {} for {}", implementation, clazz);
} else {
implementation = defaultImplementation;
LOG.trace(
"no override available for {}, using default implementation {}",
clazz, implementation);
}
return implementation;
}
}

View File

@@ -0,0 +1,176 @@
/**
* 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.lifecycle.modules;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import sonia.scm.Validateable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class ClassOverride implements Validateable
{
/**
* Method description
*
*
* @param obj
*
* @return
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final ClassOverride other = (ClassOverride) obj;
return Objects.equal(bind, other.bind) && Objects.equal(to, other.to);
}
/**
* Method description
*
*
* @return
*/
@Override
public int hashCode()
{
return Objects.hashCode(bind, to);
}
/**
* Method description
*
*
* @return
*/
@Override
public String toString()
{
//J-
return MoreObjects.toStringHelper(this)
.add("bind", bind)
.add("to", to)
.toString();
//J+
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public Class<?> getBind()
{
return bind;
}
/**
* Method description
*
*
* @return
*/
public Class<?> getTo()
{
return to;
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isValid()
{
return (bind != null) && (to != null);
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param bind
*/
public void setBind(Class<?> bind)
{
this.bind = bind;
}
/**
* Method description
*
*
* @param to
*/
public void setTo(Class<?> to)
{
this.to = to;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private Class<?> bind;
/** Field description */
private Class<?> to;
}

View File

@@ -0,0 +1,326 @@
/**
* 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.lifecycle.modules;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.inject.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.ClassLoaders;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement(name = "overrides")
@XmlAccessorType(XmlAccessType.FIELD)
public class ClassOverrides implements Iterable<ClassOverride>
{
/** Field description */
public static final String OVERRIDE_PATH = "META-INF/scm/override.xml";
/**
* the logger for ClassOverrides
*/
private static final Logger logger =
LoggerFactory.getLogger(ClassOverrides.class);
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
*
* @param classLoader
* @return
*
*/
public static ClassOverrides findOverrides(ClassLoader classLoader)
{
final ClassOverrides overrides = new ClassOverrides();
try
{
final Enumeration<URL> overridesEnm =
classLoader.getResources(OVERRIDE_PATH);
final JAXBContext context = JAXBContext.newInstance(ClassOverrides.class);
ClassLoaders.executeInContext(classLoader, new Runnable()
{
@Override
public void run()
{
while (overridesEnm.hasMoreElements())
{
URL overrideUrl = overridesEnm.nextElement();
if (logger.isInfoEnabled())
{
logger.info("load override from {}",
overrideUrl.toExternalForm());
}
try
{
ClassOverrides co =
(ClassOverrides) context.createUnmarshaller().unmarshal(
overrideUrl);
overrides.append(co);
}
catch (JAXBException ex)
{
logger.error(
"could not load ".concat(overrideUrl.toExternalForm()), ex);
}
}
}
});
}
catch (IOException ex)
{
logger.error("could not load overrides", ex);
}
catch (JAXBException ex)
{
logger.error("could not create jaxb context for ClassOverrides", ex);
}
return overrides;
}
/**
* Method description
*
*
* @param overrides
*/
public void append(ClassOverrides overrides)
{
AssertUtil.assertIsNotNull(overrides);
for (ClassOverride co : overrides)
{
if (co.isValid())
{
getOverrides().add(co);
}
else if (logger.isWarnEnabled())
{
logger.warn("could not append ClassOverride, because it is not valid");
}
}
getModuleClasses().addAll(overrides.getModuleClasses());
}
/**
* Method description
*
*
* @return
*/
@Override
public Iterator<ClassOverride> iterator()
{
return getOverrides().iterator();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<Class<? extends Module>> getModuleClasses()
{
if (moduleClasses == null)
{
moduleClasses = Lists.newArrayList();
}
return moduleClasses;
}
/**
* Method description
*
*
* @return
*/
@SuppressWarnings("unchecked")
public List<? extends Module> getModules()
{
List<? extends Module> modules;
if (Util.isNotEmpty(moduleClasses))
{
modules = Lists.transform(moduleClasses,
new Function<Class<? extends Module>, Module>()
{
@Override
public Module apply(Class<? extends Module> moduleClass)
{
Module module = null;
try
{
module = moduleClass.newInstance();
}
catch (IllegalAccessException | InstantiationException ex)
{
logger.error(
"could not create module instance of ".concat(
moduleClass.getName()), ex);
}
return module;
}
});
}
else
{
modules = Collections.EMPTY_LIST;
}
return modules;
}
/**
* Method description
*
*
* @param clazz
* @param <T>
*
* @return
*/
@SuppressWarnings("unchecked")
public <T> Class<T> getOverride(Class<T> clazz)
{
Class<T> implementation = null;
for (ClassOverride co : getOverrides())
{
if (co.getBind().equals(clazz))
{
implementation = (Class<T>) co.getTo();
}
}
return implementation;
}
/**
* Method description
*
*
* @return
*/
public List<ClassOverride> getOverrides()
{
if (overrides == null)
{
overrides = Lists.newArrayList();
}
return overrides;
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
*
* @param moduleClasses
*/
public void setModuleClasses(List<Class<? extends Module>> moduleClasses)
{
this.moduleClasses = moduleClasses;
}
/**
* Method description
*
*
* @param overrides
*/
public void setOverrides(List<ClassOverride> overrides)
{
this.overrides = overrides;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@XmlElement(name = "module")
private List<Class<? extends Module>> moduleClasses;
/** Field description */
@XmlElement(name = "override")
private List<ClassOverride> overrides;
}

View File

@@ -0,0 +1,65 @@
package sonia.scm.lifecycle.modules;
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;
/**
* Guice module which captures all classes which are implementing the {@link Closeable}. These classes can be later
* closed, by injecting the {@link CloseableModule} and calling {@link #closeAll()}.
*
* @author Sebastian Sdorra
*/
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);
}
/**
* Closes all captured instances.
*/
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);
}
}
}

View File

@@ -0,0 +1,88 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
* <p>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* <p>
* 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.
* <p>
* 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.
* <p>
* http://bitbucket.org/sdorra/scm-manager
*/
package sonia.scm.lifecycle.modules;
//~--- 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.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.EagerSingleton;
import java.util.Set;
//~--- JDK imports ------------------------------------------------------------
/**
* Guice module which captures all classes which are annotated with {@link EagerSingleton}. These classes can be later
* initialized.
*
* @author Sebastian Sdorra
*/
public class EagerSingletonModule extends AbstractModule {
private static final Logger LOG = LoggerFactory.getLogger(EagerSingletonModule.class);
private final Set<Class<?>> eagerSingletons = Sets.newHashSet();
/**
* Initialize all captured classes.
*
* @param injector injector for initialization
*/
void initialize(Injector injector) {
for (Class<?> clazz : eagerSingletons) {
LOG.info("initialize eager singleton {}", clazz.getName());
injector.getInstance(clazz);
}
}
@Override
protected void configure() {
bindListener(MoreMatchers.isAnnotatedWith(EagerSingleton.class), new TypeListener() {
@Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
Class<? super I> rawType = type.getRawType();
LOG.trace("register eager singleton {}", rawType);
eagerSingletons.add(rawType);
}
});
bind(EagerSingletonModule.class).toInstance(this);
}
}

View File

@@ -0,0 +1,58 @@
package sonia.scm.lifecycle.modules;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import sonia.scm.Default;
import sonia.scm.lifecycle.LifeCycle;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import java.util.Optional;
public class InjectionLifeCycle implements LifeCycle {
private final Injector injector;
public InjectionLifeCycle(Injector injector) {
this.injector = injector;
}
public void initialize() {
initializeEagerSingletons();
initializeServletContextListeners();
}
public void shutdown() {
destroyServletContextListeners();
closeRegisteredCloseables();
}
private void initializeServletContextListeners() {
ServletContextListenerHolder instance = injector.getInstance(ServletContextListenerHolder.class);
ServletContext context = injector.getInstance(Key.get(ServletContext.class, Default.class));
instance.contextInitialized(new ServletContextEvent(context));
}
private void initializeEagerSingletons() {
findInstance(EagerSingletonModule.class).ifPresent(m -> m.initialize(injector));
}
private void closeRegisteredCloseables() {
findInstance(CloseableModule.class).ifPresent(CloseableModule::closeAll);
}
private void destroyServletContextListeners() {
ServletContextListenerHolder instance = injector.getInstance(ServletContextListenerHolder.class);
ServletContext context = injector.getInstance(Key.get(ServletContext.class, Default.class));
instance.contextDestroyed(new ServletContextEvent(context));
}
private <T> Optional<T> findInstance(Class<T> clazz) {
Binding<T> binding = injector.getExistingBinding(Key.get(clazz));
if (binding != null) {
return Optional.of(binding.getProvider().get());
}
return Optional.empty();
}
}

View File

@@ -0,0 +1,11 @@
package sonia.scm.lifecycle.modules;
import com.google.inject.Module;
import java.util.Collection;
public interface ModuleProvider {
Collection<Module> createModules();
}

View File

@@ -0,0 +1,60 @@
package sonia.scm.lifecycle.modules;
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()))));
}
}

View File

@@ -0,0 +1,76 @@
package sonia.scm.lifecycle.modules;
import com.google.inject.Injector;
import org.jboss.resteasy.plugins.guice.ModuleProcessor;
import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher;
import org.jboss.resteasy.plugins.server.servlet.ListenerBootstrap;
import org.jboss.resteasy.spi.Registry;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.ws.rs.ext.RuntimeDelegate;
/**
* Resteasy initialization and dispatching. This servlet combines the initialization of
* {@link org.jboss.resteasy.plugins.guice.GuiceResteasyBootstrapServletContextListener} and the dispatching of
* {@link HttpServletDispatcher}. The combination is required to fix the initialization order.
*/
@Singleton
public class ResteasyAllInOneServletDispatcher extends HttpServletDispatcher {
private static final Logger LOG = LoggerFactory.getLogger(ResteasyAllInOneServletDispatcher.class);
private final Injector injector;
private ResteasyDeployment deployment;
@Inject
public ResteasyAllInOneServletDispatcher(Injector injector) {
this.injector = injector;
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
LOG.info("init resteasy");
ServletContext servletContext = servletConfig.getServletContext();
createDeployment(servletContext);
ModuleProcessor processor = createModuleProcessor();
processor.processInjector(injector);
super.init(servletConfig);
}
private void createDeployment(ServletContext servletContext) {
ListenerBootstrap config = new ListenerBootstrap(servletContext);
deployment = config.createDeployment();
deployment.start();
servletContext.setAttribute(ResteasyDeployment.class.getName(), deployment);
}
private ModuleProcessor createModuleProcessor() {
Registry registry = deployment.getRegistry();
ResteasyProviderFactory providerFactory = deployment.getProviderFactory();
return new ModuleProcessor(registry, providerFactory);
}
@Override
public void destroy() {
LOG.info("destroy resteasy");
super.destroy();
deployment.stop();
// ensure everything gets cleared, to avoid classloader leaks
ResteasyProviderFactory.clearInstanceIfEqual(ResteasyProviderFactory.getInstance());
ResteasyProviderFactory.clearContextData();
RuntimeDelegate.setInstance(null);
}
}

View File

@@ -0,0 +1,18 @@
package sonia.scm.lifecycle.modules;
import com.google.common.collect.ImmutableMap;
import com.google.inject.servlet.ServletModule;
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;
import java.util.Map;
/**
* Module to configure resteasy with guice.
*/
public class ResteasyModule extends ServletModule {
@Override
protected void configureServlets() {
Map<String, String> initParams = ImmutableMap.of(ResteasyContextParameters.RESTEASY_SERVLET_MAPPING_PREFIX, "/api");
serve("/api/*").with(ResteasyAllInOneServletDispatcher.class, initParams);
}
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
* <p>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* <p>
* 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.
* <p>
* 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.
* <p>
* http://bitbucket.org/sdorra/scm-manager
*/
package sonia.scm.lifecycle.modules;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.Matchers;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
import sonia.scm.event.ScmEventBus;
/**
* Registers every instance to the scm-manager event bus.
*
* @author Sebastian Sdorra
*/
public class ScmEventBusModule extends AbstractModule {
private final ScmEventBus eventBus;
public ScmEventBusModule() {
this(ScmEventBus.getInstance());
}
@VisibleForTesting
ScmEventBusModule(ScmEventBus eventBus) {
this.eventBus = eventBus;
}
@Override
protected void configure() {
bindListener(Matchers.any(), new TypeListener() {
@Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
encounter.register((InjectionListener<I>) object -> eventBus.register(object));
}
});
}
}

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
* <p>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* <p>
* 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.
* <p>
* 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.
* <p>
* http://bitbucket.org/sdorra/scm-manager
*/
package sonia.scm.lifecycle.modules;
//~--- non-JDK imports --------------------------------------------------------
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.Initable;
import sonia.scm.SCMContext;
/**
* Initializes all instances which are implementing the {@link Initable} interface.
*
* @author Sebastian Sdorra
*/
public class ScmInitializerModule extends AbstractModule {
private static final Logger LOG = LoggerFactory.getLogger(ScmInitializerModule.class);
@Override
protected void configure() {
bindListener(MoreMatchers.isSubtypeOf(Initable.class), new TypeListener() {
@Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
encounter.register((InjectionListener<I>) i -> {
LOG.trace("initialize initable {}", i.getClass());
Initable initable = (Initable) i;
initable.init(SCMContext.getContext());
});
}
});
}
}

View File

@@ -0,0 +1,145 @@
/**
* 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.lifecycle.modules;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.name.Names;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.guice.web.ShiroWebModule;
import org.apache.shiro.realm.Realm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.plugin.ExtensionProcessor;
//~--- JDK imports ------------------------------------------------------------
import javax.servlet.ServletContext;
import org.apache.shiro.mgt.RememberMeManager;
import sonia.scm.security.DisabledRememberMeManager;
/**
*
* @author Sebastian Sdorra
*/
public class ScmSecurityModule extends ShiroWebModule
{
/** Field description */
private static final int ITERATIONS = 8192;
/**
* the logger for ScmSecurityModule
*/
private static final Logger logger =
LoggerFactory.getLogger(ScmSecurityModule.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param servletContext
* @param extensionProcessor
*/
public ScmSecurityModule(ServletContext servletContext, ExtensionProcessor extensionProcessor)
{
super(servletContext);
this.extensionProcessor = extensionProcessor;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
@Override
@SuppressWarnings("unchecked")
protected void configureShiroWeb()
{
bind(PasswordService.class).toInstance(createPasswordService());
// expose password service to global injector
expose(PasswordService.class);
// disable remember me cookie generation
bind(RememberMeManager.class).to(DisabledRememberMeManager.class);
// bind realm
for (Class<? extends Realm> realm : extensionProcessor.byExtensionPoint(Realm.class))
{
logger.info("bind security realm {}", realm);
bindRealm().to(realm);
}
// bind constant
bindConstant().annotatedWith(Names.named("shiro.loginUrl")).to(
"/index.html");
// disable access to mustache resources
addFilterChain("/**.mustache", filterConfig(ROLES, "nobody"));
// disable session
addFilterChain("/**", NO_SESSION_CREATION);
}
/**
* Creates a {@link PasswordService} with a smaller size of iteration, because
* large iterations will slow down subversion.
*
* @return instance of {@link PasswordService}
*/
private PasswordService createPasswordService()
{
DefaultPasswordService passwordService = new DefaultPasswordService();
DefaultHashService hashService = new DefaultHashService();
hashService.setHashIterations(ITERATIONS);
passwordService.setHashService(hashService);
return passwordService;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final ExtensionProcessor extensionProcessor;
}

View File

@@ -0,0 +1,411 @@
/**
* 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.lifecycle.modules;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Provider;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.servlet.RequestScoped;
import com.google.inject.servlet.ServletModule;
import com.google.inject.throwingproviders.ThrowingProviderBinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.Default;
import sonia.scm.PushStateDispatcher;
import sonia.scm.PushStateDispatcherProvider;
import sonia.scm.Undecorated;
import sonia.scm.api.rest.ObjectMapperProvider;
import sonia.scm.cache.CacheManager;
import sonia.scm.cache.GuavaCacheManager;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.event.ScmEventBus;
import sonia.scm.group.DefaultGroupDisplayManager;
import sonia.scm.group.DefaultGroupManager;
import sonia.scm.group.GroupDAO;
import sonia.scm.group.GroupDisplayManager;
import sonia.scm.group.GroupManager;
import sonia.scm.group.GroupManagerProvider;
import sonia.scm.group.xml.XmlGroupDAO;
import sonia.scm.net.SSLContextProvider;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.net.ahc.ContentTransformer;
import sonia.scm.net.ahc.DefaultAdvancedHttpClient;
import sonia.scm.net.ahc.JsonContentTransformer;
import sonia.scm.net.ahc.XmlContentTransformer;
import sonia.scm.plugin.DefaultPluginManager;
import sonia.scm.plugin.PluginLoader;
import sonia.scm.plugin.PluginManager;
import sonia.scm.repository.DefaultRepositoryManager;
import sonia.scm.repository.DefaultRepositoryProvider;
import sonia.scm.repository.DefaultRepositoryRoleManager;
import sonia.scm.repository.HealthCheckContextListener;
import sonia.scm.repository.NamespaceStrategy;
import sonia.scm.repository.NamespaceStrategyProvider;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryManagerProvider;
import sonia.scm.repository.RepositoryProvider;
import sonia.scm.repository.RepositoryRoleDAO;
import sonia.scm.repository.RepositoryRoleManager;
import sonia.scm.repository.api.HookContextFactory;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.repository.spi.HookEventFacade;
import sonia.scm.repository.xml.XmlRepositoryDAO;
import sonia.scm.repository.xml.XmlRepositoryRoleDAO;
import sonia.scm.schedule.CronScheduler;
import sonia.scm.schedule.Scheduler;
import sonia.scm.security.AccessTokenCookieIssuer;
import sonia.scm.security.AuthorizationChangedEventProducer;
import sonia.scm.security.ConfigurableLoginAttemptHandler;
import sonia.scm.security.DefaultAccessTokenCookieIssuer;
import sonia.scm.security.DefaultSecuritySystem;
import sonia.scm.security.LoginAttemptHandler;
import sonia.scm.security.SecuritySystem;
import sonia.scm.template.MustacheTemplateEngine;
import sonia.scm.template.TemplateEngine;
import sonia.scm.template.TemplateEngineFactory;
import sonia.scm.template.TemplateServlet;
import sonia.scm.user.DefaultUserDisplayManager;
import sonia.scm.user.DefaultUserManager;
import sonia.scm.user.UserDAO;
import sonia.scm.user.UserDisplayManager;
import sonia.scm.user.UserManager;
import sonia.scm.user.UserManagerProvider;
import sonia.scm.user.xml.XmlUserDAO;
import sonia.scm.util.DebugServlet;
import sonia.scm.util.ScmConfigurationUtil;
import sonia.scm.web.UserAgentParser;
import sonia.scm.web.cgi.CGIExecutorFactory;
import sonia.scm.web.cgi.DefaultCGIExecutorFactory;
import sonia.scm.web.filter.LoggingFilter;
import sonia.scm.web.security.AdministrationContext;
import sonia.scm.web.security.DefaultAdministrationContext;
import javax.net.ssl.SSLContext;
import static sonia.scm.api.v2.resources.ScmPathInfo.REST_API_PATH;
/**
*
* @author Sebastian Sdorra
*/
public class ScmServletModule extends ServletModule
{
/** Field description */
public static final String[] PATTERN_ADMIN = new String[] {
REST_API_PATH + "/groups*",
REST_API_PATH + "/users*", REST_API_PATH + "/plguins*" };
/** Field description */
public static final String PATTERN_ALL = "/*";
/** Field description */
public static final String PATTERN_CONFIG = REST_API_PATH + "/config*";
/** Field description */
public static final String PATTERN_DEBUG = "/debug.html";
/** Field description */
public static final String PATTERN_INDEX = "/index.html";
/** Field description */
public static final String PATTERN_PAGE = "*.html";
/** Field description */
public static final String PATTERN_PLUGIN_SCRIPT = "/plugins/resources/js/*";
/** Field description */
public static final String PATTERN_RESTAPI = "/api/*";
/** Field description */
public static final String PATTERN_SCRIPT = "*.js";
/** Field description */
public static final String PATTERN_STYLESHEET = "*.css";
/** Field description */
public static final String RESOURCE_REGEX =
"^/(?:resources|api|plugins|index)[\\./].*(?:html|\\.css|\\.js|\\.xml|\\.json|\\.txt)";
/** Field description */
public static final String REST_PACKAGE = "sonia.scm.api.rest";
/** Field description */
public static final String SYSTEM_PROPERTY_DEBUG_HTTP = "scm.debug.http";
/** Field description */
public static final String[] PATTERN_STATIC_RESOURCES = new String[] {
PATTERN_SCRIPT,
PATTERN_STYLESHEET, "*.jpg", "*.gif", "*.png" };
/** Field description */
public static final String[] PATTERN_COMPRESSABLE = new String[] {
PATTERN_SCRIPT,
PATTERN_STYLESHEET, "*.json", "*.xml", "*.txt" };
/** Field description */
private static final Logger logger =
LoggerFactory.getLogger(ScmServletModule.class);
//~--- constructors ---------------------------------------------------------
public ScmServletModule(PluginLoader pluginLoader, ClassOverrides overrides)
{
this.pluginLoader = pluginLoader;
this.overrides = overrides;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
@Override
protected void configureServlets()
{
install(ThrowingProviderBinder.forModule(this));
ScmConfiguration config = getScmConfiguration();
bind(NamespaceStrategy.class).toProvider(NamespaceStrategyProvider.class);
// bind repository provider
ThrowingProviderBinder.create(binder())
.bind(RepositoryProvider.class, Repository.class)
.to(DefaultRepositoryProvider.class)
.in(RequestScoped.class);
// bind event api
bind(ScmEventBus.class).toInstance(ScmEventBus.getInstance());
// bind core
bind(ScmConfiguration.class).toInstance(config);
bind(PluginManager.class, DefaultPluginManager.class);
// bind scheduler
bind(Scheduler.class).to(CronScheduler.class);
// bind health check stuff
bind(HealthCheckContextListener.class);
// bind extensions
pluginLoader.getExtensionProcessor().processAutoBindExtensions(binder());
// bind security stuff
bind(LoginAttemptHandler.class).to(ConfigurableLoginAttemptHandler.class);
bind(AuthorizationChangedEventProducer.class);
bind(SecuritySystem.class).to(DefaultSecuritySystem.class);
bind(AdministrationContext.class, DefaultAdministrationContext.class);
// bind cache
bind(CacheManager.class, GuavaCacheManager.class);
bind(org.apache.shiro.cache.CacheManager.class, GuavaCacheManager.class);
// bind dao
bind(GroupDAO.class, XmlGroupDAO.class);
bind(UserDAO.class, XmlUserDAO.class);
bind(RepositoryDAO.class, XmlRepositoryDAO.class);
bind(RepositoryRoleDAO.class, XmlRepositoryRoleDAO.class);
bind(RepositoryRoleManager.class).to(DefaultRepositoryRoleManager.class);
bindDecorated(RepositoryManager.class, DefaultRepositoryManager.class,
RepositoryManagerProvider.class);
bindDecorated(UserManager.class, DefaultUserManager.class,
UserManagerProvider.class);
bind(UserDisplayManager.class, DefaultUserDisplayManager.class);
bindDecorated(GroupManager.class, DefaultGroupManager.class,
GroupManagerProvider.class);
bind(GroupDisplayManager.class, DefaultGroupDisplayManager.class);
bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class);
// bind sslcontext provider
bind(SSLContext.class).toProvider(SSLContextProvider.class);
// bind ahc
Multibinder<ContentTransformer> transformers =
Multibinder.newSetBinder(binder(), ContentTransformer.class);
transformers.addBinding().to(XmlContentTransformer.class);
transformers.addBinding().to(JsonContentTransformer.class);
bind(AdvancedHttpClient.class).to(DefaultAdvancedHttpClient.class);
// bind repository service factory
bind(RepositoryServiceFactory.class);
// bind new hook api
bind(HookContextFactory.class);
bind(HookEventFacade.class);
// bind user-agent parser
bind(UserAgentParser.class);
// bind debug logging filter
if ("true".equalsIgnoreCase(System.getProperty(SYSTEM_PROPERTY_DEBUG_HTTP)))
{
filter(PATTERN_ALL).through(LoggingFilter.class);
}
// debug servlet
serve(PATTERN_DEBUG).with(DebugServlet.class);
// template
serve(PATTERN_INDEX, "/").with(TemplateServlet.class);
Multibinder<TemplateEngine> engineBinder =
Multibinder.newSetBinder(binder(), TemplateEngine.class);
engineBinder.addBinding().to(MustacheTemplateEngine.class);
bind(TemplateEngine.class).annotatedWith(Default.class).to(
MustacheTemplateEngine.class);
bind(TemplateEngineFactory.class);
bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class);
// bind events
bind(AccessTokenCookieIssuer.class).to(DefaultAccessTokenCookieIssuer.class);
bind(PushStateDispatcher.class).toProvider(PushStateDispatcherProvider.class);
}
/**
* Method description
*
*
* @param clazz
* @param defaultImplementation
* @param <T>
*/
private <T> void bind(Class<T> clazz,
Class<? extends T> defaultImplementation)
{
Class<? extends T> implementation = find(clazz, defaultImplementation);
if (logger.isDebugEnabled())
{
logger.debug("bind {} to {}", clazz, implementation);
}
bind(clazz).to(implementation);
}
/**
* Method description
*
*
* @param clazz
* @param defaultImplementation
* @param providerClass
* @param <T>
*/
private <T> void bindDecorated(Class<T> clazz,
Class<? extends T> defaultImplementation,
Class<? extends Provider<T>> providerClass)
{
Class<? extends T> implementation = find(clazz, defaultImplementation);
if (logger.isDebugEnabled())
{
logger.debug("bind undecorated {} to {}", clazz, implementation);
}
bind(clazz).annotatedWith(Undecorated.class).to(implementation);
if (logger.isDebugEnabled())
{
logger.debug("bind {} to provider {}", clazz, providerClass);
}
bind(clazz).toProvider(providerClass);
}
/**
* Method description
*
*
* @param clazz
* @param defaultImplementation
* @param <T>
*
* @return
*/
private <T> Class<? extends T> find(Class<T> clazz,
Class<? extends T> defaultImplementation)
{
Class<? extends T> implementation = overrides.getOverride(clazz);
if (implementation != null)
{
logger.info("found override {} for {}", implementation, clazz);
}
else
{
implementation = defaultImplementation;
if (logger.isTraceEnabled())
{
logger.trace(
"no override available for {}, using default implementation {}",
clazz, implementation);
}
}
return implementation;
}
//~--- get methods ----------------------------------------------------------
/**
* Load ScmConfiguration with JAXB
*/
private ScmConfiguration getScmConfiguration()
{
ScmConfiguration configuration = new ScmConfiguration();
ScmConfigurationUtil.getInstance().load(configuration);
return configuration;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final ClassOverrides overrides;
/** Field description */
private final PluginLoader pluginLoader;
}

View File

@@ -0,0 +1,85 @@
/**
* 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.lifecycle.modules;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
//~--- JDK imports ------------------------------------------------------------
import java.util.Collections;
import java.util.Set;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
public class ServletContextListenerHolder implements ServletContextListener {
static class ListenerHolder {
@Inject(optional = true)
private Set<ServletContextListener> listenerSet;
private Set<ServletContextListener> getListenerSet() {
if (listenerSet == null) {
return Collections.emptySet();
}
return listenerSet;
}
}
private final Set<ServletContextListener> listenerSet;
@Inject
public ServletContextListenerHolder(ListenerHolder listeners)
{
this.listenerSet = listeners.getListenerSet();
}
@Override
public void contextInitialized(ServletContextEvent sce) {
listenerSet.forEach(listener -> listener.contextInitialized(sce));
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
listenerSet.forEach(listener -> listener.contextDestroyed(sce));
}
}

View File

@@ -0,0 +1,14 @@
package sonia.scm.lifecycle.modules;
import com.google.inject.servlet.ServletModule;
import sonia.scm.Default;
import javax.servlet.ServletContext;
public class ServletContextModule extends ServletModule {
@Override
protected void configureServlets() {
bind(ServletContext.class).annotatedWith(Default.class).toInstance(getServletContext());
}
}

View File

@@ -0,0 +1,24 @@
package sonia.scm.lifecycle.modules;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
import sonia.scm.migration.UpdateStep;
import sonia.scm.plugin.PluginLoader;
public class UpdateStepModule extends AbstractModule {
private final PluginLoader pluginLoader;
public UpdateStepModule(PluginLoader pluginLoader) {
this.pluginLoader = pluginLoader;
}
@Override
protected void configure() {
Multibinder<UpdateStep> updateStepBinder = Multibinder.newSetBinder(binder(), UpdateStep.class);
pluginLoader
.getExtensionProcessor()
.byExtensionPoint(UpdateStep.class)
.forEach(stepClass -> updateStepBinder.addBinding().to(stepClass));
}
}