/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.generator.gsp;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.granite.generator.Template;
import org.granite.generator.exception.TemplateCompilationException;
import org.granite.generator.exception.TemplateExecutionException;
import org.granite.generator.exception.TemplateParsingException;
import org.granite.generator.gsp.token.Token;
import org.granite.util.URIUtil;
/**
* @author Franck WOLFF
*/
public class GroovyTemplate implements Template {
private final URI uri;
private final boolean base;
private final Charset charset;
private String source = null;
private Script script = null;
private long lastModified = -1L;
GroovyTemplate(URI uri, boolean base, Charset charset) {
if (uri == null || charset == null)
throw new IllegalArgumentException("uri and charset cannot be null");
this.uri = uri;
this.base = base;
this.charset = charset;
}
protected void reset(boolean cleanSource) {
if (cleanSource)
source = null;
script = null;
lastModified = -1L;
}
protected void reset() {
reset(true);
}
@Override
public URI getUri() {
return uri;
}
public long getLastModified() {
return lastModified;
}
protected long readLastModified() {
long readLastModified = -1L;
if ("file".equals(uri.getScheme())) {
readLastModified = new File(uri).lastModified();
if (readLastModified == 0L)
readLastModified = -1L;
}
else
readLastModified = Long.MAX_VALUE;
return readLastModified;
}
public boolean isOutdated() {
long newLastModified = readLastModified();
return script != null && (newLastModified == -1 || lastModified < newLastModified);
}
@Override
public boolean isBase() {
return base;
}
@Override
public String getMarkup() {
try {
return URIUtil.getContentAsString(uri);
} catch (Exception e) {
return "Could not load uri content: " + uri + " (" + e.toString() + ")";
}
}
@Override
public String getSource() {
return source;
}
@Override
public void compile() throws IOException, TemplateParsingException, TemplateCompilationException {
reset();
InputStream is = null;
try {
is = URIUtil.getInputStream(uri, getClass().getClassLoader());
lastModified = readLastModified();
Reader reader = new BufferedReader(new InputStreamReader(is, charset));
Parser parser = new Parser();
List<Token> tokens = parser.parse(reader);
GroovyRenderer renderer = new GroovyRenderer();
source = renderer.renderSource(tokens);
// Warning: the classloader for javax annotations is defined in BuilderParentClassLoader
// in the case of the Eclipse generator
GroovyShell shell = new GroovyShell(Thread.currentThread().getContextClassLoader());
script = shell.parse(source);
} catch (ParseException e) {
throw new TemplateParsingException(this, "Could not parse template: " + uri, e);
} catch (CompilationFailedException e) {
throw new TemplateCompilationException(this, "Could not compile template: " + uri, e);
} finally {
if (script == null)
reset(false);
if (is != null)
is.close();
}
}
@Override
public void execute(Map<String, Object> bindings, Writer out)
throws IOException, TemplateParsingException, TemplateCompilationException, TemplateExecutionException {
if (script == null)
compile();
try {
Binding binding = (bindings == null ? new Binding() : new Binding(bindings));
Script scriptInstance = InvokerHelper.createScript(script.getClass(), binding);
scriptInstance.setProperty("out", out);
scriptInstance.run();
out.flush();
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new TemplateExecutionException(this, "Could not execute template: " + uri, e);
}
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof GroovyTemplate))
return false;
return uri.equals(((GroovyTemplate)obj).uri);
}
@Override
public int hashCode() {
return uri.hashCode();
}
}