001package org.unix4j.codegen.def;
002
003import java.lang.reflect.Field;
004import java.lang.reflect.Modifier;
005import java.util.LinkedHashMap;
006import java.util.Map;
007
008import freemarker.template.ObjectWrapper;
009import freemarker.template.TemplateHashModel;
010import freemarker.template.TemplateModel;
011import freemarker.template.TemplateModelException;
012
013/**
014 * Abstract base class for all element definitions. Public fields define visible
015 * properties or nested elements.
016 */
017abstract public class AbstractElementDef implements TemplateHashModel {
018
019        private Map<String, Field> fields;
020
021        private final Map<String, Field> getFields() {
022                if (fields == null) {
023                        fields = initFields();
024                }
025                return fields;
026        }
027        private final Map<String, Field> initFields() {
028                final Map<String, Field> fields = new LinkedHashMap<String, Field>();
029                for (final Field field : getClass().getFields()) {
030                        if (0 == (field.getModifiers() & Modifier.STATIC)) {
031                                fields.put(field.getName(), field);
032                        }
033                }
034                return fields;
035        }
036
037        @Override
038        public boolean isEmpty() throws TemplateModelException {
039                return getFields().isEmpty();
040        }
041
042        @Override
043        public TemplateModel get(String key) throws TemplateModelException {
044                final Object value = getFieldValue(key);
045                if (value instanceof TemplateModel) {
046                        return (TemplateModel) value;
047                }
048                return value == null ? null : ObjectWrapper.DEFAULT_WRAPPER.wrap(value);
049        }
050
051        public Object getFieldValue(String name) {
052                final Field field = getFields().get(name);
053                try {
054                        return field == null ? null : field.get(this);
055                } catch (Exception e) {
056                        return "ERROR: cannot read field " + field.getName() + "e=" + e;
057                }
058        }
059
060        @Override
061        public String toString() {
062                return toMap().toString();
063        }
064
065        public Map<String, Object> toMap() {
066                final Map<String, Object> map = new LinkedHashMap<String, Object>();
067                for (final String name : getFields().keySet()) {
068                        map.put(name, getFieldValue(name));
069                }
070                return map;
071        }
072
073        public String toString(String indent) {
074                return toMultiLineString(indent, toMap());
075        }
076
077        protected static String toMultiLineString(String indent, Map<String, ?> map) {
078                final StringBuilder sb = new StringBuilder();
079                int maxKeyLen = 0;
080                for (final String key : map.keySet()) {
081                        maxKeyLen = Math.max(maxKeyLen, String.valueOf(key).length());
082                }
083                for (final Map.Entry<String, ?> e : map.entrySet()) {
084                        sb.append(indent).append(e.getKey()).append(": ");
085                        final int keyLen = String.valueOf(e.getKey()).length();
086                        for (int i = keyLen; i < maxKeyLen; i++) {
087                                sb.append(' ');
088                        }
089                        sb.append(e.getValue()).append('\n');
090                }
091                return sb.toString();
092        }
093}