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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.browsing.ui.common;
\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
25 * The default implementation of <code>EvaluatorData</code>.
\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
39 * <li>the input object is assignable to the <code>Evaluator</code>'s class
\r
43 * This implementation keeps a <code>Class</code>→<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
51 * @author Tuukka Lehtonen
\r
53 public class EvaluatorDataImpl implements EvaluatorData {
\r
55 private static final boolean DEBUG = false;
\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
62 protected HashMap<Class<?>, Collection<Evaluator>> originals = new HashMap<Class<?>, Collection<Evaluator>>();
\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
69 protected HashMap<Class<?>, Collection<Evaluator>> evaluators = new HashMap<Class<?>, Collection<Evaluator>>();
\r
71 private Object browseContext;
\r
73 public EvaluatorDataImpl() {
\r
76 public void setBrowseContext(Object browseContext) {
\r
77 this.browseContext = browseContext;
\r
81 public Evaluator newEvaluator() {
\r
82 return new EvaluatorImpl();
\r
85 private synchronized void addEvaluator(HashMap<Class<?>, Collection<Evaluator>> map, Class<?> clazz, Evaluator eval) {
\r
86 Collection<Evaluator> es = map.get(clazz);
\r
88 es = new ArrayList<Evaluator>();
\r
93 // new Exception().printStackTrace();
\r
94 System.out.println("EvaluatorDataImpl: ADDED Evaluator: " + clazz + ": " + eval);
\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
101 es = new ArrayList<Evaluator>();
\r
102 map.put(clazz, es);
\r
106 System.out.println("EvaluatorDataImpl: ADDED Evaluators: " + clazz + ": " + evals);
\r
109 public synchronized void addEvaluator(Class<?> clazz, Evaluator eval) {
\r
110 addEvaluator(originals, clazz, eval);
\r
113 public synchronized void addEvaluators(Class<?> clazz, Collection<Evaluator> evals) {
\r
114 addEvaluators(originals, clazz, evals);
\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
123 System.out.println("EvaluatorDataImpl: get cached: " + clazz + ": " + evaluator);
\r
127 Collection<Evaluator> evals = findAndCacheEvaluatorsForClass(clazz);
\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
141 private synchronized Collection<Evaluator> findAndCacheEvaluatorsForClass(Class<?> clazz) {
\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
149 while (!fifo.isEmpty()) {
\r
150 Class<?> c = fifo.removeFirst();
\r
151 if (!usedClasses.add(c))
\r
153 Class<?> superClass = c.getSuperclass();
\r
154 if (superClass != null)
\r
155 fifo.addLast(superClass);
\r
156 for (Class<?> i : c.getInterfaces())
\r
158 Collection<Evaluator> evals = originals.get(c);
\r
160 for (Evaluator eval : evals)
\r
161 if (used.add(eval))
\r
164 if (result.isEmpty()) {
\r
165 result = Collections.emptyList();
\r
167 evaluators.put(clazz, result);
\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
180 static class EvaluatorEntryImpl implements EvaluatorEntry {
\r
181 private final Class<?> clazz;
\r
182 private final Collection<Evaluator> evaluators;
\r
184 public EvaluatorEntryImpl(Class<?> clazz, Collection<Evaluator> evaluators) {
\r
185 this.clazz = clazz;
\r
186 this.evaluators = evaluators;
\r
190 public Class<?> getClazz() {
\r
195 public Collection<Evaluator> getEvaluators() {
\r
200 public String toString() {
\r
201 return "class " + clazz.getSimpleName();
\r
206 public <T> T getBrowseContext() {
\r
207 return (T)browseContext;
\r