-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
eschleb
committed
Oct 1, 2024
1 parent
556da6f
commit c8dbdc7
Showing
29 changed files
with
1,344 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
# Magnolia Templatebuilder | ||
|
||
The TemplateBuilder module is a builder for Magnolia templates in a java. | ||
|
||
## Setup | ||
|
||
### Add Maven dependency: | ||
```xml | ||
<dependency> | ||
<groupId>com.merkle.oss.magnolia</groupId> | ||
<artifactId>magnolia-templatebuilder</artifactId> | ||
<version>1.4.0</version> | ||
</dependency> | ||
``` | ||
|
||
### DI-Bindings | ||
```xml | ||
<module> | ||
<name>SomeModule</name> | ||
... | ||
<components> | ||
<id>main</id> | ||
<configurer> | ||
<class>GuiceComponentConfigurer</class> | ||
</configurer> | ||
</components> | ||
... | ||
</module> | ||
``` | ||
|
||
```java | ||
import info.magnolia.objectfactory.guice.AbstractGuiceComponentConfigurer; | ||
import info.magnolia.virtualuri.VirtualUriMapping; | ||
|
||
import org.apache.commons.lang3.reflect.TypeLiteral; | ||
import org.reflections.Reflections; | ||
|
||
import com.google.inject.multibindings.Multibinder; | ||
import com.merkle.oss.magnolia.templatebuilder.annotation.Template; | ||
import com.merkle.oss.magnolia.templatebuilder.annotation.TemplateFactories; | ||
|
||
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<Class<?>> templateFactoryMultibinder = Multibinder.newSetBinder(binder, new TypeLiteral<>() {}, TemplateFactories.class); | ||
new Reflections(getClass()).getTypesAnnotatedWith(Template.class).forEach(clazz -> templateFactoryMultibinder.addBinding().toInstance(clazz)); | ||
} | ||
} | ||
``` | ||
|
||
## How to use | ||
|
||
## Example | ||
|
||
### Area-component-category | ||
```java | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
import com.merkle.oss.magnolia.templatebuilder.annotation.area.ComponentCategory; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.TYPE) | ||
@ComponentCategory | ||
public @interface ContentArea {} | ||
``` | ||
|
||
### Component-template | ||
|
||
```java | ||
import com.merkle.oss.magnolia.templatebuilder.annotation.Template; | ||
|
||
@ContentArea | ||
@Template( | ||
id = SomeComponent.ID, | ||
title = "templates.components." + SomeComponent.NAME + ".title", | ||
dialog = SomeComponentDialog.ID, | ||
description = "templates.components." + SomeComponent.NAME + ".description", | ||
renderer = "freemarker", | ||
templateScript = "/someModule/templates/components/someComponent.ftl" | ||
) | ||
public class SomeComponent extends BaseComponent { | ||
public static final String NAME = "SomeComponent"; | ||
public static final String ID = "SomeApp:components/" + NAME; | ||
} | ||
``` | ||
### Page-template with area | ||
|
||
```java | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import javax.jcr.Node; | ||
|
||
import com.merkle.oss.magnolia.templatebuilder.annotation.Available; | ||
import com.merkle.oss.magnolia.templatebuilder.annotation.Template; | ||
import com.merkle.oss.magnolia.templatebuilder.annotation.area.Area; | ||
import com.merkle.oss.magnolia.templatebuilder.annotation.area.AvailableComponentClasses; | ||
import com.merkle.oss.magnolia.templatebuilder.annotation.area.AvailableComponents; | ||
|
||
@Template( | ||
id = SomePage.ID, | ||
title = "templates.pages." + SomePage.NAME + ".title", | ||
dialog = SomePageDialog.ID, | ||
description = "templates.pages." + SomePage.NAME + ".description", | ||
renderer = "freemarker", | ||
templateScript = "/someModule/templates/pages/somePage.ftl" | ||
) | ||
public class SomePage { | ||
public static final String NAME = "SomePage"; | ||
public static final String ID = "SomeApp:pages/" + NAME; | ||
|
||
@Available | ||
public boolean isAvailable(final Node node) { | ||
//TODO implement | ||
return true; | ||
} | ||
|
||
@Area( | ||
id = ContentArea.ID, | ||
name = ContentArea.NAME, | ||
title = "templates.areas." + SomePage.ContentArea.NAME + ".title", | ||
renderer = "freemarker", //optional, uses templates renderer if not specified | ||
templateScript = "/someModule/templates/areas/contentArea.ftl" | ||
) | ||
@AvailableComponentClasses({ ContentArea.class }) | ||
@AvailableComponents({ "someComponentId" }) | ||
public static class ContentArea { | ||
public static final String NAME = "ContentArea"; | ||
public static final String ID = SomePage.ID + "/" + NAME; | ||
} | ||
} | ||
``` | ||
|
||
## Customization | ||
### Definition decorators | ||
Implement a decorator: | ||
```java | ||
import info.magnolia.config.registry.DefinitionProvider; | ||
import info.magnolia.config.registry.DefinitionProviderWrapper; | ||
import info.magnolia.config.registry.Registry; | ||
import info.magnolia.config.registry.decoration.DefinitionDecorator; | ||
import info.magnolia.config.registry.decoration.DefinitionDecoratorMetadata; | ||
import info.magnolia.rendering.template.TemplateDefinition; | ||
|
||
|
||
public class CustomTemplateDefinitionDecorator implements DefinitionDecorator<TemplateDefinition> { | ||
@Override | ||
public DefinitionDecoratorMetadata metadata() { | ||
return () -> "someModule"; | ||
} | ||
|
||
@Override | ||
public boolean appliesTo(final DefinitionProvider<TemplateDefinition> definitionProvider) { | ||
//TODO implement | ||
return true; | ||
} | ||
|
||
@Override | ||
public DefinitionProvider<TemplateDefinition> decorate(final DefinitionProvider<TemplateDefinition> definitionProvider) { | ||
return new DefinitionProviderWrapper<>(definitionProvider) { | ||
@Override | ||
public TemplateDefinition get() throws Registry.InvalidDefinitionException { | ||
//TODO deorate definition | ||
return definitionProvider.get(); | ||
} | ||
}; | ||
} | ||
} | ||
``` | ||
|
||
Override the TemplateDefinitionProvider.Factory and pass your custom decorator to TemplateDefinitionProvider: | ||
```java | ||
import info.magnolia.objectfactory.Components; | ||
import info.magnolia.rendering.template.configured.ConfiguredAreaDefinition; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import javax.inject.Inject; | ||
|
||
import org.springframework.beans.BeansException; | ||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.context.ApplicationContextAware; | ||
import org.springframework.stereotype.Component; | ||
|
||
import com.merkle.oss.magnolia.templatebuilder.TemplateAvailabilityResolver; | ||
import com.merkle.oss.magnolia.templatebuilder.TemplateDefinitionProvider; | ||
|
||
public class CustomTemplateDefinitionProviderFactory extends TemplateDefinitionProvider.Factory { | ||
private final TemplateAvailabilityResolver templateAvailabilityResolver; | ||
private final CustomTemplateDefinitionDecorator customTemplateDefinitionDecorator; | ||
|
||
@Inject | ||
public CustomTemplateDefinitionProviderFactory( | ||
final TemplateAvailabilityResolver templateAvailabilityResolver, | ||
final CustomTemplateDefinitionDecorator customTemplateDefinitionDecorator | ||
) { | ||
super(templateAvailabilityResolver); | ||
this.templateAvailabilityResolver = templateAvailabilityResolver; | ||
this.customTemplateDefinitionDecorator = customTemplateDefinitionDecorator; | ||
} | ||
|
||
public TemplateDefinitionProvider create(final Set<Class<?>> templateFactories, final Class<?> factoryClass) { | ||
return new TemplateDefinitionProvider( | ||
List.of(customTemplateDefinitionDecorator), | ||
templateAvailabilityResolver, | ||
() -> Components.newInstance(ConfiguredAreaDefinition.class), | ||
templateFactories, | ||
() -> Components.newInstance(factoryClass), | ||
factoryClass | ||
); | ||
} | ||
} | ||
``` | ||
bind custom factory: | ||
```xml | ||
<component> | ||
<type>com.merkle.oss.magnolia.templatebuilder.TemplateDefinitionProvider.Factory</type> | ||
<implementation>com.somepackage.CustomTemplateDefinitionProviderFactory</implementation> | ||
</component> | ||
``` | ||
|
||
### ParameterResolver | ||
Implement and bind different AvailabilityParameterResolverFactory to customize injectable `@Availabile` method arguments. | ||
|
||
```java | ||
import info.magnolia.rendering.template.TemplateDefinition; | ||
|
||
import javax.inject.Inject; | ||
import javax.jcr.Node; | ||
|
||
import com.merkle.oss.magnolia.builder.parameter.ParameterResolver; | ||
import com.merkle.oss.magnolia.powernode.PowerNodeService; | ||
import com.merkle.oss.magnolia.templatebuilder.parameter.AvailabilityParameterResolverFactory; | ||
import com.merkle.oss.magnolia.templatebuilder.parameter.DefaultAvailabilityParameterResolver; | ||
|
||
public class CustomAvailabilityParamResolver extends ParameterResolver { | ||
|
||
public CustomAvailabilityParamResolver( | ||
final Node node, | ||
final TemplateDefinition templateDefinition | ||
) { | ||
super(new DefaultAvailabilityParameterResolver(node, templateDefinition)); | ||
} | ||
|
||
@Override | ||
public Object resolveParameter(final Class<?> parameterType) { | ||
if (parameterType.equals(SomeCustomParam.class)) { | ||
return new SomeCustomParam(); | ||
} | ||
return super.resolveParameter(parameterType); | ||
} | ||
|
||
public static class Factory implements AvailabilityParameterResolverFactory { | ||
@Override | ||
public ParameterResolver create(final Node node, final TemplateDefinition templateDefinition) { | ||
return new CustomAvailabilityParamResolver(node, templateDefinition); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
```xml | ||
<component> | ||
<type>com.merkle.oss.magnolia.templatebuilder.parameter.AvailabilityParameterResolverFactory</type> | ||
<implementation>com.somepackage.CustomAvailabilityParamResolver$Factory</implementation> | ||
</component> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>com.merkle.oss.magnolia</groupId> | ||
<artifactId>magnolia-dynamic-builder</artifactId> | ||
<version>1.4.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>magnolia-templatebuilder</artifactId> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.merkle.oss.magnolia</groupId> | ||
<artifactId>magnolia-dynamic-builder-common</artifactId> | ||
</dependency> | ||
|
||
<!-- Magnolia --> | ||
<dependency> | ||
<groupId>info.magnolia</groupId> | ||
<artifactId>magnolia-core</artifactId> | ||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>info.magnolia.ui</groupId> | ||
<artifactId>magnolia-ui-framework</artifactId> | ||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>info.magnolia</groupId> | ||
<artifactId>magnolia-rendering</artifactId> | ||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>info.magnolia.advancedcache</groupId> | ||
<artifactId>magnolia-advanced-cache-dpc</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>jakarta.servlet</groupId> | ||
<artifactId>jakarta.servlet-api</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.code.findbugs</groupId> | ||
<artifactId>jsr305</artifactId> | ||
</dependency> | ||
|
||
<!-- TESTING DEPENDENCIES --> | ||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.mockito</groupId> | ||
<artifactId>mockito-core</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
Oops, something went wrong.