Commit 71761b79 authored by Georg Fette's avatar Georg Fette
Browse files

refactored a lot

added openehr model classes
parent f83e7c07
......@@ -3,19 +3,51 @@ package de.uniwue.model;
import java.util.ArrayList;
import java.util.List;
import de.uniwue.query.DataType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
public class Concept {
public static String intTermCodes;
@JsonIgnore
public Model model;
@JsonIgnore
public Concept parent;
@JsonIgnore
// this field is for data type checks. In FHIR for example it is unusual for a Concept to indicate
// if it is an array. But for an operator interface is is an essential property of a data type if
// it is an array. This property is redundant and exists for Concepts as well as for Concept
// fields.
public boolean isArray;
public String name;
public List<String> termCodes;
public List<ConceptField> fields;
@JsonSerialize
private List<ConceptField> fields;
public String parentName;
// for serialization
private Concept() {
}
public Concept(String name, Model model) {
this.name = name;
this.model = model;
model.addConcept(this);
}
public Concept(Concept aConc, boolean isArray) {
this(aConc.name, aConc.model);
parent = model.ANY;
parentName = aConc.parentName;
this.isArray = isArray;
}
public void addField(String fieldName, List<String> fieldTypes, boolean isArrayFlag) {
if (fields == null) {
......@@ -24,15 +56,12 @@ public class Concept {
ConceptField field = new ConceptField();
field.name = fieldName;
field.isArray = isArrayFlag;
field.types = fieldTypes;
field.possibleTypes = fieldTypes;
fields.add(field);
field.parent = this;
}
public DataType getDataType() {
DataType dataType = new DataType(name, DataType.CONCEPT, false);
return dataType;
}
@JsonIgnore
public ConceptField getField(String aName) {
for (ConceptField aField : fields) {
if (aField.name.equals(aName)) {
......@@ -42,4 +71,22 @@ public class Concept {
throw new RuntimeException("field '" + aName + "' does not exist");
}
public void initialize() {
if (fields == null) {
fields = new ArrayList<ConceptField>();
}
for (ConceptField aField : fields) {
aField.parent = this;
}
parent = model.getConcept(parentName);
}
@Override
public String toString() {
String result = name;
if (isArray) {
result = "List<" + result + ">";
}
return result;
}
}
......@@ -2,30 +2,27 @@ package de.uniwue.model;
import java.util.List;
import de.uniwue.query.DataType;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class ConceptField {
@JsonIgnore
public Concept parent;
public String name;
public List<String> types;
public List<String> possibleTypes;
public boolean isArray;
public DataType getDataType() {
if (types.size() == 1) {
String fieldType = types.get(0);
if (fieldType.equals("Duration")) {
return DataType.DURATION;
} else {
return new DataType(fieldType, DataType.CONCEPT, isArray);
}
@JsonIgnore
public Concept getDataType() {
if (possibleTypes.size() == 1) {
String fieldType = possibleTypes.get(0);
return parent.model.getConcept(fieldType, isArray);
} else {
return DataType.ANY;
return parent.model.ANY;
}
}
}
......@@ -6,36 +6,90 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
public class Model {
public List<Concept> concepts = new ArrayList<Concept>();
@JsonSerialize
private List<Concept> concepts = new ArrayList<Concept>();
public Map<String, Concept> conceptMap = new HashMap<String, Concept>();
@JsonIgnore
private Map<String, Concept> conceptMap = new HashMap<String, Concept>();
@JsonIgnore
public Concept ANY, STRING, BOOLEAN, NUMBER, INTEGER, DOUBLE, DATETIME, CONCEPT, QUANTITY,
DURATION, PERIOD;
@JsonIgnore
public Concept LIST_OF_ANY, LIST_OF_STRING, LIST_OF_BOOLEAN, LIST_OF_NUMBER, LIST_OF_INTEGER,
LIST_OF_DOUBLE, LIST_OF_DATETIME, LIST_OF_CONCEPT, LIST_OF_QUANTITY, LIST_OF_PERIOD;
public static Model fromJSON(String jsonString) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
Model model = objectMapper.readValue(jsonString, Model.class);
for (Concept aConc : model.concepts) {
aConc.model = model;
if (aConc.fields != null) {
for (ConceptField aField : aConc.fields) {
aField.parent = aConc;
}
model.initialize();
return model;
}
private void initialize() {
for (Concept aConc : concepts) {
aConc.model = this;
conceptMap.put(aConc.name, aConc);
}
for (Concept aConc : concepts) {
aConc.initialize();
}
}
public void addConcept(Concept aConc) {
concepts.add(aConc);
conceptMap.put(aConc.name, aConc);
}
public void removeConcept(Concept aConc) {
concepts.remove(aConc);
conceptMap.remove(aConc.name);
}
public Concept getConcept(String aName) {
return getConcept(aName, false);
}
public List<Concept> getConcepts() {
return new ArrayList<Concept>(concepts);
}
public Concept getConcept(Concept aConc, boolean isArray) {
if (!isArray) {
return aConc;
} else {
if (aConc != null) {
return new Concept(aConc, isArray);
} else {
return null;
}
model.conceptMap.put(aConc.name, aConc);
}
return model;
}
public Concept getConcept(String aName, boolean isArray) {
Concept aConc = conceptMap.get(aName);
return getConcept(aConc, isArray);
}
public String toJSON() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
String writeValueAsString = objectMapper.writeValueAsString(this);
return writeValueAsString;
}
......
......@@ -20,7 +20,7 @@ public class StructureDef2ModelConverter {
private FhirContext ctx;
private Model model = new Model();
public Model model = new Model();
private StructureDefinition currentStrucDef;
......@@ -33,12 +33,10 @@ public class StructureDef2ModelConverter {
this.ctx = ctx;
}
public void translateStructureDefs2HAPIJavaClasses(File strucDefsOutputDir, File outDirHAPI)
throws Exception {
File structureDefDir = new File(strucDefsOutputDir, "xml");
public void convertStructureDefsDir(File aStructureDefDir) throws Exception {
IParser parser = ctx.newXmlParser();
// parser = ctx.newJsonParser();
for (File aFile : structureDefDir.listFiles()) {
for (File aFile : aStructureDefDir.listFiles()) {
System.out.println(aFile.getName());
String structureDefString = FileUtilsUniWue.file2String(aFile);
currentStrucDef = (StructureDefinition) parser.parseResource(structureDefString);
......@@ -46,13 +44,7 @@ public class StructureDef2ModelConverter {
}
}
public static void main(String[] args) throws Exception {
FhirContext ctx = FhirContext.forDstu3();
StructureDef2ModelConverter converter = new StructureDef2ModelConverter(ctx);
converter.work();
}
private void loadStructureDefsBundle(String path) throws Exception {
public void convertStructureDefsBundle(String path) throws Exception {
String dataElementsString = ResourceUtil.loadFileAsString(path);
Bundle bundle = (Bundle) ctx.newJsonParser().parseResource(dataElementsString);
List<BundleEntryComponent> entries = bundle.getEntry();
......@@ -61,20 +53,9 @@ public class StructureDef2ModelConverter {
Resource resource = anEntry.getResource();
currentStrucDef = (StructureDefinition) resource;
convertStrucDefToConcept();
System.out.print(".");
}
}
public void work() throws Exception {
String profileTypesPath = "classpath:v3/profiles-types.json";
String profileResourcesPath = "classpath:v3/profiles-resources.json";
loadStructureDefsBundle(profileTypesPath);
loadStructureDefsBundle(profileResourcesPath);
String json = model.toJSON();
FileUtilsUniWue.saveString2File(json, new File("D:\\tmp\\model.json"));
int x = 0;
}
private void fillTypeCheckLists(List<BundleEntryComponent> entries) {
for (BundleEntryComponent anEntry : entries) {
Resource resource = anEntry.getResource();
......@@ -136,15 +117,11 @@ public class StructureDef2ModelConverter {
String name = path.substring(path.lastIndexOf(".") + 1);
boolean isList = isList(anElem);
List<String> fieldTypes = new ArrayList<String>();
fieldTypes.add(path);
fieldTypes.add("BackboneElement");
parentConcept.addField(name, fieldTypes, isList);
if (fieldTypes.contains("BackboneElement")) {
Concept nestedConcept = new Concept();
model.concepts.add(nestedConcept);
nestedConcept.name = path;
addBackboneComponents(path, nestedConcept);
addNonBackboneMembers(path, nestedConcept);
}
Concept nestedConcept = new Concept(path, model);
addBackboneComponents(path, nestedConcept);
addNonBackboneMembers(path, nestedConcept);
}
private void addBackboneComponents(String path, Concept concept) {
......@@ -155,6 +132,7 @@ public class StructureDef2ModelConverter {
}
private void addNonBackboneMembers(String parentName, Concept parentConcept) {
int x = 0;
List<ElementDefinition> elements = getElements(parentName, 1);
for (ElementDefinition anElem : elements) {
addNonBackboneElement(anElem, parentConcept);
......@@ -169,20 +147,30 @@ public class StructureDef2ModelConverter {
String path = anElem.getPath();
String name = path.substring(path.lastIndexOf(".") + 1);
name = name.replaceAll("\\.", "");
name = name.replaceAll("\\[.*\\]", "");
name = name.replaceAll("\\[x\\]", "");
List<String> fhirTypes = getTypes(anElem);
boolean isList = isList(anElem);
parentConcept.addField(name, fhirTypes, isList);
}
private void addParentRelation(Concept aConcept) {
String baseDefinition = currentStrucDef.getBaseDefinition();
if (baseDefinition != null) {
String baseClass = baseDefinition.replaceAll("^.*/", "");
aConcept.parentName = baseClass;
aConcept.parent = model.getConcept(baseClass);
}
}
public void convertStrucDefToConcept() throws Exception {
Concept concept = new Concept();
String name = currentStrucDef.getName();
concept.name = name;
Concept concept = new Concept(name, model);
if (!primitiveTypes.contains(name)) {
addParentRelation(concept);
addBackboneComponents(concept.name, concept);
addNonBackboneMembers(concept.name, concept);
}
model.concepts.add(concept);
System.out.print(".");
}
}
package de.uniwue.model.models;
import java.io.File;
import java.io.IOException;
import ca.uhn.fhir.context.FhirContext;
import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.misc.util.ResourceUtil;
import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.model.StructureDef2ModelConverter;
public class FHIRModelInitializer {
private static void initialize(Model model) {
model.ANY = model.getConcept("Resource");
for (Concept aConc : model.getConcepts()) {
if ((aConc.parent == null) && ((aConc != model.ANY))) {
aConc.parent = model.ANY;
}
}
model.CONCEPT = model.getConcept("Resource");
model.BOOLEAN = model.getConcept("boolean");
model.DATETIME = model.getConcept("dateTime");
model.DOUBLE = model.getConcept("decimal");
model.DURATION = model.getConcept("Duration");
model.INTEGER = model.getConcept("integer");
model.NUMBER = new Concept("Number", model);
model.NUMBER.parent = model.ANY;
model.DOUBLE.parent = model.NUMBER;
model.INTEGER.parent = model.NUMBER;
model.PERIOD = model.getConcept("Period");
model.QUANTITY = model.getConcept("Quantity");
model.STRING = model.getConcept("string");
model.LIST_OF_ANY = model.getConcept("Resource", true);
model.LIST_OF_BOOLEAN = model.getConcept("boolean", true);
model.LIST_OF_CONCEPT = model.getConcept("Resource", true);
model.LIST_OF_DATETIME = model.getConcept("dateTime", true);
model.LIST_OF_DOUBLE = model.getConcept("decimal", true);
model.LIST_OF_INTEGER = model.getConcept("integer", true);
model.LIST_OF_NUMBER = new Concept("Number", model);
model.LIST_OF_NUMBER.isArray = true;
model.LIST_OF_PERIOD = model.getConcept("Period", true);
model.LIST_OF_QUANTITY = model.getConcept("Quantity", true);
model.LIST_OF_STRING = model.getConcept("string", true);
}
public static Model loadModel() throws IOException {
String modelJSONFilePath = "classpath:models/FHIR_v3/model.json";
String modelJSONString = ResourceUtil.loadFileAsString(modelJSONFilePath);
Model model = Model.fromJSON(modelJSONString);
initialize(model);
return model;
}
public static void main(String[] args) throws Exception {
FHIRModelInitializer initializer = new FHIRModelInitializer();
initializer.work();
}
public void work() throws Exception {
String profileTypesPath = "classpath:models/FHIR_v3/profiles-types.json";
String profileResourcesPath = "classpath:models/FHIR_v3/profiles-resources.json";
FhirContext ctx = FhirContext.forDstu3();
StructureDef2ModelConverter converter = new StructureDef2ModelConverter(ctx);
converter.convertStructureDefsBundle(profileTypesPath);
converter.convertStructureDefsBundle(profileResourcesPath);
String json = converter.model.toJSON();
FileUtilsUniWue.saveString2File(json, new File("D:\\tmp\\model.json"));
}
}
package de.uniwue.model.models;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.core.io.Resource;
import ca.uhn.fhir.context.FhirContext;
import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.misc.util.ResourceUtil;
import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.model.StructureDef2ModelConverter;
public class OpenEHRModelInitializer {
private static void initialize(Model model) {
Concept rootConcept = model.getConcept("Resource");
if (rootConcept == null) {
rootConcept = new Concept("Resource", model);
}
model.ANY = rootConcept;
for (Concept aConc : model.getConcepts()) {
if ((aConc.parent == null) && ((aConc != model.ANY))) {
aConc.parent = model.ANY;
}
}
model.CONCEPT = rootConcept;
model.BOOLEAN = model.getConcept("boolean");
model.DATETIME = model.getConcept("dateTime");
model.DOUBLE = model.getConcept("decimal");
model.DURATION = model.getConcept("Duration");
model.INTEGER = model.getConcept("integer");
model.NUMBER = new Concept("Number", model);
model.NUMBER.parent = model.ANY;
model.DOUBLE.parent = model.NUMBER;
model.INTEGER.parent = model.NUMBER;
model.PERIOD = model.getConcept("Period");
model.QUANTITY = model.getConcept("Quantity");
model.STRING = model.getConcept("string");
model.LIST_OF_ANY = model.getConcept(rootConcept, true);
model.LIST_OF_BOOLEAN = model.getConcept("boolean", true);
model.LIST_OF_CONCEPT = model.getConcept(rootConcept, true);
model.LIST_OF_DATETIME = model.getConcept("dateTime", true);
model.LIST_OF_DOUBLE = model.getConcept("decimal", true);
model.LIST_OF_INTEGER = model.getConcept("integer", true);
model.LIST_OF_NUMBER = new Concept("Number", model);
model.LIST_OF_NUMBER.isArray = true;
model.LIST_OF_PERIOD = model.getConcept("Period", true);
model.LIST_OF_QUANTITY = model.getConcept("Quantity", true);
model.LIST_OF_STRING = model.getConcept("string", true);
Concept ehr = new Concept("EHR", model);
for (Concept aConc : model.getConcepts()) {
if (aConc != ehr) {
List<String> possibleFields = new ArrayList<String>();
possibleFields.add(aConc.name);
aConc.addField(aConc.name, possibleFields, true);
}
}
}
public static Model loadModel() throws IOException {
String modelJSONFilePath = "classpath:models/openEHR/openEHR_model.json";
String modelJSONString = ResourceUtil.loadFileAsString(modelJSONFilePath);
Model model = Model.fromJSON(modelJSONString);
initialize(model);
return model;
}
public static void main(String[] args) throws Exception {
OpenEHRModelInitializer initializer = new OpenEHRModelInitializer();
initializer.work();
}
public void work() throws Exception {
FhirContext ctx = FhirContext.forDstu3();
StructureDef2ModelConverter converter = new StructureDef2ModelConverter(ctx);
String profileTypesPath = "classpath:models/FHIR_v3/profiles-types.json";
converter.convertStructureDefsBundle(profileTypesPath);
for (Concept aConc : converter.model.getConcepts()) {
if (!Character.isLowerCase(aConc.name.charAt(0))) {
converter.model.removeConcept(aConc);
}
}
String structureDefsDir = "classpath:models/openEHR/StructureDefs";
Resource resource = ResourceUtil.getResource(structureDefsDir);
converter.convertStructureDefsDir(resource.getFile());
String json = converter.model.toJSON();
FileUtilsUniWue.saveString2File(json, new File("D:\\tmp\\openEHR_model.json"));
}
}
......@@ -4,6 +4,7 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import de.uniwue.model.Model;
import de.uniwue.query.PrimitiveDateTime;
public class CQLDateTimeParser {
......@@ -43,7 +44,7 @@ public class CQLDateTimeParser {
return aDateString.matches(format);
}
public PrimitiveDateTime parseDateTime(String dateTimeStringIn) {
public PrimitiveDateTime parseDateTime(String dateTimeStringIn, Model model) {
boolean hasYears = false, hasMonths = false, hasDays = false, hasHours = false,
hasMinutes = false, hasSeconds = false, hasMillis = false;
Date parse = null;
......@@ -155,7 +156,7 @@ public class CQLDateTimeParser {
dateTimeStringLow = "@" + yearValue + "-" + dateTimeStringLow;
dateTimeStringHigh = "@" + yearValue + "-" + dateTimeStringHigh;
PrimitiveDateTime newParam = new PrimitiveDateTime(yearValueInt, monthValueInt, dayValueInt,
hourValueInt, minuteValueInt, secondValueInt, millisecValueInt, dateTimeStringIn);
hourValueInt, minuteValueInt, secondValueInt, millisecValueInt, dateTimeStringIn, model);
return newParam;
}
......
......@@ -126,8 +126,8 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
}
public QueryOperator parse(String aQueryString, Model model) throws IOException {
clear();
query.setModel(model);
initialize();
query = new QueryOperator(OperatorType.QUERY, model);
ExpressionContext e = parseWithAntlr(aQueryString);
currentOp = query;
parseExpression(e);
......@@ -295,7 +295,7 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
}
private QueryOperator startPathWithAliasRef(String text) {
QueryOperator alias = new QueryOperator(OperatorType.ALIAS_REF);