Package org.apache.slide.projector.processor

Source Code of org.apache.slide.projector.processor.TemplateRenderer$EnclosingTemplateFragment

package org.apache.slide.projector.processor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.slide.projector.ConfigurableProcessor;
import org.apache.slide.projector.ConfigurationException;
import org.apache.slide.projector.ContentType;
import org.apache.slide.projector.Context;
import org.apache.slide.projector.ProcessException;
import org.apache.slide.projector.Result;
import org.apache.slide.projector.descriptor.AnyValueDescriptor;
import org.apache.slide.projector.descriptor.ParameterDescriptor;
import org.apache.slide.projector.descriptor.ResultDescriptor;
import org.apache.slide.projector.descriptor.ResultEntryDescriptor;
import org.apache.slide.projector.descriptor.StateDescriptor;
import org.apache.slide.projector.descriptor.StringValueDescriptor;
import org.apache.slide.projector.i18n.DefaultMessage;
import org.apache.slide.projector.i18n.ErrorMessage;
import org.apache.slide.projector.i18n.ParameterMessage;
import org.apache.slide.projector.util.StreamHelper;
import org.apache.slide.projector.value.ArrayValue;
import org.apache.slide.projector.value.NullValue;
import org.apache.slide.projector.value.PrintableValue;
import org.apache.slide.projector.value.StreamableValue;
import org.apache.slide.projector.value.StringValue;
import org.apache.slide.projector.value.Value;

public class TemplateRenderer implements ConfigurableProcessor {
    private static Logger logger = Logger.getLogger(TemplateRenderer.class.getName());

    public final static String OK = "ok";
    public final static String OUTPUT = "output";
    public final static String FRAGMENT = "fragment";

    protected final static String FRAGMENT_START = "<!--*** Start of '";
    protected final static String FRAGMENT_END = "<!--*** End of '";
    protected final static String FRAGMENT_CLOSE = "' ***-->";

    protected final static String IGNORE_START = "<!--*** Start ignore ***-->";
    protected final static String IGNORE_END = "<!-- *** End ignore *** -->";

    protected final static String TAG_OPEN = "<%";
    protected final static String TAG_CLOSE = "%>";
    protected final static String CONDITION_OPEN = "<?";
    protected final static String CONDITION_CLOSE = "?>";
    protected final static char SEPARATOR = ';';
    protected final static String OPTIONAL = "optional";
    protected final static String REQUIRED = "required";

    protected final static String DEFAULT_FRAGMENT = "-default-fragment-";

    protected final static ResultDescriptor resultDescriptor = new ResultDescriptor(
            new StateDescriptor[] { StateDescriptor.OK_DESCRIPTOR },
            new ResultEntryDescriptor[]{
                new ResultEntryDescriptor(OUTPUT, new DefaultMessage("templateRenderer/result/output"), "*", true)
            });
   
    private ParameterDescriptor[] parameterDescriptors;

    protected List parameterDescriptions;
    protected boolean fragments;

    private Map templates;
    private String[] requiredFragments, optionalFragments;
    private boolean ignoreUndefinedFragments = true;
    protected List optionalParameters = new ArrayList(); // all variables used in conditions reflect optional parameters

