All Downloads are FREE. Search and download functionalities are using the official Maven repository.

groovy.text.GStringTemplateEngine Maven / Gradle / Ivy

There is a newer version: 1.5.8
Show newest version
/*
 * Copyright 2003-2007 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 groovy.text;

import groovy.lang.Closure;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyObject;
import groovy.lang.Writable;

import java.io.IOException;
import java.io.Reader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;

import org.codehaus.groovy.control.CompilationFailedException;

/**
 * @author [email protected]
 * @author Paul King
 */
public class GStringTemplateEngine extends TemplateEngine {
    private final ClassLoader parentLoader;

    public GStringTemplateEngine() {
        this(GStringTemplate.class.getClassLoader());
    }

    public GStringTemplateEngine(ClassLoader parentLoader) {
        this.parentLoader = parentLoader;
    }

    /* (non-Javadoc)
    * @see groovy.text.TemplateEngine#createTemplate(java.io.Reader)
    */
    public Template createTemplate(final Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException {
        return new GStringTemplate(reader, parentLoader);
    }

    private static class GStringTemplate implements Template {
        final Closure template;

        /**
         * Turn the template into a writable Closure
         * When executed the closure evaluates all the code embedded in the
         * template and then writes a GString containing the fixed and variable items
         * to the writer passed as a parameter
         * 

* For example: *

* '<%= "test" %> of expr and <% test = 1 %>${test} script.' *

* would compile into: *

* { out -> out << "${"test"} of expr and "; test = 1 ; out << "${test} script."}.asWritable() * * @param reader * @param parentLoader * @throws CompilationFailedException * @throws ClassNotFoundException * @throws IOException */ GStringTemplate(final Reader reader, final ClassLoader parentLoader) throws CompilationFailedException, ClassNotFoundException, IOException { final StringBuffer templateExpressions = new StringBuffer("package groovy.tmp.templates\n def getTemplate() { return { out -> delegate = new Binding(delegate); out << \"\"\""); boolean writingString = true; while (true) { int c = reader.read(); if (c == -1) break; if (c == '<') { c = reader.read(); if (c == '%') { c = reader.read(); if (c == '=') { parseExpression(reader, writingString, templateExpressions); writingString = true; continue; } else { parseSection(c, reader, writingString, templateExpressions); writingString = false; continue; } } else { appendCharacter('<', templateExpressions, writingString); writingString = true; } } else if (c == '"') { appendCharacter('\\', templateExpressions, writingString); writingString = true; } appendCharacter((char) c, templateExpressions, writingString); writingString = true; } if (writingString) { templateExpressions.append("\"\"\""); } templateExpressions.append("}.asWritable()}"); final GroovyClassLoader loader = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new GroovyClassLoader(parentLoader); } }); final Class groovyClass = loader.parseClass(new GroovyCodeSource(templateExpressions.toString(), "C", "x")); try { final GroovyObject object = (GroovyObject) groovyClass.newInstance(); this.template = (Closure) object.invokeMethod("getTemplate", null); } catch (InstantiationException e) { throw new ClassNotFoundException(e.getMessage()); } catch (IllegalAccessException e) { throw new ClassNotFoundException(e.getMessage()); } } private static void appendCharacter(final char c, final StringBuffer templateExpressions, final boolean writingString) { if (!writingString) { templateExpressions.append("out << \"\"\""); } templateExpressions.append(c); } /** * Parse a <% .... %> section * if we are writing a GString close and append ';' * then write the section as a statement * * @param pendingC * @param reader * @param writingString * @param templateExpressions * @throws IOException */ private static void parseSection(final int pendingC, final Reader reader, final boolean writingString, final StringBuffer templateExpressions) throws IOException { if (writingString) { templateExpressions.append("\"\"\"; "); } templateExpressions.append((char) pendingC); while (true) { int c = reader.read(); if (c == -1) break; if (c == '%') { c = reader.read(); if (c == '>') break; templateExpressions.append('%'); } templateExpressions.append((char) c); } templateExpressions.append(";\n "); } /** * Parse a <%= .... %> expression * * @param reader * @param writingString * @param templateExpressions * @throws IOException */ private static void parseExpression(final Reader reader, final boolean writingString, final StringBuffer templateExpressions) throws IOException { if (!writingString) { templateExpressions.append("out << \"\"\""); } templateExpressions.append("${"); while (true) { int c = reader.read(); if (c == -1) break; if (c == '%') { c = reader.read(); if (c == '>') break; templateExpressions.append('%'); } templateExpressions.append((char) c); } templateExpressions.append('}'); } public Writable make() { return make(null); } public Writable make(final Map map) { final Closure template = (Closure) this.template.clone(); template.setDelegate(map); return (Writable) template; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy