1 package org.simantics.modeling.scl.ontologymodule;
3 import java.util.Arrays;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
9 import java.util.function.Consumer;
11 import org.simantics.Simantics;
12 import org.simantics.databoard.Bindings;
13 import org.simantics.db.ReadGraph;
14 import org.simantics.db.Resource;
15 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
16 import org.simantics.db.exception.DatabaseException;
17 import org.simantics.db.request.Read;
18 import org.simantics.layer0.Layer0;
19 import org.simantics.scl.compiler.common.names.Name;
20 import org.simantics.scl.compiler.constants.StringConstant;
21 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
22 import org.simantics.scl.compiler.elaboration.expressions.EApply;
23 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
24 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
25 import org.simantics.scl.compiler.elaboration.expressions.ESimpleLambda;
26 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
27 import org.simantics.scl.compiler.elaboration.expressions.Expression;
28 import org.simantics.scl.compiler.elaboration.expressions.Variable;
29 import org.simantics.scl.compiler.elaboration.macros.MacroRule;
30 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
31 import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;
32 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
33 import org.simantics.scl.compiler.environment.filter.NamespaceFilter;
34 import org.simantics.scl.compiler.errors.Locations;
35 import org.simantics.scl.compiler.module.ImportDeclaration;
36 import org.simantics.scl.compiler.module.LazyModule;
37 import org.simantics.scl.compiler.types.TCon;
38 import org.simantics.scl.compiler.types.TVar;
39 import org.simantics.scl.compiler.types.Type;
40 import org.simantics.scl.compiler.types.Types;
41 import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException;
42 import org.simantics.scl.compiler.types.kinds.Kinds;
43 import org.simantics.scl.runtime.SCLContext;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 import gnu.trove.map.hash.THashMap;
48 import gnu.trove.procedure.TObjectProcedure;
50 public class OntologyModule extends LazyModule {
51 private static final Logger LOGGER = LoggerFactory.getLogger(OntologyModule.class);
53 private static final String DB_MODULE = "Simantics/DB";
54 private static final String VARIABLE_MODULE = "Simantics/Variable";
55 private static final Collection<ImportDeclaration> DEPENDENCIES = Arrays.asList(
56 new ImportDeclaration(DB_MODULE, null),
57 new ImportDeclaration(VARIABLE_MODULE, null)
59 private static final TCon RESOURCE = Types.con(DB_MODULE, "Resource");
60 private static final TCon BROWSABLE = Types.con(DB_MODULE, "Browsable");
61 private static final TCon VARIABLE = Types.con(VARIABLE_MODULE, "Variable");
64 String defaultLocalName;
65 THashMap<Resource,Map<String,Resource>> childMaps = new THashMap<Resource,Map<String,Resource>>();
67 public OntologyModule(ReadGraph graph, String moduleName) throws DatabaseException {
69 ontology = graph.getResource(moduleName);
70 readDefaultLocalName(graph);
71 childMaps.put(ontology, createLocalMap(graph, ontology));
74 private void readDefaultLocalName(ReadGraph graph) throws DatabaseException {
75 Layer0 L0 = Layer0.getInstance(graph);
76 defaultLocalName = graph.getPossibleRelatedValue(ontology, L0.Ontology_defaultLocalName);
77 if(defaultLocalName == null)
78 defaultLocalName = "";
82 public String getDefaultLocalName() {
83 return defaultLocalName;
87 public List<ImportDeclaration> getDependencies() {
88 //return DEPENDENCIES;
89 return Collections.emptyList();
92 private static interface ResourceSearchResult {}
93 private static class JustResource implements ResourceSearchResult {
94 public final Resource resource;
95 public JustResource(Resource resource) {
96 this.resource = resource;
99 private static class ResourceAndSuffix implements ResourceSearchResult {
100 public final Resource resource;
101 public final String suffix;
102 public ResourceAndSuffix(Resource resource, String suffix) {
103 this.resource = resource;
104 this.suffix = suffix;
108 private ResourceSearchResult getResourceOrSuffixedResource(String name) {
109 Map<String,Resource> localMap = childMaps.get(ontology);
112 Resource parent = ontology;
114 int p = name.indexOf('.');
117 String localName = name.substring(0, p);
118 parent = localMap.get(localName);
121 name = name.substring(p+1);
124 localMap = getLocalMap(parent);
128 Resource child = localMap.get(name);
130 return new JustResource(child);
132 return new ResourceAndSuffix(parent, name);
135 private Resource getResource(String name) {
136 ResourceSearchResult searchResult = getResourceOrSuffixedResource(name);
137 if(searchResult instanceof JustResource)
138 return ((JustResource)searchResult).resource;
143 private Map<String, Resource> getLocalMap(Resource parent) {
144 Map<String, Resource> localMap = childMaps.get(parent);
145 if(localMap == null) {
146 if(childMaps.contains(parent))
148 localMap = createLocalMap(parent);
149 childMaps.put(parent, localMap);
154 private static Map<String, Resource> createLocalMap(final Resource parent) {
155 ReadGraph graph = (ReadGraph)SCLContext.getCurrent().get("graph");
157 return createLocalMap(graph, parent);
160 return Simantics.getSession().syncRequest(new Read<Map<String, Resource>>() {
162 public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
163 return createLocalMap(graph, parent);
166 } catch(DatabaseException e) {
172 private static Map<String, Resource> createLocalMap(ReadGraph graph, Resource parent) {
174 return graph.syncRequest(new UnescapedChildMapOfResource(parent));
175 } catch (DatabaseException e) {
182 private static interface ResourceFunctionGenerator {
183 SCLValue createValue(Name name, Resource resource);
186 private static class RelatedValueMacroRule implements MacroRule {
187 private final Resource relation;
188 private final SCLRelationInfo relationInfo;
189 private final boolean optionalValue;
191 public RelatedValueMacroRule(Resource relation, SCLRelationInfo relationInfo, boolean optionalValue) {
192 this.relation = relation;
193 this.relationInfo = relationInfo;
194 this.optionalValue = optionalValue;
197 private Expression applyWithSubject(SimplificationContext context, Type subjectType, Expression evidence, Expression subject) {
198 if(Types.equals(subjectType, RESOURCE))
200 Locations.NO_LOCATION,
202 context.getConstant(Name.create(DB_MODULE, optionalValue ? "possibleRelatedValue2" : "relatedValue2"), relationInfo.rangeType),
204 new EExternalConstant(relation, RESOURCE));
205 else if(Types.equals(subjectType, VARIABLE))
207 Locations.NO_LOCATION,
209 context.getConstant(Name.create(DB_MODULE, optionalValue ? "untypedPossiblePropertyValue" : "untypedPropertyValue"), relationInfo.rangeType),
211 new ELiteral(new StringConstant(relationInfo.name)));
214 Locations.NO_LOCATION,
216 context.getConstant(Name.create(DB_MODULE, optionalValue ? "genericPossibleRelatedValue" : "genericRelatedValue"), subjectType, relationInfo.rangeType),
219 new EExternalConstant(relation, RESOURCE));
223 public Expression apply(SimplificationContext context, Type[] typeParameters, EApply apply) {
224 Type subjectType = typeParameters[0];
225 if(apply.parameters.length == 1) {
226 Variable subject = new Variable("subject", subjectType);
227 return new ESimpleLambda(subject, applyWithSubject(context, subjectType, apply.parameters[0], new EVariable(subject)));
229 else if(apply.parameters.length >= 2) {
230 Expression valueReplacement = applyWithSubject(context, subjectType, apply.parameters[0], apply.parameters[1]);
231 if(apply.parameters.length == 2)
232 return valueReplacement;
234 apply.set(valueReplacement, Arrays.copyOfRange(apply.parameters, 2, apply.parameters.length));
239 LOGGER.error("Application of relation following functions should have at least one parameter (the evidence of Browsable).");
245 private final static HashMap<String, ResourceFunctionGenerator> VALUE_GENERATOR_MAP = new HashMap<>();
247 TVar A = Types.var(Kinds.STAR);
248 VALUE_GENERATOR_MAP.put("value", (name, resource) -> {
249 SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource);
250 if(relationInfo == null)
253 SCLValue value = new SCLValue(name);
254 value.setType(Types.forAll(A, Types.function(Types.pred(BROWSABLE, A), Types.functionE(A, Types.READ_GRAPH, relationInfo.rangeType))));
255 value.setMacroRule(new RelatedValueMacroRule(resource, relationInfo, false));
258 VALUE_GENERATOR_MAP.put("possibleValue", (name, resource) -> {
259 SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource);
260 if(relationInfo == null)
263 SCLValue value = new SCLValue(name);
264 value.setType(Types.forAll(A, Types.function(Types.pred(BROWSABLE, A), Types.functionE(A, Types.READ_GRAPH, Types.apply(Types.MAYBE, relationInfo.rangeType)))));
265 value.setMacroRule(new RelatedValueMacroRule(resource, relationInfo, true));
271 protected SCLValue createValue(String name) {
272 ResourceSearchResult searchResult = getResourceOrSuffixedResource(name);
273 if(searchResult instanceof JustResource) {
274 Resource resource = ((JustResource)searchResult).resource;
275 SCLValue value = new SCLValue(Name.create(getName(), name));
276 value.setType(RESOURCE);
277 value.setExpression(new EExternalConstant(resource, RESOURCE));
278 value.setInlineInSimplification(true);
281 else if(searchResult instanceof ResourceAndSuffix){
282 ResourceAndSuffix resourceAndSuffix = (ResourceAndSuffix)searchResult;
283 ResourceFunctionGenerator generator = VALUE_GENERATOR_MAP.get(resourceAndSuffix.suffix);
284 if(generator == null)
287 return generator.createValue(Name.create(getName(), name), resourceAndSuffix.resource);
294 protected SCLRelation createRelation(String name) {
295 final Resource resource = getResource(name);
298 ReadGraph graph = (ReadGraph)SCLContext.getCurrent().get("graph");
300 return createRelation(graph, resource);
303 return Simantics.getSession().syncRequest(new Read<SCLRelation>() {
305 public SCLRelation perform(ReadGraph graph) throws DatabaseException {
306 return createRelation(graph, resource);
309 } catch(DatabaseException e) {
315 public static SCLRelation createRelation(ReadGraph graph, Resource relation) {
317 Layer0 L0 = Layer0.getInstance(graph);
318 if(!graph.isInstanceOf(relation, L0.Relation))
320 if(graph.isInstanceOf(relation, L0.PropertyRelation) && graph.isInstanceOf(relation, L0.FunctionalRelation)) {
321 Type valueType = getValueType(graph, relation);
322 if(valueType != null)
323 return new GraphPropertyRelation(relation, valueType);
326 Resource inverseRelation = graph.getPossibleInverse(relation);
327 return new GraphRelation(relation, getSelectivity(graph, relation),
328 inverseRelation, getSelectivity(graph, inverseRelation));
329 } catch(DatabaseException e) {
336 protected SCLEntityType createEntityType(String name) {
337 final Resource resource = getResource(name);
340 ReadGraph graph = (ReadGraph)SCLContext.getCurrent().get("graph");
342 return createEntityType(graph, resource);
345 return Simantics.getSession().syncRequest(new Read<SCLEntityType>() {
347 public SCLEntityType perform(ReadGraph graph) throws DatabaseException {
348 return createEntityType(graph, resource);
351 } catch(DatabaseException e) {
357 private SCLEntityType createEntityType(ReadGraph graph, Resource type) {
359 Layer0 L0 = Layer0.getInstance(graph);
360 if(!graph.isInstanceOf(type, L0.Type))
362 return new GraphEntityType(graph, type);
363 } catch(DatabaseException e) {
369 private static double getSelectivity(ReadGraph graph, Resource relation) throws DatabaseException {
371 return Double.POSITIVE_INFINITY;
372 Layer0 L0 = Layer0.getInstance(graph);
373 if(graph.isInstanceOf(relation, L0.FunctionalRelation))
379 private static Type getValueType(ReadGraph graph, Resource relation) throws DatabaseException {
380 Layer0 L0 = Layer0.getInstance(graph);
381 Type valueType = parseValueType((String)graph.getPossibleRelatedValue(relation, L0.RequiresValueType, Bindings.STRING));
382 if(valueType != null)
384 Resource range = graph.getPossibleObject(relation, L0.HasRange);
386 for(Resource valueTypeLiteral : graph.getAssertedObjects(range, L0.HasValueType)) {
387 valueType = parseValueType((String)graph.getValue(valueTypeLiteral, Bindings.STRING));
388 if(valueType != null)
395 private static Type parseValueType(String valueTypeString) {
396 if(valueTypeString == null)
399 return Types.parseType(valueTypeString);
400 } catch (SCLTypeParseException e) {
407 public void findValuesForPrefix(String prefix,
408 NamespaceFilter filter,
409 TObjectProcedure<SCLValue> proc) {
410 Map<String,Resource> localMap = childMaps.get(ontology);
413 String namePrefix = "";
415 int p = prefix.indexOf('.');
418 String localName = prefix.substring(0, p);
419 Resource newParent = localMap.get(localName);
420 if(newParent == null)
422 prefix = prefix.substring(p+1);
423 namePrefix = namePrefix + localName + ".";
426 localMap = getLocalMap(newParent);
430 for(String name : localMap.keySet())
431 if(name.startsWith(prefix) && filter.isValueIncluded(name))
432 proc.execute(getValue(namePrefix+name));
436 public void findValuesForPrefix(String prefix, NamespaceFilter filter, Consumer<SCLValue> consumer) {
437 Map<String,Resource> localMap = childMaps.get(ontology);
440 String namePrefix = "";
442 int p = prefix.indexOf('.');
445 String localName = prefix.substring(0, p);
446 Resource newParent = localMap.get(localName);
447 if(newParent == null)
449 prefix = prefix.substring(p+1);
450 namePrefix = namePrefix + localName + ".";
453 localMap = getLocalMap(newParent);
457 for(String name : localMap.keySet())
458 if(name.startsWith(prefix) && filter.isValueIncluded(name))
459 consumer.accept(getValue(namePrefix+name));
463 public void findTypesForPrefix(String prefix, NamespaceFilter instance, Consumer<TCon> consumer) {
468 public void dispose() {
475 public String toString() {
476 return new StringBuilder().append("OntologyModule ").append(getName()).toString();
480 public ClassLoader getParentClassLoader() {
481 return getClass().getClassLoader();