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