mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 14:35:45 +01:00
find and bind extension points automatically
This commit is contained in:
@@ -46,7 +46,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
*/
|
*/
|
||||||
@ExtensionPoint
|
@ExtensionPoint(multi=false)
|
||||||
public interface FileSystem
|
public interface FileSystem
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -47,5 +47,8 @@ import java.lang.annotation.Target;
|
|||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Target({ ElementType.TYPE })
|
@Target({ ElementType.TYPE })
|
||||||
@Retention(RetentionPolicy.CLASS)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface ExtensionPoint {}
|
public @interface ExtensionPoint
|
||||||
|
{
|
||||||
|
boolean multi() default true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,8 +30,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.plugin.ext;
|
package sonia.scm.plugin.ext;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
@@ -60,6 +65,64 @@ public class AnnotatedClass<T extends Annotation>
|
|||||||
this.annotatedClass = annotatedClass;
|
this.annotatedClass = annotatedClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param obj
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AnnotatedClass<T> other = (AnnotatedClass<T>) obj;
|
||||||
|
|
||||||
|
return Objects.equal(annotation, other.annotation)
|
||||||
|
&& Objects.equal(annotatedClass, other.annotatedClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hashCode(annotation, annotatedClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
return Objects.toStringHelper(this)
|
||||||
|
.add("annotation", annotation)
|
||||||
|
.add("annotatedClass", annotatedClass)
|
||||||
|
.toString();
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,498 +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.Binder;
|
|
||||||
import com.google.inject.Module;
|
|
||||||
import com.google.inject.multibindings.Multibinder;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sonia.scm.group.GroupListener;
|
|
||||||
import sonia.scm.io.FileSystem;
|
|
||||||
import sonia.scm.plugin.ext.Extension;
|
|
||||||
import sonia.scm.plugin.ext.ExtensionProcessor;
|
|
||||||
import sonia.scm.repository.BlameLinePreProcessor;
|
|
||||||
import sonia.scm.repository.BlameLinePreProcessorFactory;
|
|
||||||
import sonia.scm.repository.ChangesetPreProcessor;
|
|
||||||
import sonia.scm.repository.ChangesetPreProcessorFactory;
|
|
||||||
import sonia.scm.repository.FileObjectPreProcessor;
|
|
||||||
import sonia.scm.repository.FileObjectPreProcessorFactory;
|
|
||||||
import sonia.scm.repository.RepositoryHandler;
|
|
||||||
import sonia.scm.repository.RepositoryHook;
|
|
||||||
import sonia.scm.repository.RepositoryListener;
|
|
||||||
import sonia.scm.repository.RepositoryRequestListener;
|
|
||||||
import sonia.scm.repository.spi.RepositoryServiceResolver;
|
|
||||||
import sonia.scm.resources.ResourceHandler;
|
|
||||||
import sonia.scm.security.EncryptionHandler;
|
|
||||||
import sonia.scm.user.UserListener;
|
|
||||||
import sonia.scm.web.security.AuthenticationHandler;
|
|
||||||
import sonia.scm.web.security.AuthenticationListener;
|
|
||||||
import sonia.scm.web.security.DefaultAuthenticationHandler;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContextListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class BindingExtensionProcessor implements ExtensionProcessor
|
|
||||||
{
|
|
||||||
|
|
||||||
/** the logger for BindingExtensionProcessor */
|
|
||||||
private static final Logger logger =
|
|
||||||
LoggerFactory.getLogger(BindingExtensionProcessor.class);
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public BindingExtensionProcessor()
|
|
||||||
{
|
|
||||||
this.moduleSet = Sets.newHashSet();
|
|
||||||
this.extensions = Sets.newHashSet();
|
|
||||||
this.decoratorFactories = Sets.newHashSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param binder
|
|
||||||
*/
|
|
||||||
public void bindDecorators(Binder binder)
|
|
||||||
{
|
|
||||||
DecoratorBinder decoratorBinder = new DecoratorBinder(binder);
|
|
||||||
|
|
||||||
for (Class<? extends DecoratorFactory<?>> c : decoratorFactories)
|
|
||||||
{
|
|
||||||
decoratorBinder.bindFactory(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param binder
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void bindExtensions(Binder binder)
|
|
||||||
{
|
|
||||||
Multibinder<RepositoryHandler> repositoryHandlers =
|
|
||||||
Multibinder.newSetBinder(binder, RepositoryHandler.class);
|
|
||||||
Multibinder<AuthenticationHandler> authenticators =
|
|
||||||
Multibinder.newSetBinder(binder, AuthenticationHandler.class);
|
|
||||||
Multibinder<ResourceHandler> resourceHandler =
|
|
||||||
Multibinder.newSetBinder(binder, ResourceHandler.class);
|
|
||||||
Multibinder<RepositoryHook> repositoryHookBinder =
|
|
||||||
Multibinder.newSetBinder(binder, RepositoryHook.class);
|
|
||||||
|
|
||||||
// changeset pre processor
|
|
||||||
Multibinder<ChangesetPreProcessor> changesetPreProcessorBinder =
|
|
||||||
Multibinder.newSetBinder(binder, ChangesetPreProcessor.class);
|
|
||||||
Multibinder<ChangesetPreProcessorFactory> changesetPreProcessorFactoryBinder =
|
|
||||||
Multibinder.newSetBinder(binder, ChangesetPreProcessorFactory.class);
|
|
||||||
|
|
||||||
// fileobject pre processor
|
|
||||||
Multibinder<FileObjectPreProcessor> fileObjectPreProcessorBinder =
|
|
||||||
Multibinder.newSetBinder(binder, FileObjectPreProcessor.class);
|
|
||||||
Multibinder<FileObjectPreProcessorFactory> fileObjectPreProcessorFactoryBinder =
|
|
||||||
Multibinder.newSetBinder(binder, FileObjectPreProcessorFactory.class);
|
|
||||||
|
|
||||||
// blameline pre processor
|
|
||||||
Multibinder<BlameLinePreProcessor> blameLinePreProcessorBinder =
|
|
||||||
Multibinder.newSetBinder(binder, BlameLinePreProcessor.class);
|
|
||||||
Multibinder<BlameLinePreProcessorFactory> blameLinePreProcessorFactoryBinder =
|
|
||||||
Multibinder.newSetBinder(binder, BlameLinePreProcessorFactory.class);
|
|
||||||
|
|
||||||
// repository service resolver
|
|
||||||
Multibinder<RepositoryServiceResolver> repositoryServiceResolverBinder =
|
|
||||||
Multibinder.newSetBinder(binder, RepositoryServiceResolver.class);
|
|
||||||
|
|
||||||
// listeners
|
|
||||||
Multibinder<RepositoryListener> repositoryListenerBinder =
|
|
||||||
Multibinder.newSetBinder(binder, RepositoryListener.class);
|
|
||||||
Multibinder<UserListener> userListenerBinder =
|
|
||||||
Multibinder.newSetBinder(binder, UserListener.class);
|
|
||||||
Multibinder<GroupListener> groupListenerBinder =
|
|
||||||
Multibinder.newSetBinder(binder, GroupListener.class);
|
|
||||||
Multibinder<AuthenticationListener> authenticationListenerBinder =
|
|
||||||
Multibinder.newSetBinder(binder, AuthenticationListener.class);
|
|
||||||
Multibinder<RepositoryRequestListener> repositoryRequestListenerBinder =
|
|
||||||
Multibinder.newSetBinder(binder, RepositoryRequestListener.class);
|
|
||||||
Multibinder<ServletContextListener> servletContextListenerBinder =
|
|
||||||
Multibinder.newSetBinder(binder, ServletContextListener.class);
|
|
||||||
|
|
||||||
authenticators.addBinding().to(DefaultAuthenticationHandler.class);
|
|
||||||
|
|
||||||
for (Class extensionClass : extensions)
|
|
||||||
{
|
|
||||||
if (RepositoryHandler.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind RepositoryHandler {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(extensionClass);
|
|
||||||
repositoryHandlers.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (EncryptionHandler.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
bind(binder, EncryptionHandler.class, extensionClass);
|
|
||||||
}
|
|
||||||
else if (AuthenticationHandler.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind AuthenticationHandler {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(extensionClass);
|
|
||||||
authenticators.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (GroupListener.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind GroupListener {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(extensionClass);
|
|
||||||
groupListenerBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (UserListener.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind UserListener {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(extensionClass);
|
|
||||||
userListenerBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (RepositoryListener.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind RepositoryListener {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(extensionClass);
|
|
||||||
repositoryListenerBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (AuthenticationListener.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind AuthenticaitonListener {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(extensionClass);
|
|
||||||
authenticationListenerBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (ResourceHandler.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind ResourceHandler {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceHandler.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (FileSystem.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind FileSystem {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSystemClass = extensionClass;
|
|
||||||
}
|
|
||||||
else if (ChangesetPreProcessor.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind ChangesetPreProcessor {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
changesetPreProcessorBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (
|
|
||||||
ChangesetPreProcessorFactory.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind ChangesetPreProcessorFactory {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
changesetPreProcessorFactoryBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (FileObjectPreProcessor.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind FileObjectPreProcessor {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
fileObjectPreProcessorBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (
|
|
||||||
FileObjectPreProcessorFactory.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind FileObjectPreProcessorFactory {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
fileObjectPreProcessorFactoryBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (BlameLinePreProcessor.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind BlameLinePreProcessor {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
blameLinePreProcessorBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (
|
|
||||||
BlameLinePreProcessorFactory.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind BlameLinePreProcessorFactory {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
blameLinePreProcessorFactoryBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (RepositoryHook.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind RepositoryHook {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
repositoryHookBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (RepositoryRequestListener.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind RepositoryRequestListener {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
repositoryRequestListenerBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (ServletContextListener.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind ServletContextListener {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
servletContextListenerBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else if (RepositoryServiceResolver.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind RepositoryServiceResolver {}",
|
|
||||||
extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
repositoryServiceResolverBinder.addBinding().to(extensionClass);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(extensionClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param extension
|
|
||||||
* @param extensionClass
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void processExtension(Extension extension, Class extensionClass)
|
|
||||||
{
|
|
||||||
if (Module.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("add GuiceModule {}", extensionClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
addModuleClass(extensionClass);
|
|
||||||
}
|
|
||||||
else if (DecoratorFactory.class.isAssignableFrom(extensionClass))
|
|
||||||
{
|
|
||||||
decoratorFactories.add(extensionClass);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
extensions.add(extensionClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Class<? extends FileSystem> getFileSystemClass()
|
|
||||||
{
|
|
||||||
return fileSystemClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Set<RepositoryHook> getHooks()
|
|
||||||
{
|
|
||||||
return hooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Set<Module> getModuleSet()
|
|
||||||
{
|
|
||||||
return moduleSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param extensionClass
|
|
||||||
*/
|
|
||||||
private void addModuleClass(Class<? extends Module> extensionClass)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Module module = extensionClass.newInstance();
|
|
||||||
|
|
||||||
moduleSet.add(module);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.error(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param binder
|
|
||||||
* @param type
|
|
||||||
* @param bindingType
|
|
||||||
* @param <T>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private <T> void bind(Binder binder, Class<T> type,
|
|
||||||
Class<? extends T> bindingType)
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("bind {} of type {}", type.getName(), bindingType.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.bind(type).to(bindingType);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Set<Class<? extends DecoratorFactory<?>>> decoratorFactories;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Set<Class<?>> extensions;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Class<? extends FileSystem> fileSystemClass;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Set<RepositoryHook> hooks = new HashSet<RepositoryHook>();
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Set<Module> moduleSet;
|
|
||||||
}
|
|
||||||
@@ -1,128 +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.inject.Binder;
|
|
||||||
import com.google.inject.multibindings.Multibinder;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sonia.scm.group.GroupManagerDecoratorFactory;
|
|
||||||
import sonia.scm.repository.RepositoryManagerDecoratorFactory;
|
|
||||||
import sonia.scm.user.UserManagerDecoratorFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class DecoratorBinder
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the logger for DecoratorBinder
|
|
||||||
*/
|
|
||||||
private static final Logger logger =
|
|
||||||
LoggerFactory.getLogger(DecoratorBinder.class);
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param binder
|
|
||||||
*/
|
|
||||||
public DecoratorBinder(Binder binder)
|
|
||||||
{
|
|
||||||
userManagerDecoratorFactories = Multibinder.newSetBinder(binder,
|
|
||||||
UserManagerDecoratorFactory.class);
|
|
||||||
groupManagerDecoratorFactories = Multibinder.newSetBinder(binder,
|
|
||||||
GroupManagerDecoratorFactory.class);
|
|
||||||
repositoryManagerDecoratorFactories = Multibinder.newSetBinder(binder,
|
|
||||||
RepositoryManagerDecoratorFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param factoryClass
|
|
||||||
*/
|
|
||||||
public void bindFactory(Class factoryClass)
|
|
||||||
{
|
|
||||||
if (UserManagerDecoratorFactory.class.isAssignableFrom(factoryClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind user manager decorator {}");
|
|
||||||
}
|
|
||||||
|
|
||||||
userManagerDecoratorFactories.addBinding().to(factoryClass);
|
|
||||||
}
|
|
||||||
else if (GroupManagerDecoratorFactory.class.isAssignableFrom(factoryClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind group manager decorator {}");
|
|
||||||
}
|
|
||||||
|
|
||||||
groupManagerDecoratorFactories.addBinding().to(factoryClass);
|
|
||||||
}
|
|
||||||
else if (
|
|
||||||
RepositoryManagerDecoratorFactory.class.isAssignableFrom(factoryClass))
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("bind repository manager decorator {}");
|
|
||||||
}
|
|
||||||
|
|
||||||
repositoryManagerDecoratorFactories.addBinding().to(factoryClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Multibinder<GroupManagerDecoratorFactory> groupManagerDecoratorFactories;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Multibinder<RepositoryManagerDecoratorFactory> repositoryManagerDecoratorFactories;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Multibinder<UserManagerDecoratorFactory> userManagerDecoratorFactories;
|
|
||||||
}
|
|
||||||
@@ -173,15 +173,14 @@ public class ScmContextListener extends GuiceServletContextListener
|
|||||||
*/
|
*/
|
||||||
private Injector getDefaultInjector(ServletContext servletContext)
|
private Injector getDefaultInjector(ServletContext servletContext)
|
||||||
{
|
{
|
||||||
PluginLoader pluginLoader = new DefaultPluginLoader();
|
DefaultPluginLoader pluginLoader = new DefaultPluginLoader(servletContext);
|
||||||
BindingExtensionProcessor bindExtProcessor =
|
//BindingExtensionProcessor bindExtProcessor =
|
||||||
new BindingExtensionProcessor();
|
// new BindingExtensionProcessor();
|
||||||
|
|
||||||
pluginLoader.processExtensions(bindExtProcessor);
|
// pluginLoader.processExtensions(bindExtProcessor);
|
||||||
|
|
||||||
ClassOverrides overrides = ClassOverrides.findOverrides();
|
ClassOverrides overrides = ClassOverrides.findOverrides();
|
||||||
ScmServletModule main = new ScmServletModule(pluginLoader,
|
ScmServletModule main = new ScmServletModule(pluginLoader, overrides);
|
||||||
bindExtProcessor, overrides);
|
|
||||||
List<Module> moduleList = Lists.newArrayList();
|
List<Module> moduleList = Lists.newArrayList();
|
||||||
|
|
||||||
moduleList.add(new ScmInitializerModule());
|
moduleList.add(new ScmInitializerModule());
|
||||||
@@ -190,7 +189,7 @@ public class ScmContextListener extends GuiceServletContextListener
|
|||||||
moduleList.add(ShiroWebModule.guiceFilterModule());
|
moduleList.add(ShiroWebModule.guiceFilterModule());
|
||||||
moduleList.add(main);
|
moduleList.add(main);
|
||||||
moduleList.add(new ScmSecurityModule(servletContext));
|
moduleList.add(new ScmSecurityModule(servletContext));
|
||||||
moduleList.addAll(bindExtProcessor.getModuleSet());
|
moduleList.addAll(pluginLoader.getModuleSet());
|
||||||
moduleList.addAll(overrides.getModules());
|
moduleList.addAll(overrides.getModules());
|
||||||
|
|
||||||
return Guice.createInjector(moduleList);
|
return Guice.createInjector(moduleList);
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ package sonia.scm;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import com.google.common.eventbus.EventBus;
|
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
import com.google.inject.multibindings.Multibinder;
|
import com.google.inject.multibindings.Multibinder;
|
||||||
import com.google.inject.name.Names;
|
import com.google.inject.name.Names;
|
||||||
@@ -64,6 +63,7 @@ import sonia.scm.io.DefaultFileSystem;
|
|||||||
import sonia.scm.io.FileSystem;
|
import sonia.scm.io.FileSystem;
|
||||||
import sonia.scm.net.HttpClient;
|
import sonia.scm.net.HttpClient;
|
||||||
import sonia.scm.net.URLHttpClient;
|
import sonia.scm.net.URLHttpClient;
|
||||||
|
import sonia.scm.plugin.DefaultPluginLoader;
|
||||||
import sonia.scm.plugin.DefaultPluginManager;
|
import sonia.scm.plugin.DefaultPluginManager;
|
||||||
import sonia.scm.plugin.Plugin;
|
import sonia.scm.plugin.Plugin;
|
||||||
import sonia.scm.plugin.PluginLoader;
|
import sonia.scm.plugin.PluginLoader;
|
||||||
@@ -216,11 +216,9 @@ public class ScmServletModule extends ServletModule
|
|||||||
* @param bindExtProcessor
|
* @param bindExtProcessor
|
||||||
* @param overrides
|
* @param overrides
|
||||||
*/
|
*/
|
||||||
ScmServletModule(PluginLoader pluginLoader,
|
ScmServletModule(DefaultPluginLoader pluginLoader, ClassOverrides overrides)
|
||||||
BindingExtensionProcessor bindExtProcessor, ClassOverrides overrides)
|
|
||||||
{
|
{
|
||||||
this.pluginLoader = pluginLoader;
|
this.pluginLoader = pluginLoader;
|
||||||
this.bindExtProcessor = bindExtProcessor;
|
|
||||||
this.overrides = overrides;
|
this.overrides = overrides;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,9 +237,6 @@ public class ScmServletModule extends ServletModule
|
|||||||
|
|
||||||
bind(SCMContextProvider.class).toInstance(context);
|
bind(SCMContextProvider.class).toInstance(context);
|
||||||
|
|
||||||
// bind decorators
|
|
||||||
bindExtProcessor.bindDecorators(binder());
|
|
||||||
|
|
||||||
ScmConfiguration config = getScmConfiguration(context);
|
ScmConfiguration config = getScmConfiguration(context);
|
||||||
CipherUtil cu = CipherUtil.getInstance();
|
CipherUtil cu = CipherUtil.getInstance();
|
||||||
|
|
||||||
@@ -266,17 +261,10 @@ public class ScmServletModule extends ServletModule
|
|||||||
bind(KeyGenerator.class).to(DefaultKeyGenerator.class);
|
bind(KeyGenerator.class).to(DefaultKeyGenerator.class);
|
||||||
bind(CipherHandler.class).toInstance(cu.getCipherHandler());
|
bind(CipherHandler.class).toInstance(cu.getCipherHandler());
|
||||||
bind(EncryptionHandler.class, MessageDigestEncryptionHandler.class);
|
bind(EncryptionHandler.class, MessageDigestEncryptionHandler.class);
|
||||||
bindExtProcessor.bindExtensions(binder());
|
bind(FileSystem.class, DefaultFileSystem.class);
|
||||||
|
|
||||||
Class<? extends FileSystem> fileSystem =
|
// bind extensions
|
||||||
bindExtProcessor.getFileSystemClass();
|
pluginLoader.processExtensions(binder());
|
||||||
|
|
||||||
if (fileSystem == null)
|
|
||||||
{
|
|
||||||
fileSystem = DefaultFileSystem.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
bind(FileSystem.class).to(fileSystem);
|
|
||||||
|
|
||||||
// bind security stuff
|
// bind security stuff
|
||||||
bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
|
bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
|
||||||
@@ -583,12 +571,9 @@ public class ScmServletModule extends ServletModule
|
|||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private BindingExtensionProcessor bindExtProcessor;
|
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private ClassOverrides overrides;
|
private ClassOverrides overrides;
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private PluginLoader pluginLoader;
|
private DefaultPluginLoader pluginLoader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ package sonia.scm.plugin;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.common.io.Closeables;
|
||||||
|
import com.google.inject.Binder;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -46,8 +52,10 @@ import sonia.scm.plugin.ext.AnnotationScanner;
|
|||||||
import sonia.scm.plugin.ext.AnnotationScannerFactory;
|
import sonia.scm.plugin.ext.AnnotationScannerFactory;
|
||||||
import sonia.scm.plugin.ext.DefaultAnnotationScannerFactory;
|
import sonia.scm.plugin.ext.DefaultAnnotationScannerFactory;
|
||||||
import sonia.scm.plugin.ext.Extension;
|
import sonia.scm.plugin.ext.Extension;
|
||||||
|
import sonia.scm.plugin.ext.ExtensionBinder;
|
||||||
import sonia.scm.plugin.ext.ExtensionProcessor;
|
import sonia.scm.plugin.ext.ExtensionProcessor;
|
||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.plugin.ext.Extensions;
|
||||||
|
import sonia.scm.web.security.DefaultAuthenticationHandler;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -58,6 +66,7 @@ import java.io.InputStream;
|
|||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
|
||||||
@@ -66,6 +75,9 @@ import java.util.Enumeration;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
import javax.xml.bind.JAXB;
|
import javax.xml.bind.JAXB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,9 +90,18 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
/** Field description */
|
/** Field description */
|
||||||
public static final String ENCODING = "UTF-8";
|
public static final String ENCODING = "UTF-8";
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
public static final String EXTENSION_JAR = ".jar";
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
public static final String PATH_PLUGINCONFIG = "META-INF/scm/plugin.xml";
|
public static final String PATH_PLUGINCONFIG = "META-INF/scm/plugin.xml";
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
public static final String PATH_WEBINFLIB = "/WEB-INF/lib";
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
public static final String PATH_SCMCORE = PATH_WEBINFLIB.concat("/scm-core");
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
public static final String REGE_COREPLUGIN =
|
public static final String REGE_COREPLUGIN =
|
||||||
"^.*(?:/|\\\\)WEB-INF(?:/|\\\\)lib(?:/|\\\\).*\\.jar$";
|
"^.*(?:/|\\\\)WEB-INF(?:/|\\\\)lib(?:/|\\\\).*\\.jar$";
|
||||||
@@ -94,16 +115,22 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
/**
|
/**
|
||||||
* Constructs ...
|
* Constructs ...
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
* @param servletContext
|
||||||
*/
|
*/
|
||||||
public DefaultPluginLoader()
|
public DefaultPluginLoader(ServletContext servletContext)
|
||||||
{
|
{
|
||||||
|
this.servletContext = servletContext;
|
||||||
this.annotationScannerFactory = new DefaultAnnotationScannerFactory();
|
this.annotationScannerFactory = new DefaultAnnotationScannerFactory();
|
||||||
|
|
||||||
ClassLoader classLoader = getClassLoader();
|
ClassLoader classLoader = getClassLoader();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
load(classLoader);
|
locateCoreFile();
|
||||||
|
loadPlugins(classLoader);
|
||||||
|
scanForAnnotations();
|
||||||
|
findModules();
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
@@ -121,22 +148,44 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
* @param packages
|
* @param packages
|
||||||
* @param annotation
|
* @param annotation
|
||||||
* @param processor
|
* @param processor
|
||||||
|
* @param extensionPointProcessor
|
||||||
|
* @param extensionProcessor
|
||||||
* @param <T>
|
* @param <T>
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <T extends Annotation> AnnotationScanner createAnnotationScanner(
|
public <T extends Annotation> AnnotationScanner createAnnotationScanner(
|
||||||
ClassLoader classLoader, Collection<String> packages, Class<T> annotation,
|
ClassLoader classLoader, Collection<String> packages,
|
||||||
AnnotationProcessor<T> processor)
|
AnnotationProcessor<ExtensionPoint> extensionPointProcessor,
|
||||||
|
AnnotationProcessor<Extension> extensionProcessor)
|
||||||
{
|
{
|
||||||
AnnotationScanner scanner = annotationScannerFactory.create(classLoader,
|
AnnotationScanner scanner = annotationScannerFactory.create(classLoader,
|
||||||
packages);
|
packages);
|
||||||
|
|
||||||
scanner.addProcessor(annotation, processor);
|
if (extensionPointProcessor != null)
|
||||||
|
{
|
||||||
|
scanner.addProcessor(ExtensionPoint.class, extensionPointProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extensionProcessor != null)
|
||||||
|
{
|
||||||
|
scanner.addProcessor(Extension.class, extensionProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
return scanner;
|
return scanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param binder
|
||||||
|
*/
|
||||||
|
public void processExtensions(Binder binder)
|
||||||
|
{
|
||||||
|
new ExtensionBinder(binder).bind(bounds, extensionPoints, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
@@ -146,90 +195,10 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
@Override
|
@Override
|
||||||
public void processExtensions(ExtensionProcessor processor)
|
public void processExtensions(ExtensionProcessor processor)
|
||||||
{
|
{
|
||||||
ClassLoader classLoader = getClassLoader();
|
for (AnnotatedClass<Extension> extension : extensions)
|
||||||
|
|
||||||
AnnotationCollector<Extension> annotationCollector =
|
|
||||||
new AnnotationCollector<Extension>();
|
|
||||||
|
|
||||||
for (Plugin plugin : installedPlugins)
|
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
processor.processExtension(extension.getAnnotation(),
|
||||||
{
|
extension.getAnnotatedClass());
|
||||||
logger.debug("search extensions from plugin {}",
|
|
||||||
plugin.getInformation().getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream input = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Set<String> packageSet = plugin.getPackageSet();
|
|
||||||
|
|
||||||
if (packageSet == null)
|
|
||||||
{
|
|
||||||
packageSet = new HashSet<String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
packageSet.add(SCMContext.DEFAULT_PACKAGE);
|
|
||||||
|
|
||||||
File pluginFile = new File(plugin.getPath());
|
|
||||||
|
|
||||||
if (pluginFile.exists())
|
|
||||||
{
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
String type = pluginFile.isDirectory()
|
|
||||||
? "directory"
|
|
||||||
: "jar";
|
|
||||||
|
|
||||||
logger.trace("search extensions in packages {} of {} plugin {}",
|
|
||||||
new Object[] { packageSet,
|
|
||||||
type, pluginFile });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pluginFile.isDirectory())
|
|
||||||
{
|
|
||||||
createAnnotationScanner(classLoader, packageSet, Extension.class,
|
|
||||||
annotationCollector).scanDirectory(pluginFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
input = new FileInputStream(plugin.getPath());
|
|
||||||
createAnnotationScanner(classLoader, packageSet, Extension.class,
|
|
||||||
annotationCollector).scanArchive(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.error("could not find plugin file {}", plugin.getPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
logger.error("error during extension processing", ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
IOUtil.close(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<AnnotatedClass<Extension>> extensions =
|
|
||||||
annotationCollector.getAnnotatedClasses();
|
|
||||||
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("start processing {} extensions", extensions.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (AnnotatedClass<Extension> ac : extensions)
|
|
||||||
{
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("process extension {}", ac.getAnnotatedClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
processor.processExtension(ac.getAnnotation(), ac.getAnnotatedClass());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,8 +216,41 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
return installedPlugins;
|
return installedPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Set<Module> getModuleSet()
|
||||||
|
{
|
||||||
|
return moduleSet;
|
||||||
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param moduleClass
|
||||||
|
*/
|
||||||
|
private void addModule(Class moduleClass)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.info("add module {}", moduleClass);
|
||||||
|
moduleSet.add((Module) moduleClass.newInstance());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.error(
|
||||||
|
"could not create module instance of ".concat(moduleClass.getName()),
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
@@ -276,55 +278,18 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param classLoader
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private void load(ClassLoader classLoader) throws IOException
|
|
||||||
{
|
|
||||||
Enumeration<URL> urlEnum = classLoader.getResources(PATH_PLUGINCONFIG);
|
|
||||||
|
|
||||||
if (urlEnum != null)
|
|
||||||
{
|
|
||||||
while (urlEnum.hasMoreElements())
|
|
||||||
{
|
|
||||||
URL url = urlEnum.nextElement();
|
|
||||||
|
|
||||||
loadPlugin(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("loaded {} plugins", installedPlugins.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (logger.isWarnEnabled())
|
|
||||||
{
|
|
||||||
logger.warn("no plugin descriptor found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param url
|
* @param url
|
||||||
|
*
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
private void loadPlugin(URL url)
|
private String extractResourcePath(URL url)
|
||||||
{
|
{
|
||||||
String path = url.toExternalForm();
|
String path = url.toExternalForm();
|
||||||
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("try to load plugin from {}", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (path.startsWith("file:"))
|
if (path.startsWith("file:"))
|
||||||
{
|
{
|
||||||
path = path.substring("file:".length(),
|
path = path.substring("file:".length(),
|
||||||
@@ -338,6 +303,46 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
path = decodePath(path);
|
path = decodePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.trace("extrace resource path {} from url {}", path, url);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void findModules()
|
||||||
|
{
|
||||||
|
for (AnnotatedClass<Extension> extension : extensions)
|
||||||
|
{
|
||||||
|
Class extensionClass = extension.getAnnotatedClass();
|
||||||
|
|
||||||
|
if (Module.class.isAssignableFrom(extensionClass))
|
||||||
|
{
|
||||||
|
bounds.add(extension);
|
||||||
|
addModule(extensionClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
private void loadPlugin(URL url)
|
||||||
|
{
|
||||||
|
String path = extractResourcePath(url);
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace("try to load plugin from {}", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
boolean corePlugin = path.matches(REGE_COREPLUGIN);
|
boolean corePlugin = path.matches(REGE_COREPLUGIN);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
@@ -378,6 +383,234 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param classLoader
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void loadPlugins(ClassLoader classLoader) throws IOException
|
||||||
|
{
|
||||||
|
Enumeration<URL> urlEnum = classLoader.getResources(PATH_PLUGINCONFIG);
|
||||||
|
|
||||||
|
if (urlEnum != null)
|
||||||
|
{
|
||||||
|
while (urlEnum.hasMoreElements())
|
||||||
|
{
|
||||||
|
URL url = urlEnum.nextElement();
|
||||||
|
|
||||||
|
loadPlugin(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("loaded {} plugins", installedPlugins.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (logger.isWarnEnabled())
|
||||||
|
{
|
||||||
|
logger.warn("no plugin descriptor found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param classLoader
|
||||||
|
*
|
||||||
|
* @throws MalformedURLException
|
||||||
|
*/
|
||||||
|
private void locateCoreFile() throws MalformedURLException
|
||||||
|
{
|
||||||
|
Set<String> paths = servletContext.getResourcePaths(PATH_WEBINFLIB);
|
||||||
|
|
||||||
|
for (String path : paths)
|
||||||
|
{
|
||||||
|
if (path.startsWith(PATH_SCMCORE) && path.endsWith(EXTENSION_JAR))
|
||||||
|
{
|
||||||
|
coreFile = servletContext.getResource(path);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coreFile == null)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("could not find scm-core file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param classLoader
|
||||||
|
* @param packageSet
|
||||||
|
* @param extensionPointCollector
|
||||||
|
* @param extensionCollector
|
||||||
|
* @param file
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void scanFile(ClassLoader classLoader, Collection<String> packageSet,
|
||||||
|
AnnotationCollector<ExtensionPoint> extensionPointCollector,
|
||||||
|
AnnotationCollector<Extension> extensionCollector, File file)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
String type = file.isDirectory()
|
||||||
|
? "directory"
|
||||||
|
: "jar";
|
||||||
|
|
||||||
|
logger.trace("search extensions in packages {} of {} file {}",
|
||||||
|
new Object[] { packageSet,
|
||||||
|
type, file });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.isDirectory())
|
||||||
|
{
|
||||||
|
createAnnotationScanner(classLoader, packageSet, extensionPointCollector,
|
||||||
|
extensionCollector).scanDirectory(file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InputStream input = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
input = new FileInputStream(file);
|
||||||
|
createAnnotationScanner(classLoader, packageSet,
|
||||||
|
extensionPointCollector, extensionCollector).scanArchive(input);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Closeables.closeQuietly(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param processor
|
||||||
|
*
|
||||||
|
* @param binder
|
||||||
|
*/
|
||||||
|
private void scanForAnnotations()
|
||||||
|
{
|
||||||
|
ClassLoader classLoader = getClassLoader();
|
||||||
|
|
||||||
|
AnnotationCollector<ExtensionPoint> extensionPointCollector =
|
||||||
|
new AnnotationCollector<ExtensionPoint>();
|
||||||
|
AnnotationCollector<Extension> extensionCollector =
|
||||||
|
new AnnotationCollector<Extension>();
|
||||||
|
|
||||||
|
logger.debug("search extension points in {}", coreFile);
|
||||||
|
|
||||||
|
Set<String> corePackages = ImmutableSet.of("sonia.scm");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
scanURL(classLoader, corePackages, extensionPointCollector, null,
|
||||||
|
coreFile);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("could not process scm-core", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Plugin plugin : installedPlugins)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("search extensions from plugin {}",
|
||||||
|
plugin.getInformation().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Set<String> packageSet = plugin.getPackageSet();
|
||||||
|
|
||||||
|
if (packageSet == null)
|
||||||
|
{
|
||||||
|
packageSet = new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
packageSet.add(SCMContext.DEFAULT_PACKAGE);
|
||||||
|
|
||||||
|
File pluginFile = new File(plugin.getPath());
|
||||||
|
|
||||||
|
if (pluginFile.exists())
|
||||||
|
{
|
||||||
|
scanFile(classLoader, packageSet, extensionPointCollector,
|
||||||
|
extensionCollector, pluginFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.error("could not find plugin file {}", plugin.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
logger.error("error during extension processing", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//J-
|
||||||
|
extensionPoints = extensionPointCollector.getAnnotatedClasses();
|
||||||
|
extensionPoints.add(
|
||||||
|
new AnnotatedClass<ExtensionPoint>(
|
||||||
|
Extensions.createExtensionPoint(true),
|
||||||
|
ServletContextListener.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
extensions = extensionCollector.getAnnotatedClasses();
|
||||||
|
extensions.add(
|
||||||
|
new AnnotatedClass<Extension>(
|
||||||
|
Extensions.createExtension(),
|
||||||
|
DefaultAuthenticationHandler.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param classLoader
|
||||||
|
* @param packageSet
|
||||||
|
* @param extensionPointCollector
|
||||||
|
* @param extensionCollector
|
||||||
|
* @param file
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void scanURL(ClassLoader classLoader, Collection<String> packageSet,
|
||||||
|
AnnotationCollector<ExtensionPoint> extensionPointCollector,
|
||||||
|
AnnotationCollector<Extension> extensionCollector, URL file)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
InputStream content = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
content = file.openStream();
|
||||||
|
createAnnotationScanner(classLoader, packageSet, extensionPointCollector,
|
||||||
|
extensionCollector).scanArchive(content);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Closeables.closeQuietly(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -408,6 +641,24 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
/** Field description */
|
/** Field description */
|
||||||
private AnnotationScannerFactory annotationScannerFactory;
|
private AnnotationScannerFactory annotationScannerFactory;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private Set<AnnotatedClass<Extension>> bounds = Sets.newHashSet();
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private URL coreFile;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private Set<AnnotatedClass<ExtensionPoint>> extensionPoints;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private Set<AnnotatedClass<Extension>> extensions;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private Set<Module> moduleSet = Sets.newHashSet();
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private Set<Plugin> installedPlugins = new HashSet<Plugin>();
|
private Set<Plugin> installedPlugins = new HashSet<Plugin>();
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private ServletContext servletContext;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.plugin.ext;
|
package sonia.scm.plugin.ext;
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
@@ -146,7 +147,7 @@ public class DefaultAnnotationScanner implements AnnotationScanner
|
|||||||
@Override
|
@Override
|
||||||
public void scanDirectory(File directory)
|
public void scanDirectory(File directory)
|
||||||
{
|
{
|
||||||
Preconditions.checkArgument(!directory.isDirectory(),
|
Preconditions.checkArgument(directory.isDirectory(),
|
||||||
"file must be a directory");
|
"file must be a directory");
|
||||||
|
|
||||||
String basePath = directory.getAbsolutePath();
|
String basePath = directory.getAbsolutePath();
|
||||||
@@ -202,8 +203,8 @@ public class DefaultAnnotationScanner implements AnnotationScanner
|
|||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("call processor {} with {} and {}",
|
logger.debug("call processor {} with {} and {}", ap.getClass(),
|
||||||
ap.getClass(), annotation, managedClass);
|
annotation, managedClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
ap.processAnnotation(annotation, managedClass);
|
ap.processAnnotation(annotation, managedClass);
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/**
|
||||||
|
* 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.plugin.ext;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.inject.Binder;
|
||||||
|
import com.google.inject.multibindings.Multibinder;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import sonia.scm.plugin.ExtensionPoint;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
public class ExtensionBinder
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the logger for ExtensionBinder
|
||||||
|
*/
|
||||||
|
private static final Logger logger =
|
||||||
|
LoggerFactory.getLogger(ExtensionBinder.class);
|
||||||
|
|
||||||
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param binder
|
||||||
|
*/
|
||||||
|
public ExtensionBinder(Binder binder)
|
||||||
|
{
|
||||||
|
this.binder = binder;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param bounds
|
||||||
|
* @param extensionPoints
|
||||||
|
* @param extensions
|
||||||
|
*/
|
||||||
|
public void bind(Set<AnnotatedClass<Extension>> bounds,
|
||||||
|
Set<AnnotatedClass<ExtensionPoint>> extensionPoints,
|
||||||
|
Set<AnnotatedClass<Extension>> extensions)
|
||||||
|
{
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
{
|
||||||
|
logger.info("bind {} extensions to {} extension points",
|
||||||
|
extensions.size(), extensionPoints.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AnnotatedClass<ExtensionPoint> extensionPoint : extensionPoints)
|
||||||
|
{
|
||||||
|
ExtensionPoint extensionPointAnnotation = extensionPoint.getAnnotation();
|
||||||
|
Class extensionPointClass = extensionPoint.getAnnotatedClass();
|
||||||
|
|
||||||
|
if (extensionPointAnnotation.multi())
|
||||||
|
{
|
||||||
|
bindMultiExtensionPoint(bounds, extensionPointClass, extensions);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bindExtensionPoint(bounds, extensionPointClass, extensions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<AnnotatedClass<Extension>> extensionsCopy = Sets.newHashSet(extensions);
|
||||||
|
|
||||||
|
Iterables.removeAll(extensionsCopy, bounds);
|
||||||
|
|
||||||
|
for (AnnotatedClass<Extension> extension : extensionsCopy)
|
||||||
|
{
|
||||||
|
logger.info("bind {}, without extensionpoint",
|
||||||
|
extension.getAnnotatedClass());
|
||||||
|
binder.bind(extension.getAnnotatedClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param found
|
||||||
|
* @param extensionPointClass
|
||||||
|
* @param extensions
|
||||||
|
*/
|
||||||
|
private void bindExtensionPoint(Set<AnnotatedClass<Extension>> found,
|
||||||
|
Class extensionPointClass, Set<AnnotatedClass<Extension>> extensions)
|
||||||
|
{
|
||||||
|
for (AnnotatedClass<Extension> extension : extensions)
|
||||||
|
{
|
||||||
|
Class extensionClass = extension.getAnnotatedClass();
|
||||||
|
|
||||||
|
if (extensionPointClass.isAssignableFrom(extensionClass))
|
||||||
|
{
|
||||||
|
found.add(extension);
|
||||||
|
bindSingleInstance(extensionPointClass, extensionClass);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param found
|
||||||
|
* @param extensionPointClass
|
||||||
|
* @param extensions
|
||||||
|
*/
|
||||||
|
private void bindMultiExtensionPoint(Set<AnnotatedClass<Extension>> found,
|
||||||
|
Class extensionPointClass, Set<AnnotatedClass<Extension>> extensions)
|
||||||
|
{
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
{
|
||||||
|
logger.info("create multibinder for {}", extensionPointClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Multibinder multibinder = Multibinder.newSetBinder(binder,
|
||||||
|
extensionPointClass);
|
||||||
|
|
||||||
|
for (AnnotatedClass<Extension> extension : extensions)
|
||||||
|
{
|
||||||
|
Class extensionClass = extension.getAnnotatedClass();
|
||||||
|
|
||||||
|
if (extensionPointClass.isAssignableFrom(extensionClass))
|
||||||
|
{
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
{
|
||||||
|
logger.info("bind {} to multibinder of {}", extensionClass.getName(),
|
||||||
|
extensionPointClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
found.add(extension);
|
||||||
|
multibinder.addBinding().to(extensionClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param extensionPointClass
|
||||||
|
* @param extensionClass
|
||||||
|
*/
|
||||||
|
private void bindSingleInstance(Class extensionPointClass,
|
||||||
|
Class extensionClass)
|
||||||
|
{
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
{
|
||||||
|
logger.info("bind {} to {}", extensionClass.getName(),
|
||||||
|
extensionPointClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
binder.bind(extensionPointClass).to(extensionClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private Binder binder;
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
* 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.plugin.ext;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import sonia.scm.plugin.ExtensionPoint;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
public class Extensions
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Extension createExtension()
|
||||||
|
{
|
||||||
|
return new Extension()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Annotation> annotationType()
|
||||||
|
{
|
||||||
|
return Extension.class;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param multi
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static ExtensionPoint createExtensionPoint(final boolean multi)
|
||||||
|
{
|
||||||
|
return new ExtensionPoint()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean multi()
|
||||||
|
{
|
||||||
|
return multi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Annotation> annotationType()
|
||||||
|
{
|
||||||
|
return ExtensionPoint.class;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user