/** * Copyright 2010 Google Inc. * * Licensed 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.waveprotocol.box.server.rpc.render.web.template; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.MapMaker; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.text.MessageFormat; import java.util.concurrent.ConcurrentMap; import java.util.logging.Logger; import javax.annotation.Nullable; import javax.servlet.ServletContext; /** * Handles all our html templates, loading, parsing and processing them. * * @author dhanji@gmail.com (Dhanji R. Prasanna) */ @Singleton public class Templates { // Template file names go here. public static final String OUTER_TEMPLATE = "start.html.fragment"; public static final String WAVELIST_TEMPLATE = "wavelist.html.fragment"; public static final String AVATAR_TEMPLATE = "avatar.html.fragment"; public static final String DIGEST_TEMPLATE = "digest.html.fragment"; public static final String BLIP_TEMPLATE = "blip.html.fragment"; public static final String ANCHOR_TEMPLATE = "anchor.html.fragment"; public static final String HEADER_TEMPLATE = "header.html.fragment"; public static final String FEED_TEMPLATE = "feed.html.fragment"; public static final String PERMALINK_WAVE_TEMPLATE = "permalink_client.html"; public static final String CLIENT_TEMPLATE = "full_client.html"; public static final String MOBILE_TEMPLATE = "mobile_client.html"; public static final String WAVE_NOT_FOUND_TEMPLATE = "wave_not_found.html.fragment"; public static final String GA_FRAGMENT = "<script type=\"text/javascript\">" + "var gaJsHost = ((\"https:\" == document.location.protocol) ? \"https://ssl.\" : \"http://www.\");" + "document.write(unescape(\"%3Cscript src='\" + gaJsHost + \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));" + "</script>" + "<script type=\"text/javascript\">" + "try {" + "var pageTracker = _gat._getTracker(\"UA-13269470-9\");" + "pageTracker._trackPageview();" + "} catch(err) {}</script>"; private static boolean PRODUCTION_MODE = false; private static final Logger log = Logger.getLogger(Templates.class.getName()); public static String convertStreamToString(InputStream is) throws IOException { /* * To convert the InputStream to String we use the Reader.read(char[] * buffer) method. We iterate until the Reader return -1 which means there's * no more data to read. We use the StringWriter class to produce the * string. */ if (is != null) { Writer writer = new StringWriter(); char[] buffer = new char[1024]; try { Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); int n; while ((n = reader.read(buffer)) != -1) { writer.write(buffer, 0, n); } } finally { is.close(); } return writer.toString(); } else { return ""; } } public static String makeAnchorTag(String id) { return "<div class='anchor' id='" + id + "'></anchor>"; } public static void insertIntoAnchor(String id, String inner, StringBuilder outer) { String anchorPrefix = "<div class='anchor' id='" + id + "'>"; int offset = outer.indexOf(anchorPrefix); outer.insert(offset + anchorPrefix.length(), inner); } /** * file name of template -> compiled template lazy cache. */ private final ConcurrentMap<String, String> templates = new MapMaker() .makeComputingMap(new Function<String, String>() { @Override public String apply(@Nullable String template) { return loadTemplate(template); } }); private final Provider<ServletContext> servletContext; @Inject public Templates(Provider<ServletContext> servletContext) { this.servletContext = servletContext; } private String loadTemplate(String template) { // Load from jar if in production mode, otherwise servlet root. InputStream input = openResource(template); Preconditions.checkArgument(input != null, "Could not find template named: " + template); try { InputStream is = openResource(template); return convertStreamToString(is); } catch (IOException e) { log.warning(e.toString()); } return ""; } /** * Opens a packaged resource from the file system. * * @param file The name of the file/resource to open. * @return An {@linkplain InputStream} to the named file, if found */ public InputStream openResource(String file) { InputStream stream = PRODUCTION_MODE ? Templates.class.getResourceAsStream(file) : servletContext.get() .getResourceAsStream("/templates/" + file); // load + compile templates on-demand if (null == stream) { log.info("Could not find resource named: " + file); } return stream; } /** * Loads templates if necessary. * * @param template Name of the template file. example: "blip.html.fragment" * @param context an object to process against * @return the processed, filled-in template. */ public String process(String template, Object[] context) { // Reload template each time for development mode. String pattern = PRODUCTION_MODE ? templates.get(template) : loadTemplate(template); return MessageFormat.format(pattern, context); } public static void main(String[] args) { Templates templates = new Templates(null); String out = templates.process(BLIP_TEMPLATE, new String[] {"\'0\'", "\'1\'", "2", "3", "4"}); System.out.println(out); } }