All Downloads are FREE. Search and download functionalities are using the official Maven repository.
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.
com.nedap.archie.rules.evaluation.AssertionsFixer Maven / Gradle / Ivy
Go to download
tools that operate on the archie reference models and archetype object model
package com.nedap.archie.rules.evaluation;
import com.google.common.collect.Lists;
import com.nedap.archie.aom.*;
import com.nedap.archie.creation.RMObjectCreator;
import com.nedap.archie.query.RMObjectWithPath;
import com.nedap.archie.query.RMPathQuery;
import com.nedap.archie.rminfo.ModelInfoLookup;
import com.nedap.archie.rminfo.RMAttributeInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Created by pieter.bos on 05/04/2017.
*/
public class AssertionsFixer {
private static final Logger logger = LoggerFactory.getLogger(AssertionsFixer.class);
private final RMObjectCreator creator;
private final RuleEvaluation> ruleEvaluation;
private final RMObjectCreator rmObjectCreator;
private ModelInfoLookup modelInfoLookup;
public AssertionsFixer(RuleEvaluation> evaluation, RMObjectCreator creator) {
this.creator = creator;
this.ruleEvaluation = evaluation;
this.modelInfoLookup = ruleEvaluation.getModelInfoLookup();
rmObjectCreator = new RMObjectCreator(evaluation.getModelInfoLookup());
}
public Map fixSetPathAssertions(Archetype archetype, AssertionResult assertionResult) {
Map result = new HashMap<>();
Map> setPathValues = assertionResult.getSetPathValues();
for (String path : setPathValues.keySet()) {
Value> value = setPathValues.get(path);
String pathOfParent = stripLastPathSegment(path);
String lastPathSegment = getLastPathSegment(path);
List parents = ruleEvaluation.findList(pathOfParent);
int i = 0;
while (parents.isEmpty() && i < 500) { //not more than 500 times because we do not want infinite loops, and 500 is a lot already here
//there's object missing in the RMObject. Construct it here.
constructMissingStructure(archetype, pathOfParent, lastPathSegment, parents);
parents = ruleEvaluation.findList(pathOfParent);
i++;
}
for (Object parent : parents) {
RMAttributeInfo attributeInfo = ruleEvaluation.getModelInfoLookup().getAttributeInfo(parent.getClass(), lastPathSegment);
if (attributeInfo == null) {
throw new IllegalStateException("attribute " + lastPathSegment + " does not exist on type " + parent.getClass());
}
if (value.getValue() == null) {
creator.set(parent, lastPathSegment, Lists.newArrayList(value.getValue()));
} else if (attributeInfo.getType().equals(Long.class) && value.getValue().getClass().equals(Double.class)) {
Long convertedValue = ((Double) value.getValue()).longValue(); //TODO or should this round?
creator.set(parent, lastPathSegment, Lists.newArrayList(convertedValue));
} else if (attributeInfo.getType().equals(Double.class) && value.getValue().getClass().equals(Long.class)) {
Double convertedValue = ((Long) value.getValue()).doubleValue(); //TODO or should this round?
creator.set(parent, lastPathSegment, Lists.newArrayList(convertedValue));
} else {
creator.set(parent, lastPathSegment, Lists.newArrayList(value.getValue()));
}
result.putAll(modelInfoLookup.pathHasBeenUpdated(ruleEvaluation.getRMRoot(), archetype, pathOfParent, parent));
ruleEvaluation.refreshQueryContext();
}
}
return result;
}
private void constructMissingStructure(Archetype archetype, String pathOfParent, String lastPathSegment, List parents) {
//TODO: this is great but not enough. Fix it by hardcoding support for DV_CODED_TEXT and DV_ORDINAL, here or in the FixableAssertionsChecker.
String newPathOfParent = pathOfParent;
String newLastPathSegment = lastPathSegment;
while (parents.isEmpty()) {
//lookup parent of parent until found. Create empty RM object. Then repeat original query
newLastPathSegment = getLastPathSegment(newPathOfParent);
newPathOfParent = stripLastPathSegment(newPathOfParent);
parents = ruleEvaluation.findList(newPathOfParent);
}
List constraints;
if (newPathOfParent.equals("/")) {
constraints = archetype.itemsAtPath("/" + newLastPathSegment);
} else {
constraints = archetype.itemsAtPath(newPathOfParent + "/" + newLastPathSegment);
}
if (constraintsHasNoComplexObjects(constraints)) {
Object object = parents.get(0);
Object newEmptyObject = null;
newEmptyObject = constructEmptySimpleObject(newLastPathSegment, object, newEmptyObject);
creator.addElementToListOrSetSingleValues(object, newLastPathSegment, Lists.newArrayList(newEmptyObject));
ruleEvaluation.refreshQueryContext();
} else {
CObject constraint = getCObjectFromResult(constraints);
if (constraint != null) {
Object object = parents.get(0);
Object newEmptyObject = null;
if (constraint instanceof CComplexObject || constraint instanceof ArchetypeSlot) {
newEmptyObject = rmObjectCreator.create(constraint);
} else {
newEmptyObject = constructEmptySimpleObject(newLastPathSegment, object, newEmptyObject);
}
int bracketIndex = newLastPathSegment.indexOf('[');
String attributeName = newLastPathSegment;
if (bracketIndex > -1) {
attributeName = newLastPathSegment.substring(0, bracketIndex);
}
creator.addElementToListOrSetSingleValues(object, attributeName, Lists.newArrayList(newEmptyObject));
ruleEvaluation.refreshQueryContext();
}
}
}
private CObject getCObjectFromResult(List extends ArchetypeModelObject> objects) {
if (objects.size() != 1) {
//if there's more than one CObject this represents a user choice and we cannot return a single object and this cannot be automatically fixed
return null;
} else {
ArchetypeModelObject object = objects.get(0);
if (object instanceof CAttribute) {
return getCObjectFromResult(((CAttribute) object).getChildren());
}
return (CObject) object;
}
}
private Object constructEmptySimpleObject(String newLastPathSegment, Object object, Object newEmptyObject) {
RMAttributeInfo attributeInfo = ruleEvaluation.getModelInfoLookup().getAttributeInfo(object.getClass(), newLastPathSegment);
try {
newEmptyObject = attributeInfo.getTypeInCollection().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return newEmptyObject;
}
private boolean constraintsHasNoComplexObjects(List extends ArchetypeModelObject> constraints) {
for (ArchetypeModelObject constraint : constraints) {
if (constraint instanceof CAttribute) {
if (!constraintsHasNoComplexObjects(((CAttribute) constraint).getChildren())) {
return false;
}
} else if (constraint instanceof CComplexObject || constraint instanceof ArchetypeSlot) {
return false;
}
}
return true;
}
/**
* Collect all {@link AssertionResult#getPathsThatMustNotExist()} and remove from root being evaluated.
* To ensure non-existence is taken into consideration for upcoming evaluated rules.
*/
public void fixNotExistAssertions(AssertionResult assertionResult) {
List objectsToRemove = assertionResult.getPathsThatMustNotExist().stream()
.flatMap(path -> findObjectsThatMustNotExist(path).stream())
.collect(Collectors.toList());
objectsToRemove.forEach(this::removeObject);
ruleEvaluation.refreshQueryContext();
}
private List findObjectsThatMustNotExist(String path) {
String pathOfParent = stripLastPathSegment(path);
String lastPathSegment = getLastPathSegment(path);
List result = new ArrayList<>();
ruleEvaluation.findList(pathOfParent).forEach(parent -> {
String attributeName = getAttributeName(lastPathSegment);
List objectsWithPath = new RMPathQuery(lastPathSegment).findList(modelInfoLookup, parent);
objectsWithPath.forEach(rmObjectWithPath -> result.add(new ObjectToRemove(parent, attributeName, rmObjectWithPath.getObject())));
});
return result;
}
private void removeObject(ObjectToRemove objectToRemove) {
Object parent = objectToRemove.getParent();
Object object = objectToRemove.getObject();
RMAttributeInfo attributeInfo = modelInfoLookup.getAttributeInfo(parent.getClass(), objectToRemove.getAttributeName());
try {
Object attributeValue = attributeInfo.getGetMethod().invoke(parent);
if (attributeValue instanceof List) {
((List>) attributeValue).remove(object);
} else if (attributeValue == object) {
attributeInfo.getSetMethod().invoke(parent, (Object) null);
} else {
throw new IllegalStateException("Attribute value is not a list and not the object to remove");
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
/**
* Return the path with everything except the last path segment, so /items/value becomes /items.
*/
private String stripLastPathSegment(String path) {
int lastIndex = path.lastIndexOf('/');
if (lastIndex < 0) {
return path;
}
String result = path.substring(0, lastIndex);
if (result.equals("")) {
return "/";
}
return result;
}
/**
* Return the last path segment, so /items/value becomes value.
*/
private String getLastPathSegment(String path) {
int lastIndex = path.lastIndexOf('/');
if (lastIndex < 0) {
return path;
}
return path.substring(lastIndex + 1);
}
/**
* Return attribute from path segment, so items[id1] becomes items.
*/
private String getAttributeName(String pathSegment) {
int bracketIndex = pathSegment.indexOf('[');
if (bracketIndex > -1) {
return pathSegment.substring(0, bracketIndex);
}
return pathSegment;
}
/**
* Inner class to store needed information to remove objects found while running {@link #fixNotExistAssertions(AssertionResult)}.
*/
private static class ObjectToRemove {
private final Object parent;
private final String attributeName;
private final Object object;
public ObjectToRemove(Object parent, String attributeName, Object object) {
this.parent = parent;
this.attributeName = attributeName;
this.object = object;
}
public Object getParent() {
return parent;
}
public String getAttributeName() {
return attributeName;
}
public Object getObject() {
return object;
}
}
}