    // FIXME: Nested fragments
    public void configure(StreamableValue config) throws ConfigurationException {
        templates = new HashMap();
        parameterDescriptions = new ArrayList();
        try {
            String template = StreamHelper.streamToString(config);
            // ignore sections marked as ignored
            int currentPosition = 0;
            int lastPosition = 0;
            StringBuffer strippedTemplate = new StringBuffer(template.length());
            while ((currentPosition = template.indexOf(IGNORE_START, currentPosition)) >= 0) {
                strippedTemplate.append(template.substring(lastPosition, currentPosition));
                currentPosition = template.indexOf(IGNORE_END, currentPosition)+IGNORE_END.length();
                lastPosition = currentPosition;
            }
            strippedTemplate.append(template.substring(lastPosition));
            template = strippedTemplate.toString();
           
            // split template into different fragments if fragment identifiers are found
            currentPosition = 0;
            boolean fragments = false;
            while ((currentPosition = template.indexOf(FRAGMENT_START, currentPosition)) >= 0) {
                fragments = true;
                currentPosition += FRAGMENT_START.length();
                int startTagClose = template.indexOf(FRAGMENT_CLOSE, currentPosition);
                String fragmentName = template.substring(currentPosition, startTagClose);
                currentPosition = startTagClose+FRAGMENT_CLOSE.length();
                int fragmentEnd = template.indexOf(FRAGMENT_END, currentPosition);
                if ( !ignoreFragment(fragmentName) ) {
                    Template fragment = new Template(template.substring(currentPosition, fragmentEnd));
                    templates.put(fragmentName, fragment);
                }
                currentPosition = fragmentEnd+FRAGMENT_CLOSE.length();
            }
            // check if all required templates are defined
            if (requiredFragments != null ) {
                for ( int i = 0; i < requiredFragments.length; i++ ) {
                    boolean requiredFragmentDefined = false;
                    for ( Iterator j = templates.keySet().iterator(); j.hasNext(); ) {
                        String definedFragment = (String)j.next();
                        if ( definedFragment.startsWith(requiredFragments[i]) ) {
                            requiredFragmentDefined = true;
                            break;
                        }
                    }
                    if ( !requiredFragmentDefined ) {
                        throw new ConfigurationException(new ErrorMessage("templateRenderer/requiredFragmentMissing", new String[] { requiredFragments[i] }));
                    }
                }
            }
            parameterDescriptions.add(new ParameterDescriptor(FRAGMENT, new ParameterMessage("templateRenderer/fragment"), new StringValueDescriptor((String [])templates.keySet().toArray(new String[0])), new StringValue(DEFAULT_FRAGMENT)));
            if ( fragments ) {
                if ( requiredFragments != null ) {
                    templates.put(DEFAULT_FRAGMENT, templates.get(requiredFragments[0]));
                } else if ( optionalFragments != null ) {
                    templates.put(DEFAULT_FRAGMENT, templates.get(optionalFragments[0]));
                }
            } else {
                templates.put(DEFAULT_FRAGMENT, new Template(template));
            }
            parameterDescriptors = (ParameterDescriptor [])parameterDescriptions.toArray(new ParameterDescriptor[parameterDescriptions.size()]);
        } catch (IOException ioexception) {
            logger.log(Level.SEVERE, "Could not load configuration resource!");
        }
    }

    public Result process(Map parameter, Context context) throws Exception {
        String fragment = ((StringValue)parameter.get(FRAGMENT)).toString();
        Template template = getRequiredFragment(fragment);
        StringBuffer buffer = new StringBuffer(template.getLength());
        template.evaluate(buffer, parameter);
        return new Result(OK, OUTPUT, new StringValue(buffer.toString(), template.getContentType(), template.isDocument() ));
    }

    public void setRequiredFragments(String[] requiredFragments) {
        this.requiredFragments = requiredFragments;
    }

    public void setOptionalFragments(String[] optionalFragments) {
        this.optionalFragments = optionalFragments;
    }
   
  public void ignoreUndefinedFragments(boolean ignoreUndefinedFragments) {
    this.ignoreUndefinedFragments = ignoreUndefinedFragments;
  }

