1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.connector.store.jpa.util;
25
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.ListIterator;
34 import java.util.Map;
35 import java.util.Set;
36 import net.jcip.annotations.NotThreadSafe;
37 import org.modeshape.common.util.StringUtil;
38 import org.modeshape.graph.Location;
39 import org.modeshape.graph.property.Name;
40 import org.modeshape.graph.property.NamespaceRegistry;
41 import org.modeshape.graph.property.Path;
42 import org.modeshape.graph.property.PathFactory;
43
44
45
46
47 @NotThreadSafe
48 public class RequestProcessorCache {
49
50 private final Map<Long, WorkspaceCache> workspaceCaches = new HashMap<Long, WorkspaceCache>();
51 protected final PathFactory pathFactory;
52
53 public RequestProcessorCache( PathFactory pathFactory ) {
54 assert pathFactory != null;
55 this.pathFactory = pathFactory;
56 }
57
58 public Location getLocationFor( Long workspaceId,
59 Path node ) {
60 WorkspaceCache cache = workspaceCaches.get(workspaceId);
61 return cache != null ? cache.getLocationFor(node) : null;
62 }
63
64 public void addNewNode( Long workspaceId,
65 Location location ) {
66 WorkspaceCache cache = workspaceCaches.get(workspaceId);
67 if (cache == null) {
68 cache = new WorkspaceCache(workspaceId);
69 workspaceCaches.put(workspaceId, cache);
70 }
71 cache.addNewNode(location);
72 }
73
74 public void clear( Long workspaceId ) {
75 workspaceCaches.remove(workspaceId);
76 }
77
78 public LinkedList<Location> getAllChildren( Long workspaceId,
79 Path parent ) {
80 WorkspaceCache cache = workspaceCaches.get(workspaceId);
81 return cache != null ? cache.getAllChildren(parent) : null;
82 }
83
84 public void setAllChildren( Long workspaceId,
85 Path parent,
86 LinkedList<Location> children ) {
87 WorkspaceCache cache = workspaceCaches.get(workspaceId);
88 if (children == null) {
89
90 if (cache != null) cache.setAllChildren(parent, null);
91 } else {
92 if (cache == null) {
93 cache = new WorkspaceCache(workspaceId);
94 workspaceCaches.put(workspaceId, cache);
95 }
96 cache.setAllChildren(parent, children);
97 }
98 }
99
100 public boolean moveNode( Long workspaceId,
101 Location oldLocation,
102 int oldIndexInParent,
103 Location newLocation ) {
104 WorkspaceCache cache = workspaceCaches.get(workspaceId);
105 if (cache == null) {
106
107 return false;
108 }
109
110 return cache.moveNode(oldLocation, oldIndexInParent, newLocation);
111 }
112
113 public boolean removeBranch( Long workspaceId,
114 Iterable<Location> locations ) {
115 WorkspaceCache cache = workspaceCaches.get(workspaceId);
116 return cache != null ? cache.removeBranch(locations) : false;
117 }
118
119 public String getString( NamespaceRegistry namespaces ) {
120 StringBuilder sb = new StringBuilder();
121 for (WorkspaceCache cache : workspaceCaches.values()) {
122 sb.append(cache.getString(namespaces));
123 }
124 return sb.toString();
125 }
126
127
128
129
130
131
132 @Override
133 public String toString() {
134 return getString(null);
135 }
136
137 public class WorkspaceCache {
138 private final Long workspaceId;
139 private final Map<Path, Location> locationByPath = new HashMap<Path, Location>();
140 private final Map<Path, LinkedList<Location>> childrenByParentPath = new HashMap<Path, LinkedList<Location>>();
141
142 WorkspaceCache( Long workspaceId ) {
143 this.workspaceId = workspaceId;
144 }
145
146 public Location getLocationFor( Path node ) {
147 return locationByPath.get(node);
148 }
149
150 public void addNewNode( Location location ) {
151 assert location != null;
152 Path path = location.getPath();
153 assert path != null;
154 locationByPath.put(path, location);
155 }
156
157 public LinkedList<Location> getAllChildren( Path parent ) {
158 return childrenByParentPath.get(parent);
159 }
160
161 public void setAllChildren( Path parent,
162 LinkedList<Location> children ) {
163 if (children == null) {
164 childrenByParentPath.remove(parent);
165 } else {
166 childrenByParentPath.put(parent, children);
167 }
168 }
169
170 public boolean moveNode( Location oldLocation,
171 int oldIndexInParent,
172 Location newLocation ) {
173 assert oldLocation != null;
174 Path oldPath = oldLocation.getPath();
175 assert oldPath != null;
176
177
178
179 removeNodesBelow(oldPath, true);
180
181
182 LinkedList<Location> siblings = childrenByParentPath.get(oldPath.getParent());
183 boolean removed = false;
184 if (siblings != null) {
185 removed = removeChildFromParentListOfChildren(siblings, oldLocation, -1);
186 }
187
188 if (newLocation != null) {
189
190 Path newPath = newLocation.getPath();
191 assert newPath != null;
192 LinkedList<Location> newSiblings = childrenByParentPath.get(newPath.getParent());
193 if (newSiblings != null) {
194 newSiblings.add(newLocation);
195 }
196 }
197
198 return removed;
199 }
200
201 protected void removeNodesBelow( Path path,
202 boolean removeNodeAtSuppliedPath ) {
203 if (removeNodeAtSuppliedPath) {
204 locationByPath.remove(path);
205 childrenByParentPath.remove(path);
206 }
207 for (Iterator<Path> iter = locationByPath.keySet().iterator(); iter.hasNext();) {
208 Path nextPath = iter.next();
209 if (nextPath.isDecendantOf(path)) iter.remove();
210 }
211 for (Iterator<Path> iter = childrenByParentPath.keySet().iterator(); iter.hasNext();) {
212 Path nextPath = iter.next();
213 if (nextPath.isDecendantOf(path)) iter.remove();
214 }
215 }
216
217 public boolean removeBranch( Iterable<Location> locations ) {
218 if (locations == null) return false;
219 Iterator<Location> iter = locations.iterator();
220 if (!iter.hasNext()) return false;
221
222 Location topNode = iter.next();
223
224
225 boolean removed = false;
226 while (iter.hasNext()) {
227 Location location = iter.next();
228 Path path = location.getPath();
229 assert path != null;
230 if (locationByPath.remove(path) != null) removed = true;
231 if (childrenByParentPath.remove(path) != null) removed = true;
232 }
233
234
235
236 Path path = topNode.getPath();
237 assert path != null;
238 LinkedList<Location> siblings = childrenByParentPath.get(path.getParent());
239 if (siblings != null) {
240 removed = removeChildFromParentListOfChildren(siblings, topNode, -1);
241 }
242 childrenByParentPath.remove(path);
243
244 return removed;
245 }
246
247 protected boolean removeChildFromParentListOfChildren( LinkedList<Location> siblings,
248 Location deletedNode,
249 int expectedIndex ) {
250 assert siblings != null;
251 Path path = deletedNode.getPath();
252 Path parentPath = path.getParent();
253
254
255 boolean removed = false;
256 int index = 0;
257 Path.Segment deletedNodeSegment = path.getLastSegment();
258 ListIterator<Location> iter = null;
259 if (expectedIndex > -1 && expectedIndex < siblings.size()) {
260 Location locationAtExpectedIndex = siblings.get(expectedIndex);
261 if (locationAtExpectedIndex.equals(deletedNode)) {
262 siblings.remove(expectedIndex);
263 removed = true;
264 index = expectedIndex;
265 }
266 }
267 if (!removed) {
268 iter = siblings.listIterator();
269 while (iter.hasNext()) {
270 Location sibling = iter.next();
271 Path.Segment segment = sibling.getPath().getLastSegment();
272 if (segment.equals(deletedNodeSegment)) {
273 iter.remove();
274 removed = true;
275 break;
276 }
277 ++index;
278 }
279 }
280
281
282 iter = siblings.listIterator(index);
283 Name name = deletedNodeSegment.getName();
284 while (iter.hasNext()) {
285 Location laterSibling = iter.next();
286 Path siblingPath = laterSibling.getPath();
287 Path.Segment segment = siblingPath.getLastSegment();
288
289 if (segment.getName().equals(name)) {
290 assert segment.getIndex() > 1;
291 Path newPath = pathFactory.create(parentPath, name, segment.getIndex() - 1);
292 Location newLocation = laterSibling.with(newPath);
293 iter.set(newLocation);
294
295
296 locationByPath.remove(siblingPath);
297
298
299 removeNodesBelow(siblingPath, false);
300
301
302 locationByPath.put(newPath, newLocation);
303 }
304 }
305 return removed;
306 }
307
308 public String getString( NamespaceRegistry namespaces ) {
309 StringBuilder sb = new StringBuilder();
310 sb.append("Workspace ");
311 sb.append(workspaceId);
312 sb.append("\n");
313 Set<Path> pathSet = new HashSet<Path>();
314 pathSet.addAll(locationByPath.keySet());
315 pathSet.addAll(childrenByParentPath.keySet());
316 List<Path> paths = new ArrayList<Path>(pathSet);
317 Collections.sort(paths);
318
319
320 int maxLength = 0;
321 for (Path path : paths) {
322 String str = pathString(path, namespaces);
323 maxLength = Math.max(maxLength, str.length());
324 }
325 for (Path path : paths) {
326 Location loc = locationByPath.get(path);
327 String str = pathString(path, namespaces);
328 sb.append(StringUtil.justifyLeft(str, maxLength, ' '));
329 if (loc != null) {
330
331 sb.append(" @" + loc.getUuid());
332 }
333 LinkedList<Location> children = childrenByParentPath.get(path);
334 if (children != null) {
335 sb.append("\twith children: ");
336 for (int i = 0; i < children.size(); i++) {
337 Location child = children.get(i);
338 String segmentString = pathSegmentString(child.getPath().getLastSegment(), namespaces);
339 sb.append("\n");
340 sb.append(StringUtil.justifyRight(segmentString, maxLength, ' '));
341 sb.append(" @" + child.getUuid());
342 }
343 }
344 sb.append("\n");
345 }
346 return sb.toString();
347 }
348
349 protected String pathString( Path path,
350 NamespaceRegistry registry ) {
351 return path.getString(registry, null, null);
352 }
353
354 protected String pathSegmentString( Path.Segment segment,
355 NamespaceRegistry registry ) {
356 return registry != null ? segment.getString(registry) : segment.getString();
357 }
358
359
360
361
362
363
364 @Override
365 public String toString() {
366 return getString(null);
367 }
368 }
369 }