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.request.processor;
25
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.Iterator;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Queue;
34 import net.jcip.annotations.Immutable;
35 import net.jcip.annotations.NotThreadSafe;
36 import org.modeshape.common.util.CheckArg;
37 import org.modeshape.graph.ExecutionContext;
38 import org.modeshape.graph.GraphI18n;
39 import org.modeshape.graph.Location;
40 import org.modeshape.graph.cache.CachePolicy;
41 import org.modeshape.graph.connector.LockFailedException;
42 import org.modeshape.graph.observe.Changes;
43 import org.modeshape.graph.observe.Observer;
44 import org.modeshape.graph.property.DateTime;
45 import org.modeshape.graph.property.Name;
46 import org.modeshape.graph.property.Path;
47 import org.modeshape.graph.property.Property;
48 import org.modeshape.graph.property.ReferentialIntegrityException;
49 import org.modeshape.graph.request.AccessQueryRequest;
50 import org.modeshape.graph.request.CacheableRequest;
51 import org.modeshape.graph.request.ChangeRequest;
52 import org.modeshape.graph.request.CloneBranchRequest;
53 import org.modeshape.graph.request.CloneWorkspaceRequest;
54 import org.modeshape.graph.request.CompositeRequest;
55 import org.modeshape.graph.request.CopyBranchRequest;
56 import org.modeshape.graph.request.CreateNodeRequest;
57 import org.modeshape.graph.request.CreateWorkspaceRequest;
58 import org.modeshape.graph.request.DeleteBranchRequest;
59 import org.modeshape.graph.request.DeleteChildrenRequest;
60 import org.modeshape.graph.request.DestroyWorkspaceRequest;
61 import org.modeshape.graph.request.FullTextSearchRequest;
62 import org.modeshape.graph.request.GetWorkspacesRequest;
63 import org.modeshape.graph.request.InvalidRequestException;
64 import org.modeshape.graph.request.LockBranchRequest;
65 import org.modeshape.graph.request.MoveBranchRequest;
66 import org.modeshape.graph.request.ReadAllChildrenRequest;
67 import org.modeshape.graph.request.ReadAllPropertiesRequest;
68 import org.modeshape.graph.request.ReadBlockOfChildrenRequest;
69 import org.modeshape.graph.request.ReadBranchRequest;
70 import org.modeshape.graph.request.ReadNextBlockOfChildrenRequest;
71 import org.modeshape.graph.request.ReadNodeRequest;
72 import org.modeshape.graph.request.ReadPropertyRequest;
73 import org.modeshape.graph.request.RemovePropertyRequest;
74 import org.modeshape.graph.request.RenameNodeRequest;
75 import org.modeshape.graph.request.Request;
76 import org.modeshape.graph.request.SetPropertyRequest;
77 import org.modeshape.graph.request.UnlockBranchRequest;
78 import org.modeshape.graph.request.UnsupportedRequestException;
79 import org.modeshape.graph.request.UpdatePropertiesRequest;
80 import org.modeshape.graph.request.UpdateValuesRequest;
81 import org.modeshape.graph.request.VerifyNodeExistsRequest;
82 import org.modeshape.graph.request.VerifyWorkspaceRequest;
83
84
85
86
87
88
89 @NotThreadSafe
90 public abstract class RequestProcessor {
91
92 private final ExecutionContext context;
93 private final String sourceName;
94 private final DateTime nowInUtc;
95 private final CachePolicy defaultCachePolicy;
96 private List<ChangeRequest> changes;
97 private final Observer observer;
98
99 protected RequestProcessor( String sourceName,
100 ExecutionContext context,
101 Observer observer ) {
102 this(sourceName, context, observer, null, null);
103 }
104
105 protected RequestProcessor( String sourceName,
106 ExecutionContext context,
107 Observer observer,
108 DateTime now ) {
109 this(sourceName, context, observer, now, null);
110 }
111
112 protected RequestProcessor( String sourceName,
113 ExecutionContext context,
114 Observer observer,
115 DateTime now,
116 CachePolicy defaultCachePolicy ) {
117 CheckArg.isNotEmpty(sourceName, "sourceName");
118 CheckArg.isNotNull(context, "context");
119 this.context = context;
120 this.sourceName = sourceName;
121 this.nowInUtc = now != null ? now : context.getValueFactories().getDateFactory().createUtc();
122 this.defaultCachePolicy = defaultCachePolicy;
123 this.changes = observer != null ? new LinkedList<ChangeRequest>() : null;
124 this.observer = observer;
125 }
126
127
128
129
130
131
132 protected void recordChange( ChangeRequest request ) {
133 assert request != null;
134 assert !request.isCancelled();
135 assert !request.hasError();
136 if (changes != null) changes.add(request);
137 }
138
139
140
141
142
143
144 public final String getSourceName() {
145 return sourceName;
146 }
147
148
149
150
151
152
153 public final ExecutionContext getExecutionContext() {
154 return this.context;
155 }
156
157
158
159
160
161
162 public final DateTime getNowInUtc() {
163 return this.nowInUtc;
164 }
165
166
167
168
169 protected final CachePolicy getDefaultCachePolicy() {
170 return defaultCachePolicy;
171 }
172
173
174
175
176
177
178 protected void setCacheableInfo( CacheableRequest request ) {
179
180 if (request.getCachePolicy() == null && defaultCachePolicy != null) {
181 request.setCachePolicy(defaultCachePolicy);
182 }
183 request.setTimeLoaded(nowInUtc);
184 }
185
186
187
188
189
190
191
192 protected void setCacheableInfo( CacheableRequest request,
193 CachePolicy cachePolicy ) {
194 if (cachePolicy == null) cachePolicy = defaultCachePolicy;
195 if (cachePolicy != null) {
196 if (request.getCachePolicy() != null) {
197
198 if (request.getCachePolicy().getTimeToLive() > cachePolicy.getTimeToLive()) {
199 request.setCachePolicy(cachePolicy);
200 }
201 } else {
202
203 request.setCachePolicy(cachePolicy);
204 }
205 }
206 request.setTimeLoaded(nowInUtc);
207 }
208
209
210
211
212
213
214
215
216
217
218 public void process( Request request ) {
219 if (request == null) return;
220 try {
221 if (request.isCancelled()) return;
222
223 switch (request.getType()) {
224 case ACCESS_QUERY:
225 process((AccessQueryRequest)request);
226 break;
227 case COMPOSITE:
228 process((CompositeRequest)request);
229 break;
230 case CLONE_BRANCH:
231 process((CloneBranchRequest)request);
232 break;
233 case CLONE_WORKSPACE:
234 process((CloneWorkspaceRequest)request);
235 break;
236 case COPY_BRANCH:
237 process((CopyBranchRequest)request);
238 break;
239 case CREATE_NODE:
240 process((CreateNodeRequest)request);
241 break;
242 case CREATE_WORKSPACE:
243 process((CreateWorkspaceRequest)request);
244 break;
245 case DELETE_BRANCH:
246 process((DeleteBranchRequest)request);
247 break;
248 case DELETE_CHILDREN:
249 process((DeleteChildrenRequest)request);
250 break;
251 case DESTROY_WORKSPACE:
252 process((DestroyWorkspaceRequest)request);
253 break;
254 case FULL_TEXT_SEARCH:
255 process((FullTextSearchRequest)request);
256 break;
257 case GET_WORKSPACES:
258 process((GetWorkspacesRequest)request);
259 break;
260 case LAST:
261 break;
262 case LOCK_BRANCH:
263 process((LockBranchRequest)request);
264 break;
265 case MOVE_BRANCH:
266 process((MoveBranchRequest)request);
267 break;
268 case READ_ALL_CHILDREN:
269 process((ReadAllChildrenRequest)request);
270 break;
271 case READ_ALL_PROPERTIES:
272 process((ReadAllPropertiesRequest)request);
273 break;
274 case READ_BLOCK_OF_CHILDREN:
275 process((ReadBlockOfChildrenRequest)request);
276 break;
277 case READ_BRANCH:
278 process((ReadBranchRequest)request);
279 break;
280 case READ_NEXT_BLOCK_OF_CHILDREN:
281 process((ReadNextBlockOfChildrenRequest)request);
282 break;
283 case READ_NODE:
284 process((ReadNodeRequest)request);
285 break;
286 case READ_PROPERTY:
287 process((ReadPropertyRequest)request);
288 break;
289 case REMOVE_PROPERTY:
290 process((RemovePropertyRequest)request);
291 break;
292 case RENAME_NODE:
293 process((RenameNodeRequest)request);
294 break;
295 case SET_PROPERTY:
296 process((SetPropertyRequest)request);
297 break;
298 case UNLOCK_BRANCH:
299 process((UnlockBranchRequest)request);
300 break;
301 case UPDATE_PROPERTIES:
302 process((UpdatePropertiesRequest)request);
303 break;
304 case UPDATE_VALUES:
305 process((UpdateValuesRequest)request);
306 break;
307 case VERIFY_NODE_EXISTS:
308 process((VerifyNodeExistsRequest)request);
309 break;
310 case VERIFY_WORKSPACE:
311 process((VerifyWorkspaceRequest)request);
312 break;
313 default:
314 processUnknownRequest(request);
315 }
316 } catch (RuntimeException e) {
317 request.setError(e);
318 } finally {
319 completeRequest(request);
320 }
321 }
322
323 protected void completeRequest( Request request ) {
324 request.freeze();
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338
339 public void process( CompositeRequest request ) {
340 if (request == null) return;
341 boolean hasErrors = false;
342 boolean readonly = request.isReadOnly();
343
344 Iterator<Request> iter = request.iterator();
345 while (iter.hasNext()) {
346 Request embedded = iter.next();
347 assert embedded != null;
348 if (embedded.isCancelled()) return;
349 try {
350 process(embedded);
351 } catch (RuntimeException e) {
352 embedded.setError(e);
353 }
354 if (!hasErrors && embedded.hasError()) {
355 hasErrors = true;
356 if (!readonly && !embedded.isReadOnly()) {
357
358
359
360 assert embedded.getError() != null;
361 request.setError(embedded.getError());
362
363 while (iter.hasNext()) {
364 embedded = iter.next();
365
366 embedded.cancel();
367 embedded.freeze();
368 }
369 return;
370 }
371 }
372 }
373 if (hasErrors) {
374 request.checkForErrors();
375 }
376 }
377
378
379
380
381
382
383
384
385 protected void processUnknownRequest( Request request ) {
386 request.setError(new InvalidRequestException(GraphI18n.unsupportedRequestType.text(request.getClass().getName(), request)));
387 }
388
389
390
391
392
393
394
395
396
397 public abstract void process( VerifyWorkspaceRequest request );
398
399
400
401
402
403
404
405
406
407 public abstract void process( GetWorkspacesRequest request );
408
409
410
411
412
413
414
415
416
417 public abstract void process( CreateWorkspaceRequest request );
418
419
420
421
422
423
424
425
426
427 public abstract void process( CloneBranchRequest request );
428
429
430
431
432
433
434
435
436
437 public abstract void process( CloneWorkspaceRequest request );
438
439
440
441
442
443
444
445
446
447 public abstract void process( DestroyWorkspaceRequest request );
448
449
450
451
452
453
454
455
456
457 public abstract void process( CopyBranchRequest request );
458
459
460
461
462
463
464
465
466
467 public abstract void process( CreateNodeRequest request );
468
469
470
471
472
473
474
475
476
477
478
479 public abstract void process( DeleteBranchRequest request );
480
481
482
483
484
485
486
487
488
489
490
491 public void process( DeleteChildrenRequest request ) {
492 if (request == null) return;
493 if (request.isCancelled()) return;
494
495 ReadAllChildrenRequest readChildren = new ReadAllChildrenRequest(request.at(), request.inWorkspace());
496 process(readChildren);
497 if (readChildren.hasError()) {
498 request.setError(readChildren.getError());
499 return;
500 }
501 if (readChildren.isCancelled()) return;
502
503
504 for (Location child : readChildren) {
505 if (request.isCancelled()) return;
506 DeleteBranchRequest deleteChild = new DeleteBranchRequest(child, request.inWorkspace());
507 process(deleteChild);
508 request.addDeletedChild(child);
509 }
510
511
512 request.setActualLocationOfNode(readChildren.getActualLocationOfNode());
513 }
514
515
516
517
518
519
520
521
522
523 public abstract void process( MoveBranchRequest request );
524
525
526
527
528
529
530
531
532
533 public abstract void process( ReadAllChildrenRequest request );
534
535
536
537
538
539
540
541
542
543
544
545
546
547 public void process( ReadBlockOfChildrenRequest request ) {
548 if (request == null) return;
549
550 ReadAllChildrenRequest readAll = new ReadAllChildrenRequest(request.of(), request.inWorkspace());
551 process(readAll);
552 if (readAll.hasError()) {
553 request.setError(readAll.getError());
554 return;
555 }
556 List<Location> allChildren = readAll.getChildren();
557
558
559 if (allChildren.size() < request.startingAtIndex()) return;
560
561
562 int endIndex = Math.min(request.endingBefore(), allChildren.size());
563 for (int i = request.startingAtIndex(); i != endIndex; ++i) {
564 request.addChild(allChildren.get(i));
565 }
566
567 request.setActualLocationOfNode(readAll.getActualLocationOfNode());
568 setCacheableInfo(request);
569 }
570
571
572
573
574
575
576
577
578
579
580
581 public void process( ReadNextBlockOfChildrenRequest request ) {
582 if (request == null) return;
583
584
585 Location actualSiblingLocation = request.startingAfter();
586 Path path = actualSiblingLocation.getPath();
587 Path parentPath = null;
588 if (path != null) parentPath = path.getParent();
589 if (parentPath == null) {
590
591 VerifyNodeExistsRequest verifySibling = new VerifyNodeExistsRequest(request.startingAfter(), request.inWorkspace());
592 process(verifySibling);
593 actualSiblingLocation = verifySibling.getActualLocationOfNode();
594 parentPath = actualSiblingLocation.getPath().getParent();
595 }
596 assert parentPath != null;
597
598
599 ReadAllChildrenRequest readAll = new ReadAllChildrenRequest(Location.create(parentPath), request.inWorkspace());
600 process(readAll);
601 if (readAll.hasError()) {
602 request.setError(readAll.getError());
603 return;
604 }
605 List<Location> allChildren = readAll.getChildren();
606
607
608 boolean found = false;
609 int count = 0;
610 for (Location child : allChildren) {
611 if (count > request.count()) break;
612 if (!found) {
613
614 found = child.isSame(request.startingAfter());
615 } else {
616
617 ++count;
618 request.addChild(child);
619 }
620 }
621
622
623 request.setActualLocationOfStartingAfterNode(actualSiblingLocation);
624 setCacheableInfo(request);
625 }
626
627
628
629
630
631
632
633
634
635
636
637 public void process( ReadBranchRequest request ) {
638 if (request == null) return;
639
640 Queue<LocationWithDepth> locationsToRead = new LinkedList<LocationWithDepth>();
641 locationsToRead.add(new LocationWithDepth(request.at(), 1));
642
643
644 boolean first = true;
645 while (locationsToRead.peek() != null) {
646 if (request.isCancelled()) return;
647 LocationWithDepth read = locationsToRead.poll();
648
649
650 if (read.depth > request.maximumDepth()) break;
651
652
653 ReadNodeRequest readNode = new ReadNodeRequest(read.location, request.inWorkspace());
654 process(readNode);
655 if (readNode.hasError()) {
656 request.setError(readNode.getError());
657 return;
658 }
659 Location actualLocation = readNode.getActualLocationOfNode();
660 if (first) {
661
662 request.setActualLocationOfNode(actualLocation);
663 first = false;
664 }
665
666
667 request.setChildren(actualLocation, readNode.getChildren());
668 request.setProperties(actualLocation, readNode.getProperties());
669
670
671 for (Location child : readNode.getChildren()) {
672 locationsToRead.add(new LocationWithDepth(child, read.depth + 1));
673 }
674 }
675 setCacheableInfo(request);
676 }
677
678
679
680
681
682
683
684
685
686 public abstract void process( ReadAllPropertiesRequest request );
687
688
689
690
691
692
693
694
695
696
697 public void process( ReadNodeRequest request ) {
698 if (request == null) return;
699
700 ReadAllPropertiesRequest readProperties = new ReadAllPropertiesRequest(request.at(), request.inWorkspace());
701 process(readProperties);
702 if (readProperties.hasError()) {
703 request.setError(readProperties.getError());
704 return;
705 }
706
707 request.setActualLocationOfNode(readProperties.getActualLocationOfNode());
708
709
710 ReadAllChildrenRequest readChildren = new ReadAllChildrenRequest(request.at(), request.inWorkspace());
711 process(readChildren);
712 if (readChildren.hasError()) {
713 request.setError(readChildren.getError());
714 return;
715 }
716 if (request.isCancelled()) return;
717
718 for (Property property : readProperties) {
719 request.addProperty(property);
720 }
721 for (Location child : readChildren) {
722 request.addChild(child);
723 }
724 setCacheableInfo(request);
725 }
726
727
728
729
730
731
732
733
734
735
736 public void process( ReadPropertyRequest request ) {
737 if (request == null) return;
738 ReadAllPropertiesRequest readNode = new ReadAllPropertiesRequest(request.on(), request.inWorkspace());
739 process(readNode);
740 if (readNode.hasError()) {
741 request.setError(readNode.getError());
742 return;
743 }
744 Property property = readNode.getPropertiesByName().get(request.named());
745 request.setProperty(property);
746
747 request.setActualLocationOfNode(readNode.getActualLocationOfNode());
748 setCacheableInfo(request);
749 }
750
751
752
753
754
755
756
757
758
759
760 public void process( VerifyNodeExistsRequest request ) {
761 if (request == null) return;
762 ReadAllPropertiesRequest readNode = new ReadAllPropertiesRequest(request.at(), request.inWorkspace());
763 process(readNode);
764 if (readNode.hasError()) {
765 request.setError(readNode.getError());
766 return;
767 }
768
769 request.setActualLocationOfNode(readNode.getActualLocationOfNode());
770 setCacheableInfo(request);
771 }
772
773
774
775
776
777
778
779
780
781
782 public void process( RemovePropertyRequest request ) {
783 if (request == null) return;
784 Map<Name, Property> properties = Collections.singletonMap(request.propertyName(), null);
785 UpdatePropertiesRequest update = new UpdatePropertiesRequest(request.from(), request.inWorkspace(), properties);
786 process(update);
787 if (update.hasError()) {
788 request.setError(update.getError());
789 }
790
791 request.setActualLocationOfNode(update.getActualLocationOfNode());
792 }
793
794
795
796
797
798
799
800
801
802
803 public void process( SetPropertyRequest request ) {
804 if (request == null) return;
805 Property property = request.property();
806 Map<Name, Property> properties = Collections.singletonMap(property.getName(), property);
807 UpdatePropertiesRequest update = new UpdatePropertiesRequest(request.on(), request.inWorkspace(), properties);
808 process(update);
809 if (update.hasError()) {
810 request.setError(update.getError());
811 } else {
812
813 request.setActualLocationOfNode(update.getActualLocationOfNode());
814 request.setNewProperty(update.isNewProperty(property.getName()));
815 }
816 }
817
818
819
820
821
822
823
824
825
826 public abstract void process( UpdatePropertiesRequest request );
827
828
829
830
831
832
833
834
835
836 public void process( UpdateValuesRequest request ) {
837 String workspaceName = request.inWorkspace();
838 Location on = request.on();
839 Name propertyName = request.property();
840
841
842 ReadPropertyRequest readProperty = new ReadPropertyRequest(on, workspaceName, propertyName);
843 process(readProperty);
844
845 if (readProperty.hasError()) {
846 request.setError(readProperty.getError());
847 return;
848 }
849
850 Property property = readProperty.getProperty();
851 List<Object> actualRemovedValues = new ArrayList<Object>(request.removedValues().size());
852 List<Object> newValues = property == null ? new LinkedList<Object>() : new LinkedList<Object>(
853 Arrays.asList(property.getValuesAsArray()));
854
855 for (Object removedValue : request.removedValues()) {
856 for (Iterator<Object> iter = newValues.iterator(); iter.hasNext();) {
857 if (iter.next().equals(removedValue)) {
858 iter.remove();
859 actualRemovedValues.add(removedValue);
860 break;
861 }
862 }
863 }
864
865 newValues.addAll(request.addedValues());
866 Property newProperty = getExecutionContext().getPropertyFactory().create(propertyName, newValues);
867
868
869 SetPropertyRequest setProperty = new SetPropertyRequest(on, workspaceName, newProperty);
870 process(setProperty);
871
872 if (setProperty.hasError()) {
873 request.setError(setProperty.getError());
874 } else {
875
876 request.setActualLocation(setProperty.getActualLocationOfNode(), request.addedValues(), actualRemovedValues);
877 request.setActualProperty(newProperty, setProperty.isNewProperty());
878 }
879
880 }
881
882
883
884
885
886
887
888
889
890
891
892
893 public void process( RenameNodeRequest request ) {
894 if (request == null) return;
895 Location from = request.at();
896 if (!from.hasPath()) {
897 throw new UnsupportedOperationException();
898 }
899 Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(from.getPath(), request.toName());
900 Location to = Location.create(newPath);
901 MoveBranchRequest move = new MoveBranchRequest(from, to, request.inWorkspace());
902 process(move);
903
904 request.setActualLocations(move.getActualLocationBefore(), move.getActualLocationAfter());
905 }
906
907
908
909
910
911
912
913
914
915
916
917
918
919 public void process( LockBranchRequest request ) {
920 Location actualLocation = request.at();
921 if (!actualLocation.hasPath()) {
922 VerifyNodeExistsRequest nodeExists = new VerifyNodeExistsRequest(request.at(), request.inWorkspace());
923
924 process(nodeExists);
925
926 if (nodeExists.hasError()) {
927 request.setError(nodeExists.getError());
928 return;
929 }
930
931 actualLocation = nodeExists.getActualLocationOfNode();
932 }
933
934 request.setActualLocation(actualLocation);
935 }
936
937
938
939
940
941
942
943
944
945
946 public void process( UnlockBranchRequest request ) {
947 Location actualLocation = request.at();
948 if (!actualLocation.hasPath()) {
949 VerifyNodeExistsRequest nodeExists = new VerifyNodeExistsRequest(request.at(), request.inWorkspace());
950
951 process(nodeExists);
952
953 if (nodeExists.hasError()) {
954 request.setError(nodeExists.getError());
955 return;
956 }
957
958 actualLocation = nodeExists.getActualLocationOfNode();
959 }
960
961 request.setActualLocation(actualLocation);
962 }
963
964
965
966
967
968
969
970
971
972
973
974 public void process( AccessQueryRequest request ) {
975 processUnknownRequest(request);
976 }
977
978
979
980
981
982
983
984
985
986
987 public void process( FullTextSearchRequest request ) {
988 processUnknownRequest(request);
989 }
990
991
992
993
994 public void close() {
995
996 }
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011 public List<ChangeRequest> getChanges() {
1012 return changes;
1013 }
1014
1015
1016
1017
1018
1019 public void notifyObserverOfChanges() {
1020 if (observer == null) {
1021 if (changes != null) changes.clear();
1022 return;
1023 }
1024 if (this.changes.isEmpty()) return;
1025
1026 String userName = context.getSecurityContext() != null ? context.getSecurityContext().getUserName() : null;
1027 if (userName == null) userName = "";
1028 String contextId = context.getId();
1029 String processId = null;
1030 Map<String, String> userData = context.getData();
1031 Changes changes = new Changes(processId, contextId, userName, getSourceName(), getNowInUtc(), this.changes, userData);
1032 observer.notify(changes);
1033
1034 this.changes = null;
1035 }
1036
1037
1038
1039
1040
1041
1042 @Immutable
1043 protected class LocationWithDepth {
1044 protected final Location location;
1045 protected final int depth;
1046
1047 public LocationWithDepth( Location location,
1048 int depth ) {
1049 this.location = location;
1050 this.depth = depth;
1051 }
1052
1053 public Location getLocation() {
1054 return location;
1055 }
1056
1057 public int getDepth() {
1058 return depth;
1059 }
1060
1061 @Override
1062 public int hashCode() {
1063 return location.hashCode();
1064 }
1065
1066 @Override
1067 public String toString() {
1068 return location.toString() + " at depth " + depth;
1069 }
1070 }
1071
1072 }