mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-05-07 12:17:00 +02:00
Auto mapper binding (#1807)
Bind mapper implementations automatically to related mappers using the annotation processor. With this change it is not longer required to bind mapper explicitly using mapper modules which reduces some boilerplate code.
This commit is contained in:
2
gradle/changelog/auto_mapper_binding.yaml
Normal file
2
gradle/changelog/auto_mapper_binding.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: Changed
|
||||
description: Bind mappers automatically to mapper implementations ([#1807](https://github.com/scm-manager/scm-manager/pull/1807))
|
||||
@@ -37,6 +37,9 @@ dependencies {
|
||||
// rest api
|
||||
implementation libraries.jaxRs
|
||||
|
||||
// mapper
|
||||
implementation libraries.mapstruct
|
||||
|
||||
// events
|
||||
implementation libraries.legman
|
||||
|
||||
|
||||
@@ -24,46 +24,26 @@
|
||||
|
||||
package sonia.scm.annotation;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.github.legman.Subscribe;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import org.kohsuke.MetaInfServices;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import sonia.scm.annotation.ClassSetElement.ClassWithAttributes;
|
||||
import sonia.scm.plugin.PluginAnnotation;
|
||||
import sonia.scm.plugin.Requires;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
@@ -72,14 +52,11 @@ import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
@@ -91,6 +68,14 @@ import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import static javax.lang.model.util.ElementFilter.methodsIn;
|
||||
|
||||
@@ -112,7 +97,8 @@ public final class ScmAnnotationProcessor extends AbstractProcessor {
|
||||
ImmutableSet.of(Subscribe.class.getName());
|
||||
private static final Set<ClassAnnotation> CLASS_ANNOTATIONS =
|
||||
ImmutableSet.of(new ClassAnnotation("rest-resource", Path.class),
|
||||
new ClassAnnotation("rest-provider", Provider.class));
|
||||
new ClassAnnotation("rest-provider", Provider.class),
|
||||
new ClassAnnotation("mapper", Mapper.class));
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations,
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
@@ -34,93 +32,70 @@ import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.Set;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@XmlRootElement(name = "module")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class ScmModule
|
||||
{
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
public class ScmModule {
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<ClassElement> getEvents()
|
||||
{
|
||||
@XmlElement(name = "indexed-type")
|
||||
private Set<ClassElement> indexedTypes;
|
||||
|
||||
@XmlElement(name = "event")
|
||||
private Set<ClassElement> events;
|
||||
|
||||
@XmlElement(name = "extension-point")
|
||||
private Set<ExtensionPointElement> extensionPoints;
|
||||
|
||||
@XmlElement(name = "extension")
|
||||
private Set<ClassElement> extensions;
|
||||
|
||||
@XmlElement(name = "rest-provider")
|
||||
private Set<ClassElement> restProviders;
|
||||
|
||||
@XmlElement(name = "rest-resource")
|
||||
private Set<ClassElement> restResources;
|
||||
|
||||
@XmlElement(name = "mapper")
|
||||
private Set<ClassElement> mappers;
|
||||
|
||||
@XmlElement(name = "subscriber")
|
||||
private Set<SubscriberElement> subscribers;
|
||||
|
||||
@XmlElement(name = "web-element")
|
||||
private Set<WebElementDescriptor> webElements;
|
||||
|
||||
public Iterable<ClassElement> getEvents() {
|
||||
return nonNull(events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<ExtensionPointElement> getExtensionPoints()
|
||||
{
|
||||
public Iterable<ExtensionPointElement> getExtensionPoints() {
|
||||
return nonNull(extensionPoints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<ClassElement> getExtensions()
|
||||
{
|
||||
public Iterable<ClassElement> getExtensions() {
|
||||
return nonNull(extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<ClassElement> getRestProviders()
|
||||
{
|
||||
public Iterable<ClassElement> getRestProviders() {
|
||||
return nonNull(restProviders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<ClassElement> getRestResources()
|
||||
{
|
||||
public Iterable<ClassElement> getRestResources() {
|
||||
return nonNull(restResources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<SubscriberElement> getSubscribers()
|
||||
{
|
||||
public Iterable<ClassElement> getMappers() {
|
||||
return nonNull(mappers);
|
||||
}
|
||||
|
||||
public Iterable<SubscriberElement> getSubscribers() {
|
||||
return nonNull(subscribers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<WebElementDescriptor> getWebElements()
|
||||
{
|
||||
public Iterable<WebElementDescriptor> getWebElements() {
|
||||
return nonNull(webElements);
|
||||
}
|
||||
|
||||
@@ -128,58 +103,11 @@ public class ScmModule
|
||||
return nonNull(indexedTypes);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param iterable
|
||||
* @param <T>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private <T> Iterable<T> nonNull(Iterable<T> iterable)
|
||||
{
|
||||
if (iterable == null)
|
||||
{
|
||||
private <T> Iterable<T> nonNull(Iterable<T> iterable) {
|
||||
if (iterable == null) {
|
||||
iterable = ImmutableSet.of();
|
||||
}
|
||||
|
||||
return iterable;
|
||||
}
|
||||
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
@XmlElement(name = "indexed-type")
|
||||
private Set<ClassElement> indexedTypes;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "event")
|
||||
private Set<ClassElement> events;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "extension-point")
|
||||
private Set<ExtensionPointElement> extensionPoints;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "extension")
|
||||
private Set<ClassElement> extensions;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "rest-provider")
|
||||
private Set<ClassElement> restProviders;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "rest-resource")
|
||||
private Set<ClassElement> restResources;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "subscriber")
|
||||
private Set<SubscriberElement> subscribers;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "web-element")
|
||||
private Set<WebElementDescriptor> webElements;
|
||||
}
|
||||
|
||||
@@ -27,73 +27,20 @@ package sonia.scm.api.v2.resources;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.servlet.ServletScopes;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import sonia.scm.security.gpg.PublicKeyMapper;
|
||||
import sonia.scm.web.api.RepositoryToHalMapper;
|
||||
|
||||
public class MapperModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(UserDtoToUserMapper.class).to(Mappers.getMapperClass(UserDtoToUserMapper.class));
|
||||
bind(UserToUserDtoMapper.class).to(Mappers.getMapperClass(UserToUserDtoMapper.class));
|
||||
bind(UserCollectionToDtoMapper.class);
|
||||
bind(PublicKeyMapper.class).to(Mappers.getMapperClass(PublicKeyMapper.class));
|
||||
|
||||
bind(GroupDtoToGroupMapper.class).to(Mappers.getMapperClass(GroupDtoToGroupMapper.class));
|
||||
bind(GroupToGroupDtoMapper.class).to(Mappers.getMapperClass(GroupToGroupDtoMapper.class));
|
||||
bind(GroupCollectionToDtoMapper.class);
|
||||
|
||||
bind(ScmConfigurationToConfigDtoMapper.class).to(Mappers.getMapperClass(ScmConfigurationToConfigDtoMapper.class));
|
||||
bind(ConfigDtoToScmConfigurationMapper.class).to(Mappers.getMapperClass(ConfigDtoToScmConfigurationMapper.class));
|
||||
|
||||
bind(RepositoryToRepositoryDtoMapper.class).to(Mappers.getMapperClass(RepositoryToRepositoryDtoMapper.class));
|
||||
bind(RepositoryDtoToRepositoryMapper.class).to(Mappers.getMapperClass(RepositoryDtoToRepositoryMapper.class));
|
||||
|
||||
bind(RepositoryTypeToRepositoryTypeDtoMapper.class).to(Mappers.getMapperClass(RepositoryTypeToRepositoryTypeDtoMapper.class));
|
||||
bind(RepositoryTypeCollectionToDtoMapper.class);
|
||||
|
||||
bind(BranchToBranchDtoMapper.class).to(Mappers.getMapperClass(BranchToBranchDtoMapper.class));
|
||||
bind(RepositoryPermissionDtoToRepositoryPermissionMapper.class).to(Mappers.getMapperClass(RepositoryPermissionDtoToRepositoryPermissionMapper.class));
|
||||
bind(RepositoryPermissionToRepositoryPermissionDtoMapper.class).to(Mappers.getMapperClass(RepositoryPermissionToRepositoryPermissionDtoMapper.class));
|
||||
|
||||
bind(RepositoryRoleToRepositoryRoleDtoMapper.class).to(Mappers.getMapperClass(RepositoryRoleToRepositoryRoleDtoMapper.class));
|
||||
bind(RepositoryRoleDtoToRepositoryRoleMapper.class).to(Mappers.getMapperClass(RepositoryRoleDtoToRepositoryRoleMapper.class));
|
||||
bind(RepositoryRoleCollectionToDtoMapper.class);
|
||||
|
||||
// These mappers are special and cannot be bound automatically by the annotation processor
|
||||
bind(ChangesetToChangesetDtoMapper.class).to(Mappers.getMapperClass(DefaultChangesetToChangesetDtoMapper.class));
|
||||
bind(ChangesetToParentDtoMapper.class).to(Mappers.getMapperClass(ChangesetToParentDtoMapper.class));
|
||||
|
||||
bind(TagToTagDtoMapper.class).to(Mappers.getMapperClass(TagToTagDtoMapper.class));
|
||||
|
||||
bind(BrowserResultToFileObjectDtoMapper.class).to(Mappers.getMapperClass(BrowserResultToFileObjectDtoMapper.class));
|
||||
bind(ModificationsToDtoMapper.class).to(Mappers.getMapperClass(ModificationsToDtoMapper.class));
|
||||
|
||||
bind(ReducedObjectModelToDtoMapper.class).to(Mappers.getMapperClass(ReducedObjectModelToDtoMapper.class));
|
||||
|
||||
bind(ResteasyViolationExceptionToErrorDtoMapper.class).to(Mappers.getMapperClass(ResteasyViolationExceptionToErrorDtoMapper.class));
|
||||
bind(ScmViolationExceptionToErrorDtoMapper.class).to(Mappers.getMapperClass(ScmViolationExceptionToErrorDtoMapper.class));
|
||||
bind(ExceptionWithContextToErrorDtoMapper.class).to(Mappers.getMapperClass(ExceptionWithContextToErrorDtoMapper.class));
|
||||
|
||||
bind(RepositoryToHalMapper.class).to(Mappers.getMapperClass(RepositoryToRepositoryDtoMapper.class));
|
||||
|
||||
bind(BlameResultToBlameDtoMapper.class).to(Mappers.getMapperClass(BlameResultToBlameDtoMapper.class));
|
||||
bind(UpdateInfoMapper.class).to(Mappers.getMapperClass(UpdateInfoMapper.class));
|
||||
|
||||
// no mapstruct required
|
||||
bind(MeDtoFactory.class);
|
||||
bind(UIPluginDtoMapper.class);
|
||||
bind(UIPluginDtoCollectionMapper.class);
|
||||
|
||||
bind(ScmPathInfoStore.class).in(ServletScopes.REQUEST);
|
||||
|
||||
bind(PluginDtoMapper.class).to(Mappers.getMapperClass(PluginDtoMapper.class));
|
||||
|
||||
bind(ApiKeyToApiKeyDtoMapper.class).to(Mappers.getMapperClass(ApiKeyToApiKeyDtoMapper.class));
|
||||
|
||||
bind(RepositoryExportInformationToDtoMapper.class).to(Mappers.getMapperClass(RepositoryExportInformationToDtoMapper.class));
|
||||
bind(RepositoryImportDtoToRepositoryImportParametersMapper.class).to(Mappers.getMapperClass(RepositoryImportDtoToRepositoryImportParametersMapper.class));
|
||||
|
||||
bind(QueryResultMapper.class).to(Mappers.getMapperClass(QueryResultMapper.class));
|
||||
bind(SearchableTypeMapper.class).to(Mappers.getMapperClass(SearchableTypeMapper.class));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,51 +21,40 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.binder.AnnotatedBindingBuilder;
|
||||
import com.google.inject.binder.ScopedBindingBuilder;
|
||||
import com.google.inject.multibindings.Multibinder;
|
||||
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.EagerSingleton;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class ExtensionBinder
|
||||
{
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public final class ExtensionBinder {
|
||||
|
||||
private static final String TYPE_LOOSE_EXT = "loose extension";
|
||||
private static final String TYPE_REST_RESOURCE = "rest resource";
|
||||
private static final String AS_EAGER_SINGLETON = " as eager singleton";
|
||||
|
||||
/**
|
||||
* the logger for ExtensionBinder
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ExtensionBinder.class);
|
||||
|
||||
public ExtensionBinder(Binder binder)
|
||||
{
|
||||
public ExtensionBinder(Binder binder) {
|
||||
this.binder = binder;
|
||||
}
|
||||
|
||||
public void bind(ExtensionCollector collector)
|
||||
{
|
||||
public void bind(ExtensionCollector collector) {
|
||||
logger.debug("bind extensions to extension points");
|
||||
|
||||
for (ExtensionPointElement epe : collector.getExtensionPointElements())
|
||||
{
|
||||
for (ExtensionPointElement epe : collector.getExtensionPointElements()) {
|
||||
bindExtensionPoint(collector, epe);
|
||||
}
|
||||
|
||||
@@ -75,63 +64,49 @@ public final class ExtensionBinder
|
||||
bindRestProviders(collector.getRestProviders());
|
||||
logger.debug("bind rest resources");
|
||||
bindRestResource(collector.getRestResources());
|
||||
logger.debug("bind mapper modules");
|
||||
bindMapperModules(collector.getMappers());
|
||||
}
|
||||
|
||||
private void bindExtensionPoint(ExtensionCollector collector,
|
||||
ExtensionPointElement epe)
|
||||
{
|
||||
if (epe.isAutoBind())
|
||||
{
|
||||
if (epe.isMultiple())
|
||||
{
|
||||
ExtensionPointElement epe) {
|
||||
if (epe.isAutoBind()) {
|
||||
if (epe.isMultiple()) {
|
||||
bindMultiExtensionPoint(epe, collector.byExtensionPoint(epe));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Class extension = collector.oneByExtensionPoint(epe);
|
||||
|
||||
if (extension != null)
|
||||
{
|
||||
if (extension != null) {
|
||||
bindSingleInstance(epe, extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
logger.warn("could not find extension for extension point {}",
|
||||
epe.getClazz());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
logger.debug("bind type of {} is manual", epe.getClazz());
|
||||
}
|
||||
}
|
||||
|
||||
private void bindLooseExtensions(Iterable<Class> extensions)
|
||||
{
|
||||
for (Class extension : extensions)
|
||||
{
|
||||
private void bindLooseExtensions(Iterable<Class> extensions) {
|
||||
for (Class extension : extensions) {
|
||||
singleBind(TYPE_LOOSE_EXT, extension);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindMultiExtensionPoint(ExtensionPointElement extensionPoint, Iterable<Class> extensions)
|
||||
{
|
||||
private void bindMultiExtensionPoint(ExtensionPointElement extensionPoint, Iterable<Class> extensions) {
|
||||
Class extensionPointClass = extensionPoint.getClazz();
|
||||
|
||||
logger.debug("create multibinder for {}", extensionPointClass.getName());
|
||||
|
||||
Multibinder multibinder = Multibinder.newSetBinder(binder, extensionPointClass);
|
||||
for (Class extensionClass : extensions)
|
||||
{
|
||||
for (Class extensionClass : extensions) {
|
||||
boolean eagerSingleton = isEagerSingleton(extensionClass);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
if (logger.isDebugEnabled()) {
|
||||
String as = Util.EMPTY_STRING;
|
||||
|
||||
if (eagerSingleton)
|
||||
{
|
||||
if (eagerSingleton) {
|
||||
as = AS_EAGER_SINGLETON;
|
||||
}
|
||||
|
||||
@@ -141,42 +116,40 @@ public final class ExtensionBinder
|
||||
|
||||
ScopedBindingBuilder sbb = multibinder.addBinding().to(extensionClass);
|
||||
|
||||
if (eagerSingleton)
|
||||
{
|
||||
if (eagerSingleton) {
|
||||
sbb.asEagerSingleton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindRestProviders(Iterable<Class> restProviders)
|
||||
{
|
||||
for (Class restProvider : restProviders)
|
||||
{
|
||||
private void bindRestProviders(Iterable<Class> restProviders) {
|
||||
for (Class restProvider : restProviders) {
|
||||
logger.debug("bind rest provider {}", restProvider);
|
||||
binder.bind(restProvider).in(Singleton.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindRestResource(Iterable<Class> restResources)
|
||||
{
|
||||
for (Class restResource : restResources)
|
||||
{
|
||||
private void bindRestResource(Iterable<Class> restResources) {
|
||||
for (Class restResource : restResources) {
|
||||
singleBind(TYPE_REST_RESOURCE, restResource);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindMapperModules(Iterable<Class> mapperModules) {
|
||||
for (Class mapperModule : mapperModules) {
|
||||
binder.bind(mapperModule).to(Mappers.getMapperClass(mapperModule));
|
||||
}
|
||||
}
|
||||
|
||||
private void bindSingleInstance(ExtensionPointElement extensionPoint,
|
||||
Class extensionClass)
|
||||
{
|
||||
Class extensionClass) {
|
||||
Class extensionPointClass = extensionPoint.getClazz();
|
||||
boolean eagerSingleton = isEagerSingleton(extensionClass);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
if (logger.isDebugEnabled()) {
|
||||
String as = Util.EMPTY_STRING;
|
||||
|
||||
if (eagerSingleton)
|
||||
{
|
||||
if (eagerSingleton) {
|
||||
as = AS_EAGER_SINGLETON;
|
||||
}
|
||||
|
||||
@@ -187,22 +160,19 @@ public final class ExtensionBinder
|
||||
ScopedBindingBuilder sbb =
|
||||
binder.bind(extensionPointClass).to(extensionClass);
|
||||
|
||||
if (eagerSingleton)
|
||||
{
|
||||
if (eagerSingleton) {
|
||||
sbb.asEagerSingleton();
|
||||
}
|
||||
}
|
||||
|
||||
private void singleBind(String type, Class extension)
|
||||
{
|
||||
private void singleBind(String type, Class extension) {
|
||||
StringBuilder log = new StringBuilder();
|
||||
|
||||
log.append("bind ").append(type).append(" ").append(extension);
|
||||
|
||||
AnnotatedBindingBuilder abb = binder.bind(extension);
|
||||
|
||||
if (isEagerSingleton(extension))
|
||||
{
|
||||
if (isEagerSingleton(extension)) {
|
||||
log.append(AS_EAGER_SINGLETON);
|
||||
abb.asEagerSingleton();
|
||||
}
|
||||
@@ -212,8 +182,7 @@ public final class ExtensionBinder
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEagerSingleton(Class extensionClass)
|
||||
{
|
||||
private boolean isEagerSingleton(Class extensionClass) {
|
||||
return extensionClass.isAnnotationPresent(EagerSingleton.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -42,20 +40,22 @@ import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class ExtensionCollector
|
||||
{
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public final class ExtensionCollector {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ExtensionCollector.class);
|
||||
|
||||
private final Set<String> pluginIndex;
|
||||
|
||||
private final Set<WebElementExtension> webElements = Sets.newHashSet();
|
||||
private final Set<Class<?>> indexedTypes = Sets.newHashSet();
|
||||
private final Set<Class> restResources = Sets.newHashSet();
|
||||
private final Set<Class> restProviders = Sets.newHashSet();
|
||||
private final Set<Class> mappers = Sets.newHashSet();
|
||||
private final Set<Class> looseExtensions = Sets.newHashSet();
|
||||
private final Multimap<ExtensionPointElement, Class> extensions = HashMultimap.create();
|
||||
private final Map<Class, ExtensionPointElement> extensionPointIndex = Maps.newHashMap();
|
||||
|
||||
public ExtensionCollector(ClassLoader moduleClassLoader, Set<ScmModule> modules, Set<InstalledPlugin> installedPlugins) {
|
||||
this.pluginIndex = createPluginIndex(installedPlugins);
|
||||
|
||||
@@ -82,144 +82,62 @@ public final class ExtensionCollector
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param epe
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<Class> byExtensionPoint(ExtensionPointElement epe)
|
||||
{
|
||||
public Collection<Class> byExtensionPoint(ExtensionPointElement epe) {
|
||||
Collection<Class> collection = extensions.get(epe);
|
||||
|
||||
if (collection == null)
|
||||
{
|
||||
if (collection == null) {
|
||||
collection = Collections.emptySet();
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param clazz
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<Class> byExtensionPoint(Class clazz)
|
||||
{
|
||||
public Collection<Class> byExtensionPoint(Class clazz) {
|
||||
Collection<Class> exts;
|
||||
ExtensionPointElement epe = extensionPointIndex.get(clazz);
|
||||
|
||||
if (epe != null)
|
||||
{
|
||||
if (epe != null) {
|
||||
exts = byExtensionPoint(epe);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
exts = Collections.emptySet();
|
||||
}
|
||||
|
||||
return exts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param epe
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class oneByExtensionPoint(ExtensionPointElement epe)
|
||||
{
|
||||
public Class oneByExtensionPoint(ExtensionPointElement epe) {
|
||||
return Iterables.getFirst(byExtensionPoint(epe), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param clazz
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class oneByExtensionPoint(Class clazz)
|
||||
{
|
||||
public Class oneByExtensionPoint(Class clazz) {
|
||||
return Iterables.getFirst(byExtensionPoint(clazz), null);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<ExtensionPointElement> getExtensionPointElements()
|
||||
{
|
||||
public Iterable<ExtensionPointElement> getExtensionPointElements() {
|
||||
return extensionPointIndex.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Multimap<ExtensionPointElement, Class> getExtensions()
|
||||
{
|
||||
public Multimap<ExtensionPointElement, Class> getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<Class> getLooseExtensions()
|
||||
{
|
||||
public Set<Class> getLooseExtensions() {
|
||||
return looseExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<Class> getRestProviders()
|
||||
{
|
||||
public Set<Class> getRestProviders() {
|
||||
return restProviders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<Class> getRestResources()
|
||||
{
|
||||
public Set<Class> getRestResources() {
|
||||
return restResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<WebElementExtension> getWebElements()
|
||||
{
|
||||
public Set<Class> getMappers() {
|
||||
return mappers;
|
||||
}
|
||||
|
||||
public Set<WebElementExtension> getWebElements() {
|
||||
return webElements;
|
||||
}
|
||||
|
||||
@@ -227,22 +145,11 @@ public final class ExtensionCollector
|
||||
return indexedTypes;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param extension
|
||||
*/
|
||||
private void appendExtension(Class extension)
|
||||
{
|
||||
private void appendExtension(Class extension) {
|
||||
boolean found = false;
|
||||
|
||||
for (Entry<Class, ExtensionPointElement> e : extensionPointIndex.entrySet())
|
||||
{
|
||||
if (e.getKey().isAssignableFrom(extension))
|
||||
{
|
||||
for (Entry<Class, ExtensionPointElement> e : extensionPointIndex.entrySet()) {
|
||||
if (e.getKey().isAssignableFrom(extension)) {
|
||||
extensions.put(e.getValue(), extension);
|
||||
found = true;
|
||||
|
||||
@@ -250,8 +157,7 @@ public final class ExtensionCollector
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (!found) {
|
||||
looseExtensions.add(extension);
|
||||
}
|
||||
}
|
||||
@@ -316,47 +222,16 @@ public final class ExtensionCollector
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param module
|
||||
*/
|
||||
private void collectRootElements(ClassLoader classLoader, ScmModule module)
|
||||
{
|
||||
for (ExtensionPointElement epe : module.getExtensionPoints())
|
||||
{
|
||||
private void collectRootElements(ClassLoader classLoader, ScmModule module) {
|
||||
for (ExtensionPointElement epe : module.getExtensionPoints()) {
|
||||
extensionPointIndex.put(epe.getClazz(), epe);
|
||||
}
|
||||
|
||||
restProviders.addAll(collectClasses(classLoader, module.getRestProviders()));
|
||||
restResources.addAll(collectClasses(classLoader, module.getRestResources()));
|
||||
mappers.addAll(collectClasses(classLoader, module.getMappers()));
|
||||
|
||||
webElements.addAll(collectWebElementExtensions(classLoader, module.getWebElements()));
|
||||
indexedTypes.addAll(collectIndexedTypes(classLoader, module.getIndexedTypes()));
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final Set<WebElementExtension> webElements = Sets.newHashSet();
|
||||
|
||||
private final Set<Class<?>> indexedTypes = Sets.newHashSet();
|
||||
|
||||
/** Field description */
|
||||
private final Set<Class> restResources = Sets.newHashSet();
|
||||
|
||||
/** Field description */
|
||||
private final Set<Class> restProviders = Sets.newHashSet();
|
||||
|
||||
/** Field description */
|
||||
private final Set<Class> looseExtensions = Sets.newHashSet();
|
||||
|
||||
/** Field description */
|
||||
private final Multimap<ExtensionPointElement, Class> extensions =
|
||||
HashMultimap.create();
|
||||
|
||||
/** Field description */
|
||||
private final Map<Class, ExtensionPointElement> extensionPointIndex =
|
||||
Maps.newHashMap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user