Commit 116de98d authored by Georg Fette's avatar Georg Fette
Browse files

- fixed AQL model bugs

- tried to create Fuzzer
- refactored model structure
parent ec114c30
......@@ -47,14 +47,9 @@ public class Concept {
public Concept(Concept aConc, boolean isArray) {
this.name = aConc.name;
this.model = aConc.model;
parentConcept = model.ANY;
parent = aConc.parent;
this.parent = aConc.parent;
this.isArray = isArray;
for (Concept x : model.getConcepts()) {
if (x.isArray()) {
int y = 0;
}
}
model.addConcept(this);
}
public ConceptField addField(String fieldName, List<String> fieldTypes, boolean isArrayFlag) {
......@@ -70,7 +65,6 @@ public class Concept {
return field;
}
@JsonIgnore
public ConceptField getField(String aName) {
if (isArray()) {
throw new RuntimeException("array fields cannot access fields");
......@@ -83,6 +77,16 @@ public class Concept {
throw new RuntimeException("field '" + aName + "' does not exist");
}
// @JsonIgnore
public List<ConceptField> getFields() {
if (isArray()) {
throw new RuntimeException("array fields do not have fields");
}
List<ConceptField> result = new ArrayList<ConceptField>();
result.addAll(fields);
return result;
}
public void initialize() {
if (fields == null) {
fields = new ArrayList<ConceptField>();
......@@ -91,7 +95,7 @@ public class Concept {
aField.parent = this;
}
if (parent != null) {
parentConcept = model.getConcept(parent);
parentConcept = model.getConcept(parent, isArray);
}
}
......@@ -109,4 +113,20 @@ public class Concept {
return isArray;
}
@JsonIgnore
public boolean inheritsFrom(Concept typeToCheckTo) {
if (typeToCheckTo == null) {
return false;
}
Concept currentType = this;
while ((currentType != null) && (currentType != typeToCheckTo)) {
currentType = currentType.parentConcept;
}
if (currentType == typeToCheckTo) {
return true;
} else {
return false;
}
}
}
......@@ -3,8 +3,10 @@ package de.uniwue.model;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
......@@ -16,6 +18,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.uniwue.query.opInterfaces.OperatorType;
public class Model {
@JsonSerialize
......@@ -24,6 +28,9 @@ public class Model {
@JsonIgnore
private Map<String, Concept> conceptMap = new HashMap<String, Concept>();
@JsonIgnore
private Map<String, Concept> arrayConceptMap = new HashMap<String, Concept>();
@JsonIgnore
public Concept ANY, STRING, BOOLEAN, NUMBER, INTEGER, DOUBLE, DATETIME, CONCEPT, QUANTITY,
DURATION, PERIOD;
......@@ -32,30 +39,84 @@ public class Model {
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 {
@JsonIgnore
public Set<Concept> primitiveTypes = new HashSet<Concept>();
public static Model fromJSON(String jsonString, Class aModelClass) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
Model model = objectMapper.readValue(jsonString, Model.class);
Model model = (Model) objectMapper.readValue(jsonString, aModelClass);
model.initialize();
model.initializePrimitiveTypes();
model.initializeListTypes();
OperatorType.initializeOps(model);
return model;
}
private void initialize() {
private void initializeListTypes() {
LIST_OF_ANY = getConcept(ANY.name, true);
LIST_OF_ANY.parentConcept = ANY;
LIST_OF_BOOLEAN = getConcept(BOOLEAN.name, true);
LIST_OF_CONCEPT = getConcept(CONCEPT.name, true);
LIST_OF_CONCEPT.parentConcept = LIST_OF_ANY;
LIST_OF_DATETIME = getConcept(DATETIME.name, true);
LIST_OF_DOUBLE = getConcept(DOUBLE.name, true);
LIST_OF_INTEGER = getConcept(INTEGER.name, true);
LIST_OF_NUMBER = getConcept(NUMBER.name, true);
LIST_OF_STRING = getConcept(STRING.name, true);
if (PERIOD != null) {
LIST_OF_PERIOD = getConcept(PERIOD.name, true);
}
if (QUANTITY != null) {
LIST_OF_QUANTITY = getConcept(QUANTITY.name, true);
}
}
private void initializePrimitiveTypes() {
if (BOOLEAN != null) {
primitiveTypes.add(BOOLEAN);
}
if (STRING != null) {
primitiveTypes.add(STRING);
}
if (NUMBER != null) {
primitiveTypes.add(NUMBER);
}
if (INTEGER != null) {
primitiveTypes.add(INTEGER);
}
if (DOUBLE != null) {
primitiveTypes.add(DOUBLE);
}
if (DATETIME != null) {
primitiveTypes.add(DATETIME);
}
}
protected void initialize() {
for (Concept aConc : concepts) {
aConc.model = this;
conceptMap.put(aConc.name, aConc);
arrayConceptMap.put(aConc.name, new Concept(aConc, true));
}
if (!containsConcept("Element")) {
new Concept("Element", this);
}
}
for (Concept aConc : concepts) {
aConc.initialize();
}
for (Concept aConc : arrayConceptMap.values()) {
aConc.initialize();
}
}
public void addConcept(Concept aConc) {
concepts.add(aConc);
conceptMap.put(aConc.name, aConc);
if (aConc.isArray()) {
arrayConceptMap.put(aConc.name, aConc);
} else {
concepts.add(aConc);
conceptMap.put(aConc.name, aConc);
}
}
public void removeConcept(Concept aConc) {
......@@ -75,24 +136,20 @@ public class Model {
return new ArrayList<Concept>(concepts);
}
public Concept getConcept(Concept aConc, boolean isArray) {
if (!isArray) {
return aConc;
public Concept getConcept(String aName, boolean isArrayConceptDesired) {
Concept result;
if (!isArrayConceptDesired) {
result = conceptMap.get(aName);
if (result == null) {
throw new RuntimeException("Concept '" + aName + "' does not exist");
}
} else {
if (aConc != null) {
return new Concept(aConc, isArray);
} else {
return null;
result = arrayConceptMap.get(aName);
if (result == null) {
throw new RuntimeException("Concept 'List<" + aName + ">' does not exist");
}
}
}
public Concept getConcept(String aName, boolean isArray) {
Concept aConc = conceptMap.get(aName);
if (aConc == null) {
throw new RuntimeException("Concept '" + aName + "' does not exist");
}
return getConcept(aConc, isArray);
return result;
}
public String toJSON() throws JsonProcessingException {
......
......@@ -10,46 +10,47 @@ import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.model.StructureDef2ModelConverter;
public class FHIRModelInitializer {
public class FHIRModelInitializer extends Model {
private static void initialize(Model model) {
model.ANY = model.getConcept("Resource");
for (Concept aConc : model.getConcepts()) {
if ((aConc.parentConcept == null) && ((aConc != model.ANY))) {
aConc.parentConcept = model.ANY;
protected void initialize() {
super.initialize();
ANY = getConcept("Element");
CONCEPT = getConcept("Resource");
CONCEPT.parentConcept = ANY;
for (Concept aConc : getConcepts()) {
if ((aConc != ANY) && (aConc != CONCEPT)) {
if (aConc.parentConcept == null) {
aConc.parentConcept = ANY;
}
if (Character.isUpperCase(aConc.name.charAt(0)) && (aConc.parent.equals("Element"))) {
aConc.parent = "Resource";
aConc.parentConcept = CONCEPT;
}
}
}
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.parentConcept = model.ANY;
model.DOUBLE.parentConcept = model.NUMBER;
model.INTEGER.parentConcept = 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 = model.getConcept("Number", 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);
BOOLEAN = getConcept("boolean");
DATETIME = getConcept("dateTime");
DOUBLE = getConcept("decimal");
DURATION = getConcept("Duration");
INTEGER = getConcept("integer");
NUMBER = new Concept("Number", this);
NUMBER.parentConcept = ANY;
DOUBLE.parentConcept = NUMBER;
INTEGER.parentConcept = NUMBER;
LIST_OF_NUMBER = new Concept(NUMBER, true);
LIST_OF_DOUBLE = new Concept(DOUBLE, true);
LIST_OF_DOUBLE.parentConcept = LIST_OF_NUMBER;
LIST_OF_INTEGER = new Concept(INTEGER, true);
LIST_OF_INTEGER.parentConcept = LIST_OF_NUMBER;
PERIOD = getConcept("Period");
QUANTITY = getConcept("Quantity");
STRING = getConcept("string");
}
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);
Model model = Model.fromJSON(modelJSONString, FHIRModelInitializer.class);
return model;
}
......
......@@ -12,42 +12,39 @@ import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.model.StructureDef2ModelConverter;
public class OpenEHRModelInitializer {
public class OpenEHRModelInitializer extends Model {
private static void initialize(Model model) {
Concept root = new Concept("Element", model);
model.ANY = root;
for (Concept aConc : model.getConcepts()) {
if ((aConc.parentConcept == null) && ((aConc != model.ANY))) {
aConc.parentConcept = model.ANY;
protected void initialize() {
ANY = new Concept("Element", this);
addConcept(ANY);
super.initialize();
for (Concept aConc : getConcepts()) {
if ((aConc.parentConcept == null) && ((aConc != ANY))) {
aConc.parentConcept = ANY;
}
}
model.CONCEPT = model.getConcept("DomainResource");
model.BOOLEAN = model.getConcept("boolean");
model.DATETIME = model.getConcept("dateTime");
model.DOUBLE = model.getConcept("decimal");
model.INTEGER = model.getConcept("integer");
model.NUMBER = new Concept("Number", model);
model.NUMBER.parentConcept = model.ANY;
model.DOUBLE.parentConcept = model.NUMBER;
model.INTEGER.parentConcept = model.DOUBLE;
model.STRING = model.getConcept("string");
CONCEPT = getConcept("DomainResource");
BOOLEAN = getConcept("boolean");
DATETIME = getConcept("dateTime");
DOUBLE = getConcept("decimal");
INTEGER = getConcept("integer");
NUMBER = new Concept("Number", this);
NUMBER.parentConcept = ANY;
DOUBLE.parentConcept = NUMBER;
INTEGER.parentConcept = DOUBLE;
LIST_OF_NUMBER = new Concept(NUMBER, true);
LIST_OF_DOUBLE = new Concept(DOUBLE, true);
LIST_OF_DOUBLE.parentConcept = LIST_OF_NUMBER;
LIST_OF_INTEGER = new Concept(INTEGER, true);
LIST_OF_INTEGER.parentConcept = LIST_OF_NUMBER;
model.LIST_OF_ANY = model.getConcept(root, true);
model.LIST_OF_BOOLEAN = model.getConcept("boolean", true);
model.LIST_OF_CONCEPT = model.getConcept(root, 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 = model.getConcept("Number", true);
model.LIST_OF_STRING = model.getConcept("string", true);
STRING = getConcept("string");
}
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);
Model model = fromJSON(modelJSONString, OpenEHRModelInitializer.class);
return model;
}
......
package de.uniwue.query.CQL;
import de.uniwue.model.Model;
import de.uniwue.query.LanguageManager;
public class CQLLanguageManager extends LanguageManager {
public CQLLanguageManager(Model model) {
super(new CQL_2_Graph_Mapper(model), new Graph_2_CQL_Mapper(model));
}
public static String system = "CQL";
public String getSystem() {
return system;
}
}
package de.uniwue.query.CQL;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
......@@ -85,6 +84,7 @@ import de.uniwue.model.Model;
import de.uniwue.query.Primitive;
import de.uniwue.query.PrimitiveDateTime;
import de.uniwue.query.QueryOperator;
import de.uniwue.query.QueryParseException;
import de.uniwue.query.System_2_Graph_Mapper;
import de.uniwue.query.opInterfaces.OperatorType;
......@@ -99,7 +99,7 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
}
public String getSystem() {
return Graph_2_CQL_Mapper.system;
return CQLLanguageManager.system;
}
@Override
......@@ -122,9 +122,9 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
return expression;
}
public QueryOperator parse(String aQueryString, Model model) throws IOException {
public QueryOperator parse(String aQueryString) throws QueryParseException {
initialize();
query = new QueryOperator(OperatorType.QUERY, model);
query = new QueryOperator(OperatorType.QUERY, getModel());
ExpressionContext e = parseWithAntlr(aQueryString);
currentOp = query;
parseExpression(e);
......
......@@ -16,8 +16,6 @@ import de.uniwue.query.opInterfaces.OperatorType;
public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
public static String system = "CQL";
private String[] aliasNames = { "A", "B", "C", "D", "E", "F" };
private int aliasIndex;
......@@ -45,10 +43,14 @@ public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
OperatorType.TIME, OperatorType.NOW, OperatorType.TIMEOFDAY, OperatorType.TODAY }));
public Graph_2_CQL_Mapper(Model model) {
super(model, system);
super(model);
initializeOpMappings();
}
public String getSystem() {
return CQLLanguageManager.system;
}
@Override
protected void initialize(QueryOperator aQuery) {
super.initialize(aQuery);
......@@ -58,7 +60,7 @@ public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
nextPrimitiveIsValueSet = false;
}
public String visit(QueryOperator aQuery) {
public String parse(QueryOperator aQuery) {
initialize(aQuery);
String result = "";
Expression expression = aQuery.getParameters().get(0);
......@@ -449,10 +451,6 @@ public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
return result;
}
public String getSystem() {
return Graph_2_CQL_Mapper.system;
}
private void initializeOpMappings() {
initializeStdOpMappings();
addOpType("is", OperatorType.IS);
......@@ -473,10 +471,8 @@ public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
addOpType("First", OperatorType.FIRST);
addOpType("Last", OperatorType.LAST);
addOpType("In", OperatorType.IN);
addOpType("contains", OperatorType.CONTAINS);
addOpType("in", OperatorType.IN_VALUE_SET);
addOpType("contains", OperatorType.CONTAINS);
addOpType("Now", OperatorType.NOW);
addOpType("Today", OperatorType.TODAY);
......
package de.uniwue.query;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import de.uniwue.model.Concept;
import de.uniwue.model.ConceptField;
import de.uniwue.model.Model;
import de.uniwue.query.StructureProblem.ProblemType;
import de.uniwue.query.opInterfaces.OperatorType;
import de.uniwue.query.opInterfaces.OperatorType.InterfaceFlags;
public class Fuzzer {
private Model model;
private QueryOperator currentOp;
private Random rand;
private List<QueryOperator> opParts = new ArrayList<QueryOperator>();
private QueryOperator query, returnOp;
private int maxOpPartsCount = 50;
private double primitiveProb = 0.5;
public Fuzzer(Model model) {
this.model = model;
}
public QueryOperator createQuery() {
QueryOperator result = new QueryOperator(OperatorType.QUERY, model);
currentOp = result;
addOp();
return result;
rand = new Random(1);
query = new QueryOperator(OperatorType.QUERY, model);
returnOp = new QueryOperator(OperatorType.RETURN, model);
opParts.add(query);
opParts.add(returnOp);
while (opParts.size() < maxOpPartsCount) {
createOp();
}
List<StructureProblem> checkProblems;
do {
combineOpsIfPossible();
if (opParts.size() == maxOpPartsCount) {
removeOneOpPart();
}
while (opParts.size() < maxOpPartsCount) {
createOp();
}
checkProblems = query.checkProblems();
} while (checkProblems.size() > 0);
return query;
}
protected void combineOpsIfPossible() {
List<QueryOperator> unfinishedOps = new ArrayList<QueryOperator>();
List<QueryOperator> finishedOps = new ArrayList<QueryOperator>();
for (QueryOperator anOp : opParts) {
if (isFinished(anOp)) {
finishedOps.add(anOp);
} else {
unfinishedOps.add(anOp);
}
}
finishedOps.remove(query);
finishedOps.remove(returnOp);
Collections.shuffle(unfinishedOps);
for (QueryOperator anOp : unfinishedOps) {
if (anOp.type == OperatorType.ALIAS_REF) {
fillOpAliasRef(anOp);
} else if ((anOp.type == OperatorType.FIELD) && anOp.getParameters().size() == 1) {
fillOpField2ndParam(anOp);
} else if (anOp.type == OperatorType.QUERY) {
fillOpQuery(anOp, finishedOps);
} else {
combinOpGeneric(anOp, finishedOps);
}
if (isFinished(anOp)) {
return;
}
}
}
private void combinOpGeneric(QueryOperator anOp, List<QueryOperator> finishedOps) {
List<Concept> possibleDataTypesForParamIndex = getPossibleDataTypesForParamIndex(anOp,
anOp.getParameters().size());
boolean allowsPrimitiveTypes = allowsPrimitiveTypes(possibleDataTypesForParamIndex);