    public StringValue renderFragment(String fragment, Map parameterthrows ProcessException {
        Template template = getRequiredFragment(fragment);
        return renderFragment(template, parameter);
    }

    public StringValue renderFragment(Template template, Map parameterthrows ProcessException {
        StringBuffer buffer = new StringBuffer(template.getLength());
        template.evaluate(buffer, parameter);
        return new StringValue(buffer.toString());
    }

    public void renderFragment(StringBuffer buffer, String fragment, Map parameter) throws ProcessException {
        Template template = getRequiredFragment(fragment);
        template.evaluate(buffer, parameter);
    }

    protected Template getRequiredFragment(String fragment) throws ProcessException {
        Template template = (Template)templates.get(fragment);
        if ( template == null ) throw new ProcessException(new ErrorMessage("templateArrayRenderer/fragmentNotFound", new String[] { fragment }));
        return template;
    }

    protected Template getOptionalFragment(String fragment) {
        return (Template)templates.get(fragment);
    }

    protected Template getOptionalFragment(String fragment, Template defaultTemplate) {
        Template optionalFragment = (Template)templates.get(fragment);
        if ( optionalFragment == null ) return defaultTemplate;
        return optionalFragment;
    }

    public ParameterDescriptor[] getParameterDescriptors() {
        return parameterDescriptors;
    }

    public ResultDescriptor getResultDescriptor() {
        return resultDescriptor;
    }

    protected String[] getDefinedFragments() {
        return (String [])templates.keySet().toArray(new String[templates.size()]);
    }

    protected List getTemplateParameterDescriptor(String[] fragments) {
        List templateParameterDescriptors = new ArrayList();
        for ( int i = 0; i < fragments.length; i++ ) {
            Template template = (Template)templates.get(fragments[i]);
            if ( template != null ) {
                templateParameterDescriptors.addAll(template.getTemplateParameterDescriptors().values());
            }
        }
        return templateParameterDescriptors;
    }

    protected boolean ignoreFragment(String fragmentName) {
        if ( requiredFragments == null && optionalFragments == null ) return false;
        if ( requiredFragments != null ) {
            for ( int i = 0; i < requiredFragments.length; i++ ) {
                if ( fragmentName.startsWith(requiredFragments[i])) return false;
            }
        }
        if ( optionalFragments != null ) {
            for ( int i = 0; i < optionalFragments.length; i++ ) {
                if ( fragmentName.startsWith(optionalFragments[i])) return false;
            }
        }
        return ignoreUndefinedFragments;
    }

    protected class Template {
        private boolean document;
        private int length;
        private String contentType;
        private EnclosingTemplateFragment compiledTemplate = new EnclosingTemplateFragment();
        private Map templateParameterDescriptors = new HashMap();

        public Template(String template) {
            length = template.length();
            compileTemplate(template, 0, template.length(), compiledTemplate, false);
            document = ContentType.determineIsDocument(template);
            contentType = ContentType.determineContentType(template);
        }

        public int getLength() {
            return length;
        }

        private int compileTemplate(String template, int currentPosition, int length, EnclosingTemplateFragment compiledTemplate, boolean condition) {
            boolean tagsLeft = true;
            do {
                int nextOpeningVariable = template.indexOf(TAG_OPEN, currentPosition);
                int nextOpeningCondition = template.indexOf(CONDITION_OPEN, currentPosition);
                int nextClosingCondition = template.indexOf(CONDITION_CLOSE, currentPosition);
                if ( nextClosingCondition != -1 && ( nextClosingCondition < nextOpeningCondition || nextOpeningCondition == -1 ) && ( nextClosingCondition < nextOpeningVariable || nextOpeningVariable == -1 ) ) {
                    compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition, nextClosingCondition)));
                    currentPosition = nextClosingCondition+CONDITION_CLOSE.length();
                    return currentPosition;
                } else if ( nextOpeningCondition != -1 && ( nextOpeningCondition < nextOpeningVariable || nextOpeningVariable == -1 ) ) {
                    compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition, nextOpeningCondition)));
                    currentPosition = nextOpeningCondition+CONDITION_OPEN.length();
                    String variable = template.substring(currentPosition, template.indexOf(' ', currentPosition));
                    currentPosition += variable.length()+1;
                    ConditionalTemplateFragment conditionalTemplateFragment = new ConditionalTemplateFragment(variable);
                    compiledTemplate.addNestedTemplateFragment(conditionalTemplateFragment);
                    currentPosition = compileTemplate(template, currentPosition, length, conditionalTemplateFragment, true);
                } else if ( nextOpeningVariable != -1 ) {
                    compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition, nextOpeningVariable)));
                    currentPosition = nextOpeningVariable+TAG_OPEN.length();
                    int close = template.indexOf(TAG_CLOSE, currentPosition);
                    String variableName = template.substring(currentPosition, close);
                    String allowedContentTypes = null;
                    boolean required = !condition;
                    int modeSeparator = variableName.indexOf(SEPARATOR);
                    if ( modeSeparator > 0 ) {
                        String mode = variableName.substring(modeSeparator+1);
                        variableName = variableName.substring(0, modeSeparator);
                        int contentTypeSeparator = mode.indexOf(SEPARATOR);
                        if ( contentTypeSeparator > 0 ) {
                            allowedContentTypes = mode.substring(contentTypeSeparator+1);
                            mode = mode.substring(0, contentTypeSeparator);
                        }
                        if ( mode.equals(OPTIONAL) ) {
                            required = false;
                        } else if ( mode.equals(REQUIRED) ) {
                            required = true;
                        } else {
                            logger.log(Level.SEVERE, "Mode '"+mode+"' not allowed. Only optional or required are valid modes");
                        }
                    }
                    AnyValueDescriptor resourceValueDescriptor = new AnyValueDescriptor();
                    if ( !required || optionalParameters.contains(variableName)) {
//                        resourceValueDescriptor.addAllowedContentType(NullResource.CONTENT_TYPE);
                    }
                    if ( allowedContentTypes != null ) {
                        StringTokenizer tokenizer = new StringTokenizer(allowedContentTypes, ",");
                        while (tokenizer.hasMoreElements()) {
                            String contentTypeToken = tokenizer.nextToken();
                            resourceValueDescriptor.addAllowedContentType(contentTypeToken);
                        }
                        compiledTemplate.addNestedTemplateFragment(new Variable(variableName, resourceValueDescriptor.getAllowedContentTypes(), required));
                    } else {
//                        resourceValueDescriptor.addAllowedContentType(ContentType.ANY_TEXT);
                        compiledTemplate.addNestedTemplateFragment(new Variable(variableName, required));
                    }
                    ParameterDescriptor parameterDescriptor;
                    if ( required ) {
                        parameterDescriptor = new ParameterDescriptor(variableName, new ParameterMessage("templateVariable", new String[] { variableName }), resourceValueDescriptor);
                    } else {
                        parameterDescriptor = new ParameterDescriptor(variableName, new ParameterMessage("templateVariable", new String[] { variableName }), resourceValueDescriptor, new NullValue());
                    }
                    if ( !parameterDescriptions.contains(parameterDescriptor) ) {
                      parameterDescriptions.add(parameterDescriptor);
                    }
                    templateParameterDescriptors.put(variableName, parameterDescriptor);
                    currentPosition = close+TAG_CLOSE.length();
                } else {
                    tagsLeft = false;
                }
            } while ( tagsLeft );
            compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition)));
            return currentPosition;
        }

        public Map getTemplateParameterDescriptors() {
            return templateParameterDescriptors;
        }

        public boolean isDocument() {
            return document;
        }

        public String getContentType() {
            return contentType;
        }

        public void evaluate(StringBuffer buffer, Map parameter) throws ProcessException {
            evaluate(buffer, parameter,  0);
        }

        public void evaluate(StringBuffer buffer, Map parameter, int index) throws ProcessException {
            compiledTemplate.render(buffer, parameter, index);
        }
    }

    interface TemplateFragment {
        public void render(StringBuffer buffer, Map parameter, int index) throws ProcessException;
    }

    class StaticTemplateFragment implements TemplateFragment {
        private String content;

        public StaticTemplateFragment(String content) {
            this.content = content;
        }

        public void render(StringBuffer buffer, Map parameter, int index) throws ProcessException {
            buffer.append(content);
        }
    }

    class EnclosingTemplateFragment implements TemplateFragment {
        private List nestedTemplateFragments = new ArrayList();

        public void render(StringBuffer buffer, Map parameter, int index) throws ProcessException {
            for ( Iterator i = nestedTemplateFragments.iterator(); i.hasNext(); ) {
                TemplateFragment fragment = (TemplateFragment)i.next();
                fragment.render(buffer, parameter, index);
            }
        }

        public void addNestedTemplateFragment(Object fragment) {
            nestedTemplateFragments.add(fragment);
        }
    }

    class ConditionalTemplateFragment extends EnclosingTemplateFragment {
        private String variable;

        public ConditionalTemplateFragment(String variable) {
            this.variable = variable;
            optionalParameters.add(variable);
            if ( parameterDescriptions.contains(variable) ) {
                ((AnyValueDescriptor)((ParameterDescriptor)parameterDescriptions.get(parameterDescriptions.indexOf(variable))).getValueDescriptor()).addAllowedContentType(NullValue.CONTENT_TYPE);
            }
        }

        public String getVariable() {
            return variable;
        }

        public void render(StringBuffer buffer, Map parameter, int index) throws ProcessException {
            Object variableValue = parameter.get(variable);
            if ( variableValue != null && !(variableValue instanceof NullValue) ) {
                 super.render(buffer, parameter, index);
            }
        }
    }

    class Variable implements TemplateFragment {
        private String name;
        private String[] allowedContentTypes;
        private boolean required;

        public Variable(String name, boolean required) {
            this.name = name;
            this.required = required;
        }

        public Variable(String name, String []allowedContentType, boolean required) {
            this.name = name;
            this.allowedContentTypes = allowedContentType;
            this.required = required;
        }

        public void render(StringBuffer buffer, Map parameter, int index) throws ProcessException {
            Object variableValue = parameter.get(name);
            if ( variableValue == null ) variableValue = new NullValue();
            if ( variableValue instanceof ArrayValue ) {
                Value []array = (((ArrayValue)variableValue).getArray());
                if ( index > array.length-1 ) {
                    variableValue = array[index % array.length];
                } else {
                    variableValue = array[index];
                }
            }
            if ( (required && variableValue instanceof NullValue )) {
                throw new ProcessException(new ErrorMessage("templateRenderer/unsetValueNotAllowed", new Object[] { name }));
            }
            if ( allowedContentTypes != null && !ContentType.matches(allowedContentTypes, ((Value)variableValue).getContentType())) {
                throw new ProcessException(new ErrorMessage("templateRenderer/contentTypeMismatch", new Object[] { name, ContentType.getContentTypesAsString(allowedContentTypes), ((Value)variableValue).getContentType() }));
            }
            if ( variableValue instanceof PrintableValue ) {
                ((PrintableValue)variableValue).print(buffer);
            } else {
                buffer.append(variableValue);
            }
        }
    }
}
TOP

Related Classes of org.apache.slide.projector.processor.TemplateRenderer$EnclosingTemplateFragment

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.