package org.simantics.modeling.scl; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Consumer; import org.simantics.Simantics; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.uri.UnescapedChildMapOfResource; import org.simantics.db.exception.DatabaseException; import org.simantics.db.request.Read; import org.simantics.layer0.Layer0; import org.simantics.scl.compiler.common.names.Name; import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant; import org.simantics.scl.compiler.elaboration.modules.SCLValue; import org.simantics.scl.compiler.elaboration.relations.SCLEntityType; import org.simantics.scl.compiler.elaboration.relations.SCLRelation; import org.simantics.scl.compiler.environment.filter.NamespaceFilter; import org.simantics.scl.compiler.module.ImportDeclaration; import org.simantics.scl.compiler.module.LazyModule; import org.simantics.scl.compiler.types.TCon; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException; import org.simantics.scl.runtime.SCLContext; import gnu.trove.map.hash.THashMap; import gnu.trove.procedure.TObjectProcedure; public class OntologyModule extends LazyModule { private static final String DB_MODULE = "Simantics/DB"; private static final Collection DEPENDENCIES = Arrays.asList( new ImportDeclaration(DB_MODULE, null) ); private static final TCon RESOURCE = Types.con(DB_MODULE, "Resource"); Resource ontology; THashMap> childMaps = new THashMap>(); public OntologyModule(ReadGraph graph, String moduleName) throws DatabaseException { super(moduleName); ontology = graph.getResource(moduleName); childMaps.put(ontology, createLocalMap(graph, ontology)); } @Override public List getDependencies() { //return DEPENDENCIES; return Collections.emptyList(); } private Resource getResource(String name) { Map localMap = childMaps.get(ontology); if(localMap == null) return null; while(true) { int p = name.indexOf('.'); if(p < 0) break; String localName = name.substring(0, p); Resource newParent = localMap.get(localName); if(newParent == null) return null; name = name.substring(p+1); // Get new local map localMap = getLocalMap(newParent); if(localMap == null) return null; } return localMap.get(name); } private Map getLocalMap(Resource parent) { Map localMap = childMaps.get(parent); if(localMap == null) { if(childMaps.contains(parent)) return null; localMap = createLocalMap(parent); childMaps.put(parent, localMap); } return localMap; } private static Map createLocalMap(final Resource parent) { ReadGraph graph = (ReadGraph)SCLContext.getCurrent().get("graph"); if(graph != null) return createLocalMap(graph, parent); else try { return Simantics.getSession().syncRequest(new Read>() { @Override public Map perform(ReadGraph graph) throws DatabaseException { return createLocalMap(graph, parent); } }); } catch(DatabaseException e) { e.printStackTrace(); return null; } } private static Map createLocalMap(ReadGraph graph, Resource parent) { try { return graph.syncRequest(new UnescapedChildMapOfResource(parent)); } catch (DatabaseException e) { e.printStackTrace(); return null; } } @Override protected SCLValue createValue(String name) { Resource resource = getResource(name); if(resource == null) return null; SCLValue value = new SCLValue(Name.create(getName(), name)); value.setType(RESOURCE); value.setExpression(new EExternalConstant(resource, RESOURCE)); value.setInlineInSimplification(true); return value; } @Override protected SCLRelation createRelation(String name) { final Resource resource = getResource(name); if(resource == null) return null; ReadGraph graph = (ReadGraph)SCLContext.getCurrent().get("graph"); if(graph != null) return createRelation(graph, resource); else try { return Simantics.getSession().syncRequest(new Read() { @Override public SCLRelation perform(ReadGraph graph) throws DatabaseException { return createRelation(graph, resource); } }); } catch(DatabaseException e) { e.printStackTrace(); return null; } } public static SCLRelation createRelation(ReadGraph graph, Resource relation) { try { Layer0 L0 = Layer0.getInstance(graph); if(!graph.isInstanceOf(relation, L0.Relation)) return null; if(graph.isInstanceOf(relation, L0.PropertyRelation) && graph.isInstanceOf(relation, L0.FunctionalRelation)) { Type valueType = getValueType(graph, relation); if(valueType != null) return new GraphPropertyRelation(relation, valueType); } Resource inverseRelation = graph.getPossibleInverse(relation); return new GraphRelation(relation, getSelectivity(graph, relation), inverseRelation, getSelectivity(graph, inverseRelation)); } catch(DatabaseException e) { e.printStackTrace(); return null; } } @Override protected SCLEntityType createEntityType(String name) { final Resource resource = getResource(name); if(resource == null) return null; ReadGraph graph = (ReadGraph)SCLContext.getCurrent().get("graph"); if(graph != null) return createEntityType(graph, resource); else try { return Simantics.getSession().syncRequest(new Read() { @Override public SCLEntityType perform(ReadGraph graph) throws DatabaseException { return createEntityType(graph, resource); } }); } catch(DatabaseException e) { e.printStackTrace(); return null; } } private SCLEntityType createEntityType(ReadGraph graph, Resource type) { try { Layer0 L0 = Layer0.getInstance(graph); if(!graph.isInstanceOf(type, L0.Type)) return null; return new GraphEntityType(graph, type); } catch(DatabaseException e) { e.printStackTrace(); return null; } } private static double getSelectivity(ReadGraph graph, Resource relation) throws DatabaseException { if(relation == null) return Double.POSITIVE_INFINITY; Layer0 L0 = Layer0.getInstance(graph); if(graph.isInstanceOf(relation, L0.FunctionalRelation)) return 1.0; else return 10.0; } private static Type getValueType(ReadGraph graph, Resource relation) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Type valueType = parseValueType((String)graph.getPossibleRelatedValue(relation, L0.RequiresValueType, Bindings.STRING)); if(valueType != null) return valueType; Resource range = graph.getPossibleObject(relation, L0.HasRange); if(range != null) { for(Resource valueTypeLiteral : graph.getAssertedObjects(range, L0.HasValueType)) { valueType = parseValueType((String)graph.getValue(valueTypeLiteral, Bindings.STRING)); if(valueType != null) return valueType; } } return null; } private static Type parseValueType(String valueTypeString) { if(valueTypeString == null) return null; try { return Types.parseType(valueTypeString); } catch (SCLTypeParseException e) { e.printStackTrace(); return null; } } @Override public void findValuesForPrefix(String prefix, NamespaceFilter filter, TObjectProcedure proc) { Map localMap = childMaps.get(ontology); if(localMap == null) return; String namePrefix = ""; while(true) { int p = prefix.indexOf('.'); if(p < 0) break; String localName = prefix.substring(0, p); Resource newParent = localMap.get(localName); if(newParent == null) return; prefix = prefix.substring(p+1); namePrefix = namePrefix + localName + "."; // Get new local map localMap = getLocalMap(newParent); if(localMap == null) return; } for(String name : localMap.keySet()) if(name.startsWith(prefix) && filter.isValueIncluded(name)) proc.execute(getValue(namePrefix+name)); } @Override public void findValuesForPrefix(String prefix, NamespaceFilter filter, Consumer consumer) { Map localMap = childMaps.get(ontology); if(localMap == null) return; String namePrefix = ""; while(true) { int p = prefix.indexOf('.'); if(p < 0) break; String localName = prefix.substring(0, p); Resource newParent = localMap.get(localName); if(newParent == null) return; prefix = prefix.substring(p+1); namePrefix = namePrefix + localName + "."; // Get new local map localMap = getLocalMap(newParent); if(localMap == null) return; } for(String name : localMap.keySet()) if(name.startsWith(prefix) && filter.isValueIncluded(name)) consumer.accept(getValue(namePrefix+name)); } @Override public void findTypesForPrefix(String prefix, NamespaceFilter instance, Consumer consumer) { } @Override public void dispose() { childMaps.clear(); childMaps = null; ontology = null; } @Override public String toString() { return new StringBuilder().append("OntologyModule ").append(getName()).toString(); } }