Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.openehr.binding.XMLBinding Maven / Gradle / Ivy
/*
* component: "openEHR Java Reference Implementation"
* description: "Class XMLBinding"
* keywords: "XML binding"
*
* author: "Rong Chen "
* copyright: "Copyright (c) 2008-2010 Cambio Healthcare Systems, Sweden"
* license: "See notice at bottom of class"
*
* file: "$URL$"
* revision: "$LastChangedRevision$"
* last_change: "$LastChangedDate$"
*/
package org.openehr.binding;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.*;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlOptions;
import org.openehr.build.RMObjectBuilder;
import org.openehr.build.RMObjectBuildingException;
import org.openehr.build.SystemValue;
import org.openehr.rm.datatypes.quantity.ProportionKind;
import org.openehr.rm.datatypes.text.CodePhrase;
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;
/**
* Bind data from XMLBeans class to openEHR RM classes
*
* @author Rong.Chen
* @author minor modifications by Erik Sundvall, Linköping University
*/
public class XMLBinding {
private final Map> classAttributeMap = new HashMap>();
/**
* Constructor allowing use of a custom SystemValue Map
*/
public XMLBinding(Map values) throws XMLBindingException {
try {
init(values);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("failed to start XMLBinding...");
}
}
/**
* Default constructor starting the XML-binding using the following system values
*
* TERMINOLOGY_SERVICE = an instance of SimpleTerminologyService
* MEASUREMENT_SERVICE = an instance of SimpleMeasurementService
* TERMINOLOGY_SERVICE = an instance of CodePhrase("IANA_character-sets", "UTF-8");
*
*/
public XMLBinding() throws XMLBindingException {
try {
TerminologyService termServ = SimpleTerminologyService
.getInstance();
MeasurementService measureServ = SimpleMeasurementService
.getInstance();
CodePhrase charset = new CodePhrase("IANA_character-sets",
"UTF-8");
Map values = new HashMap();
values.put(SystemValue.TERMINOLOGY_SERVICE, termServ);
values.put(SystemValue.MEASUREMENT_SERVICE, measureServ);
values.put(SystemValue.CHARSET, charset);
init(values);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("failed to start XMLBinding..");
}
}
/**
* Binds data from reference model instance to XML binding classes
*
* @param obj
* @return
* @throws XMLBindingException
*/
public Object bindToXML(Object obj) throws XMLBindingException {
if(obj == null) {
return null;
}
String className = obj.getClass().getSimpleName();
Method[] methods = obj.getClass().getMethods();
try {
Class xmlClass = Class.forName(XML_BINDING_PACKAGE +
className.toUpperCase());
// debug code only
if(xmlClass.getClasses().length != 1) {
log.debug("XMLBinding: bindToXML(): xmlClass.getClass()=" + xmlClass.getClass());
log.debug("XMLBinding: bindToXML(): xmlClass.toString()=" + xmlClass.toString());
for(Class clazz : xmlClass.getClasses()) {
log.debug("\t clazz.getClass()=" + clazz.getClass());
log.debug("\t clazz.toString()=" + clazz.toString());
}
}
Class factoryClass = xmlClass.getClasses()[0];
// ES modification: Add xmlOptions containing openehr (default) and xsi namespaces
// Method factoryMethod = factoryClass.getMethod(NEW_INSTANCE, null);
// Changed to pick the method with an XmlOptions parameter instead
Method factoryMethod = factoryClass.getMethod(NEW_INSTANCE, XmlOptions.class);
// First prameter null because it's a static method, see:
// http://java.sun.com/docs/books/tutorial/reflect/member/methodInvocation.html
// Second parameter should be the parameter of XmlObject.Factory.newInstance(XmlOptions options)
// see: http://xmlbeans.apache.org/docs/2.2.0/reference/org/apache/xmlbeans/XmlObject.Factory.html
//
// Previous code was: Object xmlObj = factoryMethod.invoke(null, null);
Object xmlObj = factoryMethod.invoke(null, xopt);
Map attributes = getClassAttributes(className);
Set attributeNames = attributes.keySet();
Object attributeValue = null;
Method setterMethod = null;
for (Method method : methods) {
String name = method.getName();
// cause dead-loop
if("getParent".equals(name)) {
continue; //
}
if (isGetter(name, attributeNames)) {
log.debug("getter: " + name);
if(method.getParameterTypes().length > 0) {
continue;
}
attributeValue = method.invoke(obj, null);
if (attributeValue == null) {
continue;
}
log.debug("value.class: " + attributeValue.getClass());
boolean isList = false;
if (attributeValue.getClass().isArray()) {
Object[] array = (Object[]) attributeValue;
if(array.length == 0) {
continue;
}
Object[] done = new Object[array.length];
for (int i = 0; i < array.length; i++) {
done[i] = bindToXML(array[i]);
}
attributeValue = done;
} else if (ProportionKind.class.equals(
attributeValue.getClass())) {
ProportionKind kind = (ProportionKind) attributeValue;
attributeValue = BigInteger.valueOf(kind.getValue());
} else if (isOpenEHRRMClass(attributeValue)) {
attributeValue = bindToXML(attributeValue);
} else if(List.class.isAssignableFrom(
attributeValue.getClass())) {
isList = true;
List list = (List) attributeValue;
log.debug("list.size: " + list.size());
String attributeName = getAttributeNameFromGetter(name);
setterMethod = findSetter(attributeName, xmlClass, isList);
Method addNew = findAddNew(attributeName, xmlClass);
log.debug("setter: " + setterMethod.getName() + ", xmlClass: " + xmlClass);
for(int i = 0, j = list.size() - 1; i <= j; i++) {
Object value = list.get(i);
Object[] array = new Object[2];
addNew.invoke(xmlObj, null);
array[0] = Integer.valueOf(i);
array[1] = bindToXML(value);
setterMethod.invoke(xmlObj, array);
log.debug("list.member value set!!!!");
}
}
if( ! isList) {
String attributeName = getAttributeNameFromGetter(name);
log.debug("attribute: " + attributeName + ", value(" + attributeValue + "), " +
"type: " + attributeValue.getClass());
// TODO fix for mismatched attribute name in XSD and RM
if("nullFlavor".equals(attributeName)) {
attributeName = "nullFlavour";
}
// skip function according to specs
if("isMerged".equals(attributeName)) {
continue;
}
setterMethod = findSetter(attributeName, xmlClass, isList);
if(setterMethod == null) {
log.error("failed to find setterMethod for attribute: "
+ attributeName + " with type: " + xmlClass);
continue;
}
// special handling deals with 'real' typed
// attributes in specs but typed 'float' in xsd
String setter = setterMethod.getName();
if("setAccuracy".equals(setter)
|| "setDenominator".equals(setter)
|| "setNumerator".equals(setter)) {
Double d = (Double) attributeValue;
attributeValue = d.floatValue();
}
log.debug("setter: " + setterMethod.getName() +
", xmlClass: " + xmlClass +
", attributeValue: " + attributeValue +
", attributeValue.class: " + attributeValue.getClass());
setterMethod.invoke(xmlObj, attributeValue);
}
}
}
return xmlObj;
} catch(Exception e) {
e.printStackTrace();
throw new XMLBindingException("exception caught when bind obj to "
+ className + ", " + e.getMessage());
}
}
Method findSetter(String attributeName, Class xmlClass, boolean isList) {
Method[] methods = xmlClass.getMethods();
String name = "set" + attributeName.substring(0, 1).toUpperCase() +
attributeName.substring(1);
if(isList) {
name += "Array";
}
log.debug("search method of name '" + name + "'");
for(Method method : methods) {
if(method.getName().equals(name)) {
Type[] paras = method.getParameterTypes();
if(isList) {
if(paras.length == 2) {
return method;
}
} else if(paras.length == 1) {
return method;
}
}
}
return null;
}
Method findAddNew(String attributeName, Class xmlClass) {
Method[] methods = xmlClass.getMethods();
String name = "addNew" + attributeName.substring(0, 1).toUpperCase() +
attributeName.substring(1);
log.debug("search method of name '" + name + "'");
for(Method method : methods) {
if(method.getName().equals(name)) {
return method;
}
}
return null;
}
Class findXMLAbstractClass(Class xmlClass) throws ClassNotFoundException {
if( ! xmlClass.getName().contains(XML_BINDING_PACKAGE)) {
return xmlClass; // primitive class
}
String className = xmlClass.getSimpleName();
if (className.endsWith("Impl")) {
className = className.substring(0, className.length() - 4);
}
Class abstractClass = Class.forName(XML_BINDING_PACKAGE + className);
return abstractClass;
}
private Map getClassAttributes(final String className)
throws Exception {
Map classMap = classAttributeMap.get(className);
if (classMap == null) {
classMap = builder.retrieveAttribute(className);
classAttributeMap.put(className, classMap);
}
return classMap;
}
/**
* Binds data from XML binding classes to RM classes using reflection
*
* @param value
* @return
* @throws Exception
*/
public Object bindToRM(Object object) throws Exception {
Method[] methods = object.getClass().getMethods();
Object value = null;
Map valueMap = new HashMap();
String className = object.getClass().getSimpleName();
if (className.endsWith("Impl")) {
className = className.substring(0, className.length() - 4);
}
Map attributes = getClassAttributes(className);
Set attributeNames = attributes.keySet();
log.debug("attributeNames: " + attributeNames);
for (Method method : methods) {
String name = method.getName();
if (isGetter(name, attributeNames)) {
if(method.getParameterTypes().length > 0) {
continue;
}
String attribute = getAttributeNameFromGetter(name);
value = method.invoke(object, null);
log.info("getter: " + name + ", attribute: " + attribute +
", value: " + value);
if (value == null) {
continue;
}
log.debug("value.class: " + value.getClass() + ", "
+ isXMLBindingClass(value));
if (value.getClass().isArray()) {
Object[] array = (Object[]) value;
if(array.length == 0) {
// special fix for item_structure.items
if("items".equals(attribute)) {
valueMap.put(attribute, new ArrayList());
}
continue;
} else {
Object[] done = new Object[array.length];
for (int i = 0; i < array.length; i++) {
done[i] = bindToRM(array[i]);
}
value = done;
}
} else if (isXMLBindingClass(value)) {
value = bindToRM(value);
}
log.debug("attribute: " + attribute + ", value(" + value + ")");
valueMap.put(attribute, value);
}
}
log.info("building rm class: " + className
+ ", with valueMap: " + valueMap);
Object rmObj = null;
try {
rmObj = builder.construct(className, valueMap);
} catch (RMObjectBuildingException e) {
log.warn(">>> FAILED to build instance of " + className
+ ", exception: " + e.getMessage());
}
return rmObj;
}
/* checks if the given method is a known getter of attributes */
private boolean isGetter(String method, Set attributes) {
if (!method.startsWith("get")) {
return false;
}
String name = getAttributeNameFromGetter(method);
return attributes.contains(name);
}
/* turns a getter's name into an attribute name */
private String getAttributeNameFromGetter(String name) {
name = name.substring(3, name.length());
name = name.substring(0, 1).toLowerCase() + name.substring(1);
if(name.endsWith("Array")) {
name = name.substring(0, name.length() - 5);
}
return name;
}
private boolean isXMLBindingClass(Object obj) {
return obj.getClass().getName().contains(XML_BINDING_PACKAGE);
}
private boolean isOpenEHRRMClass(Object obj) {
return obj.getClass().getName().contains(OPENEHR_RM_PACKAGE);
}
protected void init(Map values) throws XMLBindingException{
// Set up xml defaults
xopt = new XmlOptions();
HashMap uriToPrefixMap = new HashMap();
uriToPrefixMap.put(SCHEMA_XSI, "xsi");
uriToPrefixMap.put(SCHEMA_OPENEHR_ORG_V1, "v1");
xopt.setSaveSuggestedPrefixes(uriToPrefixMap);
xopt.setSaveAggressiveNamespaces();
xopt.setSavePrettyPrint();
xopt.setCharacterEncoding("UTF-8");
try {
builder = new RMObjectBuilder(values);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("failed to start XMLBinding...");
}
}
/* logger */
private static Logger log = Logger.getLogger(XMLBinding.class);
/* namespace for generated binding class */
private static String XML_BINDING_PACKAGE = "org.openehr.schemas.v1.";
/* namespace for rm class */
private static String OPENEHR_RM_PACKAGE = "org.openehr.rm.";
/* factory method name */
private static String NEW_INSTANCE = "newInstance";
public static final String SCHEMA_XSI = "http://www.w3.org/2001/XMLSchema-instance";
public static final String SCHEMA_OPENEHR_ORG_V1 = "http://schemas.openehr.org/v1";
/* the builder used to create rm objects */
private RMObjectBuilder builder;
/* ES: XMLOptions to make nicer XML */
private XmlOptions xopt;
}
/*
* ***** 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 XMLBinding.java
*
* The Initial Developer of the Original Code is Rong Chen. Portions created by
* the Initial Developer are Copyright (C) 2003-2010 the Initial Developer. All
* Rights Reserved.
*
* Contributor(s): Erik Sundvall
*
* 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 *****
*/