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.graph.connector.map;
25
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.UUID;
34 import org.modeshape.common.i18n.I18n;
35 import org.modeshape.common.util.CheckArg;
36 import org.modeshape.graph.ModeShapeLexicon;
37 import org.modeshape.graph.ExecutionContext;
38 import org.modeshape.graph.GraphI18n;
39 import org.modeshape.graph.JcrLexicon;
40 import org.modeshape.graph.Location;
41 import org.modeshape.graph.observe.Observer;
42 import org.modeshape.graph.property.Name;
43 import org.modeshape.graph.property.Path;
44 import org.modeshape.graph.property.PathFactory;
45 import org.modeshape.graph.property.PathNotFoundException;
46 import org.modeshape.graph.property.Property;
47 import org.modeshape.graph.property.PropertyFactory;
48 import org.modeshape.graph.property.Path.Segment;
49 import org.modeshape.graph.query.QueryResults;
50 import org.modeshape.graph.request.AccessQueryRequest;
51 import org.modeshape.graph.request.CloneBranchRequest;
52 import org.modeshape.graph.request.CloneWorkspaceRequest;
53 import org.modeshape.graph.request.CopyBranchRequest;
54 import org.modeshape.graph.request.CreateNodeRequest;
55 import org.modeshape.graph.request.CreateWorkspaceRequest;
56 import org.modeshape.graph.request.DeleteBranchRequest;
57 import org.modeshape.graph.request.DestroyWorkspaceRequest;
58 import org.modeshape.graph.request.FullTextSearchRequest;
59 import org.modeshape.graph.request.GetWorkspacesRequest;
60 import org.modeshape.graph.request.InvalidRequestException;
61 import org.modeshape.graph.request.InvalidWorkspaceException;
62 import org.modeshape.graph.request.LockBranchRequest;
63 import org.modeshape.graph.request.MoveBranchRequest;
64 import org.modeshape.graph.request.ReadAllChildrenRequest;
65 import org.modeshape.graph.request.ReadAllPropertiesRequest;
66 import org.modeshape.graph.request.Request;
67 import org.modeshape.graph.request.UnlockBranchRequest;
68 import org.modeshape.graph.request.UpdatePropertiesRequest;
69 import org.modeshape.graph.request.VerifyWorkspaceRequest;
70 import org.modeshape.graph.request.processor.RequestProcessor;
71
72
73
74
75 public class MapRequestProcessor extends RequestProcessor {
76 private final PathFactory pathFactory;
77 private final PropertyFactory propertyFactory;
78 private final MapRepository repository;
79 private final boolean updatesAllowed;
80
81 public MapRequestProcessor( ExecutionContext context,
82 MapRepository repository,
83 Observer observer,
84 boolean updatesAllowed ) {
85 super(repository.getSourceName(), context, observer);
86 this.repository = repository;
87 pathFactory = context.getValueFactories().getPathFactory();
88 propertyFactory = context.getPropertyFactory();
89 this.updatesAllowed = updatesAllowed;
90 }
91
92
93
94
95
96
97 @Override
98 public void process( ReadAllChildrenRequest request ) {
99 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
100 MapNode node = getTargetNode(workspace, request, request.of());
101 if (node == null) {
102 assert request.hasError();
103 return;
104 }
105
106 Location actualLocation = getActualLocation(request.of(), node);
107 assert actualLocation != null;
108 Path path = actualLocation.getPath();
109
110 List<MapNode> children = node.getChildren();
111 for (MapNode child : children) {
112 Segment childName = child.getName();
113 Path childPath = pathFactory.create(path, childName);
114 request.addChild(childPath, propertyFactory.create(ModeShapeLexicon.UUID, child.getUuid()));
115 }
116 request.setActualLocationOfNode(actualLocation);
117 setCacheableInfo(request);
118 }
119
120 @Override
121 public void process( LockBranchRequest request ) {
122 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
123 MapNode node = getTargetNode(workspace, request, request.at());
124 if (node == null) return;
125
126 workspace.lockNode(node, request.lockScope(), request.lockTimeoutInMillis());
127
128 Location actualLocation = getActualLocation(request.at(), node);
129 request.setActualLocation(actualLocation);
130 recordChange(request);
131 }
132
133 @Override
134 public void process( UnlockBranchRequest request ) {
135 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
136 MapNode node = getTargetNode(workspace, request, request.at());
137 if (node == null) return;
138
139 workspace.unlockNode(node);
140
141 Location actualLocation = getActualLocation(request.at(), node);
142 request.setActualLocation(actualLocation);
143 recordChange(request);
144 }
145
146 @Override
147 public void process( ReadAllPropertiesRequest request ) {
148 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
149 MapNode node = getTargetNode(workspace, request, request.at());
150 if (node == null) {
151 assert request.hasError();
152 return;
153 }
154
155
156 Location actualLocation = getActualLocation(request.at(), node);
157 request.addProperty(propertyFactory.create(ModeShapeLexicon.UUID, node.getUuid()));
158 for (Property property : node.getProperties().values()) {
159 request.addProperty(property);
160 }
161
162 assert actualLocation != null;
163 request.setActualLocationOfNode(actualLocation);
164 setCacheableInfo(request);
165 }
166
167
168
169
170
171
172 @Override
173 public void process( CloneBranchRequest request ) {
174 if (!updatesAllowed(request)) return;
175
176 MapWorkspace workspace = getWorkspace(request, request.fromWorkspace());
177 MapWorkspace newWorkspace = getWorkspace(request, request.intoWorkspace());
178 if (workspace == null || newWorkspace == null) return;
179 MapNode node = getTargetNode(workspace, request, request.from());
180 if (node == null) return;
181
182
183 Path newParentPath = request.into().getPath();
184 MapNode newParent = newWorkspace.getNode(newParentPath);
185 Set<Location> removedExistingNodes = new HashSet<Location>();
186 MapNode newNode = workspace.cloneNode(getExecutionContext(),
187 node,
188 newWorkspace,
189 newParent,
190 request.desiredName(),
191 request.desiredSegment(),
192 request.removeExisting(),
193 removedExistingNodes);
194 Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
195 Location oldLocation = getActualLocation(request.from(), node);
196 Location newLocation = Location.create(newPath, newNode.getUuid());
197 request.setActualLocations(oldLocation, newLocation);
198 request.setRemovedNodes(Collections.unmodifiableSet(removedExistingNodes));
199 recordChange(request);
200 }
201
202
203
204
205
206
207 @Override
208 public void process( CopyBranchRequest request ) {
209 if (!updatesAllowed(request)) return;
210
211 MapWorkspace workspace = getWorkspace(request, request.fromWorkspace());
212 MapWorkspace newWorkspace = getWorkspace(request, request.intoWorkspace());
213 if (workspace == null || newWorkspace == null) return;
214 MapNode node = getTargetNode(workspace, request, request.from());
215 if (node == null) return;
216
217
218 Path newParentPath = request.into().getPath();
219 Name desiredName = request.desiredName();
220 MapNode newParent = newWorkspace.getNode(newParentPath);
221 MapNode newNode = workspace.copyNode(getExecutionContext(), node, newWorkspace, newParent, desiredName, true);
222 Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
223 Location oldLocation = getActualLocation(request.from(), node);
224 Location newLocation = Location.create(newPath, newNode.getUuid());
225 request.setActualLocations(oldLocation, newLocation);
226 recordChange(request);
227 }
228
229
230
231
232
233
234 @Override
235 public void process( CreateNodeRequest request ) {
236 if (!updatesAllowed(request)) return;
237
238 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
239 if (workspace == null) return;
240 Path parent = request.under().getPath();
241 CheckArg.isNotNull(parent, "request.under().getPath()");
242 MapNode node = null;
243
244
245 MapNode parentNode = workspace.getNode(parent);
246 if (parentNode == null) {
247 Path lowestExisting = workspace.getLowestExistingPath(parent);
248 request.setError(new PathNotFoundException(request.under(), lowestExisting, GraphI18n.nodeDoesNotExist.text(parent)));
249 return;
250 }
251
252 UUID uuid = null;
253
254 List<Property> propsToStore = new ArrayList<Property>(request.properties().size());
255 for (Property property : request.properties()) {
256 if (property.getName().equals(ModeShapeLexicon.UUID) || property.getName().equals(JcrLexicon.UUID)) {
257 uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next());
258 } else {
259 if (property.size() > 0) propsToStore.add(property);
260 }
261 }
262
263 switch (request.conflictBehavior()) {
264 case APPEND:
265 node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
266 break;
267 case DO_NOT_REPLACE:
268 for (MapNode child : parentNode.getChildren()) {
269 if (request.named().equals(child.getName().getName())) {
270 node = child;
271 break;
272 }
273 }
274 if (node == null) {
275 node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
276 }
277 break;
278 case REPLACE:
279
280 node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
281 if (node != null) {
282 workspace.removeNode(getExecutionContext(), node);
283 }
284 node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
285 break;
286 case UPDATE:
287
288 node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
289 if (node == null) {
290 node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
291 }
292 break;
293 }
294 assert node != null;
295 Path path = getExecutionContext().getValueFactories().getPathFactory().create(parent, node.getName());
296
297 Location actualLocation = getActualLocation(Location.create(path), node);
298 request.setActualLocationOfNode(actualLocation);
299 recordChange(request);
300 }
301
302
303
304
305
306
307 @Override
308 public void process( DeleteBranchRequest request ) {
309 if (!updatesAllowed(request)) return;
310
311 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
312 if (workspace == null) return;
313 MapNode node = getTargetNode(workspace, request, request.at());
314 if (node == null) return;
315 workspace.removeNode(getExecutionContext(), node);
316 Location actualLocation = getActualLocation(request.at(), node);
317 request.setActualLocationOfNode(actualLocation);
318 recordChange(request);
319 }
320
321
322
323
324
325
326 @Override
327 public void process( MoveBranchRequest request ) {
328 if (!updatesAllowed(request)) return;
329
330 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
331 if (workspace == null) return;
332
333 MapNode beforeNode = request.before() != null ? getTargetNode(workspace, request, request.before()) : null;
334 MapNode node = getTargetNode(workspace, request, request.from());
335 if (node == null) return;
336 if (request.hasError()) return;
337
338 Path newParentPath;
339
340 if (request.into() != null) {
341 newParentPath = request.into().getPath();
342 } else {
343
344 assert beforeNode != null;
345
346
347 LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
348 MapNode current = beforeNode.getParent();
349 while (!current.equals(workspace.getRoot())) {
350 segments.addFirst(current.getName());
351 current = current.getParent();
352 }
353 newParentPath = getExecutionContext().getValueFactories().getPathFactory().createAbsolutePath(segments);
354 }
355
356 MapNode newParent = workspace.getNode(newParentPath);
357 if (newParent == null) {
358 Path lowestExisting = workspace.getLowestExistingPath(newParentPath);
359 request.setError(new PathNotFoundException(request.into(), lowestExisting,
360 GraphI18n.nodeDoesNotExist.text(newParentPath)));
361 return;
362 }
363 workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace, newParent, beforeNode);
364 assert node.getParent().equals(newParent);
365 Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
366 Location oldLocation = getActualLocation(request.from(), node);
367 Location newLocation = Location.create(newPath, node.getUuid());
368 request.setActualLocations(oldLocation, newLocation);
369 recordChange(request);
370 }
371
372
373
374
375
376
377 @Override
378 public void process( UpdatePropertiesRequest request ) {
379 if (!updatesAllowed(request)) return;
380
381 MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
382 MapNode node = getTargetNode(workspace, request, request.on());
383 if (node == null) return;
384
385 for (Map.Entry<Name, Property> propertyEntry : request.properties().entrySet()) {
386 Property property = propertyEntry.getValue();
387 if (property == null) {
388 node.removeProperty(propertyEntry.getKey());
389 continue;
390 }
391 Name propName = property.getName();
392 if (!propName.equals(ModeShapeLexicon.UUID)) {
393 if (node.getProperties().get(propName) == null) {
394
395 request.setNewProperty(propName);
396 }
397 node.setProperty(property);
398 }
399 }
400 Location actualLocation = getActualLocation(request.on(), node);
401 request.setActualLocationOfNode(actualLocation);
402 recordChange(request);
403 }
404
405
406
407
408
409
410 @Override
411 public void process( CreateWorkspaceRequest request ) {
412 if (!updatesAllowed(request)) return;
413
414 MapWorkspace workspace = repository.createWorkspace(getExecutionContext(),
415 request.desiredNameOfNewWorkspace(),
416 request.conflictBehavior());
417 if (workspace == null) {
418 String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(request.desiredNameOfNewWorkspace(),
419 repository.getSourceName());
420 request.setError(new InvalidWorkspaceException(msg));
421 } else {
422 MapNode root = workspace.getRoot();
423 request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
424 request.setActualWorkspaceName(workspace.getName());
425 recordChange(request);
426 }
427 }
428
429
430
431
432
433
434 @Override
435 public void process( DestroyWorkspaceRequest request ) {
436 if (!updatesAllowed(request)) return;
437
438 MapWorkspace workspace = repository.getWorkspace(request.workspaceName());
439 if (workspace != null) {
440 MapNode root = workspace.getRoot();
441 request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
442 recordChange(request);
443 } else {
444 String msg = GraphI18n.workspaceDoesNotExistInRepository.text(request.workspaceName(), repository.getSourceName());
445 request.setError(new InvalidWorkspaceException(msg));
446 }
447 }
448
449
450
451
452
453
454 @Override
455 public void process( GetWorkspacesRequest request ) {
456 Set<String> names = repository.getWorkspaceNames();
457 request.setAvailableWorkspaceNames(new HashSet<String>(names));
458 setCacheableInfo(request);
459 }
460
461
462
463
464
465
466 @Override
467 public void process( VerifyWorkspaceRequest request ) {
468 MapWorkspace original = getWorkspace(request, request.workspaceName());
469 if (original != null) {
470 Path path = getExecutionContext().getValueFactories().getPathFactory().createRootPath();
471 request.setActualRootLocation(Location.create(path, original.getRoot().getUuid()));
472 request.setActualWorkspaceName(original.getName());
473 }
474 }
475
476
477
478
479
480
481 @Override
482 public void process( CloneWorkspaceRequest request ) {
483 if (!updatesAllowed(request)) return;
484
485
486 final ExecutionContext context = getExecutionContext();
487 String targetWorkspaceName = request.desiredNameOfTargetWorkspace();
488 String nameOfWorkspaceToBeCloned = request.nameOfWorkspaceToBeCloned();
489 MapWorkspace original = repository.getWorkspace(nameOfWorkspaceToBeCloned);
490 MapWorkspace target = repository.getWorkspace(targetWorkspaceName);
491
492 if (target != null) {
493 String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName());
494 request.setError(new InvalidWorkspaceException(msg));
495 return;
496 }
497
498 if (original == null) {
499 switch (request.cloneConflictBehavior()) {
500 case DO_NOT_CLONE:
501 String msg = GraphI18n.workspaceDoesNotExistInRepository.text(nameOfWorkspaceToBeCloned,
502 repository.getSourceName());
503 request.setError(new InvalidWorkspaceException(msg));
504 return;
505 case SKIP_CLONE:
506 target = repository.createWorkspace(context, targetWorkspaceName, request.targetConflictBehavior());
507 assert target != null;
508
509 MapNode root = target.getRoot();
510 request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
511 request.setActualWorkspaceName(target.getName());
512 return;
513 }
514 }
515 assert original != null;
516 target = repository.createWorkspace(context,
517 targetWorkspaceName,
518 request.targetConflictBehavior(),
519 nameOfWorkspaceToBeCloned);
520 assert target != null;
521 MapNode root = target.getRoot();
522 request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
523 request.setActualWorkspaceName(target.getName());
524 recordChange(request);
525 }
526
527
528
529
530
531
532 @Override
533 public void process( AccessQueryRequest request ) {
534 MapWorkspace workspace = getWorkspace(request, request.workspace());
535 if (workspace == null) return;
536 final ExecutionContext context = getExecutionContext();
537 QueryResults results = workspace.query(context, request);
538 if (results != null) {
539 request.setResults(results.getTuples(), results.getStatistics());
540 } else {
541 super.processUnknownRequest(request);
542 }
543 }
544
545
546
547
548
549
550 @Override
551 public void process( FullTextSearchRequest request ) {
552 MapWorkspace workspace = getWorkspace(request, request.workspace());
553 if (workspace == null) return;
554 final ExecutionContext context = getExecutionContext();
555 QueryResults results = workspace.search(context, request.expression());
556 if (results != null) {
557 request.setResults(results.getColumns(), results.getTuples(), results.getStatistics());
558 } else {
559 super.processUnknownRequest(request);
560 }
561 }
562
563 protected Location getActualLocation( Location location,
564 MapNode node ) {
565 Path path = location.getPath();
566 if (path == null) {
567
568 LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
569 MapNode n = node;
570 while (n != null) {
571 if (n.getParent() == null) break;
572 segments.addFirst(n.getName());
573 n = n.getParent();
574 }
575 path = pathFactory.createAbsolutePath(segments);
576 }
577
578 assert location.getUuid() == null || location.getUuid().equals(node.getUuid());
579 if (location.hasIdProperties()) {
580 return location.with(path);
581 }
582 return Location.create(path, node.getUuid());
583 }
584
585 protected MapWorkspace getWorkspace( Request request,
586 String workspaceName ) {
587
588 MapWorkspace workspace = repository.getWorkspace(workspaceName);
589 if (workspace == null) {
590 String msg = GraphI18n.workspaceDoesNotExistInRepository.text(workspaceName, repository.getSourceName());
591 request.setError(new InvalidWorkspaceException(msg));
592 }
593 return workspace;
594 }
595
596 protected boolean updatesAllowed( Request request ) {
597 if (!updatesAllowed) {
598 request.setError(new InvalidRequestException(GraphI18n.sourceIsReadOnly.text(getSourceName())));
599 }
600 return !request.hasError();
601 }
602
603 protected MapNode getTargetNode( MapWorkspace workspace,
604 Request request,
605 Location location ) {
606 if (workspace == null) return null;
607
608 MapNode node = null;
609 UUID uuid = location.getUuid();
610 if (uuid != null) {
611 node = workspace.getNode(uuid);
612 }
613 Path path = null;
614 if (node == null) {
615
616 path = location.getPath();
617 if (path != null) {
618 node = workspace.getNode(path);
619 }
620 }
621 if (node == null && request != null) {
622 if (path == null) {
623 if (uuid == null) {
624
625 I18n msg = GraphI18n.inMemoryConnectorRequestsMustHavePathOrUuid;
626 request.setError(new IllegalArgumentException(msg.text()));
627 return null;
628 }
629
630 request.setError(new PathNotFoundException(location, pathFactory.createRootPath(),
631 GraphI18n.nodeDoesNotExist.text(path)));
632 return null;
633 }
634
635 Path lowestExisting = workspace.getLowestExistingPath(path);
636 request.setError(new PathNotFoundException(location, lowestExisting, GraphI18n.nodeDoesNotExist.text(path)));
637 }
638 return node;
639 }
640 }