]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/internal/GENodeQueryManager.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.browsing.ui.common / src / org / simantics / browsing / ui / common / internal / GENodeQueryManager.java
diff --git a/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/internal/GENodeQueryManager.java b/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/internal/GENodeQueryManager.java
new file mode 100644 (file)
index 0000000..bcbe40f
--- /dev/null
@@ -0,0 +1,512 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.browsing.ui.common.internal;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Deque;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.simantics.browsing.ui.DataSource;\r
+import org.simantics.browsing.ui.NodeContext;\r
+import org.simantics.browsing.ui.NodeContext.CacheKey;\r
+import org.simantics.browsing.ui.NodeContext.PrimitiveQueryKey;\r
+import org.simantics.browsing.ui.NodeContext.QueryKey;\r
+import org.simantics.browsing.ui.NodeQueryManager;\r
+import org.simantics.browsing.ui.NodeQueryProcessor;\r
+import org.simantics.browsing.ui.PrimitiveQueryProcessor;\r
+import org.simantics.browsing.ui.PrimitiveQueryUpdater;\r
+import org.simantics.browsing.ui.common.internal.IGECache.IGECacheEntry;\r
+import org.simantics.browsing.ui.exception.NoDataSourceException;\r
+import org.simantics.browsing.ui.exception.NoQueryProcessorException;\r
+\r
+public class GENodeQueryManager implements NodeQueryManager, PrimitiveQueryUpdater {\r
+\r
+    private static final boolean DEBUG = false;\r
+\r
+    protected IGraphExplorerContext ge;\r
+    protected NodeContext parentContext;\r
+    protected CacheKey<?> parentKey;\r
+    protected UIElementReference treeReference;\r
+    protected boolean disposed = false;\r
+    List<GENodeQueryManager> children = new ArrayList<GENodeQueryManager>();\r
+\r
+    void indent() {\r
+        ge.queryIndent(1);\r
+    }\r
+\r
+    void unindent() {\r
+        ge.queryIndent(-1);\r
+    }\r
+\r
+    void queryDebug(String s) {\r
+        for (int i = 0; i < ge.queryIndent(); ++i)\r
+            System.err.append("   ");\r
+        System.err.println(s);\r
+    }\r
+\r
+    String toString(UIElementReference ref) {\r
+        return ref == null ? "" : ref.toString();\r
+    }\r
+\r
+    String toString(Set<UIElementReference> refs) {\r
+        if (refs == null || refs.isEmpty())\r
+            return "{}";\r
+        StringBuilder b = new StringBuilder();\r
+        for (UIElementReference ref : refs) {\r
+            b.append(toString(ref));\r
+        }\r
+        return b.toString();\r
+    }\r
+\r
+    String toString(NodeContext ctx, CacheKey<?> key) {\r
+        if (ctx == null)\r
+            return "null";\r
+        Set<UIElementReference> refs = ge.getCache().getTreeReference(ctx, key);\r
+        //return String.valueOf(System.identityHashCode(ctx)) + toString(ref);\r
+        //return String.valueOf(ctx.hashCode()) + ":" + String.valueOf(System.identityHashCode(ctx)) + toString(ref);\r
+        return ctx + toString(refs);\r
+    }\r
+\r
+\r
+    public GENodeQueryManager(GENodeQueryManager parent, NodeContext parentContext, CacheKey<?> parentKey, UIElementReference treeReference) {\r
+        this.ge = parent.ge;\r
+        this.parentContext = parentContext;\r
+        this.parentKey = parentKey;\r
+        this.treeReference = treeReference;\r
+        parent.children.add(this);\r
+    }\r
+    public GENodeQueryManager(IGraphExplorerContext ge, NodeContext parentContext, CacheKey<?> parentKey, UIElementReference treeReference) {\r
+        this.ge = ge;\r
+        this.parentContext = parentContext;\r
+        this.parentKey = parentKey;\r
+        this.treeReference = treeReference;\r
+    }\r
+\r
+    @Override\r
+    public Object getExplorerContext() {\r
+        return ge;\r
+    }\r
+    \r
+    public void dispose() {\r
+       if (disposed)\r
+               return;\r
+       disposed = true;\r
+       if (ge != null && parentContext != null && parentKey != null) {\r
+               ge.getCache().remove(parentContext, parentKey);\r
+       }\r
+       ge = null;\r
+       parentContext = null;\r
+       parentKey = null;\r
+       treeReference = null;\r
+       for (GENodeQueryManager m : children)\r
+               m.dispose();\r
+       children.clear();\r
+       children = null;\r
+    }\r
+\r
+//    @Override\r
+//    public String toString() {\r
+//        return "GENodeQueryManager[parentKey=" + parentKey + ", parentContext=" + "]";\r
+//    }\r
+//\r
+//    @Override\r
+//    public CacheKey getParentKey() {\r
+//        return parentKey;\r
+//    }\r
+//\r
+//    @Override\r
+//    public INodeContext getParentContext() {\r
+//        return parentContext;\r
+//    }\r
+\r
+//    static int koss = 0;\r
+    \r
+//    @Override\r
+    public <T> void replaceResult(NodeContext context, PrimitiveQueryKey<T> key, T newResult, int indent) {\r
+\r
+        IGraphExplorerContext ge = this.ge;\r
+       if (isDisposed())\r
+            return;\r
+       \r
+        if(DEBUG) {\r
+            queryDebug("replaceResult[" + ge.getCache().hashCode() + "] " + key + " -> " + newResult);\r
+            indent();\r
+        }\r
+        \r
+//        if((koss++ % 5000) == 0) {\r
+//            System.out.println("R" + koss);\r
+//        }\r
+        \r
+        IGECache cache = ge.getCache();\r
+        IGECacheEntry oldEntry = cache.getEntry(context, key);\r
+        if (oldEntry != null) {\r
+            cache.put(context, key, newResult);\r
+            propagate(context, key, oldEntry, indent);\r
+\r
+            Set<UIElementReference> refs = cache.removeTreeReference(context, key);\r
+\r
+            if (refs != null) {\r
+                //queryDebug("(replaceResult) found tree references " + toString(refs));\r
+                for (UIElementReference ref : refs)\r
+                    ge.update(ref);\r
+            }\r
+        } else {\r
+            // TODO: explain why this check is here or remove it!\r
+\r
+            // Consistency checking, no TreeReference should ever exist in this case!\r
+            Set<UIElementReference> ref = cache.getTreeReference(context, key);\r
+            assert ref == null;\r
+        }\r
+    }\r
+\r
+//    @Override\r
+    public <T> void clearResult(NodeContext context, CacheKey<T> key, int indent) {\r
+//        if (key == BuiltinKeys.FINAL_CHILDREN) {\r
+//            queryDebug("Clear final children for " + context);\r
+//        }\r
+        if(DEBUG) queryDebug("clearResult[" + ge.getCache().hashCode() + "] " + key + " " + context);\r
+\r
+        IGraphExplorerContext ge = this.ge;\r
+        if (isDisposed())\r
+            return;\r
+\r
+        IGECache cache = ge.getCache();\r
+        IGECacheEntry entry = cache.getEntry(context, key);\r
+        if (entry != null) {\r
+            cache.remove(context, key);\r
+            propagate(context, key, entry, indent);\r
+        }\r
+\r
+        Set<UIElementReference> refs = cache.removeTreeReference(context, key);\r
+        if (refs != null) {\r
+            //queryDebug("(clearResult) found tree reference " + toString(refs));\r
+            for (UIElementReference ref : refs)\r
+                ge.update(ref);\r
+        }\r
+    }\r
+\r
+    public <T> void propagate(NodeContext context, CacheKey<T> key, IGECacheEntry entry, int indent) {\r
+\r
+        if (isDisposed())\r
+            return;\r
+\r
+        if(DEBUG) queryDebug("propagate[" + ge.getCache().hashCode() + "] " + key + " - " + context);\r
+\r
+        assert entry != null;\r
+\r
+        for(IGECacheEntry dependency : entry.getDependencies()) {\r
+            clearResult(dependency.getContext(), dependency.getKey(), indent + 3);\r
+        }\r
+\r
+        entry.reset();\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public <T> T query(NodeContext context, QueryKey<T> key) throws NoQueryProcessorException {\r
+\r
+        assert(!ge.isDisposed());\r
+\r
+        if(DEBUG) {\r
+            queryDebug("Query[" + ge.getCache().hashCode() + "] " + key + " " + toString(context, key) + " - " + parentKey + " " + toString(parentContext, parentKey));\r
+            indent();\r
+        }\r
+\r
+        assert(!(context == parentContext && key == parentKey));\r
+\r
+        assert(context != null);\r
+        assert(key != null);\r
+\r
+        T result = null;\r
+        IGECache cache = ge.getCache();\r
+\r
+        synchronized(ge.getPropagateLock()) {\r
+\r
+            IGECacheEntry entry = cache.getEntry(context, key);\r
+            //queryDebug("  CACHED RESULT: " + entry);\r
+            if(entry == null) {\r
+                entry = cache.put(context, key, null);\r
+                NodeQueryProcessor<T> processor = ge.getProcessor(key);\r
+                if(processor == null) {\r
+                    throw new NoQueryProcessorException(key);\r
+                }\r
+//                queryDebug("PERFORMING QUERY...");\r
+                T value = processor.query(new GENodeQueryManager(this, context, key, null), context);\r
+//                queryDebug("RESULT: " + value);\r
+                entry.setValue(value);\r
+            }\r
+\r
+            if(treeReference != null) {\r
+                UIElementReference cachedTreeReference = treeReference;\r
+\r
+                Set<UIElementReference> oldRefs = cache.getTreeReference(context, key);\r
+                if (oldRefs != null) {\r
+                    if (cachedTreeReference.isDisposed()) {\r
+                        oldRefs.remove(cachedTreeReference);\r
+                    } else {\r
+                        cache.putTreeReference(context, key, cachedTreeReference);\r
+                    }\r
+                } else {\r
+                    cache.putTreeReference(context, key, cachedTreeReference);\r
+                }\r
+            }\r
+\r
+            if(parentContext != null) {\r
+                assert(parentKey != null);\r
+                IGECacheEntry parentEntry = cache.getEntry(parentContext, parentKey);\r
+                if(parentEntry != null)\r
+                    entry.addDependency(parentEntry);\r
+            }\r
+\r
+            result = (T) entry.getValue();\r
+        }\r
+\r
+        unindent();\r
+        return result;\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public <T> T query(NodeContext context, PrimitiveQueryKey<T> key) throws NoQueryProcessorException {\r
+\r
+        assert(!ge.isDisposed());\r
+\r
+        if(DEBUG) {\r
+            queryDebug("Primitive Query[" + ge.getCache().hashCode() + "] " + key + " " + toString(context, key) + " - " + parentKey + " " + toString(parentContext, key) + " " + Thread.currentThread().getName());\r
+            indent();\r
+        }\r
+\r
+        assert(!(context == parentContext && key == parentKey));\r
+\r
+        // Primitive queries must be leaf queries!\r
+        assert(!(parentKey instanceof PrimitiveQueryKey));\r
+\r
+        assert(context != null);\r
+        assert(key != null);\r
+\r
+        T result = null;\r
+\r
+        IGECache cache = ge.getCache();\r
+\r
+        synchronized(ge.getPropagateLock()) {\r
+            IGECacheEntry entry = cache.getEntry(context, key);\r
+            if(DEBUG) queryDebug("  CACHED PRIMITIVE RESULT[" + cache.hashCode() + "]: " + ((entry != null) ? (entry.hashCode() + "|" + System.identityHashCode(entry)) : 0));\r
+            if(entry == null) {\r
+                entry = cache.put(context, key, null);\r
+                PrimitiveQueryProcessor<T> processor = ge.getPrimitiveProcessor(key.processorIdenfitier());\r
+                if(processor == null) {\r
+                    throw new NoQueryProcessorException(key);\r
+                }\r
+//                queryDebug("PERFORMING PRIMITIVE QUERY...");\r
+                T value = processor.query(new GENodeQueryManager(this, context, key, null), context, key);\r
+//                queryDebug("PRIMITIVE RESULT: " + value);\r
+                entry.setValue(value);\r
+            }\r
+\r
+            if(treeReference != null) {\r
+                UIElementReference cachedTreeReference = treeReference;\r
+\r
+                Set<UIElementReference> oldRefs = cache.getTreeReference(context, key);\r
+                if (oldRefs != null) {\r
+                    if (cachedTreeReference.isDisposed()) {\r
+                        oldRefs.remove(cachedTreeReference);\r
+                    } else {\r
+                        cache.putTreeReference(context, key, cachedTreeReference);\r
+                    }\r
+                } else {\r
+                    cache.putTreeReference(context, key, cachedTreeReference);\r
+                }\r
+            }\r
+\r
+            if(parentContext != null) {\r
+                assert(parentKey != null);\r
+                IGECacheEntry parentEntry = cache.getEntry(parentContext, parentKey);\r
+                if(parentEntry != null) {\r
+                    entry.addDependency(parentEntry);\r
+                }\r
+            }\r
+\r
+            result = (T) entry.getValue();\r
+        }\r
+\r
+        unindent();\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public <T> DataSource<T> tryGetDataSource(Class<T> clazz) {\r
+        return ge.getDataSource(clazz);\r
+    }\r
+\r
+    @Override\r
+    public <T> DataSource<T> getDataSource(Class<T> clazz) {\r
+        DataSource<T> dsp = ge.getDataSource(clazz);\r
+        if (dsp == null)\r
+            throw new NoDataSourceException(clazz);\r
+        return dsp;\r
+    }\r
+\r
+//    @Override\r
+//    public <T> void scheduleClear(final INodeContext context, final PrimitiveQueryKey<T> key) {\r
+//        ge.scheduler.execute(new Runnable() {\r
+//            @Override\r
+//            public void run() {\r
+//                synchronized(ge.propagate) {\r
+//                    clearResult(context, key, 0);\r
+//                }\r
+//            }\r
+//        });\r
+//    }\r
+\r
+\r
+//    @Override\r
+//    public <T> void create(final INodeContext context, final PrimitiveQueryKey<T> key, final T newResult) {\r
+//        ge.cache.put(context, key, newResult);\r
+//    }\r
+\r
+    @Override\r
+    public <T> void scheduleReplace(final NodeContext context, final PrimitiveQueryKey<T> key, final T newResult) {\r
+\r
+        if(DEBUG) queryDebug("scheduleReplace[" + ge.getCache().hashCode() + "] context=" + context + " key=" + key);\r
+\r
+        IGraphExplorerContext ge = this.ge;\r
+        if (isDisposed())\r
+            return;\r
+\r
+        class PropagateRunner implements Runnable {\r
+\r
+            @Override\r
+            public void run() {\r
+                IGraphExplorerContext ge = GENodeQueryManager.this.ge;\r
+                if (isDisposed())\r
+                    return;\r
+\r
+                int delay = 0;\r
+\r
+                List<Runnable> todo = null;\r
+                \r
+                synchronized(ge.getPropagateListLock()) {\r
+\r
+                    ge.setPropagating(true);\r
+\r
+                    List<Runnable> scheduleList = ge.getScheduleList();\r
+                    Deque<Integer> activity = ge.getActivity();\r
+\r
+                    activity.addFirst(scheduleList.size());\r
+                    activity.pollLast();\r
+\r
+                    int activityInt = 0;\r
+                    for(int i : activity) {\r
+                        activityInt += i;\r
+                    }\r
+                    ge.setActivityInt(activityInt);\r
+\r
+                    if(activityInt < 100) {\r
+                        delay = 10;\r
+                        //System.out.println("Scheduling propagate after 10ms.");\r
+                    } else if (activityInt < 1000) {\r
+                        delay = 500;\r
+                        //System.out.println("Scheduling propagate after 500ms.");\r
+                    } else {\r
+                        delay = 3000;\r
+                        //System.out.println("Scheduling propagate after 3000ms.");\r
+                    }\r
+                    \r
+                    todo = ge.getScheduleList();\r
+                    ge.setScheduleList(new ArrayList<Runnable>());\r
+\r
+                }\r
+\r
+                try {\r
+                    if(delay > 0)\r
+                        Thread.sleep(delay);\r
+                } catch (InterruptedException e) {\r
+                    e.printStackTrace();\r
+                }\r
+                if (isDisposed())\r
+                       return;\r
+                \r
+                synchronized(ge.getPropagateLock()) {\r
+\r
+                    for(Runnable r : todo) r.run();\r
+\r
+                }\r
+                if (isDisposed())\r
+                       return;\r
+                \r
+                synchronized(ge.getPropagateListLock()) {\r
+\r
+                    ge.setPropagating(false);\r
+\r
+                    if(!ge.getScheduleList().isEmpty())\r
+                        ge.scheduleQueryUpdate(new PropagateRunner());\r
+\r
+                }\r
+\r
+            }\r
+\r
+        }\r
+\r
+        synchronized(ge.getPropagateListLock()) {\r
+//            System.out.println("Schedule Replace: " + key + " - " + context);\r
+//            new Exception().printStackTrace();\r
+            List<Runnable> scheduleList = ge.getScheduleList();\r
+            scheduleList.add(new Runnable() {\r
+                @Override\r
+                public void run() {\r
+                    replaceResult(context, key, newResult, 0);\r
+                }\r
+            });\r
+\r
+            if(ge.isPropagating()) return;\r
+\r
+            ge.scheduleQueryUpdate(new PropagateRunner());\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public boolean isDisposed() {\r
+        if (disposed)\r
+               return true;\r
+        if (ge.isDisposed()) {\r
+               dispose();\r
+               return true;\r
+        }\r
+        return false;\r
+    }\r
+    \r
+    @Override\r
+    public boolean isShown(NodeContext context) {\r
+        IGraphExplorerContext ge = this.ge;\r
+       if (isDisposed())\r
+               return false;\r
+       return ge.getCache().isShown(context);\r
+    }\r
+\r
+    @Override\r
+    public void incRef(NodeContext context) {\r
+        IGraphExplorerContext ge = this.ge;\r
+       if (isDisposed())\r
+               return;\r
+       ge.getCache().incRef(context);\r
+    }\r
+    \r
+    @Override\r
+    public void decRef(NodeContext context) {\r
+        IGraphExplorerContext ge = this.ge;\r
+       if (isDisposed())\r
+               return;\r
+       ge.getCache().decRef(context);\r
+    }\r
+    \r
+}\r