From 3850fec72035293b9a4ede780d01aedc5fbc9056 Mon Sep 17 00:00:00 2001 From: Antti Villberg Date: Thu, 17 May 2018 07:37:51 +0300 Subject: [PATCH] Multiple readers and variable optimization gitlab #5 gitlab #6 (refs #6961) Change-Id: Iabc5ff369cb42e8a3813519b6e5d981f538ebdff --- .../db/common/request/AdaptValue.java | 16 +- .../db/impl/graph/ReadGraphImpl.java | 12 +- .../db/impl/graph/ReadGraphSupport.java | 2 +- .../db/impl/query/AssertedPredicates.java | 28 +- .../db/impl/query/AssertedStatements.java | 8 +- .../{NamespaceIndex.java => ChildMap.java} | 100 ++------ .../org/simantics/db/impl/query/CodeGen.java | 12 +- .../db/impl/query/DirectPredicates.java | 2 +- .../org/simantics/db/impl/query/IntSet.java | 10 +- .../org/simantics/db/impl/query/Objects.java | 26 +- .../simantics/db/impl/query/Predicates.java | 64 +++-- .../simantics/db/impl/query/QueryCache.java | 108 +++++--- .../db/impl/query/QueryCacheBase.java | 111 +++++--- .../db/impl/query/QueryCollectorImpl.java | 20 +- .../db/impl/query/QueryProcessor.java | 61 +++-- .../db/impl/query/RelationInfoQuery.java | 4 +- .../simantics/db/impl/query/Statements.java | 14 +- .../db/impl/query/SuperRelations.java | 5 +- .../org/simantics/db/impl/query/Types.java | 15 +- .../db/impl/query/URIToResource.java | 55 ++-- bundles/org.simantics.db.layer0/adapters.xml | 15 ++ .../adapter/ReflectionExternalValue.java | 25 ++ .../db/layer0/adapter/SCLExternalValue.java | 29 +++ .../layer0/request/PropertyInfoRequest.java | 5 +- .../AbstractExpressionAnalysisRequest.java | 240 ++++++++++++++++++ .../AbstractExpressionCompilationRequest.java | 7 +- .../db/layer0/scl/CompileValueRequest.java | 17 ++ .../db/layer0/scl/ExpressionAnalysis.java | 29 +++ .../db/layer0/variable/VariableMapImpl.java | 4 +- .../internal/CollectionSupportImpl.java | 193 -------------- .../procore/internal/ObjectResourceMap.java | 218 ++++++++++++++++ .../simantics/db/ConverterExternalValue.java | 10 + .../src/org/simantics/db/ExternalValue.java | 9 + .../org/simantics/db/ObjectResourceIdMap.java | 10 + .../simantics/debug/ui/VariableDebugger.java | 2 +- .../graph/Components.pgraph | 6 +- .../graph/Functions.pgraph | 4 +- .../graph/Properties.pgraph | 2 +- .../adapters.xml | 5 + .../scl/Document/All.scl | 5 + .../document/server/DocumentProperties.java | 14 + .../document/server/DocumentServerUtils.java | 48 ++-- .../simantics/document/server/Functions.java | 34 ++- .../document/server/SCLExternalValue.java | 29 +++ .../document/server/request/NodeRequest.java | 63 ++--- .../request/ServerSCLHandlerValueRequest.java | 73 +++--- .../server/request/ServerSCLValueRequest.java | 32 ++- .../document/swt/core/widget/ComboWidget.java | 1 + .../graph/db/TransferableGraphs.java | 14 + .../graph/Layer0SCL.pgraph | 2 + .../graph/Layer0Values.pgraph | 9 + bundles/org.simantics.modeling/adapters.xml | 6 + .../ImmutableComponentPropertyContent.java | 26 ++ ...utableComponentPropertyContentRequest.java | 159 ++++++++++++ .../ImmutableComponentPropertyVariable.java | 153 +++++++++++ .../modeling/ImmutableComponentVariable.java | 122 +++++++++ .../ImmutableComponentVariableBuilder.java | 31 +++ .../ImmutableComponentVariableContent.java | 19 ++ ...utableComponentVariableContentRequest.java | 75 ++++++ .../modeling/scl/AnalyseSCLValueRequest.java | 42 +++ .../synchronization/Synchronizer.java | 2 +- .../scl/Simantics/Structural.scl | 2 +- .../simantics/structural2/ConnectionImpl.java | 72 ++++++ .../org/simantics/structural2/Functions.java | 58 +---- .../queries/ConnectionPointMapOfResource.java | 10 +- ...AbstractAnalyseStructuralValueRequest.java | 154 +++++++++++ .../scl/AnalyseStructuralValueRequest.java | 103 ++++++++ .../structural2/utils/StructuralUtils.java | 6 +- .../structural2/variables/Connection.java | 6 +- .../StandardProceduralChildVariable.java | 6 +- .../feature.xml | 4 + 71 files changed, 2145 insertions(+), 738 deletions(-) rename bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/{NamespaceIndex.java => ChildMap.java} (59%) create mode 100644 bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/ReflectionExternalValue.java create mode 100644 bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/SCLExternalValue.java create mode 100644 bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionAnalysisRequest.java create mode 100644 bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/ExpressionAnalysis.java create mode 100644 bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ObjectResourceMap.java create mode 100644 bundles/org.simantics.db/src/org/simantics/db/ConverterExternalValue.java create mode 100644 bundles/org.simantics.db/src/org/simantics/db/ExternalValue.java create mode 100644 bundles/org.simantics.db/src/org/simantics/db/ObjectResourceIdMap.java create mode 100644 bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentProperties.java create mode 100644 bundles/org.simantics.document.server/src/org/simantics/document/server/SCLExternalValue.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContent.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContentRequest.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyVariable.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariable.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableBuilder.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContent.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContentRequest.java create mode 100644 bundles/org.simantics.modeling/src/org/simantics/modeling/scl/AnalyseSCLValueRequest.java create mode 100644 bundles/org.simantics.structural2/src/org/simantics/structural2/ConnectionImpl.java create mode 100644 bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AbstractAnalyseStructuralValueRequest.java create mode 100644 bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AnalyseStructuralValueRequest.java diff --git a/bundles/org.simantics.db.common/src/org/simantics/db/common/request/AdaptValue.java b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/AdaptValue.java index 02877596b..c8bd03257 100644 --- a/bundles/org.simantics.db.common/src/org/simantics/db/common/request/AdaptValue.java +++ b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/AdaptValue.java @@ -1,13 +1,12 @@ package org.simantics.db.common.request; +import org.simantics.db.ExternalValue; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.utils.Functions; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.RuntimeDatabaseException; import org.simantics.layer0.Layer0; -import org.simantics.scl.reflection.ReflectionUtils; -import org.simantics.scl.reflection.ValueNotFoundException; import org.simantics.scl.runtime.function.FunctionImpl3; /** @@ -20,7 +19,7 @@ public class AdaptValue extends ResourceRead { super(resource); } - private static final FunctionImpl3 functionApplication = new FunctionImpl3() { + public static final FunctionImpl3 functionApplication = new FunctionImpl3() { @Override public Object apply(ReadGraph graph, Resource resource, Object context) { @@ -36,12 +35,11 @@ public class AdaptValue extends ResourceRead { @Override public Object perform(ReadGraph graph) throws DatabaseException { String uri = graph.getURI(resource); - try { - if(Layer0.URIs.Functions_functionApplication.equals(uri)) return functionApplication; - return ReflectionUtils.getValue(uri).getValue(); - } catch (ValueNotFoundException e) { - throw new DatabaseException("Couldn't adapt the value " + uri, e); - } + if(Layer0.URIs.Functions_functionApplication.equals(uri)) return functionApplication; + + ExternalValue ev = graph.adapt(resource, ExternalValue.class); + return ev.getValue(graph, resource); + } } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java index 25438ef1e..e3e7d50ec 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java @@ -45,6 +45,7 @@ import org.simantics.databoard.util.binary.BinaryFile; import org.simantics.databoard.util.binary.RandomAccessBinary; import org.simantics.db.AsyncReadGraph; import org.simantics.db.DevelopmentKeys; +import org.simantics.db.ExternalValue; import org.simantics.db.ExternalValueSupport; import org.simantics.db.ReadGraph; import org.simantics.db.RelationContext; @@ -6453,7 +6454,8 @@ public class ReadGraphImpl implements ReadGraph { for(Resource converter : graph.getObjects(resource, L0.ConvertsToValueWith)) { try { if(L0.Functions_functionApplication.equals(converter)) { - return (Function3)graph.syncRequest(new AdaptValue(resource)); + return AdaptValue.functionApplication; + //return (Function3)graph.syncRequest(new AdaptValue(resource)); } else { return graph.getValue2(converter, resource); } @@ -6511,9 +6513,11 @@ public class ReadGraphImpl implements ReadGraph { } } else if(types.contains(L0.ExternalValue)) { try { - return (T)ReflectionUtils.getValue(getURI(r)).getValue(); - } catch(ValueNotFoundException e) { - throw new DatabaseException(e); + ExternalValue ev = adapt(r, ExternalValue.class); + return ev.getValue(this, r); + //return (T)ReflectionUtils.getValue(getURI(r)).getValue(); +// } catch(ValueNotFoundException e) { +// throw new DatabaseException(e); } catch(ClassCastException e) { throw new DatabaseException(e); } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphSupport.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphSupport.java index d8fda07b7..3f7e6f4e6 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphSupport.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphSupport.java @@ -72,7 +72,7 @@ public interface ReadGraphSupport { void forPossibleSuperrelation(ReadGraphImpl graph, Resource subject, AsyncProcedure procedure); void forSuperrelations(ReadGraphImpl graph, Resource subject, AsyncProcedure> procedure); byte[] getValue(ReadGraphImpl graph, Resource subject) throws DatabaseException; - byte[] forValue(ReadGraphImpl graph, Resource subject, AsyncProcedure procedure); + void forValue(ReadGraphImpl graph, Resource subject, AsyncProcedure procedure); void forPossibleValue(ReadGraphImpl graph, Resource subject, AsyncProcedure procedure); void forInverse(ReadGraphImpl graph, Resource relation, AsyncProcedure procedure); void forResource(ReadGraphImpl graph, String id, AsyncProcedure procedure); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedPredicates.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedPredicates.java index 8013c1a47..410db7118 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedPredicates.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedPredicates.java @@ -160,40 +160,16 @@ final public class AssertedPredicates extends CollectionUnaryQuery } - final static InternalProcedure ip = new InternalProcedure() { - - @Override - public void execute(ReadGraphImpl graph, RelationInfo result) { - } - - @Override - public void exception(ReadGraphImpl graph, Throwable throwable) { - } - - }; - - final static InternalProcedure ip2 = new InternalProcedure() { - - @Override - public void execute(ReadGraphImpl graph, IntSet result) { - } - - @Override - public void exception(ReadGraphImpl graph, Throwable throwable) { - } - - }; - synchronized private void addOrSetHiding(ReadGraphImpl graph, int add, CacheEntry parent) throws DatabaseException { assert(isPending()); IntArray value = (IntArray)getResult(); - RelationInfo ri = QueryCacheBase.resultRelationInfoQuery(graph, add, parent, null, ip); + RelationInfo ri = QueryCacheBase.resultRelationInfoQuery(graph, add, parent, null); if(ri.isFunctional) { // Replace existing functional predicate if found try { - IntSet supers = QueryCache.resultSuperRelations(graph, add, parent, null, ip2); + IntSet supers = QueryCache.resultSuperRelations(graph, add, parent, null); if(value.data == null) { if(value.sizeOrData != IntArray.NO_DATA) { if(supers.contains(value.sizeOrData)) { diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedStatements.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedStatements.java index a9ce7c6f8..90daa9a84 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedStatements.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AssertedStatements.java @@ -145,7 +145,7 @@ final public class AssertedStatements extends CollectionBinaryQuery>> { +final public class ChildMap extends UnaryQuery>> { - NamespaceIndex(final String id) { - super(id); + ChildMap(final int r) { + super(r); } @Override final public void removeEntry(QueryProcessor provider) { provider.cache.remove(this); } - - final static private void index(ReadGraphImpl graph, int root, NamespaceIndex entry, final InternalProcedure> procedure) throws DatabaseException { + + @Override + public Object compute(ReadGraphImpl graph, final InternalProcedure> procedure) throws DatabaseException { + computeForEach(graph, id, this, procedure); + return getResult(); + } + + public static void computeForEach(ReadGraphImpl graph, final int root, final ChildMap entry, final InternalProcedure> procedure) throws DatabaseException { if(root == 0) { if(entry != null) entry.add2(graph, null); procedure.execute(graph, null); -// System.err.println("NamespaceIndex[" + id + "]->null"); return; } @@ -48,7 +52,7 @@ final public class NamespaceIndex extends StringQuery result = new TObjectIntHashMap(); + ObjectResourceIdMap result = graph.getService(CollectionSupport.class).createObjectResourceMap(String.class); QueryCache.runnerObjects(graph, root, consistsOf, entry, null, new SyncIntProcedure() { @@ -67,8 +71,6 @@ final public class NamespaceIndex extends StringQuery " + obj); inc(); @@ -91,12 +93,7 @@ final public class NamespaceIndex extends StringQuery> procedure) throws DatabaseException { - computeForEach(graph, id, this, procedure); - return getResult(); - } - - public static void computeForEach(ReadGraphImpl graph, final String id, final NamespaceIndex entry, final InternalProcedure> procedure) throws DatabaseException { - - QueryProcessor processor = graph.processor; - -// System.err.println("NamespaceIndex " + id); - - if("http://".equals(id) || "http:/".equals(id)) { - index(graph, processor.getRootLibrary(), entry, procedure); - } else { - final String[] parts = URIStringUtils.splitURI(id); - if(parts != null) { - QueryCache.runnerNamespaceIndex(graph, parts[0], entry, null, new InternalProcedure>() { - - @Override - public void execute(ReadGraphImpl graph, TObjectIntHashMap index) throws DatabaseException { - - if(index != null) { - index(graph, index.get(parts[1]), entry, procedure); - } else { - if(entry != null) entry.add2(graph, null); - procedure.execute(graph, null); -// System.err.println("NamespaceIndex[" + id + "]->null"); - } - - } - - @Override - public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException { - if(DebugException.DEBUG) new DebugException(t).printStackTrace(); - if(entry != null) entry.except(t); - procedure.exception(graph, t); - } - - }); - } else { - if(entry != null) entry.add2(graph, null); - procedure.execute(graph, null); -// System.err.println("NamespaceIndex[" + id + "]->null"); - } - - } - - } - @Override public String toString() { - return "NamespaceIndex[" + id + "]"; + return "ChildMap[" + id + "]"; } - private void add2(ReadGraphImpl graph, TObjectIntHashMap result) { - - if(!isPending()) { - new Exception(""+hashCode()).printStackTrace(); - } + private void add2(ReadGraphImpl graph, ObjectResourceIdMap result) { assert(isPending()); @@ -211,13 +153,13 @@ final public class NamespaceIndex extends StringQuery> procedure) throws DatabaseException { + public Object performFromCache(ReadGraphImpl graph, InternalProcedure> procedure) throws DatabaseException { assert(isReady()); if(handleException(graph, procedure)) return (Throwable)statusOrException; - TObjectIntHashMap result = (TObjectIntHashMap)getResult(); + ObjectResourceIdMap result = (ObjectResourceIdMap)getResult(); procedure.execute(graph, result); @@ -228,10 +170,10 @@ final public class NamespaceIndex extends StringQuery>() { + compute(graph, new InternalProcedure>() { @Override - public void execute(ReadGraphImpl graph, TObjectIntHashMap result) { + public void execute(ReadGraphImpl graph, ObjectResourceIdMap result) { } @Override diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CodeGen.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CodeGen.java index 857d93487..ed6039847 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CodeGen.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CodeGen.java @@ -7,6 +7,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; +import org.simantics.db.ObjectResourceIdMap; import org.simantics.utils.FileUtils; public class CodeGen { @@ -23,6 +24,7 @@ public class CodeGen { String[] signatureR2TIP = { "int r1, int r2", "r1,r2", "keyR2", "long", "TripleIntProcedure", "entry.id" }; String[] signatureID1 = { "String id", "id", "keyID", "String", "InternalProcedure", "entry.id" }; String[] signatureID2 = { "String id", "id", "keyID", "String", "InternalProcedure>", "entry.id" }; + String[] signatureChildMap = { "int r", "r", "keyR", "long", "InternalProcedure>", "entry.id" }; String[] signatureRead = { "Read r", "r", "id", "long", "AsyncProcedure", "entry.request" }; String[] signatureAsyncRead = { "AsyncRead r", "r", "id", "long", "AsyncProcedure", "entry.request" }; String[] signatureMultiRead = { "MultiRead r", "r", "id", "long", "AsyncMultiProcedure", "entry.request" }; @@ -45,13 +47,13 @@ public class CodeGen { public void generateRunner(StringBuilder content, String clazz, String[] signature, boolean shortcut) { line(content, "public static void runner" + clazz + "(ReadGraphImpl graph, " + signature[0] + ", CacheEntry parent, ListenerBase listener, " + signature[4] + " procedure) throws DatabaseException {"); + line(content, " QueryCache cache = graph.processor.cache;"); if(shortcut) { - line(content, " if(parent == null && listener == null) {"); + line(content, " if(parent == null && listener == null && !cache.shouldCache(graph.processor, " + signature[1] + ")) {"); line(content, " " + clazz + ".computeForEach(graph, " + signature[1] + ", null, procedure);"); line(content, " return;"); line(content, " }"); } - line(content, " QueryCache cache = graph.processor.cache;"); line(content, " if(procedure == null) procedure = emptyProcedure" + clazz + ";"); line(content, " " + clazz + " entry = (" + clazz + ")cache.getOrCreate" + clazz + "(" + signature[1] + ");"); line(content, " ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false);"); @@ -92,6 +94,7 @@ public class CodeGen { line(content, " existing.clearResult(querySupport);"); line(content, " existing.setPending();"); line(content, " " + lower + "Map.put(" + signature[2] + "(" + signature[1] + "), existing);"); + line(content, " size++;"); line(content, " return existing;"); line(content, " }"); line(content, " if(existing.requiresComputation()) {"); @@ -121,6 +124,8 @@ public class CodeGen { StringBuilder content = new StringBuilder(); content.append("package org.simantics.db.impl.query;\n"); content.append("\n"); + + content.append("import org.simantics.db.ObjectResourceIdMap;\n"); content.append("import org.simantics.db.RelationInfo;\n"); content.append("import org.simantics.db.exception.DatabaseException;\n"); content.append("import org.simantics.db.impl.graph.ReadGraphImpl;\n"); @@ -157,7 +162,8 @@ public class CodeGen { generateQuery(content, "ReadEntry", signatureRead, true); generateQuery(content, "AsyncReadEntry", signatureAsyncRead, true); generateQuery(content, "Types", signatureR1IntSet, true); - generateQuery(content, "NamespaceIndex", signatureID2, true); + //generateQuery(content, "NamespaceIndex", signatureID2, true); + generateQuery(content, "ChildMap", signatureChildMap, true); generateQuery(content, "AssertedStatements", signatureR2TIP, false); generateQuery(content, "AssertedPredicates", signatureR1IP, false); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/DirectPredicates.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/DirectPredicates.java index 2d15b6b80..feb0533ef 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/DirectPredicates.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/DirectPredicates.java @@ -42,7 +42,7 @@ final public class DirectPredicates extends CollectionUnaryQuery { @Override public void execute(ReadGraphImpl graph, int type) throws DatabaseException { if(result == null) { - result = QueryCacheBase.resultAssertedStatements(graph, type, r2, entry, null, NOPT); + result = QueryCacheBase.resultAssertedStatements(graph, type, r2, entry, null); } else { if (first) { IntArray ia = result; @@ -91,7 +91,7 @@ final public class Objects extends CollectionBinaryQuery { } first = false; } - IntArray ia = QueryCacheBase.resultAssertedStatements(graph, type, r2, entry, null, NOPT); + IntArray ia = QueryCacheBase.resultAssertedStatements(graph, type, r2, entry, null); if(ia.data != null) { for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]); } @@ -151,7 +151,7 @@ final public class Objects extends CollectionBinaryQuery { IntSet candidateIs = null; try { - candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null, NOP); + candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null); } catch (DatabaseException e) { if(entry != null) entry.except(e); procedure.exception(graph, e); @@ -173,7 +173,7 @@ final public class Objects extends CollectionBinaryQuery { IntSet nextIs = null; try { - nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null, NOP); + nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null); } catch (DatabaseException e) { if(entry != null) entry.except(e); procedure.exception(graph, e); @@ -312,7 +312,7 @@ final public class Objects extends CollectionBinaryQuery { } else { // Note! The dependency is intentionally cut! - IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null, QueryCache.emptyProcedureDirectPredicates); + IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null); direct.forEach(graph, new SyncIntProcedure() { boolean found = false; @@ -544,7 +544,7 @@ final public class Objects extends CollectionBinaryQuery { } else { // Note! The dependency is intentionally cut! - IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null, QueryCache.emptyProcedureDirectPredicates); + IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null); direct.forEach(graph, new SyncIntProcedure() { @Override @@ -656,7 +656,7 @@ final public class Objects extends CollectionBinaryQuery { public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) throws DatabaseException { - RelationInfo ri = QueryCache.resultRelationInfoQuery(graph, r2, entry, null, ip); + RelationInfo ri = QueryCache.resultRelationInfoQuery(graph, r2, entry, null); graph.ensureLoaded(r1, r2); if(ri.isFunctional) { computeFunctionalIndex(graph, r1, r2, entry, ri, procedure); @@ -666,18 +666,6 @@ final public class Objects extends CollectionBinaryQuery { } - final static InternalProcedure ip = new InternalProcedure() { - - @Override - public void execute(ReadGraphImpl graph, RelationInfo result) { - } - - @Override - public void exception(ReadGraphImpl graph, Throwable throwable) { - } - - }; - @Override public String toString() { return "Objects[" + r1() + " - " + r2() + "]"; diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Predicates.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Predicates.java index 3841e1d14..e5cb6dfa1 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Predicates.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Predicates.java @@ -85,45 +85,39 @@ final public class Predicates extends UnaryQuery> { public static void computeForEach(ReadGraphImpl graph, final int r, final Predicates entry, final InternalProcedure procedure) throws DatabaseException { - - IntSet direct = QueryCache.resultDirectPredicates(graph, r, entry, null, procedure); - IntSet result = new IntSet(); - direct.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - result.add(value); - return true; - } - }); + IntSet direct = QueryCache.resultDirectPredicates(graph, r, entry, null); + IntSet result = new IntSet(graph.processor.querySupport); forAssertions(graph, r, entry, result); -// DirectPredicates.queryEach(graph, r, processor, entry, null, new IntProcedure() { -// -// @Override -// public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException { -// result.add(pred); -// } -// -// @Override -// public void finished(ReadGraphImpl graph) throws DatabaseException { -// -// -// } -// -// @Override -// public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException { -// procedure.exception(graph, t); -// } -// -// }); - - if(entry != null) { - entry.setResult(result); - entry.setReady(); - } + if(result.isEmpty()) { + + if(entry != null) { + entry.setResult(direct); + entry.setReady(); + } + + procedure.execute(graph, direct); + + } else { + + direct.forEach(new TIntProcedure() { + @Override + public boolean execute(int value) { + result.add(value); + return true; + } + }); + + if(entry != null) { + entry.setResult(result); + entry.setReady(); + } + + procedure.execute(graph, result); + + } - procedure.execute(graph, result); } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java index dbd0068c3..49e02dece 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java @@ -1,5 +1,6 @@ package org.simantics.db.impl.query; +import org.simantics.db.ObjectResourceIdMap; import org.simantics.db.RelationInfo; import org.simantics.db.exception.DatabaseException; import org.simantics.db.impl.graph.ReadGraphImpl; @@ -30,6 +31,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); objectsMap.put(keyR2(r1,r2), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -48,11 +50,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) { Objects.computeForEach(graph, r1,r2, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureObjects; Objects entry = (Objects)cache.getOrCreateObjects(r1,r2); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -72,6 +74,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); statementsMap.put(keyR2(r1,r2), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -90,11 +93,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, TripleIntProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) { Statements.computeForEach(graph, r1,r2, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureStatements; Statements entry = (Statements)cache.getOrCreateStatements(r1,r2); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -114,6 +117,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); directObjectsMap.put(keyR2(r1,r2), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -132,11 +136,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerDirectObjects(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r1,r2)) { DirectObjects.computeForEach(graph, r1,r2, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureDirectObjects; DirectObjects entry = (DirectObjects)cache.getOrCreateDirectObjects(r1,r2); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -156,6 +160,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); relationInfoQueryMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -174,11 +179,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerRelationInfoQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { RelationInfoQuery.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureRelationInfoQuery; RelationInfoQuery entry = (RelationInfoQuery)cache.getOrCreateRelationInfoQuery(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -198,6 +203,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); uRIToResourceMap.put(keyID(id), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -216,11 +222,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerURIToResource(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, id)) { URIToResource.computeForEach(graph, id, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureURIToResource; URIToResource entry = (URIToResource)cache.getOrCreateURIToResource(id); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -240,6 +246,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); valueQueryMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -258,11 +265,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerValueQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { ValueQuery.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureValueQuery; ValueQuery entry = (ValueQuery)cache.getOrCreateValueQuery(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -282,6 +289,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); orderedSetMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -300,11 +308,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerOrderedSet(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { OrderedSet.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureOrderedSet; OrderedSet entry = (OrderedSet)cache.getOrCreateOrderedSet(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -324,6 +332,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); principalTypesMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -342,11 +351,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerPrincipalTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, IntProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { PrincipalTypes.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedurePrincipalTypes; PrincipalTypes entry = (PrincipalTypes)cache.getOrCreatePrincipalTypes(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -366,6 +375,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); directPredicatesMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -384,11 +394,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerDirectPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { DirectPredicates.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureDirectPredicates; DirectPredicates entry = (DirectPredicates)cache.getOrCreateDirectPredicates(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -408,6 +418,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); predicatesMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -426,11 +437,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { Predicates.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedurePredicates; Predicates entry = (Predicates)cache.getOrCreatePredicates(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -450,6 +461,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); readEntryMap.put(id(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -468,11 +480,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerReadEntry(ReadGraphImpl graph, Read r, CacheEntry parent, ListenerBase listener, AsyncProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { ReadEntry.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureReadEntry; ReadEntry entry = (ReadEntry)cache.getOrCreateReadEntry(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -492,6 +504,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); asyncReadEntryMap.put(id(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -510,11 +523,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerAsyncReadEntry(ReadGraphImpl graph, AsyncRead r, CacheEntry parent, ListenerBase listener, AsyncProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { AsyncReadEntry.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureAsyncReadEntry; AsyncReadEntry entry = (AsyncReadEntry)cache.getOrCreateAsyncReadEntry(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -534,6 +547,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); typesMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -552,11 +566,11 @@ public class QueryCache extends QueryCacheBase { } public static void runnerTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - if(parent == null && listener == null) { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { Types.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; if(procedure == null) procedure = emptyProcedureTypes; Types entry = (Types)cache.getOrCreateTypes(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); @@ -567,15 +581,16 @@ public class QueryCache extends QueryCacheBase { } } - NamespaceIndex getOrCreateNamespaceIndex(String id) throws DatabaseException { - NamespaceIndex existing = null; - synchronized(namespaceIndexMap) { - existing = (NamespaceIndex)namespaceIndexMap.get(id); + ChildMap getOrCreateChildMap(int r) throws DatabaseException { + ChildMap existing = null; + synchronized(childMapMap) { + existing = (ChildMap)childMapMap.get(r); if(existing == null) { - existing = new NamespaceIndex(id); + existing = new ChildMap(r); existing.clearResult(querySupport); existing.setPending(); - namespaceIndexMap.put(keyID(id), existing); + childMapMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -587,24 +602,24 @@ public class QueryCache extends QueryCacheBase { return existing; } - void remove(NamespaceIndex entry) { - synchronized(namespaceIndexMap) { - namespaceIndexMap.remove(entry.id); + void remove(ChildMap entry) { + synchronized(childMapMap) { + childMapMap.remove(entry.id); } } - public static void runnerNamespaceIndex(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener, InternalProcedure> procedure) throws DatabaseException { - if(parent == null && listener == null) { - NamespaceIndex.computeForEach(graph, id, null, procedure); + public static void runnerChildMap(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure> procedure) throws DatabaseException { + QueryCache cache = graph.processor.cache; + if(parent == null && listener == null && !cache.shouldCache(graph.processor, r)) { + ChildMap.computeForEach(graph, r, null, procedure); return; } - QueryCache cache = graph.processor.cache; - if(procedure == null) procedure = emptyProcedureNamespaceIndex; - NamespaceIndex entry = (NamespaceIndex)cache.getOrCreateNamespaceIndex(id); + if(procedure == null) procedure = emptyProcedureChildMap; + ChildMap entry = (ChildMap)cache.getOrCreateChildMap(r); ListenerEntry listenerEntry = cache.registerDependencies(graph, entry, parent, listener, procedure, false); if(entry.isReady()) entry.performFromCache(graph, procedure); else { - NamespaceIndex.computeForEach(graph, id, entry, procedure); + ChildMap.computeForEach(graph, r, entry, procedure); if(listenerEntry != null) cache.primeListenerEntry(listenerEntry, entry.getResult()); } } @@ -618,6 +633,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); assertedStatementsMap.put(keyR2(r1,r2), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -656,6 +672,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); assertedPredicatesMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -694,6 +711,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); directSuperRelationsMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -732,6 +750,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); superTypesMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -770,6 +789,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); typeHierarchyMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -808,6 +828,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); superRelationsMap.put(keyR(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -846,6 +867,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); multiReadEntryMap.put(id(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -884,6 +906,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); asyncMultiReadEntryMap.put(id(r), existing); + size++; return existing; } if(existing.requiresComputation()) { @@ -922,6 +945,7 @@ public class QueryCache extends QueryCacheBase { existing.clearResult(querySupport); existing.setPending(); externalReadEntryMap.put(id(r), existing); + size++; return existing; } if(existing.requiresComputation()) { diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java index e2737f891..f75cd9dcd 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java @@ -5,6 +5,7 @@ import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ObjectResourceIdMap; import org.simantics.db.RelationInfo; import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; @@ -38,7 +39,8 @@ public class QueryCacheBase { public boolean collecting = false; final protected THashMap uRIToResourceMap; - final protected THashMap namespaceIndexMap; + //final protected THashMap namespaceIndexMap; + final protected UnaryQueryHashMap>> childMapMap; final protected DoubleKeyQueryHashMap objectsMap; final protected DoubleKeyQueryHashMap assertedStatementsMap; final protected DoubleKeyQueryHashMap directObjectsMap; @@ -79,7 +81,8 @@ public class QueryCacheBase { valueQueryMap = new UnaryQueryHashMap(); principalTypesMap = new UnaryQueryHashMap(); uRIToResourceMap = new THashMap(); - namespaceIndexMap = new THashMap(); + //namespaceIndexMap = new THashMap(); + childMapMap = new UnaryQueryHashMap>>(); relationInfoQueryMap = new UnaryQueryHashMap(); typeHierarchyMap = new UnaryQueryHashMap(); superTypesMap = new UnaryQueryHashMap(); @@ -373,12 +376,15 @@ public class QueryCacheBase { } - synchronized public ListenerEntry registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) { + public ListenerEntry registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) { if (parent != null && !inferred) { try { - if(!child.isImmutable(graph)) - child.addParent(parent); + if(!child.isImmutable(graph)) { + synchronized(child) { + child.addParent(parent); + } + } } catch (DatabaseException e) { Logger.defaultLogError(e); } @@ -393,7 +399,7 @@ public class QueryCacheBase { } - public ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) { + public synchronized ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) { assert (entry != null); @@ -510,7 +516,8 @@ public class QueryCacheBase { realSize += directSuperRelationsMap.size(); realSize += principalTypesMap.size(); realSize += uRIToResourceMap.size(); - realSize += namespaceIndexMap.size(); + //realSize += namespaceIndexMap.size(); + realSize += childMapMap.size(); realSize += relationInfoQueryMap.size(); realSize += superTypesMap.size(); @@ -547,9 +554,11 @@ public class QueryCacheBase { for(CacheEntryBase e : uRIToResourceMap.values()) if(e.getLevel() <= level) result.add(e); - for(CacheEntryBase e : namespaceIndexMap.values()) - if(e.getLevel() <= level) - result.add(e); +// for(CacheEntryBase e : namespaceIndexMap.values()) +// if(e.getLevel() <= level) +// result.add(e); + + childMapMap.values(level, result); relationInfoQueryMap.values(level, result); superTypesMap.values(level, result); @@ -585,7 +594,8 @@ public class QueryCacheBase { entries.addAll(directSuperRelationsMap.values()); entries.addAll(principalTypesMap.values()); entries.addAll(uRIToResourceMap.values()); - entries.addAll(namespaceIndexMap.values()); + //entries.addAll(namespaceIndexMap.values()); + entries.addAll(childMapMap.values()); entries.addAll(relationInfoQueryMap.values()); entries.addAll(superTypesMap.values()); entries.addAll(superRelationsMap.values()); @@ -643,7 +653,9 @@ public class QueryCacheBase { // System.err.println("ready:"); // base.ready.printStackTrace(); // } - System.err.println("asd"); + new Exception("Timeout waiting for request to complete: " + entry.getOriginalRequest().toString()).printStackTrace(); + throw new DatabaseException("Timeout waiting for request to complete."); + //System.err.println("asd"); //base.getQuery().recompute(null, null, entry); } } catch (InterruptedException e) { @@ -796,6 +808,19 @@ public class QueryCacheBase { }; + protected static InternalProcedure> emptyChildMapProcedure = new InternalProcedure>() { + + @Override + public void execute(ReadGraphImpl graph, ObjectResourceIdMap i) { + } + + @Override + public void exception(ReadGraphImpl graph, Throwable throwable) { + } + + }; + + protected static IntProcedure emptyIntProcedure = new IntProcedure() { @@ -878,6 +903,7 @@ public class QueryCacheBase { protected static InternalProcedure emptyProcedureURIToResource = emptyIntegerProcedure; protected static InternalProcedure> emptyProcedureNamespaceIndex = emptyNamespaceProcedure; + protected static InternalProcedure> emptyProcedureChildMap = emptyChildMapProcedure; protected static InternalProcedure emptyProcedureRelationInfoQuery = emptyRelationInfoProcedure; protected static AsyncProcedure emptyProcedureReadEntry = emptyAsyncProcedure; @@ -956,11 +982,12 @@ public class QueryCacheBase { static class IntSetWrapper implements IntProcedure { private IntProcedure procedure; - private IntSet result = new IntSet(); + final private IntSet result; private Throwable throwable = null; - IntSetWrapper(IntProcedure procedure) { + IntSetWrapper(ReadGraphImpl graph, IntProcedure procedure) { this.procedure = procedure; + result = new IntSet(graph.processor.querySupport); } @Override @@ -1037,53 +1064,77 @@ public class QueryCacheBase { return wrap.get(); } - public static byte[] resultValueQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(procedure); + public static byte[] resultValueQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(null); QueryCache.runnerValueQuery(graph, r, parent, listener, wrap); return wrap.get(); } - public static RelationInfo resultRelationInfoQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(procedure); + public static RelationInfo resultRelationInfoQuery(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(null); QueryCache.runnerRelationInfoQuery(graph, r, parent, listener, wrap); return wrap.get(); } - public static IntSet resultSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(procedure); + public static IntSet resultSuperRelations(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(null); QueryCache.runnerSuperRelations(graph, r, parent, listener, wrap); return wrap.get(); } - public static IntSet resultSuperTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(procedure); + public static IntSet resultSuperTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(null); QueryCache.runnerSuperTypes(graph, r, parent, listener, wrap); return wrap.get(); } - public static IntSet resultTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(procedure); + public static IntSet resultTypes(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(null); QueryCache.runnerTypes(graph, r, parent, listener, wrap); return wrap.get(); } - public static IntSet resultPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(procedure); + public static IntSet resultPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(null); QueryCache.runnerPredicates(graph, r, parent, listener, wrap); return wrap.get(); } - public static IntSet resultDirectPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener, InternalProcedure procedure) throws DatabaseException { - InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(procedure); + public static IntSet resultDirectPredicates(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper<>(null); QueryCache.runnerDirectPredicates(graph, r, parent, listener, wrap); return wrap.get(); } - public static IntArray resultAssertedStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener, TripleIntProcedure procedure) throws DatabaseException { - TripleIntProcedureWrapper wrap = new TripleIntProcedureWrapper(procedure); + public static IntArray resultAssertedStatements(ReadGraphImpl graph, int r1, int r2, CacheEntry parent, ListenerBase listener) throws DatabaseException { + TripleIntProcedureWrapper wrap = new TripleIntProcedureWrapper(null); QueryCache.runnerAssertedStatements(graph, r1, r2, parent, listener, wrap); return wrap.get(); } + public static Integer resultURIToResource(ReadGraphImpl graph, String id, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper wrap = new InternalProcedureWrapper(null); + QueryCache.runnerURIToResource(graph, id, parent, listener, wrap); + return wrap.get(); + } + + public static ObjectResourceIdMap resultChildMap(ReadGraphImpl graph, int r, CacheEntry parent, ListenerBase listener) throws DatabaseException { + InternalProcedureWrapper> wrap = new InternalProcedureWrapper>(null); + QueryCache.runnerChildMap(graph, r, parent, listener, wrap); + return wrap.get(); + } + + static boolean shouldCache(QueryProcessor processor, int r) { + return processor.isImmutable(r); + } + + static boolean shouldCache(QueryProcessor processor, int r, int r2) { + return processor.isImmutable(r); + } + + static boolean shouldCache(QueryProcessor processor, Object o) { + return false; + } + } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java index 965f1e39f..8ea760b75 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java @@ -29,10 +29,11 @@ class QueryCollectorImpl implements QueryProcessor.QueryCollector { */ boolean propagate = true; - private static final int COLLECT_N = 1000; + private long allowance = 100; private long spent = 0; + private long collectionCounter = 0; QueryCollectorImpl(QueryProcessor queryProcessor, QueryCollectorSupport support) { this.queryProcessor = queryProcessor; @@ -41,14 +42,28 @@ class QueryCollectorImpl implements QueryProcessor.QueryCollector { @Override public void collect(int youngTarget, int allowedTimeInMs) { - + long start = System.nanoTime(); // Refresh current size int size = support.calculateCurrentSize(); + +// if(collectionCounter > allowance) { +// collectionCounter = 0; +// allowance = (allowance * 1100) / 1000; +// } + int bound = queryProcessor.boundQueries; int young = size - bound; int youngPct = size > 0 ? 100*young / size : 0; + + // System.err.println("Collect size = " + size + " bound=" + bound + " allowance=" + allowance); + + // Allowance maintains a reasonable set of queries + if(size < allowance) return; + + // No need to collect anything if the amount of free queries is small compared to the amount of bound queries + if(youngPct < youngTarget) return; // Initialize support for new run // If support returns 0 we are starting from 0 @@ -182,6 +197,7 @@ class QueryCollectorImpl implements QueryProcessor.QueryCollector { support.remove(); propagate = true; moreAll++; + collectionCounter++; doneAll = false; return true; } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java index a6c987a9d..a54484a65 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java @@ -16,6 +16,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -279,10 +280,29 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap public boolean resume(ReadGraphImpl graph) { return executors[0].runSynchronized(); } + + //private WeakReference garbageTracker; + + private class GarbageTracker { + + @Override + protected void finalize() throws Throwable { + +// System.err.println("GarbageTracker"); +// +// garbageTracker = new WeakReference(new GarbageTracker()); + + super.finalize(); + + } + + } public QueryProcessor(final int threads, QuerySupport core, Set threadSet) throws DatabaseException { + //garbageTracker = new WeakReference(new GarbageTracker()); + THREADS = threads; THREAD_MASK = threads - 1; @@ -2324,11 +2344,8 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap @Override final public IntSet getPredicates(final ReadGraphImpl impl, final Resource subject) throws Throwable { - - return QueryCacheBase.resultPredicates(impl, querySupport.getId(subject), impl.parent, null, null); - + return QueryCacheBase.resultPredicates(impl, querySupport.getId(subject), impl.parent, null); } - @Override final public void forEachStatement(final ReadGraphImpl impl, final Resource subject, @@ -3424,7 +3441,7 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap assert(subject != null); - return QueryCacheBase.resultTypes(impl, querySupport.getId(subject), impl.parent, null, null); + return QueryCacheBase.resultTypes(impl, querySupport.getId(subject), impl.parent, null); } @@ -3647,17 +3664,18 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap } final public byte[] getValue(final ReadGraphImpl impl, final int subject) throws DatabaseException { - return QueryCache.resultValueQuery(impl, subject, impl.parent, null, null); + return QueryCache.resultValueQuery(impl, subject, impl.parent, null); } @Override - final public byte[] forValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure procedure) { + final public void forValue(final ReadGraphImpl impl, final Resource subject, final AsyncProcedure procedure) { assert(subject != null); + assert(procedure != null); int sId = querySupport.getId(subject); - if(procedure != null) { +// if(procedure != null) { final ListenerBase listener = getListenerBase(procedure); @@ -3699,23 +3717,18 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap // else impl.state.barrier.inc(null, null); try { - return QueryCacheBase.resultValueQuery(impl, sId, impl.parent, listener, ip); + QueryCache.runnerValueQuery(impl, sId, impl.parent, listener, ip); } catch (DatabaseException e) { - Logger.defaultLogError(e); - } - - - } else { + throw new IllegalStateException("Internal error"); + } - try { - return QueryCacheBase.resultValueQuery(impl, sId, impl.parent, null, null); - } catch (DatabaseException e) { - Logger.defaultLogError(e); - } - - } - - throw new IllegalStateException("Internal error"); +// } else { +// +// return QueryCacheBase.runnerValueQuery(impl, sId, impl.parent, null, null); +// +// } +// +// throw new IllegalStateException("Internal error"); } @@ -3973,7 +3986,7 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap final ListenerBase listener = getListenerBase(procedure); try { - IntSet result = QueryCache.resultDirectPredicates(impl, querySupport.getId(subject), impl.parent, listener,QueryCache.emptyProcedureDirectPredicates); + IntSet result = QueryCache.resultDirectPredicates(impl, querySupport.getId(subject), impl.parent, listener); procedure.execute(impl, !result.isEmpty()); } catch (DatabaseException e) { procedure.exception(impl, e); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/RelationInfoQuery.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/RelationInfoQuery.java index 667d2f125..d55768aaa 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/RelationInfoQuery.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/RelationInfoQuery.java @@ -78,8 +78,8 @@ final public class RelationInfoQuery extends UnaryQuery @Override public void execute(ReadGraphImpl graph, int type) throws DatabaseException { if(result == null) { - result = QueryCache.resultAssertedStatements(graph, type, r2, entry, null, NOPT); + result = QueryCache.resultAssertedStatements(graph, type, r2, entry, null); } else { if (first) { IntArray ia = result; @@ -107,7 +107,7 @@ final public class Statements extends CollectionBinaryQuery } first = false; } - IntArray ia = QueryCache.resultAssertedStatements(graph, type, r2, entry, null, NOPT); + IntArray ia = QueryCache.resultAssertedStatements(graph, type, r2, entry, null); if(ia.data != null) { for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]); } @@ -170,7 +170,7 @@ final public class Statements extends CollectionBinaryQuery IntSet candidateIs = null; try { - candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null, NOP); + candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null); } catch (DatabaseException e) { if(entry != null) entry.except(e); procedure.exception(graph, e); @@ -202,7 +202,7 @@ final public class Statements extends CollectionBinaryQuery IntSet nextIs = null; try { - nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null, NOP); + nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null); } catch (DatabaseException e) { if(entry != null) entry.except(e); procedure.exception(graph, e); @@ -322,7 +322,7 @@ final public class Statements extends CollectionBinaryQuery final AtomicBoolean found = new AtomicBoolean(false); // Note! The dependency is intentionally cut! - IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null, QueryCache.emptyProcedureDirectPredicates); + IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null); direct.forEach(graph, new SyncIntProcedure() { @Override @@ -554,7 +554,7 @@ final public class Statements extends CollectionBinaryQuery } else { // Note! The dependency is intentionally cut! - IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null, QueryCache.emptyProcedureDirectPredicates); + IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null); direct.forEach(graph, new SyncIntProcedure() { @Override @@ -599,7 +599,7 @@ final public class Statements extends CollectionBinaryQuery try { - IntSet result = QueryCache.resultSuperRelations(graph, pred2, entry, null, null); + IntSet result = QueryCache.resultSuperRelations(graph, pred2, entry, null); if(result.contains(r2)) { inc(); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/SuperRelations.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/SuperRelations.java index 479bd71cd..0f076fb34 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/SuperRelations.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/SuperRelations.java @@ -37,7 +37,6 @@ final public class SuperRelations extends UnaryQuery> } static int histoCounter = 0; - static IntSet EMPTY_SET = new IntSet(); static int counter = 0; class Koss { @@ -121,8 +120,8 @@ final public class SuperRelations extends UnaryQuery> if(size == 0) { - addOrSet(graph, EMPTY_SET, processor); - proc.execute(graph, EMPTY_SET); + addOrSet(graph, IntSet.EMPTY, processor); + proc.execute(graph, IntSet.EMPTY); } else if (size == 1) { diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Types.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Types.java index 96afa8c4f..155bc209b 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Types.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Types.java @@ -38,10 +38,6 @@ final public class Types extends UnaryQuery> { public static void computeForEach(final ReadGraphImpl graph, int id, Types entry, final InternalProcedure procedure) throws DatabaseException { - if(entry != null) - if(entry.isReady()) - System.err.println("asd"); - assert(procedure != null); QueryProcessor processor = graph.processor; @@ -56,7 +52,10 @@ final public class Types extends UnaryQuery> { @Override public void execute(ReadGraphImpl graph, IntSet types) throws DatabaseException { - if(entry != null) entry.addOrSet(graph, types, processor); + if(entry != null) { + entry.addOrSet(graph, types, processor); + entry.finish(); + } procedure.execute(graph, types); } @@ -67,6 +66,8 @@ final public class Types extends UnaryQuery> { } }); + + return; } @@ -103,9 +104,7 @@ final public class Types extends UnaryQuery> { @Override public void execute(ReadGraphImpl graph, int i) throws DatabaseException { - synchronized(result) { - result.add(i); - } + result.add(i); inc(); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/URIToResource.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/URIToResource.java index 5a44fc2eb..78ae0d12d 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/URIToResource.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/URIToResource.java @@ -12,13 +12,11 @@ package org.simantics.db.impl.query; import org.simantics.databoard.util.URIStringUtils; +import org.simantics.db.ObjectResourceIdMap; import org.simantics.db.common.exception.DebugException; import org.simantics.db.exception.DatabaseException; import org.simantics.db.impl.graph.ReadGraphImpl; import org.simantics.db.impl.procedure.InternalProcedure; -import org.simantics.db.procedure.ListenerBase; - -import gnu.trove.map.hash.TObjectIntHashMap; public class URIToResource extends StringQuery> { @@ -30,38 +28,6 @@ public class URIToResource extends StringQuery> { final public void removeEntry(QueryProcessor provider) { provider.cache.remove(this); } - - private static void lookup(ReadGraphImpl graph, final URIToResource entry, final InternalProcedure procedure, final String namespace, final String name) throws DatabaseException { - - QueryCache.runnerNamespaceIndex(graph, namespace, entry, null, new InternalProcedure>() { - - @Override - public void execute(ReadGraphImpl graph, TObjectIntHashMap index) throws DatabaseException { - - if(index != null) { - int result = index.get(name); - if(result != 0) { - if(entry != null) entry.addOrSet(graph, graph.processor, result); - procedure.execute(graph, result); - return; - } - } - - Integer zero = 0; - if(entry != null) entry.addOrSet(graph, graph.processor, zero); - procedure.execute(graph, zero); - - } - - @Override - public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException { - if(entry != null) entry.except(t); - procedure.exception(graph, t); - } - - }); - - } @Override public Object compute(ReadGraphImpl graph, final InternalProcedure procedure) throws DatabaseException { @@ -81,9 +47,24 @@ public class URIToResource extends StringQuery> { final String[] parts = URIStringUtils.splitURI(id); if (parts != null) { - lookup(graph, entry, procedure, parts[0], parts[1]); + + Integer parentId = QueryCache.resultURIToResource(graph, parts[0], entry, null); + ObjectResourceIdMap map = QueryCache.resultChildMap(graph, parentId, entry, null); + if(map == null) { + procedure.execute(graph, 0); + if(entry != null) entry.addOrSet(graph, graph.processor, 0); + } else { + int result = map.getId(URIStringUtils.unescape(parts[1])); + if(entry != null) entry.addOrSet(graph, graph.processor, result); + procedure.execute(graph, result); + } + } else { - lookup(graph, entry, procedure, "http://", id.replaceFirst("http://", "")); + + DatabaseException e = new DatabaseException("No URI for " + id); + if(entry != null) entry.except(e); + procedure.exception(graph, e); + } } diff --git a/bundles/org.simantics.db.layer0/adapters.xml b/bundles/org.simantics.db.layer0/adapters.xml index 9e85e9a1b..fe6066561 100644 --- a/bundles/org.simantics.db.layer0/adapters.xml +++ b/bundles/org.simantics.db.layer0/adapters.xml @@ -283,5 +283,20 @@ class="org.simantics.db.layer0.adapter.impl.ModelImportAdvisorFactory"> + + + + + + + + + + + + diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/ReflectionExternalValue.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/ReflectionExternalValue.java new file mode 100644 index 000000000..6bc6afb3b --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/ReflectionExternalValue.java @@ -0,0 +1,25 @@ +package org.simantics.db.layer0.adapter; + +import org.simantics.db.ExternalValue; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.scl.reflection.ReflectionUtils; +import org.simantics.scl.reflection.ValueNotFoundException; + +public class ReflectionExternalValue implements ExternalValue { + + @Override + public T getValue(ReadGraph graph, Resource resource) throws DatabaseException { + + try { + return (T)ReflectionUtils.getValue(graph.getURI(resource)).getValue(); + } catch(ValueNotFoundException e) { + throw new DatabaseException(e); + } catch(ClassCastException e) { + throw new DatabaseException(e); + } + + } + +} diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/SCLExternalValue.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/SCLExternalValue.java new file mode 100644 index 000000000..12e950c87 --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/SCLExternalValue.java @@ -0,0 +1,29 @@ +package org.simantics.db.layer0.adapter; + +import org.simantics.db.ConverterExternalValue; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.scl.CompileValueRequest; +import org.simantics.layer0.Layer0; +import org.simantics.scl.reflection.ReflectionUtils; +import org.simantics.scl.reflection.ValueNotFoundException; +import org.simantics.scl.runtime.function.Function1; + +public class SCLExternalValue implements ConverterExternalValue { + + @Override + public T getValue(ReadGraph graph, Resource resource) throws DatabaseException { + try { + return (T)ReflectionUtils.getValue(Layer0.URIs.Functions_computeExpression).getValue(); + } catch (ValueNotFoundException e) { + throw new DatabaseException(e); + } + } + + @Override + public Function1 getFunction(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException { + return CompileValueRequest.compile(graph, s, o, p); + } + +} diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfoRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfoRequest.java index 3b819cbab..ca81e1630 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfoRequest.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfoRequest.java @@ -1,7 +1,5 @@ package org.simantics.db.layer0.request; -import gnu.trove.map.hash.THashMap; - import java.util.Collection; import java.util.Collections; import java.util.Map; @@ -11,7 +9,6 @@ import org.simantics.databoard.Bindings; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.accessor.reference.IndexReference; import org.simantics.databoard.accessor.reference.NameReference; -import org.simantics.databoard.binding.Binding; import org.simantics.databoard.type.Datatype; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; @@ -24,6 +21,8 @@ import org.simantics.layer0.Layer0; import org.simantics.operation.Layer0X; import org.simantics.utils.datastructures.Pair; +import gnu.trove.map.hash.THashMap; + final public class PropertyInfoRequest extends ResourceRead { public PropertyInfoRequest(Resource resource) { diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionAnalysisRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionAnalysisRequest.java new file mode 100644 index 000000000..2cb0501a9 --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionAnalysisRequest.java @@ -0,0 +1,240 @@ +package org.simantics.db.layer0.scl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.RuntimeDatabaseException; +import org.simantics.db.request.Read; +import org.simantics.layer0.Layer0; +import org.simantics.scl.compiler.common.names.Name; +import org.simantics.scl.compiler.constants.StringConstant; +import org.simantics.scl.compiler.elaboration.expressions.EApply; +import org.simantics.scl.compiler.elaboration.expressions.EConstant; +import org.simantics.scl.compiler.elaboration.expressions.ELiteral; +import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet; +import org.simantics.scl.compiler.elaboration.expressions.EVariable; +import org.simantics.scl.compiler.elaboration.expressions.Expression; +import org.simantics.scl.compiler.elaboration.expressions.Variable; +import org.simantics.scl.compiler.environment.AbstractLocalEnvironment; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.environment.LocalEnvironment; +import org.simantics.scl.compiler.errors.CompilationError; +import org.simantics.scl.compiler.runtime.RuntimeEnvironment; +import org.simantics.scl.compiler.top.ExpressionEvaluator; +import org.simantics.scl.compiler.top.SCLExpressionCompilationException; +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.MatchException; +import org.simantics.scl.compiler.types.kinds.Kinds; +import org.simantics.scl.compiler.types.util.MultiFunction; +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.utils.datastructures.Pair; + +import gnu.trove.map.hash.THashMap; + +/** + *

