Skip to content

Commit

Permalink
Implement templateBuilder module
Browse files Browse the repository at this point in the history
  • Loading branch information
eschleb committed Oct 1, 2024
1 parent 556da6f commit c8dbdc7
Show file tree
Hide file tree
Showing 29 changed files with 1,344 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ The DialogBuilder module is a builder for Magnolia dialogs in a java.

## [Magnolia-VirtualUriMapping-builder](magnolia-virtualUriMapping-builder/README.md)
The VirtualUriMapping-Builder module is a builder for Magnolia virtualUriMappings in a java.

## [Magnolia-templatebuilder](magnolia-templatebuilder/README.md)
The TemplateBuilder module is a builder for Magnolia templates in a java.
273 changes: 273 additions & 0 deletions magnolia-templatebuilder/README.md
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>
```
63 changes: 63 additions & 0 deletions magnolia-templatebuilder/pom.xml
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>
Loading

0 comments on commit c8dbdc7

Please sign in to comment.