jetbrick.template.JetTemplate.java Source code

Java tutorial

Introduction

Here is the source code for jetbrick.template.JetTemplate.java

Source

/**
 * jetbrick-template
 * http://subchen.github.io/jetbrick-template/
 *
 * Copyright 2010-2013 Guoqiang Chen. All rights reserved.
 * Email: subchen@gmail.com
 *
 * 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 jetbrick.template;

import java.io.*;
import java.util.Map;
import jetbrick.template.parser.*;
import jetbrick.template.parser.code.Code;
import jetbrick.template.parser.grammer.JetTemplateLexer;
import jetbrick.template.parser.grammer.JetTemplateParser;
import jetbrick.template.resource.Resource;
import jetbrick.template.runtime.*;
import jetbrick.template.utils.ExceptionUtils;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class JetTemplate {
    private static final Logger log = LoggerFactory.getLogger(JetTemplate.class);

    private final JetEngine engine;
    private final Resource resource;
    private final String encoding;
    private final boolean reloadable;
    private final File javaSourceFile;
    private final File javaClassFile;
    private JetPage pageObject;

    protected JetTemplate(JetEngine engine, Resource resource) {
        JetConfig config = engine.getConfig();

        this.engine = engine;
        this.resource = resource;
        this.encoding = config.getOutputEncoding();
        this.reloadable = config.isTemplateReloadable();
        this.javaSourceFile = engine.getJdkCompiler().getGenerateJavaSourceFile(resource.getQualifiedClassName());
        this.javaClassFile = engine.getJdkCompiler().getGenerateJavaClassFile(resource.getQualifiedClassName());

        // compile and load
        if ((!config.isCompileAlways()) && javaClassFile.lastModified() > resource.lastModified()) {
            try {
                loadClassFile();
            } catch (Throwable e) {
                //  load ???
                log.warn(e.getClass().getName() + ": " + e.getMessage());
                log.warn("Try to recompile the template.");
                compileAndLoadClass();
            }
        } else {
            compileAndLoadClass();
        }
    }

    protected void checkLastModified() {
        if (reloadable && javaClassFile.lastModified() < resource.lastModified()) {
            synchronized (this) {
                // double check
                if (javaClassFile.lastModified() < resource.lastModified()) {
                    compileAndLoadClass();
                }
            }
        }
    }

    //  disk ?
    private void loadClassFile() throws Exception {
        log.info("Loading template class file: " + javaClassFile.getAbsolutePath());
        Class<?> cls = engine.getClassLoader().loadClass(resource.getQualifiedClassName());

        // ??
        if (!encoding.equals(cls.getDeclaredField("$ENC").get(null))) {
            throw new IllegalStateException("The encoding of last compiled template class is not " + encoding);
        }

        pageObject = (JetPage) cls.newInstance();
    }

    //  source  class ? load class
    private void compileAndLoadClass() {
        log.info("Loading template source file: " + resource.getAbsolutePath());

        // generateJavaSource
        String source = generateJavaSource(resource);
        if (log.isInfoEnabled() && engine.getConfig().isCompileDebug()) {
            StringBuilder sb = new StringBuilder(source.length() + 128);
            sb.append("generateJavaSource: ");
            sb.append(javaSourceFile.getAbsolutePath());
            sb.append("\n");
            sb.append("===========================================================================\n");
            sb.append(source);
            sb.append("\n");
            sb.append("===========================================================================");
            log.info(sb.toString());
        }
        // compile
        Class<?> cls = engine.getJdkCompiler().compile(resource.getQualifiedClassName(), source);
        log.info("generateJavaClass: " + javaClassFile.getAbsolutePath());
        try {
            pageObject = (JetPage) cls.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.uncheck(e);
        }
    }

    private String generateJavaSource(Resource resource) {
        char[] source = resource.getSource();
        ANTLRInputStream is = new ANTLRInputStream(source, source.length);
        is.name = resource.getAbsolutePath(); // set source file name, it will be displayed in error report.

        JetTemplateParser parser = new JetTemplateParser(new CommonTokenStream(new JetTemplateLexer(is)));
        parser.removeErrorListeners(); // remove ConsoleErrorListener
        parser.addErrorListener(new JetTemplateErrorListener());
        parser.setErrorHandler(new JetTemplateErrorStrategy());

        JetTemplateCodeVisitor visitor = new JetTemplateCodeVisitor(engine, engine.getVariableResolver(), parser,
                resource);
        Code code = parser.template().accept(visitor);
        return code.getSource();
    }

    public void render(Map<String, Object> context, Writer out) {
        render(new JetContext(context), out);
    }

    public void render(Map<String, Object> context, OutputStream out) {
        render(new JetContext(context), out);
    }

    public void render(JetContext context, Writer out) {
        JetWriter writer = JetWriter.create(out, encoding);
        render(new JetPageContext(this, context, writer));
    }

    public void render(JetContext context, OutputStream out) {
        JetWriter writer = JetWriter.create(out, encoding);
        render(new JetPageContext(this, context, writer));
    }

    public void render(JetContext context, JetWriter writer) {
        render(new JetPageContext(this, context, writer));
    }

    private void render(JetPageContext ctx) {
        try {
            pageObject.render(ctx);
        } catch (Throwable e) {
            throw ExceptionUtils.uncheck(e);
        }
    }

    public JetEngine getEngine() {
        return engine;
    }

    public String getName() {
        return resource.getName();
    }
}