AbstractFreemarkerBuilder.java
- package fr.sii.ogham.template.freemarker.builder;
- import static freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS;
- import java.util.ArrayList;
- import java.util.List;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import fr.sii.ogham.core.builder.Builder;
- import fr.sii.ogham.core.builder.context.BuildContext;
- import fr.sii.ogham.core.builder.context.DefaultBuildContext;
- import fr.sii.ogham.core.builder.resolution.ClassPathResolutionBuilder;
- import fr.sii.ogham.core.builder.resolution.FileResolutionBuilder;
- import fr.sii.ogham.core.builder.resolution.ResourceResolutionBuilder;
- import fr.sii.ogham.core.builder.resolution.ResourceResolutionBuilderHelper;
- import fr.sii.ogham.core.builder.resolution.StringResolutionBuilder;
- import fr.sii.ogham.core.builder.template.DetectorBuilder;
- import fr.sii.ogham.core.fluent.AbstractParent;
- import fr.sii.ogham.core.resource.resolver.FirstSupportingResourceResolver;
- import fr.sii.ogham.core.resource.resolver.ResourceResolver;
- import fr.sii.ogham.core.template.detector.FixedEngineDetector;
- import fr.sii.ogham.core.template.detector.OrTemplateDetector;
- import fr.sii.ogham.core.template.detector.SimpleResourceEngineDetector;
- import fr.sii.ogham.core.template.detector.TemplateEngineDetector;
- import fr.sii.ogham.core.template.parser.TemplateParser;
- import fr.sii.ogham.template.freemarker.FreeMarkerFirstSupportingTemplateLoader;
- import fr.sii.ogham.template.freemarker.FreeMarkerParser;
- import fr.sii.ogham.template.freemarker.FreeMarkerTemplateDetector;
- import fr.sii.ogham.template.freemarker.SkipLocaleForStringContentTemplateLookupStrategy;
- import fr.sii.ogham.template.freemarker.TemplateLoaderOptions;
- import fr.sii.ogham.template.freemarker.adapter.ClassPathResolverAdapter;
- import fr.sii.ogham.template.freemarker.adapter.FileResolverAdapter;
- import fr.sii.ogham.template.freemarker.adapter.FirstSupportingResolverAdapter;
- import fr.sii.ogham.template.freemarker.adapter.StringResolverAdapter;
- import fr.sii.ogham.template.freemarker.adapter.TemplateLoaderAdapter;
- import freemarker.cache.TemplateLoader;
- import freemarker.template.Configuration;
- import freemarker.template.TemplateExceptionHandler;
- @SuppressWarnings("squid:S00119")
- public abstract class AbstractFreemarkerBuilder<MYSELF extends AbstractFreemarkerBuilder<MYSELF, P>, P> extends AbstractParent<P>
- implements DetectorBuilder<MYSELF>, ResourceResolutionBuilder<MYSELF>, Builder<TemplateParser> {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractFreemarkerBuilder.class);
- protected final MYSELF myself;
- protected final BuildContext buildContext;
- private TemplateEngineDetector detector;
- private ResourceResolutionBuilderHelper<MYSELF> resourceResolutionBuilderHelper;
- private Configuration configuration;
- private List<TemplateLoaderAdapter> customAdapters;
- private FreemarkerConfigurationBuilder<MYSELF> configurationBuilder;
- private ClassLoader classLoader;
- protected AbstractFreemarkerBuilder(Class<?> selfType) {
- this(selfType, null, new DefaultBuildContext());
- }
- @SuppressWarnings("unchecked")
- protected AbstractFreemarkerBuilder(Class<?> selfType, P parent, BuildContext buildContext) {
- super(parent);
- myself = (MYSELF) selfType.cast(this);
- this.buildContext = buildContext;
- customAdapters = new ArrayList<>();
- }
- @Override
- public MYSELF detector(TemplateEngineDetector detector) {
- this.detector = detector;
- return myself;
- }
- @Override
- public ClassPathResolutionBuilder<MYSELF> classpath() {
- initResolutionBuilder();
- return resourceResolutionBuilderHelper.classpath();
- }
- @Override
- public FileResolutionBuilder<MYSELF> file() {
- initResolutionBuilder();
- return resourceResolutionBuilderHelper.file();
- }
- @Override
- public StringResolutionBuilder<MYSELF> string() {
- initResolutionBuilder();
- return resourceResolutionBuilderHelper.string();
- }
- @Override
- public MYSELF resolver(ResourceResolver resolver) {
- initResolutionBuilder();
- return resourceResolutionBuilderHelper.resolver(resolver);
- }
- /**
- * Ogham provides a generic resource resolution mechanism
- * ({@link ResourceResolver}). Freemarker uses its own template resolution
- * mechanism ({@link TemplateLoader}). A resolver adapter
- * ({@link TemplateLoaderAdapter}) is the way to transform a
- * {@link ResourceResolver} into a {@link TemplateLoader}.
- *
- * <p>
- * Ogham provides and registers default resolver adapters but you may need
- * to use a custom {@link ResourceResolver}. So you also need to provide the
- * corresponding {@link TemplateLoaderAdapter}.
- *
- * @param adapter
- * the resolver adapter
- * @return this instance for fluent chaining
- */
- public MYSELF resolverAdapter(TemplateLoaderAdapter adapter) {
- customAdapters.add(adapter);
- return myself;
- }
- /**
- * Fluent configurer for Freemarker configuration.
- *
- * @return the fluent builder for Freemarker configuration object
- */
- public FreemarkerConfigurationBuilder<MYSELF> configuration() {
- if (configurationBuilder == null) {
- configurationBuilder = new FreemarkerConfigurationBuilder<>(myself, buildContext);
- }
- return configurationBuilder;
- }
- /**
- * Sets a Freemarker configuration.
- *
- * This value preempts any other value defined by calling
- * {@link #configuration()} method. It means that the provided configuration
- * is used as-is and any call to {@link #configuration()} builder methods
- * has no effect on the provided configuration. You have to manually
- * configure it.
- *
- * If this method is called several times, only the last provided
- * configuration is used.
- *
- * @param configuration
- * the Freemarker configuration
- * @return this instance for fluent chaining
- */
- public MYSELF configuration(Configuration configuration) {
- this.configuration = configuration;
- return myself;
- }
- /**
- * Merge an existing Freemarker configuration with previously provided
- * configuration.
- *
- * <p>
- * The provided configuration is used and any call to
- * {@link #configuration()} builder methods are applied to the provided
- * configuration.
- *
- *
- * @param configuration
- * The Freemarker configuration to apply
- * @return this instance for fluent chaining
- */
- public MYSELF mergeConfiguration(Configuration configuration) {
- configuration().base(configuration);
- return myself;
- }
- /**
- * Set the {@link ClassLoader} to use for loading classpath resources.
- *
- * <p>
- * Loading resources from classpath requires a {@link ClassLoader}. Several
- * class loaders may be defined in an application to isolate parts of the
- * application. FreeMarker requires you to provide a {@link ClassLoader} for
- * finding resources in the classpath. This is done for security reasons.
- *
- * <p>
- * By default, Ogham uses the current thread class loader.
- *
- * @param classLoader
- * the class loader to use
- * @return this instance for fluent chaining
- */
- public MYSELF classLoader(ClassLoader classLoader) {
- this.classLoader = classLoader;
- return myself;
- }
- @Override
- public TemplateParser build() {
- LOG.info("Freemarker parser is registered");
- return buildContext.register(new FreeMarkerParser(buildConfiguration(), buildResolver()));
- }
- @Override
- public TemplateEngineDetector buildDetector() {
- return detector == null ? buildDefaultDetector() : detector;
- }
- private TemplateEngineDetector buildDefaultDetector() {
- FirstSupportingResourceResolver resolver = buildResolver();
- OrTemplateDetector or = buildContext.register(new OrTemplateDetector());
- or.addDetector(buildContext.register(new FreeMarkerTemplateDetector(resolver, ".ftl", ".ftlh")));
- or.addDetector(buildContext.register(new SimpleResourceEngineDetector(resolver, buildContext.register(new FixedEngineDetector(true)))));
- return or;
- }
- /**
- * Builds the resolver used by Freemarker to resolve resources
- *
- * @return the resource resolver
- */
- public FirstSupportingResourceResolver buildResolver() {
- return buildContext.register(new FirstSupportingResourceResolver(buildResolvers()));
- }
- private Configuration buildConfiguration() {
- Configuration builtConfiguration;
- if (this.configuration != null) {
- builtConfiguration = this.configuration;
- } else if (configurationBuilder != null) {
- builtConfiguration = configurationBuilder.build();
- } else {
- builtConfiguration = new Configuration(DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
- builtConfiguration.setDefaultEncoding("UTF-8");
- builtConfiguration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
- }
- FirstSupportingResourceResolver builtResolver = buildResolver();
- FirstSupportingResolverAdapter builtAdapter = buildAdapter();
- builtConfiguration.setTemplateLoader(buildContext.register(new FreeMarkerFirstSupportingTemplateLoader(builtResolver, builtAdapter)));
- builtConfiguration.setTemplateLookupStrategy(buildContext.register(new SkipLocaleForStringContentTemplateLookupStrategy(builtConfiguration.getTemplateLookupStrategy(), builtResolver, builtAdapter)));
- return builtConfiguration;
- }
- protected List<ResourceResolver> buildResolvers() {
- initResolutionBuilder();
- return resourceResolutionBuilderHelper.buildResolvers();
- }
- protected FirstSupportingResolverAdapter buildAdapter() {
- FirstSupportingResolverAdapter adapter = new FirstSupportingResolverAdapter();
- for (TemplateLoaderAdapter custom : customAdapters) {
- adapter.addAdapter(custom);
- }
- adapter.addAdapter(buildContext.register(new ClassPathResolverAdapter(classLoader)));
- adapter.addAdapter(buildContext.register(new FileResolverAdapter()));
- adapter.addAdapter(buildContext.register(new StringResolverAdapter()));
- adapter.setOptions(buildContext.register(new TemplateLoaderOptions()));
- return adapter;
- }
- private void initResolutionBuilder() {
- if (resourceResolutionBuilderHelper == null) {
- resourceResolutionBuilderHelper = new ResourceResolutionBuilderHelper<>(myself, buildContext);
- }
- }
- }