blob: bc6eb4d6f7d0770ab6836b9f649cf39c6cb70908 [file] [log] [blame]
/* Copyright 2004-2005 the original author or authors.
*
* 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.codehaus.groovy.grails.scaffolding;
import groovy.text.SimpleTemplateEngine;
import groovy.text.Template;
import groovy.text.TemplateEngine;
import org.codehaus.groovy.control.CompilationFailedException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
import java.util.HashMap;
/**
* A template factory that looks up templates from the servlet context
*
* @author Graeme Rocher
* @since 06-Jan-2006
*/
public class ServletContextTemplateFactory implements TemplateFactory {
public static final Log LOG = LogFactory.getLog(ServletContextTemplateFactory.class);
public static final String PATH_PREFIX = "/WEB-INF/grails-app/views/scaffolding/";
public static final String PATH_SUFFIX = ".gsp";
private ServletContext servletContext;
private TemplateEngine templateEngine = new SimpleTemplateEngine();
private Map cachedTemplates = new HashMap();
private Map cachedUrls = new HashMap();
public ServletContextTemplateFactory(ServletContext servletContext) {
this.servletContext = servletContext;
}
/**
* Simple class to hold the last modified info and file name
*/
class StoredTemplate {
private Template template;
private URL url;
private long lastModified;
}
public Template findTemplateForType(Class type) {
try {
if(LOG.isTraceEnabled()) {
LOG.trace("[TemplateFactory] Attempting to retrieve template for type ["+type+"]");
}
URL templateUrl;
if(cachedTemplates.containsKey(type)) {
templateUrl = (URL)cachedUrls.get(type);
}
else {
templateUrl = locateTemplateUrl(type);
cachedUrls.put(type,templateUrl);
}
if(templateUrl != null) {
Template t;
URLConnection con = templateUrl.openConnection();
if(cachedTemplates.containsKey(type)) {
StoredTemplate st = (StoredTemplate)cachedTemplates.get(type);
if(con.getLastModified() > st.lastModified) {
t = templateEngine.createTemplate(templateUrl);
st.template = t;
st.lastModified = con.getLastModified();
}
else {
t = st.template;
}
}
else {
t = templateEngine.createTemplate(templateUrl);
StoredTemplate st = new StoredTemplate();
st.lastModified = con.getLastModified();
st.template = t;
st.url = templateUrl;
cachedTemplates.put(type,st);
}
if(LOG.isTraceEnabled()) {
LOG.trace("[TemplateFactory] Building template for URL ["+templateUrl+"]");
}
return t;
}
} catch (CompilationFailedException e) {
LOG.error("Failed to compile template for type ["+type+"]: " + e.getMessage(),e);
} catch (ClassNotFoundException e) {
LOG.error("Class not found compiling template for type ["+type+"]: " + e.getMessage(),e);
} catch (IOException e) {
LOG.error("I/O error reading template for type ["+type+"]: " + e.getMessage(),e);
}
return null;
}
private URL locateTemplateUrl(Class type)
throws MalformedURLException {
if(type == Object.class)
return null;
URL returnUrl = this.servletContext.getResource(PATH_PREFIX + type.getName() + PATH_SUFFIX);
if(returnUrl == null) {
return locateTemplateUrl(type.getSuperclass());
}
return returnUrl;
}
public Template findNamedTemplateForType(Class type, String name) {
throw new UnsupportedOperationException("Not yet implemented");
}
}