]> gerrit.simantics Code Review - simantics/platform.git/blob
03bceb6e639cab5c8da44c704b5612f0b7d83a7b
[simantics/platform.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.browsing.ui.common;\r
13 \r
14 import java.util.ArrayDeque;\r
15 import java.util.ArrayList;\r
16 import java.util.Collection;\r
17 import java.util.Collections;\r
18 import java.util.Deque;\r
19 import java.util.HashMap;\r
20 import java.util.HashSet;\r
21 import java.util.Map;\r
22 import java.util.Set;\r
23 \r
24 /**\r
25  * The default implementation of <code>EvaluatorData</code>.\r
26  * \r
27  * <p>\r
28  * <code>Evaluator</code>s can be added by invoking\r
29  * {@link #addEvaluator(Class, org.simantics.browsing.ui.common.EvaluatorData.Evaluator)\r
30  * or {@link #addEvaluators(Class, Collection)}. The specified\r
31  * <code>Evaluator</code> or collection of <code>Evaluator</code>s are bound to\r
32  * the specified Java class. The reason for such a binding is that the\r
33  * implementation of {@link #get(Object)} is based on comparing the input object\r
34  * class to the classes specified to the <code>addEvaluator</code> methods. The\r
35  * comparison works so that an <code>Evaluator</code> will be added to the\r
36  * result of {@link #get(Object)} if:\r
37  * </p>\r
38  * <ul>\r
39  * <li>the input object is assignable to the <code>Evaluator</code>'s class\r
40  * </ul>\r
41  * \r
42  * <p>\r
43  * This implementation keeps a <code>Class</code>&#8594;<code>Evaluator</code>\r
44  * cache of previous results thus quickly producing results for a given input\r
45  * object class after the result has been cached. Note that there is no way to\r
46  * reset the cache, i.e. this class is intended to be initialized once, used\r
47  * after that and finally thrown away. Do not add evaluators once in use, they\r
48  * may or may not be reflected in the results.\r
49  * </p>\r
50  * \r
51  * @author Tuukka Lehtonen\r
52  */\r
53 public class EvaluatorDataImpl implements EvaluatorData {\r
54 \r
55     private static final boolean DEBUG = false;\r
56 \r
57     /**\r
58      * Contains only the original evaluator associations made directly by the\r
59      * client. This is used for initializing the <code>evaluators</code> cache\r
60      * for different inputs.\r
61      */\r
62     protected HashMap<Class<?>, Collection<Evaluator>> originals = new HashMap<Class<?>, Collection<Evaluator>>();\r
63 \r
64     /**\r
65      * A cache that is only modified by\r
66      * {@link #findAndCacheEvaluatorsForClass(Class)}. This map is not filled in\r
67      * by client's initialization efforts.\r
68      */\r
69     protected HashMap<Class<?>, Collection<Evaluator>> evaluators = new HashMap<Class<?>, Collection<Evaluator>>();\r
70 \r
71     private Object browseContext;\r
72     \r
73     public EvaluatorDataImpl() {\r
74     }\r
75     \r
76     public void setBrowseContext(Object browseContext) {\r
77         this.browseContext = browseContext;\r
78     }\r
79     \r
80     @Override\r
81     public Evaluator newEvaluator() {\r
82         return new EvaluatorImpl();\r
83     }\r
84 \r
85     private synchronized void addEvaluator(HashMap<Class<?>, Collection<Evaluator>> map, Class<?> clazz, Evaluator eval) {\r
86         Collection<Evaluator> es = map.get(clazz);\r
87         if (es == null) {\r
88             es = new ArrayList<Evaluator>();\r
89             map.put(clazz, es);\r
90         }\r
91         es.add(eval);\r
92         if (DEBUG) {\r
93 //          new Exception().printStackTrace();\r
94             System.out.println("EvaluatorDataImpl: ADDED Evaluator: " + clazz + ": " + eval);\r
95         }\r
96     }\r
97 \r
98     private synchronized void addEvaluators(HashMap<Class<?>, Collection<Evaluator>> map, Class<?> clazz, Collection<Evaluator> evals) {\r
99         Collection<Evaluator> es = map.get(clazz);\r
100         if (es == null) {\r
101             es = new ArrayList<Evaluator>();\r
102             map.put(clazz, es);\r
103         }\r
104         es.addAll(evals);\r
105         if (DEBUG)\r
106             System.out.println("EvaluatorDataImpl: ADDED Evaluators: " + clazz + ": " + evals);\r
107     }\r
108 \r
109     public synchronized void addEvaluator(Class<?> clazz, Evaluator eval) {\r
110         addEvaluator(originals, clazz, eval);\r
111     }\r
112 \r
113     public synchronized void addEvaluators(Class<?> clazz, Collection<Evaluator> evals) {\r
114         addEvaluators(originals, clazz, evals);\r
115     }\r
116 \r
117     @Override\r
118     public Collection<Evaluator> get(Object object) {\r
119         Class<?> clazz = object.getClass();\r
120         Collection<Evaluator> evaluator = evaluators.get(clazz);\r
121         if (evaluator != null) {\r
122             if (DEBUG)\r
123                 System.out.println("EvaluatorDataImpl: get cached: " + clazz + ": " + evaluator);\r
124             return evaluator;\r
125         }\r
126 \r
127         Collection<Evaluator> evals = findAndCacheEvaluatorsForClass(clazz);\r
128         if (DEBUG) {\r
129             System.out.println("EvaluatorDataImpl: get: " + clazz + ": " + evals);\r
130             if (evals.isEmpty()) {\r
131                 System.out.println("EvaluatorDataImpl: no match, evaluators available:");\r
132                 for (Map.Entry<Class<?>, Collection<Evaluator>> e : evaluators.entrySet()) {\r
133                     if (!e.getValue().isEmpty())\r
134                         System.out.println("    " + e.getKey() + " : " + e.getValue());\r
135                 }\r
136             }\r
137         }\r
138         return evals;\r
139     }\r
140 \r
141     private synchronized Collection<Evaluator> findAndCacheEvaluatorsForClass(Class<?> clazz) {\r
142         if (DEBUG)\r
143             System.out.println("EvaluatorDataImpl: caching evaluators for " + clazz);\r
144         Set<Class<?>> usedClasses = new HashSet<Class<?>>();\r
145         Set<Evaluator> used = new HashSet<Evaluator>();\r
146         Collection<Evaluator> result = new ArrayList<Evaluator>();\r
147         Deque<Class<?>> fifo = new ArrayDeque<Class<?>>();\r
148         fifo.add(clazz);\r
149         while (!fifo.isEmpty()) {\r
150             Class<?> c = fifo.removeFirst();\r
151             if (!usedClasses.add(c))\r
152                 continue;\r
153             Class<?> superClass = c.getSuperclass();\r
154             if (superClass != null)\r
155                 fifo.addLast(superClass);\r
156             for (Class<?> i : c.getInterfaces())\r
157                 fifo.addLast(i);\r
158             Collection<Evaluator> evals = originals.get(c);\r
159             if (evals != null)\r
160                 for (Evaluator eval : evals)\r
161                     if (used.add(eval))\r
162                         result.add(eval);\r
163         }\r
164         if (result.isEmpty()) {\r
165             result = Collections.emptyList();\r
166         }\r
167         evaluators.put(clazz, result);\r
168         return result;\r
169     }\r
170 \r
171     @Override\r
172     public Collection<EvaluatorEntry> enumEvaluators() {\r
173         Collection<EvaluatorEntry> result = new ArrayList<EvaluatorEntry>();\r
174         for (Map.Entry<Class<?>, Collection<Evaluator>> entry : originals.entrySet()) {\r
175             result.add(new EvaluatorEntryImpl(entry.getKey(), entry.getValue()));\r
176         }\r
177         return result;\r
178     }\r
179 \r
180     static class EvaluatorEntryImpl implements EvaluatorEntry {\r
181         private final Class<?>              clazz;\r
182         private final Collection<Evaluator> evaluators;\r
183 \r
184         public EvaluatorEntryImpl(Class<?> clazz, Collection<Evaluator> evaluators) {\r
185             this.clazz = clazz;\r
186             this.evaluators = evaluators;\r
187         }\r
188 \r
189         @Override\r
190         public Class<?> getClazz() {\r
191             return clazz;\r
192         }\r
193 \r
194         @Override\r
195         public Collection<Evaluator> getEvaluators() {\r
196             return evaluators;\r
197         }\r
198 \r
199         @Override\r
200         public String toString() {\r
201             return "class " + clazz.getSimpleName();\r
202         }\r
203     }\r
204 \r
205     @Override\r
206     public <T> T getBrowseContext() {\r
207         return (T)browseContext;\r
208     }\r
209     \r
210 }\r