Java tutorial
/* * component: "openEHR Java Reference Implementation" * description: "Class DADLBinding" * keywords: "binding" * * author: "Rong Chen <rong.acode@gmail.com>" * copyright: "Copyright (c) 2008 Cambio Healthcare Systems, Sweden" * license: "See notice at bottom of class" * * file: "$URL$" * revision: "$LastChangedRevision$" * last_change: "$LastChangedDate$" */ package org.openehr.rm.binding; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.openehr.am.parser.AttributeValue; import org.openehr.am.parser.ComplexObjectBlock; import org.openehr.am.parser.ContentObject; import org.openehr.am.parser.KeyedObject; import org.openehr.am.parser.MultipleAttributeObjectBlock; import org.openehr.am.parser.ObjectBlock; import org.openehr.am.parser.PrimitiveObjectBlock; import org.openehr.am.parser.SimpleValue; import org.openehr.am.parser.SingleAttributeObjectBlock; import org.openehr.build.RMObjectBuilder; import org.openehr.build.RMObjectBuildingException; import org.openehr.build.SystemValue; import org.openehr.rm.Attribute; import org.openehr.rm.FullConstructor; import org.openehr.rm.RMObject; import org.openehr.rm.datatypes.quantity.ProportionKind; import org.openehr.rm.datatypes.text.CodePhrase; import org.openehr.rm.support.basic.Interval; import org.openehr.rm.support.measurement.MeasurementService; import org.openehr.rm.support.measurement.SimpleMeasurementService; import org.openehr.rm.support.terminology.TerminologyService; import org.openehr.terminology.SimpleTerminologyService; /** * Utility class that binds data in DADL format to openEHR RM * * @author rong.chen */ public class DADLBinding { public DADLBinding() { try { TerminologyService termServ; MeasurementService measureServ; termServ = SimpleTerminologyService.getInstance(); measureServ = SimpleMeasurementService.getInstance(); CodePhrase lang = new CodePhrase("ISO_639-1", "en"); CodePhrase charset = new CodePhrase("IANA_character-sets", "UTF-8"); Map<SystemValue, Object> values = new HashMap<SystemValue, Object>(); values.put(SystemValue.LANGUAGE, lang); values.put(SystemValue.CHARSET, charset); values.put(SystemValue.ENCODING, charset); values.put(SystemValue.TERMINOLOGY_SERVICE, termServ); values.put(SystemValue.MEASUREMENT_SERVICE, measureServ); builder = new RMObjectBuilder(values); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("failed to start DADLBinding.."); } } public Object bind(ContentObject co) throws DADLBindingException, RMObjectBuildingException { if (co.getAttributeValues() != null) { return bindAttributes(null, co.getAttributeValues()); } else { ComplexObjectBlock complexObj = co.getComplexObjectBlock(); return bindComplexBlock(complexObj); } } RMObject bindAttributes(String type, List<AttributeValue> attributes) throws DADLBindingException, RMObjectBuildingException { Map<String, Object> values = new HashMap<String, Object>(); for (AttributeValue attr : attributes) { String id = attr.getId(); Object value = bindObjectBlock(attr.getValue()); values.put(id, value); } return invokeRMObjectBuilder(type, values); } RMObject invokeRMObjectBuilder(String type, Map<String, Object> valueMap) throws DADLBindingException, RMObjectBuildingException { if (type == null) { type = builder.findMatchingRMClass(valueMap); if (type == null) { throw new DADLBindingException("failed untyped binding with - " + valueMap); } } RMObject rmObj = builder.construct(type, valueMap); return rmObj; } Object bindObjectBlock(ObjectBlock block) throws DADLBindingException, RMObjectBuildingException { if (block instanceof PrimitiveObjectBlock) { return bindPrimitiveBlock((PrimitiveObjectBlock) block); } else { return bindComplexBlock((ComplexObjectBlock) block); } } Object bindPrimitiveBlock(PrimitiveObjectBlock block) throws DADLBindingException { if (block.getSimpleValue() != null) { return block.getSimpleValue().getValue(); } else if (block.getSimpleListValue() != null) { List<SimpleValue> values = block.getSimpleListValue(); List list = new ArrayList(values.size()); for (SimpleValue sv : values) { list.add(sv.getValue()); } return list; } else if (block.getSimpleIntervalValue() != null) { Interval<Comparable> values = block.getSimpleIntervalValue(); // TODO return null; } else if (block.getTermCode() != null) { return block.getTermCode(); } else if (block.getTermCodeListValue() != null) { return block.getTermCodeListValue(); } else { throw new DADLBindingException("empty block"); } } Object bindComplexBlock(ComplexObjectBlock block) throws DADLBindingException, RMObjectBuildingException { if (block instanceof SingleAttributeObjectBlock) { SingleAttributeObjectBlock singleBlock = (SingleAttributeObjectBlock) block; // a special case to deal with empty attribute list if ("LIST".equalsIgnoreCase(singleBlock.getTypeIdentifier()) && singleBlock.getAttributeValues().isEmpty()) { return new ArrayList(); } return bindAttributes(singleBlock.getTypeIdentifier(), singleBlock.getAttributeValues()); } else { MultipleAttributeObjectBlock multiBlock = (MultipleAttributeObjectBlock) block; String type = multiBlock.getTypeIdentifier(); List<KeyedObject> list = multiBlock.getKeyObjects(); // TODO assume list? List<Object> valueList = new ArrayList<Object>(); for (KeyedObject ko : list) { Object key = ko.getKey().getValue(); Object value = bindObjectBlock(ko.getObject()); valueList.add(value); } return valueList; } } public List<String> toDADL(Object obj) throws Exception { List<String> lines = new ArrayList<String>(); return toDADL(obj, 1, lines); } public 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); } SortedMap<String, Attribute> attributes = attributeMap(obj.getClass()); String name = null; Object value = null; StringBuffer buf = null; for (Iterator<String> names = attributes.keySet().iterator(); names.hasNext();) { name = names.next(); Attribute attribute = attributes.get(name); if (attribute.system()) { continue; } if ("parent".equals(attribute.name())) { continue; // causing dead-loops } 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 (isOpenEHRRMClass(value) && !(value instanceof ProportionKind)) { lines.add(buf.toString()); log.debug("fetching attribute: " + name); toDADL(value, indent + 1, lines); } else if (value instanceof List) { buf.append("<"); lines.add(buf.toString()); List list = (List) value; for (int i = 0, j = list.size(); i < j; i++) { buf = new StringBuffer(); for (int k = 0; k < indent + 1; k++) { buf.append("\t"); } lines.add(buf.toString() + "[" + (i + 1) + "] = "); toDADL(list.get(i), indent + 2, lines); } buf = new StringBuffer(); for (int i = 0; i < indent; i++) { buf.append("\t"); } buf.append(">"); lines.add(buf.toString()); } else { buf.append("<"); if (value instanceof String || value instanceof Boolean) { buf.append("\""); buf.append(value); buf.append("\""); } else { buf.append(value.toString()); } buf.append(">"); lines.add(buf.toString()); } } } } buf = new StringBuffer(); for (int i = 0; i < indent - 1; i++) { buf.append("\t"); } buf.append(">"); lines.add(buf.toString()); return lines; } 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) { return method; } } } return null; } /** * Return a map with name as the key and index of position as the value for * all parameters of the full constructor in the RMObject * * @param rmClass * @return */ private SortedMap<String, Attribute> attributeMap(Class rmClass) { SortedMap<String, Attribute> map = new TreeMap<String, Attribute>(); Constructor constructor = fullConstructor(rmClass); if (constructor == null) { throw new IllegalArgumentException("Unknown RM Class: " + rmClass.getClass().getCanonicalName()); } Annotation[][] annotations = constructor.getParameterAnnotations(); for (int i = 0; i < annotations.length; i++) { if (annotations[i].length == 0) { throw new IllegalArgumentException("missing annotation at position " + i); } Attribute attribute = (Attribute) annotations[i][0]; map.put(attribute.name(), attribute); } return map; } private static Constructor fullConstructor(Class klass) { if (klass == null) { return null; } Constructor[] array = klass.getConstructors(); for (Constructor constructor : array) { if (constructor.isAnnotationPresent(FullConstructor.class)) { return constructor; } } return null; } public 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 boolean isOpenEHRRMClass(Object obj) { return obj.getClass().getName().contains(OPENEHR_RM_PACKAGE); } private RMObjectBuilder builder; private static Logger log = Logger.getLogger(DADLBinding.class); private static final String OPENEHR_RM_PACKAGE = "org.openehr.rm."; private static final String LINE_RETURN = "\r\n"; } /* * ***** BEGIN LICENSE BLOCK ***** Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (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 Original Code is DADLBinding.java * * The Initial Developer of the Original Code is Rong Chen. Portions created by * the Initial Developer are Copyright (C) 2003-2008 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 ***** */