package edu.gatech.oad.rocket.findmythings.server; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import edu.gatech.oad.rocket.findmythings.server.util.tags.PageAuthTags; import freemarker.cache.URLTemplateLoader; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import java.util.Locale; import java.util.Map; import java.util.logging.Logger; public class PageGenerator { public static final String TEMPLATES = "FMTTemplateDirectory"; public static final String LOCALE = "FMTTemplateLocale"; public static final String CHARSET = "FMTTemplateCharset"; private static final Logger LOGGER = Logger.getLogger(PageGenerator.class.getName()); private static final String EMPTY_STRING = ""; /** * The root location where the templates are stored, either a local file, * or a directory served from a remote web server. */ private final URL templateBase; private final Locale locale; private final Charset charset; private Configuration config; PageGenerator(URL templateBase, Locale locale, Charset charset) throws IOException { Preconditions.checkNotNull(templateBase); Preconditions.checkNotNull(locale); Preconditions.checkNotNull(charset); this.templateBase = templateBase; this.locale = locale; this.charset = charset; } Template getTemplate(String templateName) throws IOException { String[] names = getFileNamesForSearch(locale, templateName); IOException lastException = null; for (String nm : names) { try { Template template = getConfig().getTemplate(nm); template.setOutputEncoding(charset.name()); return template; } catch (IOException e) { lastException = e; } } if (lastException != null) { LOGGER.fine("problem getting template \"" + templateName + "\" for " + locale + " in dir " + templateBase); throw lastException; } return null; } public String createPage(String templateName, Map<String, ?> args) throws IOException { Template template = getTemplate(templateName); if (template == null) { return EMPTY_STRING; } ByteArrayOutputStream os = new ByteArrayOutputStream(); try (Writer outLocal = new OutputStreamWriter(os, charset)) { template.process(args, outLocal); outLocal.close(); return new String(os.toByteArray(), charset); } catch (TemplateException e) { LOGGER.severe("Error processing template " + e.getMessage()); return EMPTY_STRING; } } public String createPage(String templateName, Object... args) throws IOException { return createPage(templateName, map(args)); } public void writePage(String templateName, Writer out, Map<String, ?> args) throws IOException { String append = createPage(templateName, args); if (append.length() != 0) { out.write(append); } } public void writePage(String templateName, Writer out, Object... args) throws IOException { writePage(templateName, out, map(args)); } // helper for variable argument (Object...) methods public static Map<String, Object> map(Object[] list) { Preconditions.checkNotNull(list); Preconditions.checkArgument(list.length % 2 == 0, "Your list has to have an even length, not " + list.length); Map<String,Object> out = Maps.newHashMap(); for (int i = 0; i < list.length; i += 2) { out.put((String)list[i], list[i+1]); } return out; } private static String[] getFileNamesForSearch(Locale locale, String templateName) { String language = locale.getLanguage().toLowerCase(); String country = locale.getCountry().toLowerCase(); return new String[]{ language + "_" + country + "_" + templateName, language + "_" + templateName, templateName }; } synchronized Configuration getConfig() { if (config == null) { config = new Configuration(); config.setObjectWrapper(new DefaultObjectWrapper()); try { config.setSetting(Configuration.CACHE_STORAGE_KEY, "strong:20, soft:250"); } catch (TemplateException e) { LOGGER.warning("Can't set freemarker cache (not fatal) " + e.getMessage()); } String charsetName = charset.name(); config.setDefaultEncoding(charsetName); config.setEncoding(locale, charsetName); config.setLocale(locale); config.setSharedVariable("shiro", new PageAuthTags()); config.setTemplateLoader(new URLTemplateLoader(){ @Override public URL getURL(String templateName) { Preconditions.checkNotNull(templateName); try { URL url = new URL(templateBase, templateName); URLConnection connect = url.openConnection(); try { connect.connect(); return url; } catch (IOException e) { return null; } } catch (IOException e) { throw new RuntimeException(e); } } }); } return config; } }