/**
* 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 com.google.wave.splash.web.template;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import org.mvel2.templates.CompiledTemplate;
import org.mvel2.templates.TemplateCompiler;
import org.mvel2.templates.TemplateRuntime;
import org.mvel2.templates.util.TemplateTools;
import org.waveprotocol.box.server.CoreSettings;
import cc.kune.common.client.log.Log;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.wave.splash.text.Markup;
// TODO: Auto-generated Javadoc
/**
* 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.
/** The Constant BLIP_TEMPLATE. */
public static final String BLIP_TEMPLATE = "blip.html.fragment";
/** The Constant CLIENT_TEMPLATE. */
public static final String CLIENT_TEMPLATE = "full_client.html";
/** The Constant FEED_TEMPLATE. */
public static final String FEED_TEMPLATE = "feed.html.fragment";
/** The Constant HEADER_TEMPLATE. */
public static final String HEADER_TEMPLATE = "header.html.fragment";
/** The Constant LOG. */
private static final Logger LOG = Logger.getLogger(Templates.class.getName());
/** The Constant MOBILE_TEMPLATE. */
public static final String MOBILE_TEMPLATE = "mobile_client.html";
/** The Constant PERMALINK_WAVE_TEMPLATE. */
public static final String PERMALINK_WAVE_TEMPLATE = "permalink_client.html";
/** The Constant TEMPLATES_LOCATION. */
private static final String TEMPLATES_LOCATION = "others/splash/";
/** The Constant WAVE_NOT_FOUND_TEMPLATE. */
public static final String WAVE_NOT_FOUND_TEMPLATE = "wave_not_found.html.fragment";
/** The markup. */
private final Markup markup;
/** The prefix. */
private String prefix;
/** The production mode. */
private final boolean productionMode = true;
/**
* file name of template -> compiled template lazy cache.
*
* FIXME: For new versions of guava
* http://code.google.com/p/guava-libraries/wiki/MapMakerMigration
*/
private final LoadingCache<String, CompiledTemplate> templates = CacheBuilder.newBuilder().build(
new CacheLoader<String, CompiledTemplate>() {
@Override
public CompiledTemplate load(final String key) throws Exception {
return loadTemplate(key);
}
});
/**
* Instantiates a new templates.
*
* @param markup
* the markup
* @param resourceBases
* the resource bases
*/
@Inject
public Templates(final Markup markup,
@Named(CoreSettings.RESOURCE_BASES) final List<String> resourceBases) {
this.markup = markup;
for (final String path : resourceBases) {
final String prefix = path + (path.endsWith(File.separator) ? "" : File.separator);
final String pathAndfilename = prefix + TEMPLATES_LOCATION + Templates.BLIP_TEMPLATE;
final File file = new File(pathAndfilename);
if (file.exists()) {
this.prefix = prefix;
break;
}
}
Preconditions.checkArgument(prefix != null, "Could not find templates");
}
/**
* Load template.
*
* @param template
* the template
* @return the compiled template
*/
private CompiledTemplate loadTemplate(final String template) {
// Load from jar if in production mode, otherwise servlet root.
final InputStream input = openResource(template);
Preconditions.checkArgument(input != null, "Could not find template named: " + template);
try {
return TemplateCompiler.compileTemplate(TemplateTools.readStream(input));
} finally {
try {
input.close();
} catch (final IOException e) {
// Can't do much.
e.printStackTrace();
LOG.warning(e.toString());
}
}
}
/**
* 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(final String file) {
// final InputStream stream = productionMode ?
// Templates.class.getResourceAsStream(file)
// : servletContext.get().getResourceAsStream("/" + file);
FileInputStream stream = null;
try {
stream = new FileInputStream(new File(prefix + TEMPLATES_LOCATION + file));
} catch (final FileNotFoundException e) {
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(final String template, final Object context) {
// Reload template each time for development mode.
CompiledTemplate compiledTemplate = null;
try {
compiledTemplate = productionMode ? templates.get(template) : loadTemplate(template);
} catch (final ExecutionException e) {
Log.error("Cannot process the template: ", e);
}
final Map<String, Object> vars = Maps.newHashMap();
vars.put("markup", markup);
return TemplateRuntime.execute(compiledTemplate, context, vars).toString();
}
}