se.cambio.cds.gdl.parser.DADLSerializer.java Source code

Java tutorial

Introduction

Here is the source code for se.cambio.cds.gdl.parser.DADLSerializer.java

Source

package se.cambio.cds.gdl.parser;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.openehr.rm.datatypes.text.CodePhrase;

import se.cambio.cds.gdl.model.ArchetypeBinding;
import se.cambio.cds.gdl.model.Binding;
import se.cambio.cds.gdl.model.ElementBinding;
import se.cambio.cds.gdl.model.ResourceDescriptionItem;
import se.cambio.cds.gdl.model.Rule;
import se.cambio.cds.gdl.model.Term;
import se.cambio.cds.gdl.model.TermBinding;
import se.cambio.cds.gdl.model.TermDefinition;
import se.cambio.cds.gdl.model.TranslationDetails;

public class DADLSerializer {

    public DADLSerializer() {
        loadProfile("gdl.properties");
    }

    /**
     * Serialize an object into DADL format using reflection
     * 
     * @param obj
     * @return List of serialized strings 
     * @throws Exception
     */
    public List<String> toDADL(Object obj) throws Exception {
        List<String> lines = new ArrayList<String>();
        return toDADL(obj, 1, lines);
    }

    private List<String> toDADL(Object obj, int indent, List<String> lines) throws Exception {

        log.debug("toDADL on obj.getClass: " + obj.getClass().getCanonicalName() + ", indent: " + indent
                + ", line.size: " + lines.size());

        Class klass = obj.getClass();
        String className = klass.getSimpleName();
        String rmName = toUnderscoreSeparated(className).toUpperCase();
        String typeHeader = "(" + rmName + ") <";
        int size = lines.size();
        if (size == 0) {
            lines.add(typeHeader);
        } else {
            String l = lines.get(size - 1);
            l += typeHeader;
            lines.set(size - 1, l);
        }
        Collection<String> attributes = attributeList(obj.getClass());

        if (profile.containsKey(className)) {
            attributes = sortByPreferredOrder(attributes, profile.get(className));
        }

        String name = null;
        Object value = null;
        StringBuffer buf = null;
        for (Iterator<String> names = attributes.iterator(); names.hasNext();) {
            name = names.next();

            // suppress Id output in GDL!!
            if ("id".equals(name) && (obj instanceof ArchetypeBinding || obj instanceof Rule
                    || obj instanceof ElementBinding || obj instanceof Binding || obj instanceof TermBinding
                    || obj instanceof Term || obj instanceof TermDefinition
                    || obj instanceof ResourceDescriptionItem || obj instanceof TranslationDetails)) {
                continue;
            }

            // skip objects generated in 2nd phase parsing
            if ("preConditionExpressions".equals(name) || "whenStatements".equals(name)
                    || "thenStatements".equals(name) || "predicateStatements".equals(name)) {
                continue;
            }

            Method getter = getter(name, obj.getClass());
            if (getter != null) {
                value = getter.invoke(obj, null);
                buf = new StringBuffer();
                if (value != null) {
                    for (int i = 0; i < indent; i++) {
                        buf.append("\t");
                    }
                    buf.append(toUnderscoreSeparated(name));
                    buf.append(" = ");

                    if (value instanceof List) {
                        if (!((List) value).isEmpty()) {
                            buf.append("<");

                            List list = (List) value;
                            Object member = null;
                            if (list.size() > 0 && isSupportedPrimitiveType(list.get(0))) {
                                if (list.get(0) instanceof String) {
                                    for (int i = 0, j = list.size(); i < j; i++) {
                                        buf.append("\"");
                                        buf.append(list.get(i));
                                        buf.append("\"");
                                        if (i != j - 1) {
                                            buf.append(", ");
                                        }
                                    }
                                } else if (list.get(0) instanceof CodePhrase) {
                                    for (int i = 0, j = list.size(); i < j; i++) {
                                        buf.append("[");
                                        buf.append(list.get(i));
                                        buf.append("]");
                                        if (i != j - 1) {
                                            buf.append(", ");
                                        }
                                    }
                                }
                                if (list.size() == 1) {
                                    buf.append(",...");
                                }
                                buf.append(">");
                                lines.add(buf.toString());
                            } else {
                                for (int i = 0, j = list.size(); i < j; i++) {
                                    member = list.get(i);
                                    lines.add(buf.toString());
                                    buf = new StringBuffer();
                                    for (int k = 0; k < indent + 1; k++) {
                                        buf.append("\t");
                                    }
                                    lines.add(buf.toString() + "[" + (i + 1) + "] = ");
                                    toDADL(member, indent + 2, lines);
                                }
                                buf = new StringBuffer();
                                for (int i = 0; i < indent; i++) {
                                    buf.append("\t");
                                }
                                buf.append(">");
                                lines.add(buf.toString());
                            }
                        }
                    } else if (value instanceof Map) {
                        if (!((Map) value).isEmpty()) {
                            buf.append("<");
                            lines.add(buf.toString());
                            Map map = (Map) value;
                            SortedSet sorted = new TreeSet(map.keySet());
                            for (Object key : sorted) {
                                buf = new StringBuffer();
                                for (int k = 0; k < indent + 1; k++) {
                                    buf.append("\t");
                                }
                                String keystr;
                                if (key instanceof CodePhrase) {
                                    keystr = "[" + key + "]";
                                } else {
                                    keystr = "\"" + key.toString() + "\"";
                                }

                                Object member = map.get(key);
                                if (member instanceof String) {
                                    buf.append("[");
                                    buf.append(keystr);
                                    buf.append("] = <\"");
                                    buf.append(member);
                                    buf.append("\">");
                                    lines.add(buf.toString());
                                } else {
                                    lines.add(buf.toString() + "[" + keystr + "] = ");
                                    toDADL(member, indent + 2, lines);
                                }
                            }
                            buf = new StringBuffer();
                            for (int i = 0; i < indent; i++) {
                                buf.append("\t");
                            }
                            buf.append(">");
                            lines.add(buf.toString());
                        }
                    } else if (isSupportedPrimitiveType(value)) {

                        log.debug("value.type: " + value.getClass());
                        buf.append("<");
                        if (value instanceof String) {
                            buf.append("\"");
                            buf.append(value);
                            buf.append("\"");
                        } else if (value instanceof CodePhrase) {
                            buf.append("[");
                            buf.append(value);
                            buf.append("]");
                        } else {
                            buf.append(value.toString());
                        }
                        buf.append(">");
                        lines.add(buf.toString());
                    } else { // complex block

                        log.debug("complex block..");

                        lines.add(buf.toString());

                        toDADL(value, indent + 1, lines);
                    }
                }
            }
        }
        buf = new StringBuffer();
        for (int i = 0; i < indent - 1; i++) {
            buf.append("\t");
        }
        buf.append(">");
        lines.add(buf.toString());
        return lines;
    }

