diff --git a/README.md b/README.md index 5addf0e..6edd4ab 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ The AppBuilder module is a builder for Magnolia apps in a java comparable to Blossom DialogBuilder. ## Requirements -* Java 11 -* Magnolia >= 6.0 +* Java 17 +* Magnolia >= 6.3 ## Setup @@ -43,19 +43,19 @@ import org.apache.commons.lang3.reflect.TypeLiteral; import org.reflections.Reflections; import com.google.inject.multibindings.Multibinder; -import com.namics.oss.magnolia.appbuilder.AppRegistrar; -import com.namics.oss.magnolia.appbuilder.ChooserDialogRegistrar; +import com.namics.oss.magnolia.appbuilder.annotations.AppFactories; import com.namics.oss.magnolia.appbuilder.annotations.AppFactory; +import com.namics.oss.magnolia.appbuilder.annotations.ChooserDialogFactories; import com.namics.oss.magnolia.appbuilder.annotations.ChooserDialogFactory; public class GuiceComponentConfigurer extends AbstractGuiceComponentConfigurer { @Override protected void configure() { // Here we use Reflections, but you can also use ClassPathScanningCandidateComponentProvider or bind each factory manually - final Multibinder> appFactoryMultibinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}, AppRegistrar.AppFactories.class); + final Multibinder> appFactoryMultibinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}, AppFactories.class); new Reflections(getClass()).getTypesAnnotatedWith(AppFactory.class).forEach(clazz -> appFactoryMultibinder.addBinding().toInstance(clazz)); - final Multibinder> chooserDialogFactoryMultibinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}, ChooserDialogRegistrar.ChooserDialogFactories.class); + final Multibinder> chooserDialogFactoryMultibinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}, ChooserDialogFactories.class); new Reflections(getClass()).getTypesAnnotatedWith(ChooserDialogFactory.class).forEach(clazz -> chooserDialogFactoryMultibinder.addBinding().toInstance(clazz)); } } diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/AppBuilderModule.java b/src/main/java/com/namics/oss/magnolia/appbuilder/AppBuilderModule.java index 0da8f96..b2c8737 100644 --- a/src/main/java/com/namics/oss/magnolia/appbuilder/AppBuilderModule.java +++ b/src/main/java/com/namics/oss/magnolia/appbuilder/AppBuilderModule.java @@ -2,6 +2,8 @@ import info.magnolia.module.ModuleLifecycle; import info.magnolia.module.ModuleLifecycleContext; +import info.magnolia.ui.api.app.registry.AppDescriptorRegistry; +import info.magnolia.ui.dialog.DialogDefinitionRegistry; import java.lang.invoke.MethodHandles; @@ -12,23 +14,31 @@ public class AppBuilderModule implements ModuleLifecycle { private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private final AppRegistrar appRegistrar; - private final ChooserDialogRegistrar chooserDialogRegistrar; + private final DialogDefinitionRegistry dialogDefinitionRegistry; + private final ChooserDialogConfigurationSource chooserDialogRegistrar; + private final AppDescriptorRegistry appDescriptorRegistry; + private final AppConfigurationSource appConfigurationSource; @Inject public AppBuilderModule( - final AppRegistrar appRegistrar, - final ChooserDialogRegistrar chooserDialogRegistrar + final AppDescriptorRegistry appDescriptorRegistry, + final AppConfigurationSource appConfigurationSource, + final DialogDefinitionRegistry dialogDefinitionRegistry, + final ChooserDialogConfigurationSource chooserDialogRegistrar ) { - this.appRegistrar = appRegistrar; + this.appDescriptorRegistry = appDescriptorRegistry; + this.appConfigurationSource = appConfigurationSource; + this.dialogDefinitionRegistry = dialogDefinitionRegistry; this.chooserDialogRegistrar = chooserDialogRegistrar; } @Override public void start(ModuleLifecycleContext moduleLifecycleContext) { LOG.debug("Starting AppBuilder Module"); - appRegistrar.register(); - chooserDialogRegistrar.register(); + appDescriptorRegistry.bindTo(appConfigurationSource); + dialogDefinitionRegistry.bindTo(chooserDialogRegistrar); + appConfigurationSource.start(); + chooserDialogRegistrar.start(); } @Override diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/AppConfigurationSource.java b/src/main/java/com/namics/oss/magnolia/appbuilder/AppConfigurationSource.java new file mode 100644 index 0000000..951e2e5 --- /dev/null +++ b/src/main/java/com/namics/oss/magnolia/appbuilder/AppConfigurationSource.java @@ -0,0 +1,93 @@ +package com.namics.oss.magnolia.appbuilder; + +import static com.google.common.base.CaseFormat.*; + +import info.magnolia.config.registry.DefinitionMetadata; +import info.magnolia.config.registry.DefinitionProvider; +import info.magnolia.config.registry.DefinitionType; +import info.magnolia.config.registry.RegistryMap; +import info.magnolia.config.source.ConfigurationSource; +import info.magnolia.config.source.ConfigurationSourceType; +import info.magnolia.config.source.ConfigurationSourceTypes; +import info.magnolia.objectfactory.Components; +import info.magnolia.ui.api.app.AppDescriptor; +import info.magnolia.ui.api.app.registry.DefinitionTypes; + +import java.lang.invoke.MethodHandles; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.namics.oss.magnolia.appbuilder.annotations.AppFactories; + +public class AppConfigurationSource implements ConfigurationSource { + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final RegistryMap registryMap = new RegistryMap<>(); + private final Set> appFactories; + private final LegacyAppDescriptorProvider.ColumnDefinitionFilter legacyAppColumnDefinitionFilter; + + @Inject + public AppConfigurationSource( + @AppFactories final Set> appFactories, + final LegacyAppDescriptorProvider.ColumnDefinitionFilter legacyAppColumnDefinitionFilter + ) { + this.appFactories = appFactories; + this.legacyAppColumnDefinitionFilter = legacyAppColumnDefinitionFilter; + } + + @Override + public ConfigurationSourceType type() { + return ConfigurationSourceTypes.code; + } + + @Override + public DefinitionType getDefinitionType() { + return DefinitionTypes.APP; + } + + @Override + public void start() { + LOG.info("Setting up {} for {} definitions", getClass().getSimpleName(), LOWER_CAMEL.to(LOWER_HYPHEN, getDefinitionType().getName())); + registryMap.removeAndPutAll( + registryMap.keySet(), + appFactories.stream() + .flatMap(this::definitionProviders) + .collect(Collectors.toSet()) + ); + } + + private Stream> definitionProviders(final Class factoryClass) { + LOG.info("Registered app '{}' from {}", factoryClass.getSimpleName(), factoryClass.getName()); + final Object factory = Components.newInstance(factoryClass); + return Stream.concat( + Stream.of(new AppDescriptorProvider(factory)), + Stream.of(new LegacyAppDescriptorProvider(factory, legacyAppColumnDefinitionFilter)).filter(LegacyAppDescriptorProvider::shouldRegister) + ); + } + + @Override + public DefinitionProvider getProvider(final DefinitionMetadata id) { + return registryMap.get(id); + } + + @Override + public DefinitionProvider getProvider(final String id) { + return registryMap.getByStringKey(id); + } + + @Override + public Collection getAllMetadata() { + return registryMap.keySet(); + } + + @Override + public Collection> getAllProviders() { + return registryMap.values(); + } +} diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/AppRegistrar.java b/src/main/java/com/namics/oss/magnolia/appbuilder/AppRegistrar.java deleted file mode 100644 index 81a170c..0000000 --- a/src/main/java/com/namics/oss/magnolia/appbuilder/AppRegistrar.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.namics.oss.magnolia.appbuilder; - -import info.magnolia.objectfactory.Components; -import info.magnolia.ui.api.app.registry.AppDescriptorRegistry; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.invoke.MethodHandles; -import java.util.Set; - -import javax.inject.Inject; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.inject.BindingAnnotation; - -public class AppRegistrar { - private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final Set> appFactories; - private final AppDescriptorRegistry appDescriptorRegistry; - private final LegacyAppDescriptorProvider.ColumnDefinitionFilter legacyAppColumnDefinitionFilter; - - @Inject - public AppRegistrar( - @AppFactories final Set> appFactories, - final AppDescriptorRegistry appDescriptorRegistry, - final LegacyAppDescriptorProvider.ColumnDefinitionFilter legacyAppColumnDefinitionFilter - ) { - this.appFactories = appFactories; - this.appDescriptorRegistry = appDescriptorRegistry; - this.legacyAppColumnDefinitionFilter = legacyAppColumnDefinitionFilter; - } - - public void register() { - appFactories.forEach(this::register); - } - - private void register(final Class factoryClass) { - LOG.info("Detected app bean with name '{}'", factoryClass.getName()); - // build app descriptor from detected factory bean - final Object factory = Components.newInstance(factoryClass); - final AppDescriptorProvider appDescriptorProvider = new AppDescriptorProvider(factory); - final LegacyAppDescriptorProvider legacyAppDescriptorProvider = new LegacyAppDescriptorProvider(factory, legacyAppColumnDefinitionFilter); - // register app descriptor - if(legacyAppDescriptorProvider.shouldRegister()) { - LOG.info("Registered legacy chooser app '{}'", legacyAppDescriptorProvider.getMetadata().getReferenceId()); - appDescriptorRegistry.register(legacyAppDescriptorProvider); - } - appDescriptorRegistry.register(appDescriptorProvider); - LOG.info("Registered app '{}'", appDescriptorProvider.getMetadata().getReferenceId()); - } - - @BindingAnnotation - @Retention(RetentionPolicy.RUNTIME) - @Target({ ElementType.PARAMETER}) - public @interface AppFactories { - } -} diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/ChooserDialogConfigurationSource.java b/src/main/java/com/namics/oss/magnolia/appbuilder/ChooserDialogConfigurationSource.java new file mode 100644 index 0000000..3cb8562 --- /dev/null +++ b/src/main/java/com/namics/oss/magnolia/appbuilder/ChooserDialogConfigurationSource.java @@ -0,0 +1,86 @@ +package com.namics.oss.magnolia.appbuilder; + +import static com.google.common.base.CaseFormat.*; + +import info.magnolia.config.registry.DefinitionMetadata; +import info.magnolia.config.registry.DefinitionProvider; +import info.magnolia.config.registry.DefinitionType; +import info.magnolia.config.registry.RegistryMap; +import info.magnolia.config.source.ConfigurationSource; +import info.magnolia.config.source.ConfigurationSourceType; +import info.magnolia.config.source.ConfigurationSourceTypes; +import info.magnolia.objectfactory.Components; +import info.magnolia.ui.dialog.DefinitionTypes; +import info.magnolia.ui.dialog.DialogDefinition; + +import java.lang.invoke.MethodHandles; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.namics.oss.magnolia.appbuilder.annotations.ChooserDialogFactories; + +public class ChooserDialogConfigurationSource implements ConfigurationSource { + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final RegistryMap registryMap = new RegistryMap<>(); + private final Set> chooserDialogFactories; + + @Inject + public ChooserDialogConfigurationSource(@ChooserDialogFactories final Set> chooserDialogFactories) { + this.chooserDialogFactories = chooserDialogFactories; + } + + @Override + public ConfigurationSourceType type() { + return ConfigurationSourceTypes.code; + } + + @Override + public DefinitionType getDefinitionType() { + return DefinitionTypes.DIALOG; + } + + @Override + public void start() { + LOG.info("Setting up {} for {} definitions", getClass().getSimpleName(), LOWER_CAMEL.to(LOWER_HYPHEN, getDefinitionType().getName())); + registryMap.removeAndPutAll( + registryMap.keySet(), + chooserDialogFactories.stream() + .flatMap(this::definitionProviders) + .collect(Collectors.toSet()) + ); + } + + private Stream> definitionProviders(final Class factoryClass) { + LOG.info("Registered dialog '{}' from {}", factoryClass.getSimpleName(), factoryClass.getName()); + final Object factory = Components.newInstance(factoryClass); + return Stream.of(new ChooserDialogDefinitionProvider<>(factory)); + } + + @Override + public DefinitionProvider getProvider(final DefinitionMetadata id) { + return registryMap.get(id); + } + + @Override + public DefinitionProvider getProvider(final String id) { + return registryMap.getByStringKey(id); + } + + @Override + public Collection getAllMetadata() { + return registryMap.keySet(); + } + + @Override + public Collection> getAllProviders() { + return registryMap.values(); + } + +} diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/ChooserDialogRegistrar.java b/src/main/java/com/namics/oss/magnolia/appbuilder/ChooserDialogRegistrar.java deleted file mode 100644 index 2178335..0000000 --- a/src/main/java/com/namics/oss/magnolia/appbuilder/ChooserDialogRegistrar.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.namics.oss.magnolia.appbuilder; - -import info.magnolia.objectfactory.Components; -import info.magnolia.ui.dialog.DialogDefinitionRegistry; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.invoke.MethodHandles; -import java.util.Set; - -import javax.inject.Inject; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.inject.BindingAnnotation; - -public class ChooserDialogRegistrar { - private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final Set> chooserDialogFactories; - private final DialogDefinitionRegistry dialogDefinitionRegistry; - - @Inject - public ChooserDialogRegistrar( - @ChooserDialogFactories final Set> chooserDialogFactories, - final DialogDefinitionRegistry dialogDefinitionRegistry - ) { - this.chooserDialogFactories = chooserDialogFactories; - this.dialogDefinitionRegistry = dialogDefinitionRegistry; - } - - public void register() { - chooserDialogFactories.forEach(this::register); - } - - private void register(final Class factoryClass) { - LOG.info("Detected chooser dialog factory bean with name '{}'", factoryClass.getName()); - final Object factory = Components.newInstance(factoryClass); - final ChooserDialogDefinitionProvider chooserDialogDefinitionProvider = new ChooserDialogDefinitionProvider<>(factory); - dialogDefinitionRegistry.register(chooserDialogDefinitionProvider); - LOG.info("Registered chooser dialog '{}'", chooserDialogDefinitionProvider.getMetadata().getReferenceId()); - } - - @BindingAnnotation - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.PARAMETER}) - public @interface ChooserDialogFactories { - } -} diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/annotations/AppFactories.java b/src/main/java/com/namics/oss/magnolia/appbuilder/annotations/AppFactories.java new file mode 100644 index 0000000..4c30843 --- /dev/null +++ b/src/main/java/com/namics/oss/magnolia/appbuilder/annotations/AppFactories.java @@ -0,0 +1,13 @@ +package com.namics.oss.magnolia.appbuilder.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +@BindingAnnotation +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.PARAMETER }) +public @interface AppFactories {} diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/annotations/ChooserDialogFactories.java b/src/main/java/com/namics/oss/magnolia/appbuilder/annotations/ChooserDialogFactories.java new file mode 100644 index 0000000..9f78b6d --- /dev/null +++ b/src/main/java/com/namics/oss/magnolia/appbuilder/annotations/ChooserDialogFactories.java @@ -0,0 +1,14 @@ +package com.namics.oss.magnolia.appbuilder.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +@BindingAnnotation +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.PARAMETER }) +public @interface ChooserDialogFactories { +} diff --git a/src/main/java/com/namics/oss/magnolia/appbuilder/configuration/AppBuilderGuiceComponentConfigurer.java b/src/main/java/com/namics/oss/magnolia/appbuilder/configuration/AppBuilderGuiceComponentConfigurer.java index 150debd..3ce2a1e 100644 --- a/src/main/java/com/namics/oss/magnolia/appbuilder/configuration/AppBuilderGuiceComponentConfigurer.java +++ b/src/main/java/com/namics/oss/magnolia/appbuilder/configuration/AppBuilderGuiceComponentConfigurer.java @@ -4,14 +4,14 @@ import com.google.inject.TypeLiteral; import com.google.inject.multibindings.Multibinder; -import com.namics.oss.magnolia.appbuilder.AppRegistrar; -import com.namics.oss.magnolia.appbuilder.ChooserDialogRegistrar; +import com.namics.oss.magnolia.appbuilder.annotations.AppFactories; +import com.namics.oss.magnolia.appbuilder.annotations.ChooserDialogFactories; public class AppBuilderGuiceComponentConfigurer extends AbstractGuiceComponentConfigurer { @Override protected void configure() { super.configure(); - Multibinder.newSetBinder(binder(), new TypeLiteral>(){}, AppRegistrar.AppFactories.class); - Multibinder.newSetBinder(binder(), new TypeLiteral>(){}, ChooserDialogRegistrar.ChooserDialogFactories.class); + Multibinder.newSetBinder(binder(), new TypeLiteral>(){}, AppFactories.class); + Multibinder.newSetBinder(binder(), new TypeLiteral>(){}, ChooserDialogFactories.class); } }