All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jooby.ftl.Ftl Maven / Gradle / Ivy

There is a newer version: 1.6.9
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jooby.ftl;

import static java.util.Objects.requireNonNull;

import java.util.Properties;
import java.util.function.BiConsumer;

import org.jooby.Env;
import org.jooby.Jooby;
import org.jooby.Renderer;
import org.jooby.internal.ftl.Engine;
import org.jooby.internal.ftl.GuavaCacheStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheBuilderSpec;
import com.google.inject.Binder;
import com.google.inject.multibindings.Multibinder;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;

import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;

/**
 * Exposes a {@link Configuration} and a {@link Renderer}.
 *
 * 

usage

*

* It is pretty straightforward: *

* *
 * {
 *   use(new Ftl());
 *
 *   get("/", req {@literal ->} Results.html("index").put("model", new MyModel());
 * }
 * 
*

* public/index.html: *

* *
 *   ${model}
 * 
* *

* Templates are loaded from root of classpath: / and must end with: .html * file extension. *

* *

configuration

*

* There are two ways of changing a Freemarker configuration: *

*

application.conf

*

* Just add a freemarker.* option to your application.conf file: *

* *
 * freemarker.default_encoding = UTF-8
 * 
* *

programmatically

* *
 * {
 *   use(new Ftl().doWith((freemarker, config) {@literal ->} {
 *     freemarker.setDefaultEncoding("UTF-8");
 *   });
 * }
 * 
* *

* Keep in mind this is just an example and you don't need to set the default encoding. Default * encoding is set to: application.charset which is UTF-8 by default. *

* *

template loader

*

* Templates are loaded from the root of classpath and must end with .html. You can * change the default template location and extensions too: *

* *
 * {
 *   use(new Ftl("/", ".ftl"));
 * }
 * 
* *

cache

*

* Cache is OFF when env=dev (useful for template reloading), otherwise is ON. *

*

* Cache is backed by Guava and default cache will expire after 100 entries. *

*

* If 100 entries is not enough or you need a more advanced cache setting, just set the * freemarker.cache option: *

* *
 * freemarker.cache = "expireAfterWrite=1h"
 * 
* *

* See {@link CacheBuilderSpec}. *

* *

* That's all folks! Enjoy it!!! *

* * @author edgar * @since 0.5.0 */ public class Ftl implements Jooby.Module { /** The logging system. */ private final Logger log = LoggerFactory.getLogger(getClass()); private final String prefix; private final String suffix; private BiConsumer configurer; public Ftl(final String prefix, final String suffix) { this.prefix = requireNonNull(prefix, "Template prefix is required."); this.suffix = requireNonNull(suffix, "Template suffix is required."); } public Ftl(final String prefix) { this(prefix, ".html"); } public Ftl() { this("/"); } public Ftl doWith(final BiConsumer configurer) { this.configurer = requireNonNull(configurer, "Configurer is required."); return this; } @Override public void configure(final Env env, final Config config, final Binder binder) { try { Configuration freemarker = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); log.debug("Freemarker: {}", Configuration.getVersion()); freemarker.setSettings(properties(config)); freemarker.setTemplateLoader(new ClassTemplateLoader(getClass().getClassLoader(), prefix)); // cache if ("dev".equals(env.name()) || config.getString("freemarker.cache").isEmpty()) { // noop cache freemarker.setCacheStorage(NullCacheStorage.INSTANCE); } else { freemarker.setCacheStorage( new GuavaCacheStorage( CacheBuilder .from(config.getString("freemarker.cache")) .build() )); } if (configurer != null) { configurer.accept(freemarker, config); } binder.bind(Configuration.class).toInstance(freemarker); Engine engine = new Engine(freemarker, suffix); Multibinder.newSetBinder(binder, Renderer.class) .addBinding().toInstance(engine); } catch (TemplateException ex) { throw new IllegalStateException("Freemarker configuration results in error", ex); } } @Override public Config config() { return ConfigFactory.parseResources(getClass(), "freemarker.conf"); } private Properties properties(final Config config) { Properties props = new Properties(); // dump config.getConfig("freemarker").entrySet().forEach(e -> { String name = e.getKey(); String value = e.getValue().unwrapped().toString(); log.debug(" freemarker.{} = {}", name, value); props.setProperty(name, value); }); // this is a jooby option props.remove("cache"); return props; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy