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

com.fizzed.rocker.runtime.DefaultRockerTemplate Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015 Fizzed 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.fizzed.rocker.runtime;

import com.fizzed.rocker.BindableRockerModel;
import com.fizzed.rocker.ContentType;
import com.fizzed.rocker.RenderingException;
import com.fizzed.rocker.RockerOutput;
import com.fizzed.rocker.RockerStringify;
import com.fizzed.rocker.RockerTemplate;
import com.fizzed.rocker.RockerContent;
import com.fizzed.rocker.RockerModel;
import com.fizzed.rocker.RockerOutputFactory;
import java.io.IOException;

public abstract class DefaultRockerTemplate extends RockerTemplate {
    
    protected Internal __internal;
    
    public DefaultRockerTemplate(RockerModel model) {
        super(model);
        this.__internal = new Internal();
    }
    
    @Override
    protected void __associate(RockerTemplate context) {
        // safe to assume its a default instance
        // subclasses should verify what type is supplied though
        DefaultRockerTemplate otherContext = (DefaultRockerTemplate)context;
        
        // configure this template from another template
        // internally the out, content type, and stringify are all shared
        __internal.setOut(otherContext.__internal.getOut());
        __internal.setContentType(otherContext.__internal.getContentType(), otherContext.__internal.getStringify());
    }
    
    @Override
    protected RockerOutput __newOutput() {
        return new ArrayOfByteArraysOutput(__internal.getContentType(), __internal.getCharset());
    }

    /**
     * Executes template and renders content to output.
     * @param context The optional context if this template is being rendered within another template
     * @param outputFactory Factory for creating output if necessary
     * @return The output of rendering process
     * @throws RenderingException Thrown if any error encountered while rendering
     *      template. Exception will include underlying cause as well as line
     *      and position of original template source that triggered exception.
     */
    final public RockerOutput __render(DefaultRockerTemplate context,
                                       RockerOutputFactory outputFactory) throws RenderingException {
        // associate with a context of another template
        if (context != null) {
            this.__associate(context);
        }
        
        //
        // verify things are setup correctly
        //
        if (this.__internal.charset == null) {
            throw new RenderingException("Template charset must be initialized before render");
        }
        
        if (this.__internal.contentType == null) {
            throw new RenderingException("Content type must be initialized before render");
        }
        
        if (this.__internal.stringify == null) {
            throw new RenderingException("Stringify must be initialized before render");
        }
        
        if (this.__internal.out == null) {
            if (outputFactory != null) {
                this.__internal.out = outputFactory.create(this.__internal.contentType, this.__internal.charset);
            } else {
                this.__internal.out = __newOutput();
            }
        }
        
        // make sure not previously used
        __internal.verifyOkToBeginRendering();

        try {
            this.__doRender();
        } catch (CompileDiagnosticException e) {
            // do not wrap the underlying exception
            throw e;
        } catch (Throwable t) {
            // include info on source line + pos where execution failed
            String templatePath = __internal.templatePackageName.replace('.', '/');
            throw new RenderingException(__internal.sourceLine, __internal.sourcePosInLine, __internal.templateName, templatePath, t.getMessage(), t);
        }
        
        return __internal.out;
    }
    
    abstract protected void __doRender() throws IOException, RenderingException;
    
    //
    // implicits to rocker templates
    //
    
    public Raw raw(Object obj) throws IOException {
        if (obj == null) {
            throw new NullPointerException("Value was null");
        }
        return Raw.of(obj.toString());
    }
    
    public Raw raw(String s) throws IOException {
        if (s == null) {
            throw new NullPointerException("Value was null");
        }
        return Raw.of(s);
    }

    /**
     * Internal state of a template.
     * 
     * Simple way to hide internal variables from template (which of course
     * are subclasses of this class).
     * 
     * This is an internal API and it may radically change over time.  Using
     * this for workaround, etc. is not recommended.
     */
    protected class Internal {
        
        // shared vars (e.g. template A calls template B)
        private String charset;
        private ContentType contentType;
        private RockerStringify stringify;
        private RockerOutput out;
        
        private boolean rendered;
        // counters for where we are in original source (helps provide better runtime exceptions)
        private int sourceLine;
        private int sourcePosInLine;
        private String templateName;
        private String templatePackageName;
        
        private Internal() {
            this.sourceLine = -1;
            this.sourcePosInLine = -1;
        }

        public String getTemplateName() {
            return templateName;
        }

        public void setTemplateName(String templateName) {
            this.templateName = templateName;
        }

        public String getTemplatePackageName() {
            return templatePackageName;
        }

        public void setTemplatePackageName(String templatePackageName) {
            this.templatePackageName = templatePackageName;
        }

        public String getCharset() {
            return charset;
        }

        public void setCharset(String charset) {
            this.charset = charset;
        }
        
        public void aboutToExecutePosInTemplate(int line, int posInLine) {
            this.sourceLine = line;
            this.sourcePosInLine = posInLine;
        }
        
        public ContentType getContentType() {
            return this.contentType;
        }

        public void setContentType(ContentType contentType) {
            // set default stringify by content type of template
            this.setContentType(contentType, ContentType.stringify(contentType));
        }
        
        public void setContentType(ContentType contentType, RockerStringify stringify) {
            this.contentType = contentType;
            this.stringify = stringify;
        }

        public RockerStringify getStringify() {
            return stringify;
        }

        public void setStringify(RockerStringify stringify) {
            this.stringify = stringify;
        }

        public RockerOutput getOut() {
            return out;
        }

        public void setOut(RockerOutput out) {
            this.out = out;
        }
        
        protected void verifyOkToBeginRendering() {
            if (this.rendered) {
                throw new RenderingException("Template already rendered (templates are single use only!)");
            }
            this.rendered = true;
        }
        
        //
        // break, continue support
        //
        public void throwBreakException() throws BreakException {
            throw new BreakException();
        }
        
        public void throwContinueException() throws ContinueException {
            throw new ContinueException();
        }
        
        //
        // method for write raw expressions
        //
        
        public void writeValue(String s) throws IOException {
            out.w(s);
        }
        
        public void writeValue(byte[] bytes) throws IOException {
            out.w(bytes);
        }
        
        //
        // methods for rendering value expressions
        //
        public boolean renderValue(RockerContent c, boolean nullSafe) throws RenderingException, IOException {
            if (nullSafe && c == null) {
                return false;
            }
            
            // delegating rendering this chunk of content to itself
            c.render();
            
            return true;
        }
        
        public boolean renderValue(DefaultRockerModel model, boolean nullSafe) throws RenderingException, IOException {
            model.doRender(DefaultRockerTemplate.this, null, null);
            
            return true;
        }
        
        public boolean renderValue(BindableRockerModel model, boolean nullSafe) throws RenderingException, IOException {
            // delegating rendering this model to itself BUT under a context
            DefaultRockerModel underlyingModel = (DefaultRockerModel)model.getModel();
            
            return this.renderValue(underlyingModel, nullSafe);
        }
        
        public boolean renderValue(Raw raw, boolean nullSafe) throws RenderingException, IOException {
            if (nullSafe && raw.getValue() == null) {
                return false;
            }
            
            // no stringify for raws
            out.w(raw.toString());
            
            return true;
        }
        
        public boolean renderValue(String value, boolean nullSafe) throws IOException {
            if (nullSafe && value == null) {
                return false;
            }
            
            String s = stringify.s(value);
            
            // also, null safe protects against a toString() that returns a null
            if (nullSafe && s == null) {
                return false;
            }
            
            out.w(s);
            
            return true;
        }
        
        public boolean renderValue(Object value, boolean nullSafe) throws IOException {
            if (nullSafe && value == null) {
                return false;
            }
            
            String s = stringify.s(value);
            
            // also, null safe protects against a toString() that returns a null
            if (nullSafe && s == null) {
                return false;
            }
            
            out.w(s);
            
            return true;
        }
        
        public boolean renderValue(byte v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }
        
        public boolean renderValue(short v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }

        public boolean renderValue(int v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }
        
        public boolean renderValue(long v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }

        public boolean renderValue(float v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }

        public boolean renderValue(double v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }

        public boolean renderValue(char v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }

        public boolean renderValue(boolean v, boolean nullSafe) throws IOException {
            // ignore nullSafe since a primitive cannot be null
            out.w(stringify.s(v));
            
            return true;
        }
        
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy