package org.simantics.db.layer0.validation; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.simantics.db.ChangeSet; import org.simantics.db.ChangeSet.StatementChange; import org.simantics.db.Issue; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.utils.Functions; import org.simantics.db.common.utils.Logger; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.event.ChangeEvent; import org.simantics.db.event.ChangeListener; import org.simantics.db.exception.DatabaseException; import org.simantics.layer0.Layer0; public class ChangeSetValidator implements ChangeListener { void reportInconsistency(ReadGraph graph, Resource subject, String description) throws DatabaseException { System.err.println("Change set validation reports the following issue: " + NameUtils.getSafeName(graph, subject, true) + ": " + description); } @Override public void graphChanged(ChangeEvent e) throws DatabaseException { ChangeSet changeSet = e.getChanges(); ReadGraph g = e.getGraph(); // Layer0 l0 = Layer0.getInstance(g); HashSet allResources = new HashSet(); for(StatementChange change : changeSet.changedStatements()) { allResources.add(change.getSubject()); allResources.add(change.getObject()); // if(change.isClaim()) { // Resource subject = change.getSubject(); // Resource predicate = change.getPredicate(); // Resource object = change.getObject(); // if(predicate == l0.InstanceOf) { // if(!isType(g, l0, object)) { // reportInconsistency(g, subject, "The range of InstanceOf relation is Type."); // } // else { // // TODO // } // } // else if(predicate == l0.SubrelationOf) { // if(!isRelation(g, l0, object)) { // reportInconsistency(g, subject, "The range of SubrelationOf relation is Relation."); // } // } // else if(predicate == l0.Inherits) { // if(!isType(g, l0, object)) { // reportInconsistency(g, subject, "The range of Inherits relation is Type."); // } // } // else { // if(!isRelation(g, l0, predicate)) { // reportInconsistency(g, subject, "The predicate of a statement must be a relation."); // } // else { // if(g.isInstanceOf(predicate, l0.FunctionalRelation)) { // if(g.getObjects(subject, predicate).size() > 1) // reportInconsistency(g, subject, // "Relation " + // NameUtils.getSafeName(g, predicate) // + " is functional."); // } // if(g.isSubrelationOf(predicate, l0.HasProperty)) { // String error = L0Validations.checkValueType(g, subject, predicate); // if(error != null) reportInconsistency(g, subject, error); // } // { // Collection domain = g.getObjects(predicate, l0.HasDomain); // if (!isInstanceOfAny(g, subject, domain, true)) { // StringBuilder sb = new StringBuilder() // .append("The domain of ") // .append(NameUtils.getSafeName(g, predicate)) // .append(" relation is "); // orString(g, sb, domain).append("."); // reportInconsistency(g, subject, sb.toString()); // } // } // { // Collection range = g.getObjects(predicate, l0.HasRange); // if (!isInstanceOfAny(g, object, range, true)) { // StringBuilder sb = new StringBuilder() // .append("The range of ") // .append(NameUtils.getSafeName(g, predicate)) // .append(" relation is "); // orString(g, sb, range).append("."); // reportInconsistency(g, object, sb.toString()); // } // } // } // } // } // else { // // TODO // } } for(Resource resource : changeSet.changedValues()) { allResources.add(resource); // if(g.hasValue(resource)) { // if(!g.isInstanceOf(resource, l0.Literal)) { // reportInconsistency(g, resource, // "Resource has a value but it is not a literal."); // } // else { // // TODO check that the value is valid for the data type // } // } // else { // if(g.isInstanceOf(resource, l0.Literal)) { // reportInconsistency(g, resource, // "Resource is a literal but it does not have a value."); // } // } } Layer0 L0 = Layer0.getInstance(g); for(Resource r : allResources) { try { for(Resource constraint : g.sync(new GetConstraints(r))) { try { Resource function = g.getSingleObject(constraint, L0.Constraint_Validator); @SuppressWarnings("unchecked") Set contexts = new HashSet((List)Functions.exec(g, function, g, r)); for(Issue i : contexts) { reportInconsistency(g, r, g.getURI(i.getType())); } } catch (Throwable t) { Logger.defaultLogError(t); } } } catch (Throwable t) { Logger.defaultLogError(t); } } } private boolean isInstanceOfAny(ReadGraph graph, Resource r, Collection types, boolean ifEmpty) throws DatabaseException { if (types.isEmpty()) return ifEmpty; for (Resource type : types) { if (graph.isInstanceOf(r, type)) { return true; } } return false; } private StringBuilder orString(ReadGraph graph, StringBuilder sb, Collection rs) throws DatabaseException { sb.append("("); boolean first = true; for (Resource r : rs) { if (!first) sb.append(" | "); first = false; sb.append(NameUtils.getSafeName(graph, r)); } sb.append(")"); return sb; } public static boolean isRelation(ReadGraph g, Layer0 l0, Resource relation) throws DatabaseException { return g.hasStatement(relation, l0.SubrelationOf) || relation == l0.IsWeaklyRelatedTo; } public static boolean isType(ReadGraph g, Layer0 l0, Resource type) throws DatabaseException { return g.hasStatement(type, l0.Inherits) || type == l0.Entity; } }