    private boolean isSupportedPrimitiveType(Object obj) {
        return (obj instanceof String) || (obj instanceof Integer) || (obj instanceof Double)
                || (obj instanceof CodePhrase);
    }

    private Method getter(String attributeName, Class klass) {
        Method[] methods = klass.getMethods();
        String name = "get" + attributeName.substring(0, 1).toUpperCase() + attributeName.substring(1);

        log.debug("search getter method of name '" + name + "'");

        for (Method method : methods) {
            if (method.getName().equals(name)) {
                Type[] paras = method.getParameterTypes();
                if (paras.length == 0) {
                    log.debug("found '" + name + "'");
                    return method;
                }
            }
        }
        return null;
    }

    private SortedSet<String> attributeList(Class klass) {
        SortedSet<String> set = new TreeSet<String>();
        Method[] methods = klass.getMethods();
        for (Method method : methods) {
            String name = method.getName();
            if (name.startsWith("set")) {
                name = name.substring(3);
                name = name.substring(0, 1).toLowerCase() + name.substring(1);
                set.add(name);
            }
        }
        log.debug("attribute list: " + set);
        return set;
    }

    private List<String> sortByPreferredOrder(Collection<String> attributes, List<String> preferred) {
        List<String> ret = new ArrayList<String>();

        for (String attr : preferred) {
            if (attributes.contains(attr)) {
                ret.add(attr); // add preferred attributes
            }
        }
        for (String attr : attributes) {
            if (!ret.contains(attr)) {
                ret.add(attr); // add the rest
            }
        }
        return ret;
    }

    private String toUnderscoreSeparated(String camelCase) {
        String[] array = StringUtils.splitByCharacterTypeCamelCase(camelCase);
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            String s = array[i];
            buf.append(s.substring(0, 1).toLowerCase());
            buf.append(s.substring(1));
            if (i != array.length - 1) {
                buf.append("_");
            }
        }
        return buf.toString();
    }

    private void loadProfile(String name) {
        profile = new HashMap<String, List<String>>();
        try {
            InputStream input = this.getClass().getClassLoader().getResourceAsStream(name);
            Properties props = new Properties();
            props.load(input);
            Enumeration keys = props.propertyNames();
            StringTokenizer tokens = null;
            List<String> attributes;
            while (keys.hasMoreElements()) {
                Object key = keys.nextElement();
                String line = props.getProperty((String) key);
                log.debug(line);

                tokens = new StringTokenizer(line, ",");
                attributes = new ArrayList<String>();
                while (tokens.hasMoreTokens()) {
                    attributes.add(tokens.nextToken());
                }
                profile.put((String) key, attributes);

                log.debug(key.toString() + " with attributes: " + attributes);
            }
            log.debug(profile.size() + " class(es) loaded..");

        } catch (Exception e) {
            log.error("failed to load " + name);
        }
    }

    private Map<String, List<String>> profile;

    private static Logger log = Logger.getLogger(DADLSerializer.class);
}
/*
 *  ***** BEGIN LICENSE BLOCK *****
 *  Version: MPL 2.0/GPL 2.0/LGPL 2.1
 *
 *  The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
 *
 *  Software distributed under the License is distributed on an 'AS IS' basis,
 *  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 *  for the specific language governing rights and limitations under the
 *  License.
 *
 *
 *  The Initial Developers of the Original Code are Iago Corbal and Rong Chen.
 *  Portions created by the Initial Developer are Copyright (C) 2012-2013
 *  the Initial Developer. All Rights Reserved.
 *
 *  Contributor(s):
 *
 * Software distributed under the License is distributed on an 'AS IS' basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 *  ***** END LICENSE BLOCK *****
 */