package com.linkedin.thirdeye.dashboard; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Locale; import java.util.Map; import java.util.concurrent.ExecutionException; import javax.ws.rs.WebApplicationException; import com.github.jknack.handlebars.Handlebars; import com.github.jknack.handlebars.Template; import com.github.jknack.handlebars.cache.GuavaTemplateCache; import com.github.jknack.handlebars.io.TemplateSource; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import io.dropwizard.views.View; import io.dropwizard.views.ViewRenderer; /** * A {@link ViewRenderer} which renders Handlebars ({@code .hbs}) templates. */ public class HandlebarsViewRenderer implements ViewRenderer { /** * For use by Handlebars.java internally. */ private static final Cache<TemplateSource, Template> templateCache = CacheBuilder .newBuilder() .build(); private static final String HANDLEBARS_FILE_SUFFIX = ".hbs"; /** * Handlebars.java does not cache reads of Template content from resources. */ @VisibleForTesting static final LoadingCache<String, Template> compilationCache = CacheBuilder .newBuilder() .build(new CacheLoader<String, Template>() { @Override public Template load(String srcUrl) throws Exception { return HANDLEBARS.compile(srcUrl.replaceAll(HANDLEBARS_FILE_SUFFIX + "$", "")); } }); /** * Exposed for use in {@link HandlebarsHelperBundle} for miscellaneous configuration. */ static final Handlebars HANDLEBARS = new Handlebars() .with(new GuavaTemplateCache(templateCache)); public HandlebarsViewRenderer() { } @Override public boolean isRenderable(View view) { return view.getTemplateName().endsWith(HANDLEBARS_FILE_SUFFIX); // || view.getTemplateName().endsWith(".mustache"); // we can replace dropwizard-views-mustache with this. } @Override public void render(View view, Locale locale, OutputStream output) throws IOException, WebApplicationException { try (Writer writer = new OutputStreamWriter(output, view.getCharset().or(Charsets.UTF_8))) { compilationCache.get(view.getTemplateName()).apply(view, writer); } catch (FileNotFoundException | ExecutionException e) { throw new FileNotFoundException("Template " + view.getTemplateName() + " not found."); } } @Override public void configure(Map<String, String> options) { // TODO Auto-generated method stub // jteoh - new method required as part of dropwizard upgrade to 0.8.2 } @Override public String getSuffix() { // TODO Auto-generated method stub // jteoh - new method required as part of dropwizard upgrade to 0.8.2 return HANDLEBARS_FILE_SUFFIX; } }