]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/EvaluatorDataImpl.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.browsing.ui.common / src / org / simantics / browsing / ui / common / EvaluatorDataImpl.java
diff --git a/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/EvaluatorDataImpl.java b/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/EvaluatorDataImpl.java
new file mode 100644 (file)
index 0000000..03bceb6
--- /dev/null
@@ -0,0 +1,210 @@
+/*******************************************************************************\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;\r
+\r
+import java.util.ArrayDeque;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Deque;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+/**\r
+ * The default implementation of <code>EvaluatorData</code>.\r
+ * \r
+ * <p>\r
+ * <code>Evaluator</code>s can be added by invoking\r
+ * {@link #addEvaluator(Class, org.simantics.browsing.ui.common.EvaluatorData.Evaluator)\r
+ * or {@link #addEvaluators(Class, Collection)}. The specified\r
+ * <code>Evaluator</code> or collection of <code>Evaluator</code>s are bound to\r
+ * the specified Java class. The reason for such a binding is that the\r
+ * implementation of {@link #get(Object)} is based on comparing the input object\r
+ * class to the classes specified to the <code>addEvaluator</code> methods. The\r
+ * comparison works so that an <code>Evaluator</code> will be added to the\r
+ * result of {@link #get(Object)} if:\r
+ * </p>\r
+ * <ul>\r
+ * <li>the input object is assignable to the <code>Evaluator</code>'s class\r
+ * </ul>\r
+ * \r
+ * <p>\r
+ * This implementation keeps a <code>Class</code>&#8594;<code>Evaluator</code>\r
+ * cache of previous results thus quickly producing results for a given input\r
+ * object class after the result has been cached. Note that there is no way to\r
+ * reset the cache, i.e. this class is intended to be initialized once, used\r
+ * after that and finally thrown away. Do not add evaluators once in use, they\r
+ * may or may not be reflected in the results.\r
+ * </p>\r
+ * \r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class EvaluatorDataImpl implements EvaluatorData {\r
+\r
+    private static final boolean DEBUG = false;\r
+\r
+    /**\r
+     * Contains only the original evaluator associations made directly by the\r
+     * client. This is used for initializing the <code>evaluators</code> cache\r
+     * for different inputs.\r
+     */\r
+    protected HashMap<Class<?>, Collection<Evaluator>> originals = new HashMap<Class<?>, Collection<Evaluator>>();\r
+\r
+    /**\r
+     * A cache that is only modified by\r
+     * {@link #findAndCacheEvaluatorsForClass(Class)}. This map is not filled in\r
+     * by client's initialization efforts.\r
+     */\r
+    protected HashMap<Class<?>, Collection<Evaluator>> evaluators = new HashMap<Class<?>, Collection<Evaluator>>();\r
+\r
+    private Object browseContext;\r
+    \r
+    public EvaluatorDataImpl() {\r
+    }\r
+    \r
+    public void setBrowseContext(Object browseContext) {\r
+       this.browseContext = browseContext;\r
+    }\r
+    \r
+    @Override\r
+    public Evaluator newEvaluator() {\r
+        return new EvaluatorImpl();\r
+    }\r
+\r
+    private synchronized void addEvaluator(HashMap<Class<?>, Collection<Evaluator>> map, Class<?> clazz, Evaluator eval) {\r
+        Collection<Evaluator> es = map.get(clazz);\r
+        if (es == null) {\r
+            es = new ArrayList<Evaluator>();\r
+            map.put(clazz, es);\r
+        }\r
+        es.add(eval);\r
+        if (DEBUG) {\r
+//          new Exception().printStackTrace();\r
+            System.out.println("EvaluatorDataImpl: ADDED Evaluator: " + clazz + ": " + eval);\r
+        }\r
+    }\r
+\r
+    private synchronized void addEvaluators(HashMap<Class<?>, Collection<Evaluator>> map, Class<?> clazz, Collection<Evaluator> evals) {\r
+        Collection<Evaluator> es = map.get(clazz);\r
+        if (es == null) {\r
+            es = new ArrayList<Evaluator>();\r
+            map.put(clazz, es);\r
+        }\r
+        es.addAll(evals);\r
+        if (DEBUG)\r
+            System.out.println("EvaluatorDataImpl: ADDED Evaluators: " + clazz + ": " + evals);\r
+    }\r
+\r
+    public synchronized void addEvaluator(Class<?> clazz, Evaluator eval) {\r
+        addEvaluator(originals, clazz, eval);\r
+    }\r
+\r
+    public synchronized void addEvaluators(Class<?> clazz, Collection<Evaluator> evals) {\r
+        addEvaluators(originals, clazz, evals);\r
+    }\r
+\r
+    @Override\r
+    public Collection<Evaluator> get(Object object) {\r
+        Class<?> clazz = object.getClass();\r
+        Collection<Evaluator> evaluator = evaluators.get(clazz);\r
+        if (evaluator != null) {\r
+            if (DEBUG)\r
+                System.out.println("EvaluatorDataImpl: get cached: " + clazz + ": " + evaluator);\r
+            return evaluator;\r
+        }\r
+\r
+        Collection<Evaluator> evals = findAndCacheEvaluatorsForClass(clazz);\r
+        if (DEBUG) {\r
+            System.out.println("EvaluatorDataImpl: get: " + clazz + ": " + evals);\r
+            if (evals.isEmpty()) {\r
+                System.out.println("EvaluatorDataImpl: no match, evaluators available:");\r
+                for (Map.Entry<Class<?>, Collection<Evaluator>> e : evaluators.entrySet()) {\r
+                    if (!e.getValue().isEmpty())\r
+                        System.out.println("    " + e.getKey() + " : " + e.getValue());\r
+                }\r
+            }\r
+        }\r
+        return evals;\r
+    }\r
+\r
+    private synchronized Collection<Evaluator> findAndCacheEvaluatorsForClass(Class<?> clazz) {\r
+        if (DEBUG)\r
+            System.out.println("EvaluatorDataImpl: caching evaluators for " + clazz);\r
+        Set<Class<?>> usedClasses = new HashSet<Class<?>>();\r
+        Set<Evaluator> used = new HashSet<Evaluator>();\r
+        Collection<Evaluator> result = new ArrayList<Evaluator>();\r
+        Deque<Class<?>> fifo = new ArrayDeque<Class<?>>();\r
+        fifo.add(clazz);\r
+        while (!fifo.isEmpty()) {\r
+            Class<?> c = fifo.removeFirst();\r
+            if (!usedClasses.add(c))\r
+                continue;\r
+            Class<?> superClass = c.getSuperclass();\r
+            if (superClass != null)\r
+                fifo.addLast(superClass);\r
+            for (Class<?> i : c.getInterfaces())\r
+                fifo.addLast(i);\r
+            Collection<Evaluator> evals = originals.get(c);\r
+            if (evals != null)\r
+                for (Evaluator eval : evals)\r
+                    if (used.add(eval))\r
+                        result.add(eval);\r
+        }\r
+        if (result.isEmpty()) {\r
+            result = Collections.emptyList();\r
+        }\r
+        evaluators.put(clazz, result);\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public Collection<EvaluatorEntry> enumEvaluators() {\r
+        Collection<EvaluatorEntry> result = new ArrayList<EvaluatorEntry>();\r
+        for (Map.Entry<Class<?>, Collection<Evaluator>> entry : originals.entrySet()) {\r
+            result.add(new EvaluatorEntryImpl(entry.getKey(), entry.getValue()));\r
+        }\r
+        return result;\r
+    }\r
+\r
+    static class EvaluatorEntryImpl implements EvaluatorEntry {\r
+        private final Class<?>              clazz;\r
+        private final Collection<Evaluator> evaluators;\r
+\r
+        public EvaluatorEntryImpl(Class<?> clazz, Collection<Evaluator> evaluators) {\r
+            this.clazz = clazz;\r
+            this.evaluators = evaluators;\r
+        }\r
+\r
+        @Override\r
+        public Class<?> getClazz() {\r
+            return clazz;\r
+        }\r
+\r
+        @Override\r
+        public Collection<Evaluator> getEvaluators() {\r
+            return evaluators;\r
+        }\r
+\r
+        @Override\r
+        public String toString() {\r
+            return "class " + clazz.getSimpleName();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public <T> T getBrowseContext() {\r
+       return (T)browseContext;\r
+    }\r
+    \r
+}\r