com.axelor.text.StringTemplates.java Source code

Java tutorial

Introduction

Here is the source code for com.axelor.text.StringTemplates.java

Source

/**
 * Axelor Business Solutions
 *
 * Copyright (C) 2005-2016 Axelor (<http://axelor.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.axelor.text;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.stringtemplate.v4.AttributeRenderer;
import org.stringtemplate.v4.AutoIndentWriter;
import org.stringtemplate.v4.Interpreter;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.compiler.Bytecode;
import org.stringtemplate.v4.misc.ObjectModelAdaptor;
import org.stringtemplate.v4.misc.STNoSuchPropertyException;

import com.axelor.common.StringUtils;
import com.axelor.db.EntityHelper;
import com.axelor.db.Model;
import com.axelor.db.mapper.Mapper;
import com.axelor.db.mapper.Property;
import com.axelor.meta.MetaStore;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.CharStreams;
import com.google.common.xml.XmlEscapers;

/**
 * The implementation of {@link Templates} for the StringTemplate (ST4) support.
 * 
 */
public class StringTemplates implements Templates {

    class StringRenderer implements AttributeRenderer {

        @Override
        public String toString(Object o, String formatString, Locale locale) {
            if (o == null)
                return "";
            if (formatString == null)
                return o.toString();
            if (formatString.equals("escape"))
                return XmlEscapers.xmlAttributeEscaper().escape(o.toString());
            if (formatString.startsWith("selection:"))
                return getSelectionTitle(formatString.substring(10).trim(), o.toString());
            return o.toString();
        }
    }

    class DataAdapter extends ObjectModelAdaptor {

        @Override
        public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName)
                throws STNoSuchPropertyException {

            if (!(o instanceof Model)) {
                return super.getProperty(interp, self, o, property, propertyName);
            }

            final Mapper mapper = Mapper.of(EntityHelper.getEntityClass(o));
            final Property field = mapper.getProperty(propertyName);

            if (field == null) {
                return null;
            }

            if (StringUtils.isBlank(field.getSelection())) {
                return field.get(o);
            }
            return getSelectionTitle(field.getSelection(), field.get(o));
        }
    }

    class StringTemplate implements Template {

        private ST template;
        private Set<String> names;

        private StringTemplate(ST template) {
            this.template = template;
            this.names = findAttributes();
        }

        private Set<String> findAttributes() {
            Set<String> names = Sets.newHashSet();
            int ip = 0;
            while (ip < template.impl.codeSize) {
                int opcode = template.impl.instrs[ip];
                Bytecode.Instruction I = Bytecode.instructions[opcode];
                ip++;
                for (int opnd = 0; opnd < I.nopnds; opnd++) {
                    if (opcode == Bytecode.INSTR_LOAD_ATTR) {
                        int nameIndex = Interpreter.getShort(template.impl.instrs, ip);
                        if (nameIndex < template.impl.strings.length) {
                            names.add(template.impl.strings[nameIndex]);
                        }
                    }
                    ip += Bytecode.OPND_SIZE_IN_BYTES;
                }
            }
            return names;
        }

        @Override
        public Renderer make(Map<String, Object> context) {
            for (String name : names) {
                try {
                    template.add(name, context.get(name));
                } catch (Exception e) {
                }
            }
            return new Renderer() {
                @Override
                public void render(Writer out) throws IOException {
                    try {
                        template.write(new AutoIndentWriter(out));
                    } catch (IOException e) {
                    }
                }
            };
        }

        @Override
        public <T extends Model> Renderer make(T context) {
            final Map<String, Object> ctx = Maps.newHashMap();
            if (context != null) {
                Mapper mapper = Mapper.of(EntityHelper.getEntityClass(context));
                for (String name : names) {
                    Property property = mapper.getProperty(name);
                    if (property != null) {
                        ctx.put(name, property.get(context));
                    }
                }
            }
            return make(ctx);
        }
    }

    private static final char DEFAULT_START_DELIMITER = '<';
    private static final char DEFAULT_STOP_DELIMITER = '>';

    private final STGroup group;

    public StringTemplates() {
        this(DEFAULT_START_DELIMITER, DEFAULT_STOP_DELIMITER);
    }

    public StringTemplates(char delimiterStartChar, char delimiterStopChar) {
        this.group = new STGroup(delimiterStartChar, delimiterStopChar);
        this.group.registerRenderer(String.class, new StringRenderer());
        this.group.registerModelAdaptor(Object.class, new DataAdapter());
    }

    @Override
    public Template fromText(String text) {
        ST template = new ST(group, text);
        return new StringTemplate(template);
    }

    @Override
    public Template from(File file) throws IOException {
        return from(new FileReader(file));
    }

    @Override
    public Template from(Reader reader) throws IOException {
        return fromText(CharStreams.toString(reader));
    }

    private String valueOf(Object value) {
        if (value == null)
            return "";
        return String.valueOf(value);
    }

    private String getSelectionTitle(String name, Object value) {
        final String val = valueOf(value);
        if (StringUtils.isBlank(val))
            return val;
        try {
            return MetaStore.getSelectionItem(name, val).getLocalizedTitle();
        } catch (Exception e) {
        }
        return val;
    }
}