This is a base implementation for compiling expressions stored into + * graph. It provides a skeleton and a set of methods that must be + * implemented to get a concrete compilation request. + * + *

The request returns an SCL function with type {@code EvaluationContext -> Result} + * where {@code EvaluationContext} is the type given by {@link #getContextVariableType()} + * and {@code Result} is the type of the expression that can be optionally restricted + * by {@link #getExpectedType(ReadGraph, AbstractExpressionCompilationContext)}. + * + *

Compilation calls {@link #getCompilationContext(ReadGraph)} to read all information + * that is needed about the context of the resource during compilation. The result must + * extend the type {@link AbstractExpressionCompilationContext} including at least information about + * {@link RuntimeEnvironment}. + * + *

Compilation calls {@link #getVariableAccessExpression(ReadGraph, AbstractExpressionCompilationContext, Variable, String)} + * to get access to local environment. The method may return null if the variable is not defined. + * + * @author Hannu Niemistö + * + * @param + */ +public abstract class AbstractExpressionAnalysisRequest +implements Read> { + + protected static final Type RESOURCE = Types.con("Simantics/DB", "Resource"); + protected static final Type VARIABLE = Types.con("Simantics/Variables", "Variable"); + protected static Name PROPERTY_VALUE = Name.create("Simantics/Variables", "propertyValue"); + protected static Name VARIABLE_PARENT = Name.create("Simantics/Variables", "variableParent"); + protected static Name FROM_DOUBLE = Name.create("Prelude", "fromDouble"); + protected static Name TO_DOUBLE = Name.create("Prelude", "toDouble"); + protected static Name FROM_DYNAMIC = Name.create("Prelude", "fromDynamic"); + + private static final Type DEFAULT_EXPECTED_EFFECT = Types.union(new Type[] {Types.PROC, Types.READ_GRAPH}); + + /** + * Returns the expression that will be compiled in textual form. + */ + protected abstract String getExpressionText(ReadGraph graph) throws DatabaseException; + /** + * Returns the context that is used for the compilation of the expression. The context + * contains information about available constants and variables. + */ + protected abstract CompilationContext getCompilationContext(ReadGraph graph) throws DatabaseException; + /** + * This should return the SCL type corresponding to generic type parameter {@code EvaluationContext}. + */ + protected abstract Type getContextVariableType(); + /** + * Returns null, if variable {@code name} is not defined. + */ + protected abstract Expression getVariableAccessExpression(ReadGraph graph, + CompilationContext context, Variable contextVariable, String name) throws DatabaseException; + + protected Type getExpectedType(ReadGraph graph, CompilationContext context) throws DatabaseException { + return Types.metaVar(Kinds.STAR); + } + + protected Type getExpectedEffect(ReadGraph graph, CompilationContext context) throws DatabaseException { + return DEFAULT_EXPECTED_EFFECT; + } + + private ExpressionEvaluator prepareEvaluator(final ReadGraph graph, final CompilationContext context, Type expectedType) throws DatabaseException { + final Variable contextVariable = new Variable("context", getContextVariableType()); + LocalEnvironment localEnvironment = new AbstractLocalEnvironment() { + THashMap> precalculatedVariables = new THashMap>(); + @Override + public Expression resolve(Environment environment, String localName) { + Pair precalculatedVariable = precalculatedVariables.get(localName); + if(precalculatedVariable == null) { + try { + Expression value = getVariableAccessExpression(graph, context, contextVariable, localName); + if(value == null) + return null; + Variable variable = new Variable(localName); + precalculatedVariable = Pair.make(variable, value); + precalculatedVariables.put(localName, precalculatedVariable); + } catch (DatabaseException e) { + throw new RuntimeDatabaseException(e); + } + } + return new EVariable(precalculatedVariable.first); + } + @Override + public Expression preDecorateExpression(Expression expression) { + for(Pair precalculatedVariable : precalculatedVariables.values()) + expression = new ESimpleLet(precalculatedVariable.first, precalculatedVariable.second, expression); + return expression; + } + @Override + protected Variable[] getContextVariables() { + return new Variable[] { contextVariable }; + } + }; + + String expressionText = getExpressionText(graph); + return new ExpressionEvaluator(context.runtimeEnvironment, expressionText) + .localEnvironment(localEnvironment) + .expectedType(expectedType) + .parseAsBlock(parseAsBlock()); + } + + protected boolean parseAsBlock() { + return false; + } + + private Function1 eval(ExpressionEvaluator evaluator, ReadGraph graph) throws DatabaseException { + Object oldGraph = SCLContext.getCurrent().put("graph", graph); + try { + return (Function1)evaluator.eval(); + } catch(RuntimeDatabaseException e) { + e.printStackTrace(); + if(e.getCause() instanceof DatabaseException) + throw (DatabaseException)e.getCause(); + else + throw e; + } catch (SCLExpressionCompilationException e) { + StringBuilder b = new StringBuilder(); + b.append("Couldn't compile '"); + b.append(evaluator.getExpressionText()); + b.append("':\n"); + StringBuilder b2 = new StringBuilder(); + for(CompilationError error : e.getErrors()) { + b2.append(error.description); + b2.append('\n'); + } + System.err.println(b.toString() + b2.toString()); + throw new SCLDatabaseException(b.toString()+b2.toString(), b2.toString(), e.getErrors()); + } catch(Throwable e) { + // Should not happen! + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + SCLContext.getCurrent().put("graph", oldGraph); + } + } + + public List getExpressionEffects(final ReadGraph graph) throws DatabaseException { + CompilationContext context = getCompilationContext(graph); + Type type = Types.metaVar(Kinds.STAR); + eval(prepareEvaluator(graph, context, type), graph); + + try { + MultiFunction mfun = Types.matchFunction(type, 1); + ArrayList concreteEffects = new ArrayList(); + mfun.effect.collectConcreteEffects(concreteEffects); + return concreteEffects; + } catch(MatchException e) { + // Should not happen! + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + @Override + public ExpressionAnalysis perform(final ReadGraph graph) throws DatabaseException { + CompilationContext context = getCompilationContext(graph); + Function1 fn = eval(prepareEvaluator(graph, context, getExpectedType(graph, context)), graph); + return getAnalysis(context, fn); + } + + protected ExpressionAnalysis getAnalysis(CompilationContext context, Function1 fn) { + return new ExpressionAnalysis(fn, Collections.emptySet()); + } + + protected static Expression getProperty(Environment environment, Expression variable, String propertyName, Type type) { + return new EApply( + new EConstant(environment.getValue(FROM_DYNAMIC), type), + new EApply( + new EConstant(environment.getValue(PROPERTY_VALUE), Types.DYNAMIC), + variable, + new ELiteral(new StringConstant(propertyName)))); + } + + protected static Expression getPropertyFlexible(Environment environment, Expression variable, String propertyName, Type type) { + return makeTypeFlexible(environment, getProperty(environment, variable, propertyName, type), type); + } + + protected static Expression makeTypeFlexible(Environment environment, Expression base, Type originalType) { + if(originalType.equals(Types.DOUBLE)) + return new EApply( + new EConstant(environment.getValue(FROM_DOUBLE)), + base); + else if(originalType.equals(Types.FLOAT)) + return new EApply( + new EConstant(environment.getValue(FROM_DOUBLE)), + new EApply( + new EConstant(environment.getValue(TO_DOUBLE), Types.FLOAT), + base)); + else + return base; + } + + protected static String resolveExpectedValueType(ReadGraph graph, org.simantics.db.layer0.variable.Variable context) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + String valueType = graph.getPossibleRelatedValue(context.getPredicateResource(graph), L0.RequiresValueType, Bindings.STRING); + return valueType; + } +} diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java index d40f82d4d..21758a2e5 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java @@ -5,6 +5,7 @@ import java.util.List; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.RuntimeDatabaseException; import org.simantics.db.request.Read; @@ -226,9 +227,9 @@ implements Read> { return base; } - protected static String resolveExpectedValueType(ReadGraph graph, org.simantics.db.layer0.variable.Variable context) throws DatabaseException { + protected static String resolveExpectedValueType(ReadGraph graph, Resource predicate) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); - String valueType = graph.getPossibleRelatedValue(context.getPredicateResource(graph), L0.RequiresValueType, Bindings.STRING); - return valueType; + return graph.getPossibleRelatedValue(predicate, L0.RequiresValueType, Bindings.STRING); } + } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/CompileValueRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/CompileValueRequest.java index e1804d790..34a312003 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/CompileValueRequest.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/CompileValueRequest.java @@ -66,6 +66,23 @@ public class CompileValueRequest extends AbstractExpressionCompilationRequest compile(ReadGraph graph, Resource component, Resource literal, Resource predicate) throws DatabaseException { + SCLContext sclContext = SCLContext.getCurrent(); + Object oldGraph = sclContext.get("graph"); + try { + Function1 exp = graph.syncRequest(new CompileValueRequest(component, literal, predicate), + TransientCacheListener.>instance()); + sclContext.put("graph", graph); + return exp; + } catch (DatabaseException e) { + throw (DatabaseException)e; + } catch (Throwable t) { + throw new DatabaseException(t); + } finally { + sclContext.put("graph", oldGraph); + } + } + @Override protected String getExpressionText(ReadGraph graph) throws DatabaseException { diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/ExpressionAnalysis.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/ExpressionAnalysis.java new file mode 100644 index 000000000..e09389d1d --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/ExpressionAnalysis.java @@ -0,0 +1,29 @@ +package org.simantics.db.layer0.scl; + +import java.util.Set; + +import org.simantics.scl.runtime.function.Function1; + +public class ExpressionAnalysis { + + final private Set consumed; + final private Function1 fn; + + public ExpressionAnalysis(Function1 fn, Set consumed) { + this.fn = fn; + this.consumed = consumed; + } + + public boolean isConsumed(String name) { + return consumed.contains(name); + } + + public Set getConsumed() { + return consumed; + } + + public Function1 getFunction() { + return fn; + } + +} diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/VariableMapImpl.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/VariableMapImpl.java index 5b6aa0820..52ecbc705 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/VariableMapImpl.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/VariableMapImpl.java @@ -18,9 +18,9 @@ abstract public class VariableMapImpl implements VariableMap { public Map getVariables(ReadGraph graph, Variable context, String classification, Map map) throws DatabaseException { Map all = getVariables(graph, context, null); - if(all.isEmpty()) return all; + + for(Map.Entry entry : all.entrySet()) { if(all.isEmpty()) return all; - for(Map.Entry entry : all.entrySet()) { Set classifications = entry.getValue().getClassifications(graph); if(classifications.contains(classification)) { if(map == null) map = new HashMap(); diff --git a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java index c8560bad8..8b4df608f 100644 --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java @@ -28,11 +28,8 @@ import gnu.trove.iterator.TIntIterator; import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.map.hash.TIntObjectHashMap; -import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.procedure.TIntObjectProcedure; import gnu.trove.procedure.TIntProcedure; -import gnu.trove.procedure.TObjectIntProcedure; -import gnu.trove.procedure.TObjectProcedure; import gnu.trove.set.hash.TIntHashSet; public class CollectionSupportImpl implements CollectionSupport { @@ -117,196 +114,6 @@ public class CollectionSupportImpl implements CollectionSupport { return new IntResourceMap(session); } - static final class ObjectResourceMap implements Map { - - final private SessionImplSocket session; - final private TObjectIntHashMap backend; - - ObjectResourceMap(SessionImplSocket session) { - this.session = session; - backend = new TObjectIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, 0); - } - - ObjectResourceMap(SessionImplSocket session, int capacity) { - this.session = session; - backend = new TObjectIntHashMap(capacity, Constants.DEFAULT_LOAD_FACTOR, 0); - } - - @Override - public int size() { - return backend.size(); - } - @Override - public boolean isEmpty() { - return backend.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return backend.contains(key); - } - - @Override - public boolean containsValue(Object value) { - ResourceImpl impl = (ResourceImpl) value; - return backend.containsValue(impl.id); - } - - @Override - public Resource get(Object key) { - try { - int result = backend.get(key); - if (result == 0) - return null; - return session.getResourceByKey(result); - } catch (ResourceNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public Resource put(T key, Resource value) { - ResourceImpl impl = (ResourceImpl) value; - int i = backend.put(key, impl.id); - if (i == 0) - return null; - else - try { - return session.getResourceByKey(i); - } catch (ResourceNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public Resource remove(Object key) { - throw new UnsupportedOperationException("remove not supported, structure is immutable"); - } - - @Override - public void putAll(Map map) { - @SuppressWarnings("unchecked") - ObjectResourceMap other = (ObjectResourceMap) map; - other.backend.forEachEntry(new TObjectIntProcedure() { - - @Override - public boolean execute(T a, int b) { - backend.put(a, b); - return true; - } - }); - } - - @Override - public void clear() { - throw new UnsupportedOperationException("clear not supported, structure is immutable"); - } - - @Override - public Set keySet() { - final Set result = new HashSet(); - backend.forEach(new TObjectProcedure() { - - @Override - public boolean execute(T object) { - result.add(object); - return true; - } - }); - return result; - } - - @Override - public Collection values() { - ArrayList result = new ArrayList(); - for (int key : backend.values()) { - try { - result.add(session.getResourceByKey(key)); - } catch (ResourceNotFoundException e) { - e.printStackTrace(); - } - } - return result; - } - - @Override - public Set> entrySet() { - final HashSet> result = new HashSet>(); - backend.forEachEntry(new TObjectIntProcedure() { - - @Override - public boolean execute(final T a, final int b) { - return result.add(new Map.Entry() { - - @Override - public T getKey() { - return a; - } - - @Override - public Resource getValue() { - return new ResourceImpl(session.resourceSupport, b); - } - - @Override - public Resource setValue(Resource value) { - throw new UnsupportedOperationException("Map.Entry.setValue not supported, structure is immutable"); - } - - }); - } - }); - return result; - } - - @Override - public int hashCode() { - return backend.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) { - if (obj instanceof Map) { - // Nonoptimal fallback for comparing against generic Map - Map m = (Map) obj; - if (m.size() != size()) - return false; - try { - Iterator> i = entrySet().iterator(); - while (i.hasNext()) { - Entry e = i.next(); - T key = e.getKey(); - Resource value = e.getValue(); - if (value == null) { - if (!(m.get(key)==null && m.containsKey(key))) - return false; - } else { - if (!value.equals(m.get(key))) - return false; - } - } - return true; - } catch (ClassCastException unused) { - return false; - } catch (NullPointerException unused) { - return false; - } - } - return false; - } - ObjectResourceMap other = (ObjectResourceMap) obj; - return session == other.session && backend.equals(other.backend); - } - - } - @SuppressWarnings("unchecked") @Override public T createObjectResourceMap(Class clazz) { diff --git a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ObjectResourceMap.java b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ObjectResourceMap.java new file mode 100644 index 000000000..b5171e136 --- /dev/null +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ObjectResourceMap.java @@ -0,0 +1,218 @@ +package fi.vtt.simantics.procore.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.simantics.db.ObjectResourceIdMap; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.impl.ResourceImpl; + +import gnu.trove.impl.Constants; +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.procedure.TObjectIntProcedure; +import gnu.trove.procedure.TObjectProcedure; + +final class ObjectResourceMap implements Map, ObjectResourceIdMap { + + final private SessionImplSocket session; + final private TObjectIntHashMap backend; + + ObjectResourceMap(SessionImplSocket session) { + this.session = session; + backend = new TObjectIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, 0); + } + + ObjectResourceMap(SessionImplSocket session, int capacity) { + this.session = session; + backend = new TObjectIntHashMap(capacity, Constants.DEFAULT_LOAD_FACTOR, 0); + } + + @Override + public int size() { + return backend.size(); + } + @Override + public boolean isEmpty() { + return backend.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return backend.contains(key); + } + + @Override + public boolean containsValue(Object value) { + ResourceImpl impl = (ResourceImpl) value; + return backend.containsValue(impl.id); + } + + @Override + public Resource get(Object key) { + try { + int result = backend.get(key); + if (result == 0) + return null; + return session.getResourceByKey(result); + } catch (ResourceNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public Resource put(T key, Resource value) { + ResourceImpl impl = (ResourceImpl) value; + int i = backend.put(key, impl.id); + if (i == 0) + return null; + else + try { + return session.getResourceByKey(i); + } catch (ResourceNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public Resource remove(Object key) { + throw new UnsupportedOperationException("remove not supported, structure is immutable"); + } + + @Override + public void putAll(Map map) { + @SuppressWarnings("unchecked") + ObjectResourceMap other = (ObjectResourceMap) map; + other.backend.forEachEntry(new TObjectIntProcedure() { + + @Override + public boolean execute(T a, int b) { + backend.put(a, b); + return true; + } + }); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("clear not supported, structure is immutable"); + } + + @Override + public Set keySet() { + final Set result = new HashSet(); + backend.forEach(new TObjectProcedure() { + + @Override + public boolean execute(T object) { + result.add(object); + return true; + } + }); + return result; + } + + @Override + public Collection values() { + ArrayList result = new ArrayList(); + for (int key : backend.values()) { + try { + result.add(session.getResourceByKey(key)); + } catch (ResourceNotFoundException e) { + e.printStackTrace(); + } + } + return result; + } + + @Override + public Set> entrySet() { + final HashSet> result = new HashSet>(); + backend.forEachEntry(new TObjectIntProcedure() { + + @Override + public boolean execute(final T a, final int b) { + return result.add(new Map.Entry() { + + @Override + public T getKey() { + return a; + } + + @Override + public Resource getValue() { + return new ResourceImpl(session.resourceSupport, b); + } + + @Override + public Resource setValue(Resource value) { + throw new UnsupportedOperationException("Map.Entry.setValue not supported, structure is immutable"); + } + + }); + } + }); + return result; + } + + @Override + public int hashCode() { + return backend.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) { + if (obj instanceof Map) { + // Nonoptimal fallback for comparing against generic Map + Map m = (Map) obj; + if (m.size() != size()) + return false; + try { + Iterator> i = entrySet().iterator(); + while (i.hasNext()) { + Entry e = i.next(); + T key = e.getKey(); + Resource value = e.getValue(); + if (value == null) { + if (!(m.get(key)==null && m.containsKey(key))) + return false; + } else { + if (!value.equals(m.get(key))) + return false; + } + } + return true; + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + return false; + } + ObjectResourceMap other = (ObjectResourceMap) obj; + return session == other.session && backend.equals(other.backend); + } + + @Override + public void putId(T t, int r) { + backend.put(t, r); + } + + @Override + public int getId(T t) { + return backend.get(t); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.db/src/org/simantics/db/ConverterExternalValue.java b/bundles/org.simantics.db/src/org/simantics/db/ConverterExternalValue.java new file mode 100644 index 000000000..cf5261679 --- /dev/null +++ b/bundles/org.simantics.db/src/org/simantics/db/ConverterExternalValue.java @@ -0,0 +1,10 @@ +package org.simantics.db; + +import org.simantics.db.exception.DatabaseException; +import org.simantics.scl.runtime.function.Function1; + +public interface ConverterExternalValue extends ExternalValue { + + Function1 getFunction(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException; + +} diff --git a/bundles/org.simantics.db/src/org/simantics/db/ExternalValue.java b/bundles/org.simantics.db/src/org/simantics/db/ExternalValue.java new file mode 100644 index 000000000..51d493410 --- /dev/null +++ b/bundles/org.simantics.db/src/org/simantics/db/ExternalValue.java @@ -0,0 +1,9 @@ +package org.simantics.db; + +import org.simantics.db.exception.DatabaseException; + +public interface ExternalValue { + + public T getValue(ReadGraph graph, Resource resource) throws DatabaseException; + +} diff --git a/bundles/org.simantics.db/src/org/simantics/db/ObjectResourceIdMap.java b/bundles/org.simantics.db/src/org/simantics/db/ObjectResourceIdMap.java new file mode 100644 index 000000000..2d104e709 --- /dev/null +++ b/bundles/org.simantics.db/src/org/simantics/db/ObjectResourceIdMap.java @@ -0,0 +1,10 @@ +package org.simantics.db; + +import java.util.Map; + +public interface ObjectResourceIdMap extends Map { + + void putId(T t, int r); + int getId(T t); + +} diff --git a/bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/VariableDebugger.java b/bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/VariableDebugger.java index 9c02bbe2a..a27cd3083 100644 --- a/bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/VariableDebugger.java +++ b/bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/VariableDebugger.java @@ -560,7 +560,7 @@ public class VariableDebugger extends Composite { if(o instanceof Connection) { Connection c = (Connection)o; ArrayList result = new ArrayList(); - for(VariableConnectionPointDescriptor v : c.getConnectionPointDescriptors(graph, null)) { + for(VariableConnectionPointDescriptor v : c.getConnectionPointDescriptors(graph, base, null)) { result.add(v.getRelativeRVI(graph, base)); } return "c " + result.toString(); diff --git a/bundles/org.simantics.document.base.ontology/graph/Components.pgraph b/bundles/org.simantics.document.base.ontology/graph/Components.pgraph index 5384db0b2..df5665ea4 100644 --- a/bundles/org.simantics.document.base.ontology/graph/Components.pgraph +++ b/bundles/org.simantics.document.base.ontology/graph/Components.pgraph @@ -63,9 +63,9 @@ COMPONENTS.Component "Variable" PROPERTIES.primitiveProperties "String" + ==> "DocumentProperties" PROPERTIES.exists @defAttribute L0.Value diff --git a/bundles/org.simantics.document.server/adapters.xml b/bundles/org.simantics.document.server/adapters.xml index 7a1476025..af1b8809a 100644 --- a/bundles/org.simantics.document.server/adapters.xml +++ b/bundles/org.simantics.document.server/adapters.xml @@ -15,4 +15,9 @@ + + + + \ No newline at end of file diff --git a/bundles/org.simantics.document.server/scl/Document/All.scl b/bundles/org.simantics.document.server/scl/Document/All.scl index 4db639f5b..4e9cdeabc 100644 --- a/bundles/org.simantics.document.server/scl/Document/All.scl +++ b/bundles/org.simantics.document.server/scl/Document/All.scl @@ -2,6 +2,9 @@ import "Simantics/DB" import "Simantics/Variables" import "JavaBuiltin" as Java +importJava "org.simantics.document.server.DocumentProperties" where + data DocumentProperties + importJava "org.simantics.document.server.io.IConsole" where data IConsole addMessage :: IConsole -> String -> () @@ -139,6 +142,8 @@ importJava "org.simantics.document.server.Functions" where compileDocumentSCLValueExpression :: Variable -> String + primitiveProperties :: DocumentProperties + propertyValueCached :: Serializable a => Typeable a => Variable -> String -> a propertyValueCached var prop = propertyValueCached_ var prop binding diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentProperties.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentProperties.java new file mode 100644 index 000000000..2951b9399 --- /dev/null +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentProperties.java @@ -0,0 +1,14 @@ +package org.simantics.document.server; + +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; + +public interface DocumentProperties { + + Collection getKeys(ReadGraph graph, Variable context) throws DatabaseException; + Object getValue(ReadGraph graph, Variable context, String key) throws DatabaseException; + +} diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentServerUtils.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentServerUtils.java index 5e1f5cc30..d8294c5e0 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentServerUtils.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentServerUtils.java @@ -12,7 +12,7 @@ import java.util.TreeMap; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.db.common.request.UnaryRead; +import org.simantics.db.common.request.BinaryRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.variable.ProxyChildVariable; @@ -24,7 +24,6 @@ import org.simantics.document.server.request.NodeRequest; import org.simantics.document.server.request.NodeRequestUtils; import org.simantics.structural2.variables.Connection; import org.simantics.structural2.variables.VariableConnectionPointDescriptor; -import org.simantics.utils.datastructures.Pair; import org.simantics.utils.strings.AlphanumComparator; public class DocumentServerUtils { @@ -127,7 +126,7 @@ public class DocumentServerUtils { public static Variable getPossibleOtherConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException { - Collection descs = conn.getConnectionPointDescriptors(graph, null); + Collection descs = conn.getConnectionPointDescriptors(graph, connectionPoint.getParent(graph), null); if(descs.size() != 2) return null; for(VariableConnectionPointDescriptor desc : descs) { @@ -141,7 +140,7 @@ public class DocumentServerUtils { public static Variable getPossibleChildConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException { - Collection descs = conn.getConnectionPointDescriptors(graph, null); + Collection descs = conn.getConnectionPointDescriptors(graph, connectionPoint.getParent(graph), null); if(descs.size() != 2) return null; DocumentationResource DOC = DocumentationResource.getInstance(graph); @@ -161,7 +160,7 @@ public class DocumentServerUtils { ArrayList connectionPoints = new ArrayList(); - Collection descs = conn.getConnectionPointDescriptors(graph, null); + Collection descs = conn.getConnectionPointDescriptors(graph, connectionPoint.getParent(graph), null); for(VariableConnectionPointDescriptor desc : descs) { if(desc.isFlattenedFrom(graph, connectionPoint)) continue; @@ -174,7 +173,7 @@ public class DocumentServerUtils { public static Variable getPossibleCommandTriggerConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException { - Collection cpts = conn.getConnectionPoints(graph, null); + Collection cpts = conn.getConnectionPoints(graph, connectionPoint.getParent(graph), null); Variable result = null; @@ -192,7 +191,7 @@ public class DocumentServerUtils { public static Collection getPossibleOtherConnectionPoints(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException { - Collection cpts = conn.getConnectionPoints(graph, null); + Collection cpts = conn.getConnectionPoints(graph, connectionPoint.getParent(graph), null); if(cpts.size() < 2) return Collections.emptyList(); @@ -237,11 +236,11 @@ public class DocumentServerUtils { if (otherCp != null) { return otherCp; } else { - Variable parentCp = graph.sync(new UnaryRead(conn) { + Variable parentCp = graph.sync(new BinaryRead(connectionPoint.getParent(graph), conn) { @Override public Variable perform(ReadGraph graph) throws DatabaseException { DocumentationResource DOC = DocumentationResource.getInstance(graph); - Collection descs = parameter.getConnectionPointDescriptors(graph, null); + Collection descs = parameter2.getConnectionPointDescriptors(graph, parameter, null); for(VariableConnectionPointDescriptor desc : descs) { if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) { @@ -294,40 +293,33 @@ public class DocumentServerUtils { return variable.getProperties(graph, DOC.Document_AttributeRelation); } - public static class AttributesRequest extends VariableRead>> { + public static class AttributesRequest extends VariableRead { public AttributesRequest(Variable variable) { super(variable); } @Override - public Pair> perform(ReadGraph graph) throws DatabaseException { - ArrayList statics = new ArrayList(); - DocumentationResource DOC = DocumentationResource.getInstance(graph); - - Variable primitives = variable.getProperty(graph, DOC.Properties_primitiveProperties); - for(Variable property : primitives.getProperties(graph)) { - statics.add(property); - // NO SUPPORT FOR DYNAMICS AT THIS STAGE - } + public JSONObject perform(ReadGraph graph) throws DatabaseException { + + DocumentationResource DOC = DocumentationResource.getInstance(graph); - JSONObject staticContent = computeStatic(graph, variable, statics); + DocumentProperties properties = variable.getPropertyValue(graph, DOC.Properties_primitiveProperties); - return new Pair>(staticContent, Collections.emptyList()); + return computeStatic(graph, variable, properties); } - JSONObject computeStatic(ReadGraph graph, Variable variable, ArrayList statics) throws DatabaseException { + JSONObject computeStatic(ReadGraph graph, Variable variable, DocumentProperties statics) throws DatabaseException { JSONObject base = graph.syncRequest(new org.simantics.document.server.request.DefaultFields(variable)); JSONObject object = base.clone(); - for(Variable attrib : statics) { - String name = attrib.getName(graph); + for(String name : statics.getKeys(graph, variable)) { try { if (name.equals(NodeRequest.PROPERTY_VALUE_EXCEPTIONS)) { @SuppressWarnings("unchecked") - Map exceptions = (Map)DocumentServerUtils.getValue(graph, attrib); + Map exceptions = (Map)statics.getValue(graph, variable, name);//(Map)DocumentServerUtils.getValue(graph, attrib); List errorList = object.getJSONField(NodeRequest.ERRORS); if(errorList == null) @@ -340,8 +332,7 @@ public class DocumentServerUtils { object.addJSONField(NodeRequest.ERRORS, errorList); } else { - Object value = DocumentServerUtils.getValue(graph, attrib); - object.addJSONField(name, value); + object.addJSONField(name, statics.getValue(graph, variable, name)); } } catch (Throwable t) { List errorList = object.getJSONField(NodeRequest.ERRORS); @@ -363,8 +354,7 @@ public class DocumentServerUtils { } public static Collection getDynamicAttributes(ReadGraph graph, final DocumentationResource DOC, Variable variable) throws DatabaseException { - Pair> attribs = graph.syncRequest(new AttributesRequest(variable)); - return attribs.second; + return Collections.emptyList(); } public static Variable getPossibleDocumentRootVariable(ReadGraph graph, Variable documentPart) throws DatabaseException { diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/Functions.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/Functions.java index 66cc0047c..0e56a7dd2 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/Functions.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/Functions.java @@ -25,7 +25,7 @@ import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.primitiverequest.Adapter; import org.simantics.db.common.procedure.adapter.TransientCacheListener; -import org.simantics.db.common.request.UnaryRead; +import org.simantics.db.common.request.BinaryRead; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.request.WriteResultRequest; import org.simantics.db.common.utils.Logger; @@ -1254,11 +1254,11 @@ public class Functions { return true; } } else { - Variable parentCp = graph.sync(new UnaryRead(conn) { + Variable parentCp = graph.sync(new BinaryRead(widget, conn) { @Override public Variable perform(ReadGraph graph) throws DatabaseException { DocumentationResource DOC = DocumentationResource.getInstance(graph); - Collection descs = parameter.getConnectionPointDescriptors(graph, null); + Collection descs = parameter2.getConnectionPointDescriptors(graph, parameter, null); for(VariableConnectionPointDescriptor desc : descs) { if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) { @@ -1310,5 +1310,33 @@ public class Functions { LOGGER.debug("", e); return e.getMessage(); } + + static class StandardDocumentProperties implements DocumentProperties { + + @Override + public Collection getKeys(ReadGraph graph, Variable context) throws DatabaseException { + + DocumentationResource DOC = DocumentationResource.getInstance(graph); + StandardGraphPropertyVariable asd = new StandardGraphPropertyVariable(graph, context, DOC.Properties_primitiveProperties); + Map ps = primitiveProperties.getVariables(graph, asd, null); + return ps.keySet(); + + } + + @Override + public Object getValue(ReadGraph graph, Variable context, String key) throws DatabaseException { + + DocumentationResource DOC = DocumentationResource.getInstance(graph); + StandardGraphPropertyVariable asd = new StandardGraphPropertyVariable(graph, context, DOC.Properties_primitiveProperties); + Map ps = primitiveProperties.getVariables(graph, asd, null); + return ps.get(key).getValue(graph); + + } + + } + + public static DocumentProperties primitiveProperties() throws DatabaseException { + return new StandardDocumentProperties(); + } } \ No newline at end of file diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/SCLExternalValue.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/SCLExternalValue.java new file mode 100644 index 000000000..d72335d74 --- /dev/null +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/SCLExternalValue.java @@ -0,0 +1,29 @@ +package org.simantics.document.server; + +import org.simantics.db.ConverterExternalValue; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.document.base.ontology.DocumentationResource; +import org.simantics.document.server.request.ServerSCLValueRequest; +import org.simantics.scl.reflection.ReflectionUtils; +import org.simantics.scl.reflection.ValueNotFoundException; +import org.simantics.scl.runtime.function.Function1; + +public class SCLExternalValue implements ConverterExternalValue { + + @Override + public T getValue(ReadGraph graph, Resource resource) throws DatabaseException { + try { + return (T)ReflectionUtils.getValue(DocumentationResource.URIs.Functions_sclValue).getValue(); + } catch (ValueNotFoundException e) { + throw new DatabaseException(e); + } + } + + @Override + public Function1 getFunction(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException { + return ServerSCLValueRequest.compile(graph, s, o, p); + } + +} diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java index d9418db99..50c8827ef 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java @@ -17,60 +17,27 @@ public class NodeRequest extends VariableRead { public static final String ERRORS = "Errors"; public static final String PROPERTY_VALUE_EXCEPTIONS = "_PropertyValueExceptions"; - - public NodeRequest(Variable node) { - super(node); - } - @SuppressWarnings("unchecked") - @Override - public JSONObject perform(ReadGraph graph) throws DatabaseException { - - long s = System.nanoTime(); - - Pair> attribs = graph.syncRequest(new AttributesRequest(variable)); - - JSONObject staticContent = attribs.first; - if(attribs.second.isEmpty()) { - - if(DocumentRequest.PROFILE) { - long dura = System.nanoTime()-s; - if(dura > DocumentRequest.PROFILE_THRESHOLD_NODEREQUEST * 1e3) { - System.err.println("NodeRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); - } - } - - return staticContent; - } - - Map dynamicContent = graph.syncRequest(new NodeRequestDynamic(variable)); - if(dynamicContent.isEmpty()) { - return staticContent; - } - - JSONObject result = staticContent.clone(); - result.add(dynamicContent); + public NodeRequest(Variable node) { + super(node); + } - if(dynamicContent.containsKey(ERRORS) || staticContent.getJSONField(ERRORS) != null) { - ArrayList errorList = new ArrayList<>(); + @SuppressWarnings("unchecked") + @Override + public JSONObject perform(ReadGraph graph) throws DatabaseException { - if(dynamicContent.containsKey(ERRORS)) - errorList.addAll((List)dynamicContent.get(ERRORS)); + long s = System.nanoTime(); - if(staticContent.getJSONField(ERRORS) != null) - errorList.addAll((List)staticContent.getJSONField(ERRORS)); + JSONObject staticContent = graph.syncRequest(new AttributesRequest(variable)); - result.addJSONField(ERRORS, errorList); - } + if(DocumentRequest.PROFILE) { + long dura = System.nanoTime()-s; + if(dura > DocumentRequest.PROFILE_THRESHOLD_NODEREQUEST * 1e3) { + System.err.println("NodeRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); + } + } - if(DocumentRequest.PROFILE) { - long dura = System.nanoTime()-s; - if(dura > DocumentRequest.PROFILE_THRESHOLD_NODEREQUEST * 1e3) { - System.err.println("NodeRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); - } - } - - return result; + return staticContent; } diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLHandlerValueRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLHandlerValueRequest.java index 4a4164303..67d4d7a44 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLHandlerValueRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLHandlerValueRequest.java @@ -8,12 +8,14 @@ import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.IndexRoot; +import org.simantics.db.common.request.PossibleTypedParent; +import org.simantics.db.common.request.UnaryRead; import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext; import org.simantics.db.layer0.scl.AbstractExpressionCompilationRequest; import org.simantics.db.layer0.util.RuntimeEnvironmentRequest2; import org.simantics.db.layer0.variable.Variable; +import org.simantics.document.base.ontology.DocumentationResource; import org.simantics.document.server.request.ServerSCLHandlerValueRequest.CompilationContext; import org.simantics.layer0.Layer0; import org.simantics.scl.compiler.elaboration.expressions.EApply; @@ -37,7 +39,6 @@ import org.simantics.utils.datastructures.Pair; public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationRequest { - private final Variable context; private final Pair componentTypeAndRoot; private final Resource literal; protected String possibleExpectedValueType; @@ -52,16 +53,19 @@ public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationR } } - private ServerSCLHandlerValueRequest(Variable context, Pair componentTypeAndRoot, Resource literal, String possibleExpectedValueType) { + private ServerSCLHandlerValueRequest(Pair componentTypeAndRoot, Resource literal, String possibleExpectedValueType) { assert(literal != null); - this.context = context; this.literal = literal; this.componentTypeAndRoot = componentTypeAndRoot; this.possibleExpectedValueType = possibleExpectedValueType; } public ServerSCLHandlerValueRequest(ReadGraph graph, Variable context) throws DatabaseException { - this(context, getComponentTypeAndRoot(graph, context), context.getRepresents(graph), resolveExpectedValueType(graph, context)); + this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph), resolveExpectedValueType(graph, context.getPredicateResource(graph))); + } + + public ServerSCLHandlerValueRequest(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException { + this(getComponentTypeAndRoot(graph, s), o, resolveExpectedValueType(graph, p)); } private static Pair getComponentTypeAndRoot(ReadGraph graph, Variable property) throws DatabaseException { @@ -74,12 +78,14 @@ public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationR return Pair.make(type, root); } } - parent = parent.getParent(graph); + while(represents == null) { + parent = parent.getParent(graph); + represents = parent.getPossibleRepresents(graph); + } Resource root = graph.syncRequest(new IndexRoot(property.getRepresents(graph))); return Pair.make(parent.getType(graph), root); } - public static List getEffects(ReadGraph graph, Variable context) throws DatabaseException { try { ServerSCLHandlerValueRequest req = new ServerSCLHandlerValueRequest(graph, context); @@ -128,25 +134,18 @@ public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationR @Override protected CompilationContext getCompilationContext(ReadGraph graph) throws DatabaseException { - return graph.syncRequest(new VariableRead(context) { + return graph.syncRequest(new UnaryRead,CompilationContext>(componentTypeAndRoot) { @Override public CompilationContext perform(ReadGraph graph) throws DatabaseException { - Pair parameter = getComponentTypeAndRoot(graph, variable); RuntimeEnvironment runtimeEnvironment = graph.syncRequest(getRuntimeEnvironmentRequest(parameter.first, parameter.second)); - Map propertyMap = graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()), TransientCacheListener.>instance()); - -// Map result = new HashMap(propertyMap); -// for(DataDefinition dd : Functions.dataDefinitions(graph, variable)) { -// result.put(dd.target, null); -// } - return new CompilationContext(runtimeEnvironment, propertyMap); + } }); @@ -229,10 +228,7 @@ public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationR @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((context == null) ? 0 : context.hashCode()); - return result; + return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode(); } @Override @@ -244,27 +240,22 @@ public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationR if (getClass() != obj.getClass()) return false; ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest) obj; - if (context == null) { - if (other.context != null) - return false; - } else if (!context.equals(other.context)) - return false; - return true; + return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot); + } + + private static Pair getComponentTypeAndRoot(ReadGraph graph, Resource component) throws DatabaseException { + if(component != null) { + Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(component)); + if(type != null) { + Resource root = graph.syncRequest(new IndexRoot(type)); + return Pair.make(type, root); + } else { + Resource doc = graph.syncRequest(new PossibleTypedParent(component, DocumentationResource.getInstance(graph).Document)); + Resource root = graph.syncRequest(new IndexRoot(component)); + return Pair.make(graph.getSingleType(doc), root); + } + } + throw new IllegalStateException(); } - -// @Override -// public int hashCode() { -// return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode(); -// } -// -// @Override -// public boolean equals(Object obj) { -// if(this == obj) -// return true; -// if(obj == null || obj.getClass() != getClass()) -// return false; -// ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest)obj; -// return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot); -// } } diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequest.java index f9181d271..77cd9b4f4 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequest.java @@ -7,12 +7,14 @@ import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.IndexRoot; +import org.simantics.db.common.request.PossibleTypedParent; import org.simantics.db.common.request.UnaryRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext; import org.simantics.db.layer0.scl.AbstractExpressionCompilationRequest; import org.simantics.db.layer0.util.RuntimeEnvironmentRequest2; import org.simantics.db.layer0.variable.Variable; +import org.simantics.document.base.ontology.DocumentationResource; import org.simantics.document.server.request.ServerSCLValueRequest.CompilationContext; import org.simantics.layer0.Layer0; import org.simantics.scl.compiler.common.names.Name; @@ -64,7 +66,11 @@ public class ServerSCLValueRequest extends AbstractExpressionCompilationRequest< } public ServerSCLValueRequest(ReadGraph graph, Variable context) throws DatabaseException { - this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph), resolveExpectedValueType(graph, context)); + this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph), resolveExpectedValueType(graph, context.getPredicateResource(graph))); + } + + public ServerSCLValueRequest(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException { + this(getComponentTypeAndRoot(graph, s), o, resolveExpectedValueType(graph, p)); } private static Pair getComponentTypeAndRoot(ReadGraph graph, Variable property) throws DatabaseException { @@ -77,11 +83,29 @@ public class ServerSCLValueRequest extends AbstractExpressionCompilationRequest< return Pair.make(type, root); } } - parent = parent.getParent(graph); + while(represents == null) { + parent = parent.getParent(graph); + represents = parent.getPossibleRepresents(graph); + } Resource root = graph.syncRequest(new IndexRoot(property.getRepresents(graph))); return Pair.make(parent.getType(graph), root); } + private static Pair getComponentTypeAndRoot(ReadGraph graph, Resource component) throws DatabaseException { + if(component != null) { + Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(component)); + if(type != null) { + Resource root = graph.syncRequest(new IndexRoot(type)); + return Pair.make(type, root); + } else { + Resource doc = graph.syncRequest(new PossibleTypedParent(component, DocumentationResource.getInstance(graph).Document)); + Resource root = graph.syncRequest(new IndexRoot(component)); + return Pair.make(graph.getSingleType(doc), root); + } + } + throw new IllegalStateException(); + } + public static Object compileAndEvaluate(ReadGraph graph, Variable context) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.get("graph"); @@ -102,6 +126,10 @@ public class ServerSCLValueRequest extends AbstractExpressionCompilationRequest< return graph.syncRequest(new ServerSCLValueRequest(graph, context), TransientCacheListener.>instance()); } + public static Function1 compile(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException { + return graph.syncRequest(new ServerSCLValueRequest(graph, s, o, p), TransientCacheListener.>instance()); + } + @Override protected String getExpressionText(ReadGraph graph) throws DatabaseException { diff --git a/bundles/org.simantics.document.swt.core/src/org/simantics/document/swt/core/widget/ComboWidget.java b/bundles/org.simantics.document.swt.core/src/org/simantics/document/swt/core/widget/ComboWidget.java index e013ef025..516b9a15c 100644 --- a/bundles/org.simantics.document.swt.core/src/org/simantics/document/swt/core/widget/ComboWidget.java +++ b/bundles/org.simantics.document.swt.core/src/org/simantics/document/swt/core/widget/ComboWidget.java @@ -20,6 +20,7 @@ public class ComboWidget extends LeafWidgetManager { private ModifyListener modifyListener = null; private StringList extractAvailable(Object o) { + if(o == null) return new StringList(new String[0]); if(o instanceof StringList) return (StringList)o; if(o instanceof List) return new StringList((List)o); if(o instanceof String[]) return new StringList((String[])o); diff --git a/bundles/org.simantics.graph.db/src/org/simantics/graph/db/TransferableGraphs.java b/bundles/org.simantics.graph.db/src/org/simantics/graph/db/TransferableGraphs.java index 2b93df74d..b4a4ed3e2 100644 --- a/bundles/org.simantics.graph.db/src/org/simantics/graph/db/TransferableGraphs.java +++ b/bundles/org.simantics.graph.db/src/org/simantics/graph/db/TransferableGraphs.java @@ -49,6 +49,7 @@ import org.simantics.db.WriteGraph; import org.simantics.db.WriteOnlyGraph; import org.simantics.db.common.CommentMetadata; import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.request.WriteOnlyRequest; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.CancelTransactionException; @@ -595,6 +596,19 @@ public class TransferableGraphs { LOGGER.info("Wrote transferable graph in {} seconds.", 1e-9*(end-start)); } + public static TransferableGraph1 create(RequestProcessor processor, TransferableGraphSource source) throws DatabaseException { + + return processor.syncRequest(new UniqueRead() { + + @Override + public TransferableGraph1 perform(ReadGraph graph) throws DatabaseException { + return create(graph, source); + } + + }); + + } + public static TransferableGraph1 create(ReadGraph graph, TransferableGraphSource source) throws DatabaseException { try { diff --git a/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph b/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph index 783f4f401..8d745a354 100644 --- a/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph +++ b/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph @@ -2,6 +2,8 @@ L0 = L0.Functions : L0.Library +// The logic of functionApplication assumes that the function is actually ExternalValue +// but it is not since it would prevent it from being converted with functionApplication L0.Function -- L0.SCLValue.Environment.moduleName --> L0.String -- L0.SCLValue.Environment.namespace --> L0.String + + + + + \ No newline at end of file diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContent.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContent.java new file mode 100644 index 000000000..92808d05d --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContent.java @@ -0,0 +1,26 @@ +package org.simantics.modeling; + +import java.util.Map; + +import org.simantics.db.Resource; +import org.simantics.db.layer0.request.PropertyInfo; +import org.simantics.scl.runtime.function.Function1; + +public class ImmutableComponentPropertyContent { + + final public PropertyInfo pi; + final public Resource valueResource; + final public Object value; + final public Function1 expression; + + public Map properties; + + ImmutableComponentPropertyContent(PropertyInfo pi, Resource valueResource, Object literal, Function1 expression) { + assert(valueResource != null); + this.pi = pi; + this.valueResource = valueResource; + this.value = literal; + this.expression = expression; + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContentRequest.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContentRequest.java new file mode 100644 index 000000000..32db2bb90 --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyContentRequest.java @@ -0,0 +1,159 @@ +package org.simantics.modeling; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import org.simantics.db.ConverterExternalValue; +import org.simantics.db.ExternalValue; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.BinaryRead; +import org.simantics.db.common.request.UniqueRead; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.PropertyInfo; +import org.simantics.db.layer0.request.UnescapedPropertyMapOfResource; +import org.simantics.db.layer0.variable.ValueAccessor; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.layer0.Layer0; +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.function.FunctionImpl1; + +public class ImmutableComponentPropertyContentRequest extends BinaryRead { + + protected ImmutableComponentPropertyContentRequest(Resource subject, PropertyInfo predicate) { + super(subject, predicate); + } + + + static class ExcludedSubjects extends UniqueRead> { + + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + return new HashSet(Arrays.asList(L0.HasName, + L0.HasLabel, + L0.HasDataType, + L0.HasValueType, + L0.RequiresValueType, + L0.hasStandardResource, + L0.RequiresValueType, + L0.HasDescription, + L0.valueAccessor, + L0.domainChildren, + L0.domainProperties, + L0.classifications, + L0.Entity_methods, + L0.default_, + L0.required, + L0.readOnly, + L0.valid, + L0.validator)); + + } + + } + + + public ImmutableComponentPropertyContent getPossibleContent(ReadGraph graph) throws DatabaseException { + + Layer0 L0 = Layer0.getInstance(graph); + + Resource resource = parameter; + PropertyInfo pi = parameter2; + + Resource value = graph.getPossibleObject(resource, pi.predicate); + if(value != null) { + + if(graph.isInstanceOf(value, L0.Literal)) { + Object literal = graph.getPossibleValue(value); + if(literal != null) { + return new ImmutableComponentPropertyContent(pi, value, literal, null); + } + } else if(graph.isInstanceOf(value, L0.SCLValue)) { + + Resource converter = graph.getPossibleObject(value, L0.ConvertsToValueWith); + if(converter != null) { + + ExternalValue ev = graph.adapt(converter, ExternalValue.class); + if(ev instanceof ConverterExternalValue) { + ConverterExternalValue cev = (ConverterExternalValue)ev; + Function1 fn = cev.getFunction(graph, resource, value, pi.predicate); + return new ImmutableComponentPropertyContent(pi, value, null, fn); + } else { + System.err.println("Undefined converter " + graph.getURI(converter)); + } + + } + + } else if(graph.isInstanceOf(value, L0.Value)) { + + Resource valueAccessor = graph.getPossibleObject(value, L0.valueAccessor); + if(valueAccessor != null) { + FunctionImpl1 fn = new FunctionImpl1() { + + @Override + public Object apply(Object p0) { + try { + ReadGraph graph = (ReadGraph)SCLContext.getCurrent().get("graph"); + ValueAccessor accessor = graph.getValue2(valueAccessor, p0); + return accessor.getValue(graph, (Variable)p0); + } catch (DatabaseException e) { + throw new IllegalStateException(e); + } + } + + }; + + return new ImmutableComponentPropertyContent(pi, value, null, fn); + + } + + } + } + + return null; + + } + + private void process(ReadGraph graph, Resource subject, ImmutableComponentPropertyContent result) throws DatabaseException { + + Set exclusions = graph.syncRequest(new ExcludedSubjects()); + if(exclusions.contains(subject)) return; + + for(PropertyInfo pi : graph.syncRequest(new UnescapedPropertyMapOfResource(subject)).values()) { + + // This is somewhat awkward + if(parameter2.predicate.equals(pi.predicate)) continue; + + try { + if(pi.isHasProperty) { + ImmutableComponentPropertyContent pc = graph.syncRequest(new ImmutableComponentPropertyContentRequest(subject, pi)); + if(pc != null) { + if(result.properties == null) result.properties = new HashMap<>(); + result.properties.put(pc.pi.name, pc); + } + } + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + } + + @Override + public ImmutableComponentPropertyContent perform(ReadGraph graph) throws DatabaseException { + + ImmutableComponentPropertyContent result = getPossibleContent(graph); + if(result == null) return null; + + process(graph, result.pi.predicate, result); + process(graph, result.valueResource, result); + + return result; + + } + + +} diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyVariable.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyVariable.java new file mode 100644 index 000000000..26185363e --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentPropertyVariable.java @@ -0,0 +1,153 @@ +package org.simantics.modeling; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.simantics.Simantics; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.type.Datatype; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.Layer0Utils; +import org.simantics.db.layer0.variable.AbstractPropertyVariable; +import org.simantics.db.layer0.variable.Variable; + +class ImmutableComponentPropertyVariable extends AbstractPropertyVariable { + + final Variable parent; + final ImmutableComponentPropertyContent content; + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((content == null) ? 0 : content.hashCode()); + result = prime * result + ((parent == null) ? 0 : parent.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ImmutableComponentPropertyVariable other = (ImmutableComponentPropertyVariable) obj; + if (content == null) { + if (other.content != null) + return false; + } else if (!content.equals(other.content)) + return false; + if (parent == null) { + if (other.parent != null) + return false; + } else if (!parent.equals(other.parent)) + return false; + return true; + } + + ImmutableComponentPropertyVariable(Variable parent, ImmutableComponentPropertyContent content) { + this.parent = parent; + this.content = content; + } + + @Override + public Resource getPropertyResource(ReadGraph graph) throws DatabaseException { + return content.pi.predicate; + } + + @Override + public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException { + return content.pi.predicate; + } + + @Override + public Resource getContainerResource(ReadGraph graph) throws DatabaseException { + throw new IllegalStateException(); + } + + @Override + public Datatype getDatatype(ReadGraph graph) throws DatabaseException { + return Layer0Utils.getDatatype(graph, this); + } + + @Override + public Resource getPredicateResource(ReadGraph graph) throws DatabaseException { + return content.pi.predicate; + } + + @Override + public Variable getPredicate(ReadGraph graph) throws DatabaseException { + throw new IllegalStateException(); + } + + @Override + public T getValue(ReadGraph graph) throws DatabaseException { + if(content.value != null) return (T)content.value; + return (T)Simantics.applySCLRead(graph, content.expression, this); + } + + @Override + public T getValue(ReadGraph graph, Binding binding) throws DatabaseException { + if(content.value != null) return (T)content.value; + return (T)Simantics.applySCLRead(graph, content.expression, this); + } + + @Override + public void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException { + throw new IllegalStateException(); + } + + @Override + public String getName(ReadGraph graph) throws DatabaseException { + return content.pi.name; + } + + @Override + public Variable getParent(ReadGraph graph) throws DatabaseException { + return parent; + } + + @Override + public Set getClassifications(ReadGraph graph) throws DatabaseException { + return content.pi.classifications; + } + + @Override + protected Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException { + + if(content.properties == null) + return null; + + ImmutableComponentPropertyContent p = content.properties.get(name); + if(p != null) + return new ImmutableComponentPropertyVariable(this, p); + + return null; + + } + + @Override + public Map collectDomainProperties(ReadGraph graph, Map map) + throws DatabaseException { + + if(content.properties == null) + return map; + + if(map == null) + map = new HashMap<>(); + + for(ImmutableComponentPropertyContent p : content.properties.values()) { + map.put(p.pi.name, new ImmutableComponentPropertyVariable(this, p)); + } + + return map; + + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariable.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariable.java new file mode 100644 index 000000000..6ed927390 --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariable.java @@ -0,0 +1,122 @@ +package org.simantics.modeling; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.AbstractChildVariable; +import org.simantics.db.layer0.variable.StandardGraphChildVariable; +import org.simantics.db.layer0.variable.Variable; + +public class ImmutableComponentVariable extends AbstractChildVariable { + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((content == null) ? 0 : content.hashCode()); + result = prime * result + ((parent == null) ? 0 : parent.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ImmutableComponentVariable other = (ImmutableComponentVariable) obj; + if (content == null) { + if (other.content != null) + return false; + } else if (!content.equals(other.content)) + return false; + if (parent == null) { + if (other.parent != null) + return false; + } else if (!parent.equals(other.parent)) + return false; + return true; + } + + final private Variable parent; + final private ImmutableComponentVariableContent content; + + ImmutableComponentVariable(Variable parent, ImmutableComponentVariableContent content) { + this.parent = parent; + this.content = content; + } + + @Override + public String getName(ReadGraph graph) throws DatabaseException { + return content.name; + } + + @Override + public Variable getParent(ReadGraph graph) throws DatabaseException { + return parent; + } + + @Override + public Resource getRepresents(ReadGraph graph) throws DatabaseException { + return content.resource; + } + + @Override + public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException { + if(content.children == null) return null; + ImmutableComponentVariableContent c = content.children.get(name); + if(c == null) return null; + return new ImmutableComponentVariable(this, c); + } + + @Override + public Collection getChildren(ReadGraph graph) throws DatabaseException { + if(content.children == null) return Collections.emptyList(); + ArrayList result = new ArrayList(content.children.size()); + for(ImmutableComponentVariableContent c : content.children.values()) { + result.add(new ImmutableComponentVariable(this, c)); + } + return result; + } + + @Override + protected Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException { + + if(content.properties == null) + return null; + + ImmutableComponentPropertyContent p = content.properties.get(name); + if(p != null) + return new ImmutableComponentPropertyVariable(this, p); + + return new StandardGraphChildVariable(parent, node, content.resource).getPossibleProperty(graph, name); + + } + + @Override + public Map collectDomainProperties(ReadGraph graph, Map map) + throws DatabaseException { + + if(content.properties == null) + return map; + + if(map == null) + map = new HashMap<>(); + + for(ImmutableComponentPropertyContent p : content.properties.values()) { + map.put(p.pi.name, new ImmutableComponentPropertyVariable(this, p)); + } + + return map; + + } + +} diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableBuilder.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableBuilder.java new file mode 100644 index 000000000..37c882c64 --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableBuilder.java @@ -0,0 +1,31 @@ +package org.simantics.modeling; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.TransientCacheListener; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.StandardGraphChildVariable; +import org.simantics.db.layer0.variable.StandardGraphPropertyVariable; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.VariableBuilder; +import org.simantics.db.layer0.variable.VariableNode; + +public class ImmutableComponentVariableBuilder implements VariableBuilder { + + @Override + public Variable buildChild(ReadGraph graph, Variable parent, VariableNode node, Resource child) throws DatabaseException { + if(graph.isImmutable(child)) { + ImmutableComponentVariableContent content = graph.syncRequest(new ImmutableComponentVariableContentRequest(child), TransientCacheListener.instance()); + return new ImmutableComponentVariable(parent, content); + } else { + return new StandardGraphChildVariable(parent, node, child); + } + } + + @Override + public Variable buildProperty(ReadGraph graph, Variable parent, VariableNode node, Resource subject, Resource predicate) throws DatabaseException { + return new StandardGraphPropertyVariable(graph, parent, node, subject, predicate); + } + +} diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContent.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContent.java new file mode 100644 index 000000000..5124228a0 --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContent.java @@ -0,0 +1,19 @@ +package org.simantics.modeling; + +import java.util.Map; + +import org.simantics.db.Resource; + +public class ImmutableComponentVariableContent { + + final public Resource resource; + final public String name; + public Map children; + public Map properties; + + ImmutableComponentVariableContent(Resource resource, String name) { + this.resource = resource; + this.name = name; + } + +} diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContentRequest.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContentRequest.java new file mode 100644 index 000000000..ac08c945e --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ImmutableComponentVariableContentRequest.java @@ -0,0 +1,75 @@ +package org.simantics.modeling; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ResourceRead; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.PropertyInfo; +import org.simantics.db.layer0.request.UnescapedPropertyMapOfResource; +import org.simantics.layer0.Layer0; +import org.simantics.structural2.ConnectionImpl; +import org.simantics.structural2.Functions.StructuralChildMapOfResource; +import org.simantics.structural2.queries.ConnectionPointMapOfResource; + +public class ImmutableComponentVariableContentRequest extends ResourceRead { + + protected ImmutableComponentVariableContentRequest(Resource resource) { + super(resource); + } + + @Override + public ImmutableComponentVariableContent perform(ReadGraph graph) throws DatabaseException { + + Layer0 L0 = Layer0.getInstance(graph); + String name = graph.getRelatedValue(resource, L0.HasName, Bindings.STRING); + ImmutableComponentVariableContent result = new ImmutableComponentVariableContent(resource, name); + + Map pis = graph.syncRequest(new UnescapedPropertyMapOfResource(resource)); + + for(Map.Entry e : pis.entrySet()) { + PropertyInfo pi = e.getValue(); + if(pi.isHasProperty) { + ImmutableComponentPropertyContent pc = graph.syncRequest(new ImmutableComponentPropertyContentRequest(resource, pi)); + if(pc != null) { + if(result.properties == null) result.properties = new HashMap<>(); + result.properties.put(pc.pi.name, pc); + } + } + } + + Map cps = graph.syncRequest(new ConnectionPointMapOfResource(graph, resource)); + for(Map.Entry e : cps.entrySet()) { + PropertyInfo pi = e.getValue(); + Resource conn = graph.getPossibleObject(resource, pi.predicate); + if(conn != null) { + if(result.properties == null) result.properties = new HashMap<>(); + result.properties.put(pi.name, new ImmutableComponentPropertyContent(pi, conn, new ConnectionImpl(pi.predicate), null)); + } + } + + HashSet childSet = null; + for(Resource child : graph.syncRequest(new StructuralChildMapOfResource(resource)).values()) { + if(childSet == null) + childSet = new HashSet<>(); + childSet.add(child); + } + + if(childSet != null) { + result.children = new HashMap<>(); + for(Resource child : childSet) { + ImmutableComponentVariableContent content = graph.syncRequest(new ImmutableComponentVariableContentRequest(child)); + result.children.put(content.name, content); + } + } + + return result; + + } + + +} diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/AnalyseSCLValueRequest.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/AnalyseSCLValueRequest.java new file mode 100644 index 000000000..f1149f9c7 --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/AnalyseSCLValueRequest.java @@ -0,0 +1,42 @@ +package org.simantics.modeling.scl; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.TransientCacheListener; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.scl.ExpressionAnalysis; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.structural2.scl.AnalyseStructuralValueRequest; + +public class AnalyseSCLValueRequest extends AnalyseStructuralValueRequest { + + public AnalyseSCLValueRequest(ReadGraph graph, Resource component, Resource value, Resource predicate) + throws DatabaseException { + super(component, value, predicate); + } + + @Override + protected ExpressionAnalysis getAnalysis(AnalysisCompilationContext context, Function1 fn) { + return new ExpressionAnalysis(fn, context.getConsumed()); + } + + public static ExpressionAnalysis analyse(ReadGraph graph, Resource component, Resource predicate, Resource value) throws DatabaseException { + SCLContext sclContext = SCLContext.getCurrent(); + Object oldGraph = sclContext.get("graph"); + try { + ExpressionAnalysis result = graph.syncRequest(new AnalyseSCLValueRequest(graph, component, value, predicate), + TransientCacheListener.>instance()); + sclContext.put("graph", graph); + return result; + } catch (DatabaseException e) { + throw (DatabaseException)e; + } catch (Throwable t) { + throw new DatabaseException(t); + } finally { + sclContext.put("graph", oldGraph); + } + } + +} diff --git a/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/Synchronizer.java b/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/Synchronizer.java index 9c7428416..4847eb551 100644 --- a/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/Synchronizer.java +++ b/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/Synchronizer.java @@ -91,7 +91,7 @@ public class Synchronizer { for(Variable conn : child.getProperties(graph, StructuralResource2.URIs.SynchronizedConnectionRelation)) { String name = conn.getName(graph); org.simantics.structural2.variables.Connection vc = conn.getValue(graph); - Collection connectionPoints = vc.getConnectionPointDescriptors(graph, null); + Collection connectionPoints = vc.getConnectionPointDescriptors(graph, child, null); List cps = new ArrayList(connectionPoints.size()); for(VariableConnectionPointDescriptor desc : connectionPoints) { if(desc.isFlattenedFrom(graph, conn)) continue; diff --git a/bundles/org.simantics.structural2/scl/Simantics/Structural.scl b/bundles/org.simantics.structural2/scl/Simantics/Structural.scl index 33b0ec147..c33e7ae9d 100644 --- a/bundles/org.simantics.structural2/scl/Simantics/Structural.scl +++ b/bundles/org.simantics.structural2/scl/Simantics/Structural.scl @@ -13,4 +13,4 @@ importJava "org.simantics.structural2.variables.Connection" where data StructuralConnection importJava "org.simantics.structural2.utils.StructuralUtils" where - structuralConnectionConnectionPoints :: StructuralConnection -> Resource -> [Variable] + structuralConnectionConnectionPoints :: Variable -> StructuralConnection -> Resource -> [Variable] diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/ConnectionImpl.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/ConnectionImpl.java new file mode 100644 index 000000000..e67851f34 --- /dev/null +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/ConnectionImpl.java @@ -0,0 +1,72 @@ +package org.simantics.structural2; + +import java.util.Collection; +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.structural2.variables.Connection; +import org.simantics.structural2.variables.ConnectionBrowser; +import org.simantics.structural2.variables.VariableConnectionPointDescriptor; + +import gnu.trove.set.hash.THashSet; + +public class ConnectionImpl implements Connection { + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((predicate == null) ? 0 : predicate.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ConnectionImpl other = (ConnectionImpl) obj; + if (predicate == null) { + if (other.predicate != null) + return false; + } else if (!predicate.equals(other.predicate)) + return false; + return true; + } + + final private Resource predicate; + + public ConnectionImpl(Resource predicate) { + this.predicate = predicate; + } + + @Override + public Collection getConnectionPoints(ReadGraph graph, Variable component, Resource relationType) throws DatabaseException { + Set result = new THashSet(); + for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, component, predicate, relationType)) { + result.add(desc.getVariable(graph)); + } + return result; + } + + @Override + public Collection getConnectionPointURIs(ReadGraph graph, Variable component, Resource relationType) throws DatabaseException { + Set result = new THashSet(); + for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, component, predicate, relationType)) { + result.add(desc.getURI(graph)); + } + return result; + } + + @Override + public Collection getConnectionPointDescriptors(ReadGraph graph, Variable component, Resource relationType) throws DatabaseException { + return ConnectionBrowser.flatten(graph, component, predicate, relationType); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/Functions.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/Functions.java index d9d8857af..19c2e8c80 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/Functions.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/Functions.java @@ -67,13 +67,10 @@ import org.simantics.structural2.queries.PossibleConnectionPointInfo; import org.simantics.structural2.scl.CompileStructuralValueRequest; import org.simantics.structural2.scl.procedural.CompileProceduralComponentTypeRequest; import org.simantics.structural2.variables.Connection; -import org.simantics.structural2.variables.ConnectionBrowser; import org.simantics.structural2.variables.StandardProceduralChildVariable; -import org.simantics.structural2.variables.VariableConnectionPointDescriptor; import org.simantics.utils.datastructures.MapList; import gnu.trove.map.hash.THashMap; -import gnu.trove.set.hash.THashSet; public class Functions { @@ -153,39 +150,6 @@ public class Functions { }; - static class ConnectionImpl implements Connection { - - final private StandardGraphPropertyVariable connectionPoint; - - public ConnectionImpl(StandardGraphPropertyVariable connectionPoint) { - this.connectionPoint = connectionPoint; - } - - @Override - public Collection getConnectionPoints(ReadGraph graph, Resource relationType) throws DatabaseException { - Set result = new THashSet(); - for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, connectionPoint.parent, connectionPoint.property.predicate, relationType)) { - result.add(desc.getVariable(graph)); - } - return result; - } - - @Override - public Collection getConnectionPointURIs(ReadGraph graph, Resource relationType) throws DatabaseException { - Set result = new THashSet(); - for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, connectionPoint.parent, connectionPoint.property.predicate, relationType)) { - result.add(desc.getURI(graph)); - } - return result; - } - - @Override - public Collection getConnectionPointDescriptors(ReadGraph graph, Resource relationType) throws DatabaseException { - return ConnectionBrowser.flatten(graph, connectionPoint.parent, connectionPoint.property.predicate, relationType); - } - - } - @SCLValue(type="ValueAccessor") public static final ValueAccessor connectionValueAccessor = new ValueAccessor() { @@ -213,7 +177,7 @@ public class Functions { @Override public Object getValue(ReadGraph graph, Variable context) throws DatabaseException { StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context; - return new ConnectionImpl(variable); + return new ConnectionImpl(variable.property.predicate); } @Override @@ -233,10 +197,10 @@ public class Functions { public Variable getPossibleConnectionPointFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException { - Map connectionPoints = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.>instance()); - Resource cp = connectionPoints.get(name); + Map connectionPoints = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.>instance()); + PropertyInfo cp = connectionPoints.get(name); if(cp == null) return null; - else return new StandardGraphPropertyVariable(graph, variable, cp); + else return new StandardGraphPropertyVariable(graph, variable, cp.predicate); } @@ -244,16 +208,16 @@ public class Functions { if(graph.isImmutable(context)) { - Map cps = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.>instance()); + Map cps = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.>instance()); if(cps.size() == 0) return map; if(map == null) map = new THashMap(cps.size()); - for(Map.Entry entry : cps.entrySet()) { + for(Map.Entry entry : cps.entrySet()) { String name = entry.getKey(); - Resource cp = entry.getValue(); - if(needSynchronized && !graph.isInstanceOf(cp, STR.SynchronizedConnectionRelation)) continue; - map.put(name, new StandardGraphPropertyVariable(graph, variable, cp)); + PropertyInfo cp = entry.getValue(); + if(needSynchronized && !graph.isInstanceOf(cp.predicate, STR.SynchronizedConnectionRelation)) continue; + map.put(name, new StandardGraphPropertyVariable(graph, variable, cp.predicate)); } return map; @@ -313,7 +277,7 @@ public class Functions { }; - static class StructuralChildMapOfResource extends ResourceRead> { + public static class StructuralChildMapOfResource extends ResourceRead> { public StructuralChildMapOfResource(Resource resource) { super(resource); @@ -337,7 +301,7 @@ public class Functions { } - static class StructuralChildMapOfResourceT extends ResourceRead> { + public static class StructuralChildMapOfResourceT extends ResourceRead> { public StructuralChildMapOfResourceT(Resource resource) { super(resource); diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/queries/ConnectionPointMapOfResource.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/queries/ConnectionPointMapOfResource.java index 3b2e42ae7..d7ba2901b 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/queries/ConnectionPointMapOfResource.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/queries/ConnectionPointMapOfResource.java @@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory; import gnu.trove.map.hash.THashMap; -public class ConnectionPointMapOfResource extends TransientResourceRead> { +public class ConnectionPointMapOfResource extends TransientResourceRead> { private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionPointMapOfResource.class); @@ -41,18 +41,18 @@ public class ConnectionPointMapOfResource extends TransientResourceRead perform(ReadGraph graph, Resource resource) throws DatabaseException { + public Map perform(ReadGraph graph, Resource resource) throws DatabaseException { Collection predicates = graph.getPredicates(resource); - THashMap result = null; + THashMap result = null; for(Resource predicate : predicates) { PropertyInfo info = graph.syncRequest(new PossibleConnectionPointInfo(predicate), TransientCacheAsyncListener.instance()); if(info != null) { - if (result == null) result = new THashMap(predicates.size()); - if (result.put(info.name, predicate) != null) + if (result == null) result = new THashMap(predicates.size()); + if (result.put(info.name, info) != null) LOGGER.error("The database contains siblings with the same name " + info.name + " (resource=$" + resource.getResourceId() + ")."); } diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AbstractAnalyseStructuralValueRequest.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AbstractAnalyseStructuralValueRequest.java new file mode 100644 index 000000000..48c95cd0c --- /dev/null +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AbstractAnalyseStructuralValueRequest.java @@ -0,0 +1,154 @@ +package org.simantics.structural2.scl; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.TransientCacheListener; +import org.simantics.db.common.request.PossibleIndexRoot; +import org.simantics.db.common.request.ResourceRead2; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.scl.AbstractExpressionAnalysisRequest; +import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext; +import org.simantics.db.layer0.util.RuntimeEnvironmentRequest; +import org.simantics.db.layer0.util.RuntimeEnvironmentRequest2; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.layer0.Layer0; +import org.simantics.scl.compiler.elaboration.expressions.EApply; +import org.simantics.scl.compiler.elaboration.expressions.EConstant; +import org.simantics.scl.compiler.elaboration.expressions.EVariable; +import org.simantics.scl.compiler.elaboration.expressions.Expression; +import org.simantics.scl.compiler.elaboration.modules.SCLValue; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.environment.Environments; +import org.simantics.scl.compiler.runtime.RuntimeEnvironment; +import org.simantics.scl.compiler.top.SCLExpressionCompilationException; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.structural2.scl.AbstractAnalyseStructuralValueRequest.AnalysisCompilationContext; + +/** + * Compiles an SCL expression that is attached to a literal + * whose parent is a component that is a part of a component type. + * + * @author Antti Villberg + */ +abstract public class AbstractAnalyseStructuralValueRequest extends AbstractExpressionAnalysisRequest { + + protected final Resource relation; + + public static class AnalysisCompilationContext extends AbstractExpressionCompilationContext { + + final private Map propertyMap; + final private Set consumed = new HashSet<>(); + + public AnalysisCompilationContext(RuntimeEnvironment runtimeEnvironment, + Map propertyMap) { + super(runtimeEnvironment); + this.propertyMap = propertyMap; + } + + public ComponentTypeProperty consume(String name) { + consumed.add(name); + return propertyMap.get(name); + } + + public Set getConsumed() { + return consumed; + } + + } + + public AbstractAnalyseStructuralValueRequest(Resource relation) { + this.relation = relation; + } + + @Override + abstract protected String getExpressionText(ReadGraph graph) throws DatabaseException; + abstract protected Resource getIndexRoot(ReadGraph graph) throws DatabaseException; + abstract protected Resource getComponentType(ReadGraph graph) throws DatabaseException; + + @Override + protected Type getExpectedType(ReadGraph graph, AnalysisCompilationContext context) + throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + String valueType = graph.getPossibleRelatedValue(relation, L0.RequiresValueType, Bindings.STRING); + if(valueType != null) { + Resource relationIndexRoot = graph.syncRequest(new PossibleIndexRoot(relation)); + RuntimeEnvironment relationRuntimeEnvironment = relationIndexRoot != null ? graph.syncRequest(new RuntimeEnvironmentRequest(relationIndexRoot)) : context.runtimeEnvironment; + try { + return Environments.getType(relationRuntimeEnvironment.getEnvironment(), valueType); + } catch (SCLExpressionCompilationException e) { + e.printStackTrace(); + } + } + return super.getExpectedType(graph, context); + } + + + + @Override + protected AnalysisCompilationContext getCompilationContext(ReadGraph graph) + throws DatabaseException { + Resource indexRoot = getIndexRoot(graph); + Resource componentType = getComponentType(graph); + if(componentType == null) { + RuntimeEnvironment runtimeEnvironment = graph.syncRequest(new RuntimeEnvironmentRequest(indexRoot)); + return new AnalysisCompilationContext(runtimeEnvironment, Collections.emptyMap()); + } else { + return graph.syncRequest(new ResourceRead2(componentType, indexRoot) { + @Override + public AnalysisCompilationContext perform(ReadGraph graph) + throws DatabaseException { + RuntimeEnvironment runtimeEnvironment = graph.syncRequest(new RuntimeEnvironmentRequest2(resource, resource2)); + Map propertyMap = + graph.syncRequest(new ReadComponentTypeInterfaceRequest(resource, runtimeEnvironment.getEnvironment()), + TransientCacheListener.>instance()); + return new AnalysisCompilationContext(runtimeEnvironment, propertyMap); + } + }); + } + } + + @Override + protected Type getContextVariableType() { + return VARIABLE; + } + + protected static Expression accessInputVariable(Environment environment, + org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable) { + SCLValue variableParentFunction = environment.getValue(VARIABLE_PARENT); + return new EApply(new EConstant(variableParentFunction), + new EApply(new EConstant(variableParentFunction), + new EVariable(contextVariable))); + } + + @Override + protected Expression getVariableAccessExpression( + ReadGraph graph, + AnalysisCompilationContext context, + org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable, + String name) throws DatabaseException { + ComponentTypeProperty property = context.consume(name); + if(property != null) { + Environment environment = context.runtimeEnvironment.getEnvironment(); + return getPropertyFlexible(environment, + accessInputVariable(environment, contextVariable), + name, + property.type); + } + else if(name.equals("input")) { + Environment environment = context.runtimeEnvironment.getEnvironment(); + return accessInputVariable(environment, contextVariable); + } + else if(name.equals("self")) + return new EVariable(contextVariable); + else + return null; + } + +} diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AnalyseStructuralValueRequest.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AnalyseStructuralValueRequest.java new file mode 100644 index 000000000..8e37f8756 --- /dev/null +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/scl/AnalyseStructuralValueRequest.java @@ -0,0 +1,103 @@ +package org.simantics.structural2.scl; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.TransientCacheListener; +import org.simantics.db.common.request.IndexRoot; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.scl.ExpressionAnalysis; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.layer0.Layer0; +import org.simantics.scl.runtime.SCLContext; + +/** + * Compiles an SCL expression that is attached to a literal + * whose parent is a component that is a part of a component type. + * + * @author Hannu Niemistö + */ +public class AnalyseStructuralValueRequest extends AbstractAnalyseStructuralValueRequest { + + protected final Resource component; + protected final Resource literal; + + public AnalyseStructuralValueRequest(Resource component, Resource literal, Resource relation) { + super(relation); + this.component = component; + this.literal = literal; + } + +// public AnalyseStructuralValueRequest(ReadGraph graph, Variable context) throws DatabaseException { +// this(context.getParent(graph).getRepresents(graph), +// context.getRepresents(graph), +// context.getPredicateResource(graph)); +// } + +// public static Object compileAndEvaluate(ReadGraph graph, Variable context) throws DatabaseException { +// SCLContext sclContext = SCLContext.getCurrent(); +// Object oldGraph = sclContext.get("graph"); +// AnalyseStructuralValueRequest request = new AnalyseStructuralValueRequest(graph, context); +// try { +// ExpressionAnalysis result = graph.syncRequest(request, TransientCacheListener.>instance()); +// sclContext.put("graph", graph); +// return result; +// } catch (Throwable t) { +// throw new DatabaseException("Compiling structural value request for component=" + request.component + ", literal=" + request.literal + " and relation " + request.relation + " failed!", t); +// } finally { +// sclContext.put("graph", oldGraph); +// } +// } + + @Override + protected String getExpressionText(ReadGraph graph) + throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + return graph.getRelatedValue(literal, L0.SCLValue_expression, Bindings.STRING); + } + + @Override + protected Resource getIndexRoot(ReadGraph graph) throws DatabaseException { + return graph.syncRequest(new IndexRoot(literal)); + } + + @Override + protected Resource getComponentType(ReadGraph graph) + throws DatabaseException { + // This is possible e.g. for interface expressions inside procedurals + if(component == null) return null; + return graph.syncRequest(new FindPossibleComponentTypeRequest(component)); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((component == null) ? 0 : component.hashCode()); + result = prime * result + ((literal == null) ? 0 : literal.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AnalyseStructuralValueRequest other = (AnalyseStructuralValueRequest) obj; + if (component == null) { + if (other.component != null) + return false; + } else if (!component.equals(other.component)) + return false; + if (literal == null) { + if (other.literal != null) + return false; + } else if (!literal.equals(other.literal)) + return false; + return true; + } + +} diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java index 9a77d100f..3181dd7c4 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java @@ -265,7 +265,7 @@ public class StructuralUtils { if(property == null) return null; Connection conn = property.getPossibleValue(graph); if(conn == null) return null; - Collection cps = conn.getConnectionPoints(graph, null); + Collection cps = conn.getConnectionPoints(graph, component, null); if(cps.size() == 2) { for(Variable var : cps) { if(property.equals(var)) continue; @@ -287,8 +287,8 @@ public class StructuralUtils { ; } - public static List structuralConnectionConnectionPoints(ReadGraph graph, Connection conn, Resource relationType) throws DatabaseException { - return new ArrayList(conn.getConnectionPoints(graph, relationType)); + public static List structuralConnectionConnectionPoints(ReadGraph graph, Variable component, Connection conn, Resource relationType) throws DatabaseException { + return new ArrayList(conn.getConnectionPoints(graph, component, relationType)); } } diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/Connection.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/Connection.java index b404932e7..b729d1f77 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/Connection.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/Connection.java @@ -13,13 +13,13 @@ public interface Connection { * Return absolute URIs of the connection points. An optional (may be null) relationType may be used * to filter the returned connection points. */ - Collection getConnectionPointURIs(ReadGraph graph, Resource relationType) throws DatabaseException; + Collection getConnectionPointURIs(ReadGraph graph, Variable component, Resource relationType) throws DatabaseException; /** * Return the connection points. An optional (may be null) relationType may be used * to filter the returned connection points. */ - Collection getConnectionPoints(ReadGraph graph, Resource relationType) throws DatabaseException; + Collection getConnectionPoints(ReadGraph graph, Variable component, Resource relationType) throws DatabaseException; - Collection getConnectionPointDescriptors(ReadGraph graph, Resource relationType) throws DatabaseException; + Collection getConnectionPointDescriptors(ReadGraph graph, Variable component, Resource relationType) throws DatabaseException; } diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/StandardProceduralChildVariable.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/StandardProceduralChildVariable.java index f133adee0..62d574633 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/StandardProceduralChildVariable.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/StandardProceduralChildVariable.java @@ -75,7 +75,7 @@ public class StandardProceduralChildVariable extends AbstractChildVariable { } @Override - public Collection getConnectionPoints(ReadGraph graph, Resource relationType) throws DatabaseException { + public Collection getConnectionPoints(ReadGraph graph, Variable component_, Resource relationType) throws DatabaseException { Set result = new THashSet(); for(Pair cp : cps) { @@ -93,7 +93,7 @@ public class StandardProceduralChildVariable extends AbstractChildVariable { } @Override - public Collection getConnectionPointURIs(ReadGraph graph, Resource relationType) throws DatabaseException { + public Collection getConnectionPointURIs(ReadGraph graph, Variable component_, Resource relationType) throws DatabaseException { Set result = new THashSet(); for(Pair cp : cps) { @@ -111,7 +111,7 @@ public class StandardProceduralChildVariable extends AbstractChildVariable { } @Override - public Collection getConnectionPointDescriptors(ReadGraph graph, Resource relationType) throws DatabaseException { + public Collection getConnectionPointDescriptors(ReadGraph graph, Variable component_, Resource relationType) throws DatabaseException { Set result = new THashSet(); for(Pair cp : cps) { diff --git a/features/org.simantics.desktop.product.feature/feature.xml b/features/org.simantics.desktop.product.feature/feature.xml index 59c224643..be715fa9a 100644 --- a/features/org.simantics.desktop.product.feature/feature.xml +++ b/features/org.simantics.desktop.product.feature/feature.xml @@ -29,6 +29,10 @@ id="org.simantics.scl.rest.feature" version="0.0.0"/> + +