package org.openehr.rm.binding;
import org.apache.log4j.Logger;
import org.openehr.rm.Attribute;
import org.openehr.rm.common.archetyped.Locatable;
import org.openehr.rm.composition.content.entry.Activity;
import org.openehr.rm.composition.content.entry.Entry;
import org.openehr.rm.datastructure.itemstructure.representation.Element;
import java.lang.reflect.Method;
import java.util.*;
public class XPathUtil {
public Set<String> extractXPaths(Locatable root) throws Exception {
Set<String> set = new HashSet<String>();
buildPath(root, "", set);
return set;
}
private void buildPath(Object obj, String path, Set<String> paths) throws Exception {
if(obj instanceof List) {
List list = (List) obj;
for(int i = 0, j = list.size(); i<j; i++) {
Object o = list.get(i);
buildPath(o, path + "[" + (i + 1) + "]", paths);
}
} else if(obj instanceof Element) {
paths.add(path);
} else if(obj instanceof Locatable) {
Locatable locatable = (Locatable) obj;
if(locatable.isArchetypeRoot() && (!path.isEmpty())) {
return;
}
inspector.retrieveRMAttributes(obj.getClass().getSimpleName());
Class klass = obj.getClass();
String className = klass.getSimpleName();
Map<String, Attribute> attributeMap = inspector.attributeMap(klass);
for(String attributeName : attributeMap.keySet()) {
Attribute attribute = attributeMap.get(attributeName);
if(attribute.system()) {
continue;
}
Method method = klass.getMethod("get" +
attributeName.substring(0, 1).toUpperCase() +
attributeName.substring(1), null);
assert(method != null);
Object value = method.invoke(obj, null);
if(value != null) {
buildPath(value, path + "/" + attributeName, paths);
}
}
}
}
public Map<String, Set<String>> extractPaths(Locatable root) throws Exception {
Map<String, Set<String>> map = new HashMap<String, Set<String>>();
buildPaths(root, "", "", map);
return map;
}
private void buildPaths(Object obj, String apath, String xpath, Map<String, Set<String>> paths) throws Exception {
//System.out.println("apath: " + apath + ", xpath: " + xpath
// + ", nodeId: " + (obj instanceof Locatable ? ((Locatable) obj).getArchetypeNodeId() : ""));
if(obj instanceof List) {
List list = (List) obj;
for(int i = 0, j = list.size(); i<j; i++) {
Object o = list.get(i);
assert (o instanceof Locatable);
if (o == null){
Logger.getLogger(XPathUtil.class).warn("Null locatable at "+obj+" index="+i);
}
Locatable loc = ((Locatable) o);
String nodeId = loc.getArchetypeNodeId();
assert (nodeId != null && !nodeId.isEmpty());
String currentAPath = apath + "[" + getNodeId(loc, nodeId) + "]";
String currentXPath = xpath + "[" + (i + 1) + "]";
buildPaths(o, currentAPath, currentXPath, paths);
}
} else if(obj instanceof Element) {
Set<String> set = paths.get(apath);
if(set == null) {
set = new HashSet<String>();
paths.put(apath, set);
}
set.add(xpath);
} else if(obj instanceof Locatable) {
Locatable locatable = (Locatable) obj;
inspector.retrieveRMAttributes(obj.getClass().getSimpleName());
Class klass = obj.getClass();
String className = klass.getSimpleName();
//System.out.println(">>> className: " + className);
Map<String, Attribute> attributeMap = inspector.attributeMap(klass);
for(String attributeName : attributeMap.keySet()) {
//System.out.println("Attribute name: " + attributeName);
Attribute attribute = attributeMap.get(attributeName);
if(attribute.system()) {
continue;
}
String methodName = "get" +
attributeName.substring(0, 1).toUpperCase() +
attributeName.substring(1);
//System.out.println("method name: " + methodName);
Method method = klass.getMethod(methodName, null);
assert(method != null);
Object value = method.invoke(obj, null);
if(value != null && !methodName.equals("getParent")) {
//System.out.println("has value..");
String nodeIdStr = "";
if (value instanceof Locatable){
nodeIdStr = "[" + ((Locatable)value).getArchetypeNodeId() + "]";
}
String currentAPath = apath + "/" + attributeName+nodeIdStr;
String currentXPath = xpath + "/" + attributeName;
//System.out.println(methodName+"> "+currentAPath);
buildPaths(value, currentAPath, currentXPath, paths);
}
}
} else {
//System.out.println("---- skip class: " + obj.getClass().getSimpleName());
}
}
private String getNodeId(Locatable loc, String nodeId) {
StringBuilder sb = new StringBuilder();
sb.append(nodeId);
if (loc instanceof Entry){
sb.append(" and name/value='" + loc.getName().getValue()+"'");
}
return sb.toString();
}
public Set<String> extractRootXPaths(Locatable root) throws Exception {
Set<String> set = new HashSet<String>();
buildRootPath(root, "", set);
return set;
}
private void buildRootPath(Object obj, String path, Set<String> paths) throws Exception {
//System.out.println("class: " + obj.getClass().getSimpleName() + ", path: " + path);
if(obj instanceof List) {
List list = (List) obj;
for(int i = 0, j = list.size(); i<j; i++) {
Object o = list.get(i);
buildRootPath(o, path + "[" + (i + 1) + "]", paths);
}
} else if(obj instanceof Locatable) {
Locatable l = (Locatable) obj;
if(l.isArchetypeRoot()) {
if( ! path.isEmpty()) {
paths.add(path);
return;
}
}
inspector.retrieveRMAttributes(obj.getClass().getSimpleName());
Class klass = obj.getClass();
String className = klass.getSimpleName();
Map<String, Attribute> attributeMap = inspector.attributeMap(klass);
for(String attributeName : attributeMap.keySet()) {
Attribute attribute = attributeMap.get(attributeName);
if(attribute.system()) {
continue; // skip system attributes
}
String getterName = "get"+
attributeName.substring(0, 1).toUpperCase() +
attributeName.substring(1);
Method method = klass.getMethod(getterName, null);
assert(method != null);
Object value = method.invoke(obj, null);
if(value != null) {
buildRootPath(value, path + "/" + attributeName, paths);
}
}
}
}
private RMInspector inspector = RMInspector.getInstance();
}