Skip to content

Package: AbstractCachedTree

AbstractCachedTree

nameinstructionbranchcomplexitylinemethod
AbstractCachedTree(IExcludedObjectsCallback)
M: 0 C: 17
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
clear()
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
createNodeEntry(Object, Object)
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
createNodeIfNecessary(Object, Object)
M: 0 C: 15
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getCachedValue(Object)
M: 3 C: 20
87%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 5
83%
M: 0 C: 1
100%
getNodes()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getRootValue()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
remove(EObject)
M: 31 C: 35
53%
M: 7 C: 5
42%
M: 5 C: 2
29%
M: 10 C: 9
47%
M: 0 C: 1
100%
removeOutdatedParentCacheIfNeeded(EObject)
M: 30 C: 20
40%
M: 5 C: 3
38%
M: 3 C: 2
40%
M: 7 C: 4
36%
M: 0 C: 1
100%
update(EObject, Object)
M: 4 C: 66
94%
M: 2 C: 8
80%
M: 2 C: 4
67%
M: 2 C: 16
89%
M: 0 C: 1
100%
updateNodeObject(Object)
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
updateParentNode(Object, Object, Object)
M: 0 C: 29
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2012 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Edgar Mueller - initial API and implementation
13: *
14: *******************************************************************************/
15: package org.eclipse.emf.ecp.common.spi.cachetree;
16:
17: import java.util.Collections;
18: import java.util.HashSet;
19: import java.util.Map;
20: import java.util.Set;
21: import java.util.concurrent.ConcurrentHashMap;
22:
23: import org.eclipse.emf.ecore.EObject;
24:
25: /**
26: * A cached tree resembles a tree structure where each node is associated with a specific value.
27: * The value stored by parent nodes within the tree hereby are influenced by the values stored within their children.
28: * Thus, if the value of a child changes, it needs to be propagated upwards.
29: * Analogously, if the child is deleted the value associated with the deleted child must not influence the value of
30: * the parent anymore. This class is responsible for adding and removing nodes and for correctly maintaining such
31: * parent/child relationships.
32: *
33: * @param <T> the actual value type that is stored by the tree
34: *
35: * @author emueller
36: * @author Tobias Verhoeven
37: * @since 1.5
38: */
39: public abstract class AbstractCachedTree<T> {
40:
41:         private final Map<Object, CachedTreeNode<T>> nodes;
42:         private CachedTreeNode<T> rootValue;
43:         private final IExcludedObjectsCallback excludedCallback;
44:
45:         /**
46:          * Private constructor.
47:          *
48:          * @param callback the {@link IExcludedObjectsCallback} to use when checking when to stop
49:          */
50:         public AbstractCachedTree(IExcludedObjectsCallback callback) {
51:                 nodes = new ConcurrentHashMap<Object, CachedTreeNode<T>>();
52:                 rootValue = createdCachedTreeNode(getDefaultValue());
53:                 this.excludedCallback = callback;
54:         }
55:
56:         /**
57:          * Gets the Nodes of the cached tree containing necessary information.
58:          *
59:          * @return the nodes
60:          */
61:         protected Map<Object, CachedTreeNode<T>> getNodes() {
62:                 return nodes;
63:         }
64:
65:         /**
66:          * Returns the default value for a cached node.<br/>
67:          * The root value will be initialized with this value, too
68:          *
69:          * @return the default value for a cached tree node
70:          */
71:         public abstract T getDefaultValue();
72:
73:         /**
74:          * Creates a cached tree node.
75:          *
76:          * @param value
77:          * the value stored by the cached tree node
78:          * @return the created node
79:          */
80:         protected abstract CachedTreeNode<T> createdCachedTreeNode(T value);
81:
82:         /**
83:          * Updates the cached entry for the given {@link EObject} with the given value.<br/>
84:          * If the cached entry does not yet exist, it will be created.
85:          *
86:          * @param eObject
87:          * the {@link EObject}
88:          * @param value
89:          * the value associated with the {@link EObject}
90:          * @return set of affected eobjects
91:          */
92:         public Set<EObject> update(EObject eObject, T value) {
93:
94:•                if (eObject == null) {
95:                         return Collections.emptySet();
96:                 }
97:
98:•                if (excludedCallback.isExcluded(eObject)) {
99:                         return Collections.emptySet();
100:                 }
101:
102:                 final CachedTreeNode<T> node = createNodeIfNecessary(eObject, value);
103:                 node.setOwnValue(value);
104:
105:                 updateNodeObject(eObject);
106:
107:                 rootValue.putIntoCache(eObject, node.getOwnValue());
108:
109:                 final Set<EObject> affectedElements = removeOutdatedParentCacheIfNeeded(eObject);
110:                 // propagate upwards
111:                 EObject parent = eObject.eContainer();
112:
113:•                while (parent != null && !excludedCallback.isExcluded(parent)) {// !isExcludedType(excludedTypes,
114:                         // parent.getClass())
115:                         updateParentNode(parent, eObject, nodes.get(eObject).getDisplayValue());
116:                         eObject = parent;
117:•                        if (nodes.get(eObject) == null) {
118:                                 break;
119:                         }
120:                         parent = parent.eContainer();
121:                         affectedElements.add(eObject);
122:                 }
123:                 return affectedElements;
124:         }
125:
126:         /**
127:          * Helper method which gets called when an update on the specified object is performed. Implementors can use this
128:          * method when they need to perform special behaviour one a node changes.
129:          *
130:          * @param object The upject for which an update on the tree is performed
131:          */
132:         protected void updateNodeObject(Object object) {
133:                 // TODO better way?
134:         }
135:
136:         // If an object has been moved the cached entries must be removed from old parents.
137:         private Set<EObject> removeOutdatedParentCacheIfNeeded(EObject eObject) {
138:
139:                 final Set<EObject> affectedElements = new HashSet<EObject>();
140:                 CachedTreeNode<T> node = nodes.get(eObject);
141:
142:•                if (node.getParent() != null && node.getParent() != eObject.eContainer()) {
143:                         EObject oldParent = (EObject) node.getParent();
144:•                        while (oldParent != null && !excludedCallback.isExcluded(oldParent)) {
145:                                 affectedElements.add(oldParent);
146:                                 node = nodes.get(oldParent);
147:                                 node.removeFromCache(eObject);
148:                                 oldParent = oldParent.eContainer();
149:                                 eObject = oldParent;
150:                         }
151:                 }
152:                 return affectedElements;
153:         }
154:
155:         /**
156:          * Returns the root value of this tree.<br/>
157:          * Note that the root is purely notional.
158:          *
159:          * @return the node
160:          */
161:         public T getRootValue() {
162:                 return rootValue.getDisplayValue();
163:         }
164:
165:         /**
166:          * Returns the cached value stored for the given {@link EObject}.
167:          *
168:          * @param eObject
169:          * the {@link EObject} whose cached value should be found
170:          *
171:          * @return the cached value associated with the given {@link EObject}, if found, otherwise
172:          * the default value which is returned via {@link #getDefaultValue()}
173:          */
174:         public T getCachedValue(Object eObject) {
175:•                if (eObject == null) {
176:                         return getDefaultValue();
177:                 }
178:
179:                 final CachedTreeNode<T> nodeEntry = nodes.get(eObject);
180:
181:•                if (nodeEntry != null) {
182:                         return nodes.get(eObject).getDisplayValue();
183:                 }
184:
185:                 return getDefaultValue();
186:         }
187:
188:         /**
189:          * Removes the cache entry that contains the given {@link EObject}.
190:          *
191:          * @param eObject
192:          * the {@link EObject} that needs to be removed from the cached tree
193:          */
194:         public void remove(EObject eObject) {
195:•                if (eObject == null) {
196:                         return;
197:                 }
198:
199:                 CachedTreeNode<T> node = nodes.get(eObject);
200:•                if (node == null) {
201:                         return;
202:                 }
203:                 final Object parentObject = node.getParent();
204:•                final CachedTreeNode<T> parentNode = parentObject == null ? null : nodes.get(parentObject);
205:
206:                 nodes.remove(eObject);
207:                 rootValue.removeFromCache(eObject);
208:
209:•                if (parentNode == null) {
210:                         return;
211:                 }
212:
213:                 // propagate removed value upwards
214:                 parentNode.removeFromCache(eObject);
215:                 EObject parent = eObject.eContainer();
216:
217:•                while (parent != null && !excludedCallback.isExcluded(parent)) {
218:
219:                         node = nodes.get(parent);
220:                         node.removeFromCache(eObject);
221:
222:                         parent = parent.eContainer();
223:                         eObject = parent;
224:                 }
225:         }
226:
227:         private CachedTreeNode<T> createNodeIfNecessary(Object object, T t) {
228:                 CachedTreeNode<T> node = nodes.get(object);
229:
230:•                if (node == null) {
231:                         node = createNodeEntry(object, t);
232:                 }
233:
234:                 return node;
235:         }
236:
237:         private CachedTreeNode<T> createNodeEntry(Object object, T t) {
238:                 final CachedTreeNode<T> node = createdCachedTreeNode(t);
239:                 nodes.put(object, node);
240:                 return node;
241:         }
242:
243:         /**
244:          * Updates the passed parent nodes cached value.
245:          *
246:          * @param parent the parent object to be updated
247:          * @param object the object for which the cached value should be changed.
248:          * @param value the the cached value for the object
249:          */
250:         protected void updateParentNode(Object parent, Object object, T value) {
251:                 final CachedTreeNode<T> node = nodes.get(object);
252:                 node.setParent(parent);
253:
254:                 final CachedTreeNode<T> parentNode = createNodeIfNecessary(parent, getDefaultValue());
255:                 parentNode.putIntoCache(object, value);
256:                 updateNodeObject(parent);
257:                 rootValue.putIntoCache(parent, parentNode.getDisplayValue());
258:         }
259:
260:         /**
261:          * Clears the cache.
262:          */
263:         public void clear() {
264:                 nodes.clear();
265:                 rootValue = createdCachedTreeNode(getDefaultValue());
266:         }
267: }