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.jcr;
25
26 import java.io.InputStream;
27 import java.security.AccessControlException;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashSet;
33 import java.util.Iterator;
34 import java.util.LinkedList;
35 import java.util.List;
36 import java.util.Set;
37 import java.util.UUID;
38 import java.util.regex.Pattern;
39 import javax.jcr.AccessDeniedException;
40 import javax.jcr.InvalidItemStateException;
41 import javax.jcr.Item;
42 import javax.jcr.ItemExistsException;
43 import javax.jcr.ItemNotFoundException;
44 import javax.jcr.ItemVisitor;
45 import javax.jcr.NoSuchWorkspaceException;
46 import javax.jcr.NodeIterator;
47 import javax.jcr.PathNotFoundException;
48 import javax.jcr.Property;
49 import javax.jcr.PropertyIterator;
50 import javax.jcr.PropertyType;
51 import javax.jcr.RepositoryException;
52 import javax.jcr.UnsupportedRepositoryOperationException;
53 import javax.jcr.Value;
54 import javax.jcr.ValueFormatException;
55 import javax.jcr.lock.Lock;
56 import javax.jcr.lock.LockException;
57 import javax.jcr.nodetype.ConstraintViolationException;
58 import javax.jcr.nodetype.NoSuchNodeTypeException;
59 import javax.jcr.nodetype.NodeDefinition;
60 import javax.jcr.nodetype.NodeType;
61 import javax.jcr.nodetype.NodeTypeManager;
62 import javax.jcr.query.Query;
63 import javax.jcr.query.QueryResult;
64 import javax.jcr.version.Version;
65 import javax.jcr.version.VersionException;
66 import javax.jcr.version.VersionHistory;
67 import net.jcip.annotations.Immutable;
68 import org.modeshape.common.i18n.I18n;
69 import org.modeshape.common.util.CheckArg;
70 import org.modeshape.graph.Location;
71 import org.modeshape.graph.connector.RepositorySourceException;
72 import org.modeshape.graph.property.Binary;
73 import org.modeshape.graph.property.DateTime;
74 import org.modeshape.graph.property.Name;
75 import org.modeshape.graph.property.NamespaceRegistry;
76 import org.modeshape.graph.property.Path;
77 import org.modeshape.graph.property.PathFactory;
78 import org.modeshape.graph.property.ValueFactories;
79 import org.modeshape.graph.query.QueryBuilder;
80 import org.modeshape.graph.query.model.QueryCommand;
81 import org.modeshape.graph.session.GraphSession.Node;
82 import org.modeshape.graph.session.GraphSession.NodeId;
83 import org.modeshape.graph.session.GraphSession.PropertyInfo;
84 import org.modeshape.jcr.SessionCache.JcrNodePayload;
85 import org.modeshape.jcr.SessionCache.JcrPropertyPayload;
86 import org.modeshape.jcr.SessionCache.NodeEditor;
87
88
89
90
91
92
93 @Immutable
94 abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node {
95
96 private static final NodeType[] EMPTY_NODE_TYPES = new NodeType[] {};
97
98 protected final NodeId nodeId;
99 protected final Location location;
100
101 AbstractJcrNode( SessionCache cache,
102 NodeId nodeId,
103 Location location ) {
104 super(cache);
105 this.nodeId = nodeId;
106 this.location = location;
107 }
108
109 abstract boolean isRoot();
110
111 public abstract AbstractJcrNode getParent() throws ItemNotFoundException, RepositoryException;
112
113 final NodeId internalId() {
114 return nodeId;
115 }
116
117 final Name name() throws RepositoryException {
118 return nodeInfo().getName();
119 }
120
121 final Path.Segment segment() throws RepositoryException {
122 return nodeInfo().getSegment();
123 }
124
125 final Node<JcrNodePayload, JcrPropertyPayload> nodeInfo()
126 throws ItemNotFoundException, AccessDeniedException, RepositoryException {
127 return cache.findNode(nodeId, location.getPath());
128 }
129
130 final NodeEditor editorForParent() throws RepositoryException {
131 try {
132 Node<JcrNodePayload, JcrPropertyPayload> parent = nodeInfo().getParent();
133 return cache.getEditorFor(parent);
134 } catch (ItemNotFoundException err) {
135 String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
136 throw new RepositoryException(msg);
137 } catch (InvalidItemStateException err) {
138 String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
139 throw new RepositoryException(msg);
140 }
141 }
142
143 final NodeEditor editor() throws RepositoryException {
144 try {
145 return cache.getEditorFor(nodeId, location.getPath());
146 } catch (ItemNotFoundException err) {
147 String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
148 throw new RepositoryException(msg);
149 } catch (InvalidItemStateException err) {
150 String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
151 throw new RepositoryException(msg);
152 }
153 }
154
155 final JcrValue valueFrom( int propertyType,
156 Object value ) {
157 return new JcrValue(cache.factories(), cache, propertyType, value);
158 }
159
160 final JcrValue valueFrom( Calendar value ) {
161 ValueFactories factories = cache.factories();
162 DateTime dateTime = factories.getDateFactory().create(value);
163 return new JcrValue(factories, cache, PropertyType.DATE, dateTime);
164 }
165
166 final JcrValue valueFrom( InputStream value ) {
167 ValueFactories factories = cache.factories();
168 Binary binary = factories.getBinaryFactory().create(value);
169 return new JcrValue(factories, cache, PropertyType.DATE, binary);
170 }
171
172 final JcrValue valueFrom( javax.jcr.Node value ) throws UnsupportedRepositoryOperationException, RepositoryException {
173 ValueFactories factories = cache.factories();
174 String uuid = factories.getStringFactory().create(value.getUUID());
175 return new JcrValue(factories, cache, PropertyType.REFERENCE, uuid);
176 }
177
178 final JcrValue[] valuesFrom( int propertyType,
179 Object[] values ) {
180
181
182
183 int len = values.length;
184 ValueFactories factories = cache.factories();
185 List<JcrValue> results = new ArrayList<JcrValue>(len);
186 for (int i = 0; i != len; ++i) {
187 if (values[i] != null) results.add(new JcrValue(factories, cache, propertyType, values[i]));
188 }
189 return results.toArray(new JcrValue[results.size()]);
190 }
191
192 @Override
193 Path path() throws RepositoryException {
194
195 return nodeInfo().getPath();
196 }
197
198 boolean isReferenceable() throws RepositoryException {
199 return isNodeType(JcrMixLexicon.REFERENCEABLE);
200 }
201
202
203
204
205
206
207 public String getUUID() throws RepositoryException {
208
209 if (!isReferenceable()) {
210 throw new UnsupportedRepositoryOperationException(JcrI18n.nodeNotReferenceable.text());
211 }
212 PropertyInfo<JcrPropertyPayload> uuidProp = nodeInfo().getProperty(JcrLexicon.UUID);
213 if (uuidProp == null) {
214 uuidProp = nodeInfo().getProperty(ModeShapeLexicon.UUID);
215 }
216 assert uuidProp != null;
217 assert !uuidProp.getProperty().isEmpty();
218 return context().getValueFactories().getStringFactory().create(uuidProp.getProperty().getFirstValue());
219 }
220
221
222
223
224
225
226
227 public final boolean isNode() {
228 return true;
229 }
230
231
232
233
234
235
236
237 public boolean isNodeType( String nodeTypeName ) throws RepositoryException {
238 return isNodeType(nameFrom(nodeTypeName));
239 }
240
241
242
243
244
245
246
247
248
249
250 public final boolean isNodeType( Name nodeTypeName ) throws RepositoryException {
251 return cache.isNodeType(nodeInfo(), nodeTypeName);
252 }
253
254
255
256
257
258
259 public NodeDefinition getDefinition() throws RepositoryException {
260 NodeDefinitionId definitionId = nodeInfo().getPayload().getDefinitionId();
261 return session().nodeTypeManager().getNodeDefinition(definitionId);
262 }
263
264
265
266
267
268
269 public JcrNodeType getPrimaryNodeType() throws RepositoryException {
270 return session().nodeTypeManager().getNodeType(getPrimaryTypeName());
271 }
272
273 Name getPrimaryTypeName() throws RepositoryException {
274 return nodeInfo().getPayload().getPrimaryTypeName();
275 }
276
277
278
279
280
281
282 public NodeType[] getMixinNodeTypes() throws RepositoryException {
283 NodeTypeManager nodeTypeManager = session().nodeTypeManager();
284 Property mixinTypesProperty = getProperty(JcrLexicon.MIXIN_TYPES);
285 if (mixinTypesProperty == null) return EMPTY_NODE_TYPES;
286 List<NodeType> mixinNodeTypes = new LinkedList<NodeType>();
287 for (Value value : mixinTypesProperty.getValues()) {
288 String nodeTypeName = value.getString();
289 NodeType nodeType = nodeTypeManager.getNodeType(nodeTypeName);
290 if (nodeType != null) mixinNodeTypes.add(nodeType);
291 }
292 return mixinNodeTypes.toArray(new NodeType[mixinNodeTypes.size()]);
293 }
294
295 List<Name> getMixinTypeNames() throws RepositoryException {
296 return nodeInfo().getPayload().getMixinTypeNames();
297 }
298
299
300
301
302
303
304 public final Item getPrimaryItem() throws RepositoryException {
305
306 NodeType primaryType = getPrimaryNodeType();
307 String primaryItemNameString = primaryType.getPrimaryItemName();
308 if (primaryItemNameString == null) {
309 I18n msg = JcrI18n.noPrimaryItemNameDefinedOnPrimaryType;
310 throw new ItemNotFoundException(msg.text(primaryType.getName(), getPath(), cache.workspaceName()));
311 }
312 try {
313 Path primaryItemPath = context().getValueFactories().getPathFactory().create(primaryItemNameString);
314 if (primaryItemPath.size() != 1 || primaryItemPath.isAbsolute()) {
315 I18n msg = JcrI18n.primaryItemNameForPrimaryTypeIsNotValid;
316 throw new ItemNotFoundException(msg.text(primaryType.getName(),
317 primaryItemNameString,
318 getPath(),
319 cache.workspaceName()));
320 }
321 return cache.findJcrItem(nodeId, location.getPath(), primaryItemPath);
322 } catch (ValueFormatException error) {
323 I18n msg = JcrI18n.primaryItemNameForPrimaryTypeIsNotValid;
324 throw new ItemNotFoundException(msg.text(primaryType.getName(),
325 primaryItemNameString,
326 getPath(),
327 cache.workspaceName()));
328 } catch (PathNotFoundException error) {
329 I18n msg = JcrI18n.primaryItemDoesNotExist;
330 throw new ItemNotFoundException(msg.text(primaryType.getName(),
331 primaryItemNameString,
332 getPath(),
333 cache.workspaceName()));
334 }
335 }
336
337
338
339
340
341
342
343 @Override
344 public boolean isSame( Item otherItem ) throws RepositoryException {
345 CheckArg.isNotNull(otherItem, "otherItem");
346 if (super.isSame(otherItem) && otherItem instanceof javax.jcr.Node) {
347 if (otherItem instanceof AbstractJcrNode) {
348 AbstractJcrNode that = (AbstractJcrNode)otherItem;
349 if (this.isReferenceable() && that.isReferenceable()) {
350
351 return getUUID().equals(((AbstractJcrNode)otherItem).getUUID());
352 }
353
354
355
356
357
358
359 CorrespondenceId thisId = this.getCorrespondenceId();
360 CorrespondenceId thatId = that.getCorrespondenceId();
361 return thisId.equals(thatId);
362 }
363
364 return otherItem.isSame(this);
365 }
366 return false;
367 }
368
369 protected CorrespondenceId getCorrespondenceId() throws RepositoryException {
370 if (this.isReferenceable()) return new CorrespondenceId(getUUID());
371 assert !this.isRoot();
372
373
374 Path currentPath = path();
375 AbstractJcrNode node = this.getParent();
376 int beginIndex = currentPath.size() - 1;
377 while (!node.isRoot() && !node.isReferenceable()) {
378 node = node.getParent();
379 --beginIndex;
380 }
381
382 Path relativePath = currentPath.relativeTo(node.path());
383 assert !relativePath.isAbsolute();
384 return new CorrespondenceId(node.getUUID(), relativePath);
385 }
386
387
388
389
390
391
392 public final boolean hasProperties() throws RepositoryException {
393 return nodeInfo().getPropertyCount() > 0;
394 }
395
396
397
398
399
400
401
402 public final boolean hasProperty( String relativePath ) throws RepositoryException {
403 CheckArg.isNotEmpty(relativePath, "relativePath");
404 if (relativePath.indexOf('/') >= 0) {
405 try {
406 getProperty(relativePath);
407 return true;
408 } catch (PathNotFoundException e) {
409 return false;
410 }
411 }
412 if (relativePath.equals(".")) return false;
413 if (relativePath.equals("..")) return false;
414
415 return nodeInfo().getProperty(nameFrom(relativePath)) != null;
416 }
417
418 public final boolean hasProperty( Name name ) throws RepositoryException {
419 return nodeInfo().getProperty(name) != null;
420 }
421
422
423
424
425
426
427 public final PropertyIterator getProperties() throws RepositoryException {
428 return new JcrPropertyIterator(cache.findJcrPropertiesFor(nodeId, location.getPath()));
429 }
430
431
432
433
434
435
436 public PropertyIterator getProperties( String namePattern ) throws RepositoryException {
437 CheckArg.isNotNull(namePattern, "namePattern");
438 namePattern = namePattern.trim();
439 if (namePattern.length() == 0) return new JcrEmptyPropertyIterator();
440 Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(nodeId, location.getPath());
441 if ("*".equals(namePattern)) return new JcrPropertyIterator(properties);
442
443
444 List<Object> patterns = createPatternsFor(namePattern);
445
446
447 boolean foundMatch = true;
448 Collection<AbstractJcrProperty> matchingProperties = new LinkedList<AbstractJcrProperty>();
449 Iterator<AbstractJcrProperty> iter = properties.iterator();
450 while (iter.hasNext()) {
451 AbstractJcrProperty property = iter.next();
452 String propName = property.getName();
453 assert foundMatch == true;
454 for (Object patternOrMatch : patterns) {
455 if (patternOrMatch instanceof Pattern) {
456 Pattern pattern = (Pattern)patternOrMatch;
457 if (pattern.matcher(propName).matches()) break;
458 } else {
459 String match = (String)patternOrMatch;
460 if (propName.equals(match)) break;
461 }
462
463 foundMatch = false;
464 }
465 if (foundMatch) {
466 matchingProperties.add(property);
467 } else {
468 foundMatch = true;
469 }
470 }
471 return new JcrPropertyIterator(matchingProperties);
472 }
473
474
475
476
477
478
479
480
481
482 protected final NodeIterator referencingNodes( int maxNumberOfNodes ) throws RepositoryException {
483 if (!this.isReferenceable()) {
484 return new JcrEmptyNodeIterator();
485 }
486 if (maxNumberOfNodes < 0) maxNumberOfNodes = Integer.MAX_VALUE;
487
488
489 String uuid = getUUID();
490 QueryBuilder builder = new QueryBuilder(context().getValueFactories().getTypeSystem());
491 QueryCommand query = builder.select("jcr:primaryType")
492 .fromAllNodesAs("allNodes")
493 .where()
494 .referenceValue("allNodes")
495 .isEqualTo(uuid)
496 .end()
497 .limit(maxNumberOfNodes)
498 .query();
499 Query jcrQuery = session().workspace().queryManager().createQuery(query);
500 QueryResult result = jcrQuery.execute();
501 return result.getNodes();
502 }
503
504
505
506
507
508
509
510 protected final boolean hasIncomingReferences() throws RepositoryException {
511 return referencingNodes(1).hasNext();
512 }
513
514
515
516
517
518
519 public final PropertyIterator getReferences() throws RepositoryException {
520 if (!this.isReferenceable()) {
521
522 return new JcrEmptyPropertyIterator();
523 }
524 NodeIterator iter = referencingNodes(Integer.MAX_VALUE);
525 if (!iter.hasNext()) {
526 return new JcrEmptyPropertyIterator();
527 }
528 String uuid = getUUID();
529 List<Property> references = new LinkedList<Property>();
530 while (iter.hasNext()) {
531 javax.jcr.Node node = iter.nextNode();
532
533 PropertyIterator propIter = node.getProperties();
534 while (propIter.hasNext()) {
535 Property prop = propIter.nextProperty();
536
537 int propType = prop.getDefinition().getRequiredType();
538 if (propType == PropertyType.REFERENCE || propType == PropertyType.UNDEFINED || propType == PropertyType.STRING) {
539 if (prop.getDefinition().isMultiple()) {
540 for (Value value : prop.getValues()) {
541 if (uuid.equals(value.getString())) {
542 references.add(prop);
543 break;
544 }
545 }
546 } else {
547 Value value = prop.getValue();
548 if (uuid.equals(value.getString())) {
549 references.add(prop);
550 }
551 }
552 }
553 }
554 }
555
556 if (references.isEmpty()) return new JcrEmptyPropertyIterator();
557 return new JcrPropertyIterator(references);
558 }
559
560
561
562
563
564
565
566
567 public final Property getProperty( Name propertyName ) throws RepositoryException {
568 Property property = cache.findJcrProperty(nodeId, location.getPath(), propertyName);
569
570 if (property != null && JcrLexicon.UUID.equals(propertyName) && !isReferenceable()) return null;
571 return property;
572 }
573
574
575
576
577
578
579
580 public final Property getProperty( String relativePath ) throws RepositoryException {
581 CheckArg.isNotEmpty(relativePath, "relativePath");
582 int indexOfFirstSlash = relativePath.indexOf('/');
583 if (indexOfFirstSlash == 0) {
584
585 throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
586 }
587 Name propertyName = null;
588 if (indexOfFirstSlash != -1) {
589
590 Path path = pathFrom(relativePath).getNormalizedPath();
591 if (path.size() > 1) {
592 try {
593 AbstractJcrItem item = cache.findJcrItem(nodeId, location.getPath(), path);
594 if (item instanceof Property) {
595 return (Property)item;
596 }
597 } catch (ItemNotFoundException e) {
598 I18n msg = JcrI18n.propertyNotFoundAtPathRelativeToReferenceNode;
599 throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
600 }
601 I18n msg = JcrI18n.propertyNotFoundAtPathRelativeToReferenceNode;
602 throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
603 }
604 propertyName = path.getLastSegment().getName();
605 } else {
606 propertyName = nameFrom(relativePath);
607 }
608
609 Property result = getProperty(propertyName);
610 if (result != null) return result;
611 I18n msg = JcrI18n.pathNotFoundRelativeTo;
612 throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
613 }
614
615
616
617
618
619
620
621 public final boolean hasNode( String relativePath ) throws RepositoryException {
622 CheckArg.isNotEmpty(relativePath, "relativePath");
623 if (relativePath.equals(".")) return true;
624 if (relativePath.equals("..")) return isRoot() ? false : true;
625 int indexOfFirstSlash = relativePath.indexOf('/');
626 if (indexOfFirstSlash == 0) {
627
628 throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
629 }
630 if (indexOfFirstSlash != -1) {
631 Path path = pathFrom(relativePath).getNormalizedPath();
632 try {
633 AbstractJcrNode item = cache.findJcrNode(nodeId, location.getPath(), path);
634 return item != null;
635 } catch (PathNotFoundException e) {
636 return false;
637 }
638 }
639
640 try {
641 Path.Segment segment = segmentFrom(relativePath);
642 return nodeInfo().getChild(segment) != null;
643 } catch (org.modeshape.graph.property.PathNotFoundException e) {
644 return false;
645 }
646 }
647
648
649
650
651
652
653 public final boolean hasNodes() throws RepositoryException {
654 return nodeInfo().getChildrenCount() > 0;
655 }
656
657
658
659
660
661
662
663 public final javax.jcr.Node getNode( String relativePath ) throws RepositoryException {
664 CheckArg.isNotEmpty(relativePath, "relativePath");
665 if (relativePath.equals(".")) return this;
666 if (relativePath.equals("..")) return this.getParent();
667 int indexOfFirstSlash = relativePath.indexOf('/');
668 if (indexOfFirstSlash == 0) {
669
670 throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
671 }
672 Path.Segment segment = null;
673 if (indexOfFirstSlash != -1) {
674
675 Path path = pathFrom(relativePath).getNormalizedPath();
676 if (path.size() == 1) {
677 if (path.getLastSegment().isSelfReference()) return this;
678 if (path.getLastSegment().isParentReference()) return this.getParent();
679 }
680
681 if (path.size() > 1) {
682 AbstractJcrItem item = cache.findJcrNode(nodeId, location.getPath(), path);
683 if (item instanceof javax.jcr.Node) {
684 return (javax.jcr.Node)item;
685 }
686 I18n msg = JcrI18n.nodeNotFoundAtPathRelativeToReferenceNode;
687 throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
688 }
689 segment = path.getLastSegment();
690 } else {
691 segment = segmentFrom(relativePath);
692 }
693
694 try {
695 return nodeInfo().getChild(segment).getPayload().getJcrNode();
696 } catch (org.modeshape.graph.property.PathNotFoundException e) {
697 String msg = JcrI18n.childNotFoundUnderNode.text(segment, getPath(), cache.workspaceName());
698 throw new PathNotFoundException(msg);
699 } catch (RepositorySourceException e) {
700 throw new RepositoryException(e.getLocalizedMessage(), e);
701 }
702 }
703
704
705
706
707
708
709 public final NodeIterator getNodes() throws RepositoryException {
710 int childCount = nodeInfo().getChildrenCount();
711 if (childCount == 0) {
712 return new JcrEmptyNodeIterator();
713 }
714 List<AbstractJcrNode> matchingChildren = new LinkedList<AbstractJcrNode>();
715 for (Node<JcrNodePayload, JcrPropertyPayload> child : nodeInfo().getChildren()) {
716 matchingChildren.add(child.getPayload().getJcrNode());
717 }
718 return new JcrChildNodeIterator(matchingChildren, childCount);
719 }
720
721
722
723
724
725
726 public NodeIterator getNodes( String namePattern ) throws RepositoryException {
727 CheckArg.isNotNull(namePattern, "namePattern");
728 namePattern = namePattern.trim();
729 if (namePattern.length() == 0) return new JcrEmptyNodeIterator();
730 if ("*".equals(namePattern)) return getNodes();
731 List<Object> patterns = createPatternsFor(namePattern);
732
733
734 List<AbstractJcrNode> matchingChildren = new LinkedList<AbstractJcrNode>();
735 NamespaceRegistry registry = namespaces();
736 boolean foundMatch = false;
737 for (Node<JcrNodePayload, JcrPropertyPayload> child : nodeInfo().getChildren()) {
738 String childName = child.getName().getString(registry);
739 for (Object patternOrMatch : patterns) {
740 if (patternOrMatch instanceof Pattern) {
741 Pattern pattern = (Pattern)patternOrMatch;
742 if (pattern.matcher(childName).matches()) foundMatch = true;
743 } else {
744 String match = (String)patternOrMatch;
745 if (childName.equals(match)) foundMatch = true;
746 }
747 if (foundMatch) {
748 foundMatch = false;
749 matchingChildren.add(child.getPayload().getJcrNode());
750 break;
751 }
752 }
753 }
754 return new JcrChildNodeIterator(matchingChildren, matchingChildren.size());
755 }
756
757
758
759
760
761
762
763 public final void accept( ItemVisitor visitor ) throws RepositoryException {
764 CheckArg.isNotNull(visitor, "visitor");
765 visitor.visit(this);
766 }
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789 public final boolean canAddMixin( String mixinName ) throws NoSuchNodeTypeException, RepositoryException {
790 CheckArg.isNotNull(mixinName, "mixinName");
791 CheckArg.isNotZeroLength(mixinName, "mixinName");
792
793
794
795
796
797
798
799
800 if (JcrMixLexicon.VERSIONABLE.getString(namespaces()).equals(mixinName)) {
801 return false;
802 }
803
804 JcrNodeType mixinCandidateType = cache.nodeTypes().getNodeType(mixinName);
805
806 if (this.isLocked()) {
807 return false;
808 }
809
810 if (this.getDefinition().isProtected()) {
811 return false;
812 }
813
814
815
816
817
818 NodeType primaryType = this.getPrimaryNodeType();
819 NodeType[] mixinTypes = this.getMixinNodeTypes();
820
821 if (!mixinCandidateType.isMixin()) {
822 return false;
823 }
824
825 if (mixinCandidateType.conflictsWith(primaryType, mixinTypes)) {
826 return false;
827 }
828
829
830
831
832 for (JcrPropertyDefinition propertyDefinition : mixinCandidateType.propertyDefinitions()) {
833 if (!hasProperty(propertyDefinition.getInternalName())) continue;
834 AbstractJcrProperty existingProp = cache.findJcrProperty(nodeId,
835 location.getPath(),
836 propertyDefinition.getInternalName());
837 if (existingProp != null) {
838 if (propertyDefinition.isMultiple()) {
839 if (!propertyDefinition.canCastToTypeAndSatisfyConstraints(existingProp.getValues())) {
840 return false;
841 }
842 } else {
843 if (!propertyDefinition.canCastToTypeAndSatisfyConstraints(existingProp.getValue())) {
844 return false;
845 }
846 }
847 }
848 }
849
850
851
852
853 Set<Name> mixinChildNodeNames = new HashSet<Name>();
854 for (JcrNodeDefinition nodeDefinition : mixinCandidateType.childNodeDefinitions()) {
855 mixinChildNodeNames.add(nodeDefinition.getInternalName());
856 }
857
858 for (Name nodeName : mixinChildNodeNames) {
859
860 int snsCount = nodeInfo().getChildrenCount(nodeName);
861 for (Node<JcrNodePayload, JcrPropertyPayload> child : nodeInfo().getChildren(nodeName)) {
862 JcrNodeDefinition match = this.cache.nodeTypes().findChildNodeDefinition(mixinCandidateType.getInternalName(),
863 Collections.<Name>emptyList(),
864 nodeName,
865 child.getPayload().getPrimaryTypeName(),
866 snsCount,
867 false);
868
869 if (match == null) {
870 return false;
871 }
872 }
873
874 }
875
876 return true;
877 }
878
879
880
881
882
883
884
885
886
887
888
889
890
891 public final void addMixin( String mixinName ) throws RepositoryException {
892 CheckArg.isNotNull(mixinName, "mixinName");
893 CheckArg.isNotZeroLength(mixinName, "mixinName");
894
895 JcrNodeType mixinCandidateType = cache.nodeTypes().getNodeType(mixinName);
896
897
898 if (this.isLocked() && !holdsLock()) {
899 throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
900 }
901
902 if (!canAddMixin(mixinName)) {
903 throw new ConstraintViolationException(JcrI18n.cannotAddMixin.text(mixinName));
904 }
905
906 this.editor().addMixin(mixinCandidateType);
907 }
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925 public final void removeMixin( String mixinName ) throws RepositoryException {
926
927 if (this.isLocked() && !holdsLock()) {
928 throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
929 }
930
931
932
933
934 Property existingMixinProperty = getProperty(JcrLexicon.MIXIN_TYPES);
935
936 if (existingMixinProperty == null) {
937 throw new NoSuchNodeTypeException(JcrI18n.invalidMixinTypeForNode.text(mixinName, getPath()));
938 }
939
940 Value[] existingMixinValues = existingMixinProperty.getValues();
941
942 if (existingMixinValues.length == 0) {
943 throw new NoSuchNodeTypeException(JcrI18n.invalidMixinTypeForNode.text(mixinName, getPath()));
944 }
945
946
947
948
949
950 int newMixinValuesCount = existingMixinValues.length - 1;
951 Value[] newMixinValues = new Value[newMixinValuesCount];
952 List<Name> newMixinNames = new ArrayList<Name>(newMixinValuesCount);
953 Name primaryTypeName = getPrimaryNodeType().getInternalName();
954
955 int j = 0;
956 for (int i = 0; i < existingMixinValues.length; i++) {
957 if (!existingMixinValues[i].getString().equals(mixinName)) {
958 if (j < newMixinValuesCount) {
959 newMixinValues[j++] = existingMixinValues[i];
960 newMixinNames.add(cache.nameFactory.create(existingMixinValues[i].getString()));
961 } else {
962 throw new NoSuchNodeTypeException(JcrI18n.invalidMixinTypeForNode.text(mixinName, getPath()));
963 }
964 }
965 }
966
967
968
969
970
971
972 for (PropertyIterator iter = getProperties(); iter.hasNext();) {
973 Property property = iter.nextProperty();
974 if (mixinName.equals(property.getDefinition().getDeclaringNodeType().getName())) {
975 JcrPropertyDefinition match;
976
977
978
979 if (property.getDefinition().isMultiple()) {
980 match = cache.nodeTypes().findPropertyDefinition(primaryTypeName,
981 newMixinNames,
982 JcrNodeType.RESIDUAL_NAME,
983 property.getValues(),
984 true);
985 } else {
986 match = cache.nodeTypes().findPropertyDefinition(primaryTypeName,
987 newMixinNames,
988 JcrNodeType.RESIDUAL_NAME,
989 property.getValue(),
990 true,
991 true);
992 }
993
994 if (match == null) {
995 throw new ConstraintViolationException(JcrI18n.noDefinition.text("property",
996 property.getName(),
997 getPath(),
998 primaryTypeName,
999 newMixinNames));
1000 }
1001 }
1002 }
1003
1004
1005
1006
1007
1008 for (NodeIterator iter = getNodes(); iter.hasNext();) {
1009 AbstractJcrNode node = (AbstractJcrNode)iter.nextNode();
1010 Name childNodeName = cache.nameFactory.create(node.getName());
1011 int snsCount = node.nodeInfo().getChildrenCount(childNodeName);
1012 if (mixinName.equals(node.getDefinition().getDeclaringNodeType().getName())) {
1013
1014
1015 JcrNodeDefinition match = cache.nodeTypes().findChildNodeDefinition(primaryTypeName,
1016 newMixinNames,
1017 JcrNodeType.RESIDUAL_NAME,
1018 node.getPrimaryNodeType().getInternalName(),
1019 snsCount,
1020 true);
1021
1022 if (match == null) {
1023 throw new ConstraintViolationException(JcrI18n.noDefinition.text("child node",
1024 node.getName(),
1025 getPath(),
1026 primaryTypeName,
1027 newMixinNames));
1028 }
1029 }
1030 }
1031
1032 editor().setProperty(JcrLexicon.MIXIN_TYPES, newMixinValues, PropertyType.NAME, false);
1033 }
1034
1035
1036
1037
1038
1039
1040 public final javax.jcr.Node addNode( String relPath )
1041 throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
1042 RepositoryException {
1043 return addNode(relPath, null, null);
1044 }
1045
1046
1047
1048
1049
1050
1051 public final javax.jcr.Node addNode( String relPath,
1052 String primaryNodeTypeName )
1053 throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
1054 RepositoryException {
1055 return this.addNode(relPath, primaryNodeTypeName, null);
1056 }
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075 final AbstractJcrNode addNode( String relPath,
1076 String primaryNodeTypeName,
1077 UUID desiredUuid )
1078 throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
1079 RepositoryException {
1080
1081 if (isLocked() && !holdsLock()) {
1082 throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
1083 }
1084
1085
1086 NodeEditor editor = null;
1087 Path path = null;
1088 try {
1089 path = cache.pathFactory().create(relPath);
1090 } catch (org.modeshape.graph.property.ValueFormatException e) {
1091 throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
1092 }
1093 if (path.size() == 0) {
1094 throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
1095 }
1096 if (path.getLastSegment().getIndex() > 1 || relPath.endsWith("]")) {
1097 throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
1098 }
1099 if (path.size() > 1) {
1100
1101 Path parentPath = path.getParent();
1102 try {
1103
1104 Node<JcrNodePayload, JcrPropertyPayload> parentOfNewNode = cache.findNode(nodeId, location.getPath(), parentPath);
1105 editor = cache.getEditorFor(parentOfNewNode);
1106 } catch (RepositoryException e) {
1107
1108 try {
1109 Node<JcrNodePayload, JcrPropertyPayload> grandparent;
1110 if (parentPath.size() > 1) {
1111
1112
1113
1114
1115 Path grandparentPath = parentPath.getParent();
1116 assert grandparentPath != null;
1117
1118 grandparent = cache.findNode(nodeId, location.getPath(), grandparentPath);
1119
1120 } else {
1121 grandparent = this.nodeInfo();
1122 }
1123
1124 if (grandparent.getProperty(parentPath.getLastSegment().getName()) != null) {
1125
1126
1127 throw new ConstraintViolationException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
1128 }
1129 } catch (PathNotFoundException e2) {
1130
1131 }
1132
1133
1134 throw e;
1135 }
1136 } else {
1137 assert path.size() == 1;
1138 editor = editor();
1139 }
1140 Name childName = path.getLastSegment().getName();
1141
1142
1143 Name childPrimaryTypeName = null;
1144 if (primaryNodeTypeName != null) {
1145 try {
1146 childPrimaryTypeName = cache.nameFactory().create(primaryNodeTypeName);
1147 } catch (org.modeshape.graph.property.ValueFormatException e) {
1148 throw new RepositoryException(JcrI18n.invalidNodeTypeNameParameter.text(primaryNodeTypeName,
1149 "primaryNodeTypeName"));
1150 }
1151 }
1152
1153
1154 return editor.createChild(childName, desiredUuid, childPrimaryTypeName);
1155 }
1156
1157 protected final Property removeExistingValuedProperty( String name ) throws ConstraintViolationException, RepositoryException {
1158 AbstractJcrProperty property = cache.findJcrProperty(nodeId, location.getPath(), nameFrom(name));
1159 if (property != null) {
1160 property.remove();
1161 return property;
1162 }
1163
1164 throw new RepositoryException(JcrI18n.propertyNotFoundOnNode.text(name, getPath(), cache.workspaceName()));
1165 }
1166
1167
1168
1169
1170
1171
1172 public final Property setProperty( String name,
1173 boolean value )
1174 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1175 return editor().setProperty(nameFrom(name), valueFrom(PropertyType.BOOLEAN, value));
1176 }
1177
1178
1179
1180
1181
1182
1183 public final Property setProperty( String name,
1184 Calendar value )
1185 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1186
1187 if (value == null) {
1188 return removeExistingValuedProperty(name);
1189 }
1190
1191 return editor().setProperty(nameFrom(name), valueFrom(value));
1192 }
1193
1194
1195
1196
1197
1198
1199 public final Property setProperty( String name,
1200 double value )
1201 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1202 return editor().setProperty(nameFrom(name), valueFrom(PropertyType.DOUBLE, value));
1203 }
1204
1205
1206
1207
1208
1209
1210 public final Property setProperty( String name,
1211 InputStream value )
1212 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1213 if (value == null) {
1214 return removeExistingValuedProperty(name);
1215 }
1216
1217 return editor().setProperty(nameFrom(name), valueFrom(value));
1218 }
1219
1220
1221
1222
1223
1224
1225 public final Property setProperty( String name,
1226 long value )
1227 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1228 return editor().setProperty(nameFrom(name), valueFrom(PropertyType.LONG, value));
1229 }
1230
1231
1232
1233
1234
1235
1236 public final Property setProperty( String name,
1237 javax.jcr.Node value )
1238 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1239 if (value == null) {
1240 return removeExistingValuedProperty(name);
1241 }
1242
1243 return editor().setProperty(nameFrom(name), valueFrom(value));
1244 }
1245
1246
1247
1248
1249
1250
1251 public final Property setProperty( String name,
1252 String value )
1253 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1254 if (value == null) {
1255 return removeExistingValuedProperty(name);
1256 }
1257
1258 return editor().setProperty(nameFrom(name), valueFrom(PropertyType.STRING, value));
1259 }
1260
1261
1262
1263
1264
1265
1266 public final Property setProperty( String name,
1267 String value,
1268 int type )
1269 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1270 if (value == null) {
1271 return removeExistingValuedProperty(name);
1272 }
1273
1274 return editor().setProperty(nameFrom(name), valueFrom(type, value));
1275 }
1276
1277
1278
1279
1280
1281
1282 public final Property setProperty( String name,
1283 String[] values )
1284 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1285 if (values == null) {
1286 return removeExistingValuedProperty(name);
1287 }
1288
1289 return editor().setProperty(nameFrom(name), valuesFrom(PropertyType.STRING, values), PropertyType.UNDEFINED);
1290 }
1291
1292
1293
1294
1295
1296
1297 public final Property setProperty( String name,
1298 String[] values,
1299 int type )
1300 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1301 if (values == null) {
1302 return removeExistingValuedProperty(name);
1303 }
1304
1305 return editor().setProperty(nameFrom(name), valuesFrom(type, values), PropertyType.UNDEFINED);
1306 }
1307
1308
1309
1310
1311
1312
1313 public final Property setProperty( String name,
1314 Value value )
1315 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1316 if (value == null) {
1317 return removeExistingValuedProperty(name);
1318 }
1319
1320 return editor().setProperty(nameFrom(name), (JcrValue)value);
1321 }
1322
1323
1324
1325
1326
1327
1328 public final Property setProperty( String name,
1329 Value value,
1330 int type )
1331 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1332 if (value == null) {
1333 return removeExistingValuedProperty(name);
1334 }
1335
1336 return editor().setProperty(nameFrom(name), ((JcrValue)value).asType(type));
1337 }
1338
1339
1340
1341
1342
1343
1344 public final Property setProperty( String name,
1345 Value[] values )
1346 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1347 if (values == null) {
1348
1349 return removeExistingValuedProperty(name);
1350 }
1351
1352 return setProperty(name, values, PropertyType.UNDEFINED);
1353 }
1354
1355
1356
1357
1358
1359
1360 public final Property setProperty( String name,
1361 Value[] values,
1362 int type )
1363 throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
1364 if (values == null) {
1365
1366 return removeExistingValuedProperty(name);
1367 }
1368
1369
1370 return editor().setProperty(nameFrom(name), values, type);
1371 }
1372
1373
1374
1375
1376
1377
1378
1379 public final boolean isCheckedOut() {
1380 return false;
1381 }
1382
1383
1384
1385
1386
1387
1388
1389 public final Version checkin() throws UnsupportedRepositoryOperationException {
1390 throw new UnsupportedRepositoryOperationException();
1391 }
1392
1393
1394
1395
1396
1397
1398
1399 public final void checkout() throws UnsupportedRepositoryOperationException {
1400 throw new UnsupportedRepositoryOperationException();
1401 }
1402
1403
1404
1405
1406
1407
1408
1409 public final boolean holdsLock()
1410 WorkspaceLockManager.ModeShapeLock lock = session().workspace().lockManager().lockFor(session(), this.location);
1411
1412 return lock != null && cache.session().lockTokens().contains(lock.getLockToken());
1413 }
1414
1415
1416
1417
1418
1419
1420
1421 public final boolean isLocked() throws LockException, RepositoryException {
1422 return lock() != null;
1423 }
1424
1425
1426
1427
1428
1429
1430 public final Lock lock( boolean isDeep,
1431 boolean isSessionScoped ) throws LockException, RepositoryException {
1432 if (isLocked()) {
1433 throw new LockException(JcrI18n.alreadyLocked.text(this.location));
1434 }
1435
1436 if (isDeep) {
1437 LinkedList<Node<JcrNodePayload, JcrPropertyPayload>> nodesToVisit = new LinkedList<Node<JcrNodePayload, JcrPropertyPayload>>();
1438 nodesToVisit.add(nodeInfo());
1439
1440 while (!nodesToVisit.isEmpty()) {
1441 Node<JcrNodePayload, JcrPropertyPayload> node = nodesToVisit.remove(nodesToVisit.size() - 1);
1442 if (session().workspace().lockManager().lockFor(session(), node.getLocation()) != null) throw new LockException(
1443 JcrI18n.parentAlreadyLocked.text(this.location,
1444 node.getLocation()));
1445
1446 for (Node<JcrNodePayload, JcrPropertyPayload> child : node.getChildren()) {
1447 nodesToVisit.add(child);
1448 }
1449 }
1450 }
1451
1452 WorkspaceLockManager.ModeShapeLock lock = session().workspace().lockManager().lock(session(),
1453 this.location,
1454 isDeep,
1455 isSessionScoped);
1456
1457 cache.session().addLockToken(lock.getLockToken());
1458 return lock.lockFor(cache);
1459 }
1460
1461
1462
1463
1464
1465
1466 public final void unlock() throws LockException, RepositoryException {
1467 WorkspaceLockManager.ModeShapeLock lock = session().workspace().lockManager().lockFor(session(), this.location);
1468
1469 if (lock == null) {
1470 throw new LockException(JcrI18n.notLocked.text(this.location));
1471 }
1472
1473 if (!session().lockTokens().contains(lock.getLockToken())) {
1474 try {
1475
1476 session().checkPermission(cache.workspaceName(), null, ModeShapePermissions.UNLOCK_ANY);
1477 } catch (AccessControlException iae) {
1478 throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
1479 }
1480 }
1481
1482 session().workspace().lockManager().unlock(session().getExecutionContext(), lock);
1483 session().removeLockToken(lock.getLockToken());
1484 }
1485
1486 private final WorkspaceLockManager.ModeShapeLock lock() throws RepositoryException {
1487
1488 if (session() == null || session().workspace() == null) return null;
1489
1490 WorkspaceLockManager lockManager = session().workspace().lockManager();
1491 WorkspaceLockManager.ModeShapeLock lock = lockManager.lockFor(session(), this.location);
1492 if (lock != null) return lock;
1493
1494 AbstractJcrNode parent = this;
1495 while (!parent.isRoot()) {
1496 parent = parent.getParent();
1497
1498 WorkspaceLockManager.ModeShapeLock parentLock = lockManager.lockFor(session(), parent.location);
1499 if (parentLock != null && parentLock.isLive()) {
1500 return parentLock.isDeep() ? parentLock : null;
1501 }
1502 }
1503 return null;
1504 }
1505
1506
1507
1508
1509
1510
1511 public final Lock getLock() throws LockException, RepositoryException {
1512 WorkspaceLockManager.ModeShapeLock lock = lock();
1513
1514 if (lock == null) throw new LockException(JcrI18n.notLocked.text(this.location));
1515 return lock.lockFor(cache);
1516 }
1517
1518
1519
1520
1521
1522
1523 public final boolean isModified() {
1524 try {
1525 Node<JcrNodePayload, JcrPropertyPayload> node = nodeInfo();
1526
1527 return !node.isNew() && node.isChanged(true);
1528 } catch (RepositoryException re) {
1529 throw new IllegalStateException(re);
1530 }
1531 }
1532
1533
1534
1535
1536
1537
1538 public final boolean isNew() {
1539 try {
1540 return nodeInfo().isNew();
1541 } catch (RepositoryException re) {
1542 throw new IllegalStateException(re);
1543 }
1544 }
1545
1546
1547
1548
1549
1550
1551
1552 public final NodeIterator merge( String srcWorkspace,
1553 boolean bestEffort ) {
1554 throw new UnsupportedOperationException();
1555 }
1556
1557
1558
1559
1560
1561
1562
1563 public final void cancelMerge( Version version ) {
1564 throw new UnsupportedOperationException();
1565 }
1566
1567
1568
1569
1570
1571
1572
1573 public final void doneMerge( Version version ) {
1574 throw new UnsupportedOperationException();
1575 }
1576
1577
1578
1579
1580
1581
1582 public final String getCorrespondingNodePath( String workspaceName )
1583 throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
1584 CheckArg.isNotNull(workspaceName, "workspace name");
1585 NamespaceRegistry namespaces = this.context().getNamespaceRegistry();
1586 return correspondingNodePath(workspaceName).getString(namespaces);
1587 }
1588
1589 protected final Path correspondingNodePath( String workspaceName )
1590 throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
1591 assert workspaceName != null;
1592 NamespaceRegistry namespaces = this.context().getNamespaceRegistry();
1593
1594
1595 AbstractJcrNode referenceableRoot = this;
1596 while (!referenceableRoot.isNodeType(JcrMixLexicon.REFERENCEABLE.getString(namespaces))) {
1597 referenceableRoot = referenceableRoot.getParent();
1598 }
1599
1600
1601 Path relativePath = path().equals(referenceableRoot.path()) ? null : path().relativeTo(referenceableRoot.path());
1602 UUID uuid = UUID.fromString(referenceableRoot.getUUID());
1603 return this.cache.getPathForCorrespondingNode(workspaceName, uuid, relativePath);
1604 }
1605
1606
1607
1608
1609
1610
1611 public final void update( String srcWorkspaceName ) throws NoSuchWorkspaceException, RepositoryException {
1612 CheckArg.isNotNull(srcWorkspaceName, "workspace name");
1613
1614 if (session().hasPendingChanges()) {
1615 throw new InvalidItemStateException(JcrI18n.noPendingChangesAllowed.text());
1616 }
1617
1618 Path correspondingPath = null;
1619 try {
1620 correspondingPath = correspondingNodePath(srcWorkspaceName);
1621 } catch (ItemNotFoundException infe) {
1622 return;
1623 }
1624
1625
1626 cache.graphSession().immediateClone(correspondingPath, srcWorkspaceName, path(), true, true);
1627
1628 session().refresh(false);
1629 }
1630
1631
1632
1633
1634
1635
1636
1637 public final VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException {
1638 throw new UnsupportedRepositoryOperationException();
1639 }
1640
1641
1642
1643
1644
1645
1646
1647 public final Version getBaseVersion() throws UnsupportedRepositoryOperationException {
1648 throw new UnsupportedRepositoryOperationException();
1649 }
1650
1651
1652
1653
1654
1655
1656
1657 public final void restore( String versionName,
1658 boolean removeExisting ) throws UnsupportedRepositoryOperationException {
1659 throw new UnsupportedRepositoryOperationException();
1660 }
1661
1662
1663
1664
1665
1666
1667
1668 public final void restore( Version version,
1669 boolean removeExisting ) throws UnsupportedRepositoryOperationException {
1670 throw new UnsupportedRepositoryOperationException();
1671 }
1672
1673
1674
1675
1676
1677
1678
1679 public final void restore( Version version,
1680 String relPath,
1681 boolean removeExisting ) throws UnsupportedRepositoryOperationException {
1682 throw new UnsupportedRepositoryOperationException();
1683 }
1684
1685
1686
1687
1688
1689
1690
1691 public final void restoreByLabel( String versionLabel,
1692 boolean removeExisting ) throws UnsupportedRepositoryOperationException {
1693 throw new UnsupportedRepositoryOperationException();
1694 }
1695
1696
1697
1698
1699
1700
1701
1702 public final void orderBefore( String srcChildRelPath,
1703 String destChildRelPath ) throws UnsupportedRepositoryOperationException, RepositoryException {
1704
1705 if (!getPrimaryNodeType().hasOrderableChildNodes()) {
1706 throw new UnsupportedRepositoryOperationException(
1707 JcrI18n.notOrderable.text(getPrimaryNodeType().getName(), getPath()));
1708 }
1709
1710 PathFactory pathFactory = this.cache.pathFactory();
1711 Path srcPath = pathFactory.create(srcChildRelPath);
1712 if (srcPath.isAbsolute() || srcPath.size() != 1) {
1713 throw new ItemNotFoundException(JcrI18n.pathNotFound.text(srcPath.getString(cache.context().getNamespaceRegistry()),
1714 cache.session().workspace().getName()));
1715 }
1716
1717 Path.Segment sourceSegment = srcPath.getLastSegment();
1718 try {
1719 nodeInfo().getChild(sourceSegment);
1720 } catch (org.modeshape.graph.property.PathNotFoundException e) {
1721 String workspaceName = this.cache.session().getWorkspace().getName();
1722 throw new ItemNotFoundException(JcrI18n.pathNotFound.text(srcPath, workspaceName));
1723 }
1724
1725 Path.Segment destSegment = null;
1726
1727 if (destChildRelPath != null) {
1728 Path destPath = pathFactory.create(destChildRelPath);
1729 if (destPath.isAbsolute() || destPath.size() != 1) {
1730 throw new ItemNotFoundException(JcrI18n.pathNotFound.text(destPath.getString(cache.context()
1731 .getNamespaceRegistry()),
1732 cache.session().workspace().getName()));
1733 }
1734
1735 destSegment = destPath.getLastSegment();
1736
1737
1738 try {
1739 nodeInfo().getChild(destSegment);
1740 } catch (org.modeshape.graph.property.PathNotFoundException e) {
1741 String workspaceName = this.cache.session().getWorkspace().getName();
1742 throw new ItemNotFoundException(JcrI18n.pathNotFound.text(destPath, workspaceName));
1743 }
1744 }
1745
1746 this.editor().orderChildBefore(sourceSegment, destSegment);
1747 }
1748
1749 protected static List<Object> createPatternsFor( String namePattern ) throws RepositoryException {
1750 List<Object> patterns = new LinkedList<Object>();
1751 for (String stringPattern : namePattern.split("[|]")) {
1752 stringPattern = stringPattern.trim();
1753 int length = stringPattern.length();
1754 if (length == 0) continue;
1755 if (stringPattern.indexOf("*") == -1) {
1756
1757 patterns.add(stringPattern);
1758 } else {
1759
1760 StringBuilder sb = new StringBuilder(length);
1761 for (int i = 0; i != length; i++) {
1762 char c = stringPattern.charAt(i);
1763 switch (c) {
1764
1765 case '/':
1766 case '[':
1767 case ']':
1768 case '\'':
1769 case '"':
1770 case '|':
1771 case '\t':
1772 case '\n':
1773 case '\r':
1774 String msg = JcrI18n.invalidNamePattern.text(c, namePattern);
1775 throw new RepositoryException(msg);
1776
1777 case '?':
1778 case '(':
1779 case ')':
1780 case '$':
1781 case '^':
1782 case '.':
1783 case '{':
1784 case '}':
1785 case '\\':
1786 sb.append("\\");
1787 sb.append(c);
1788 break;
1789 case '*':
1790
1791 sb.append(".*");
1792 break;
1793 default:
1794 sb.append(c);
1795 break;
1796 }
1797 }
1798 String escapedString = sb.toString();
1799 Pattern pattern = Pattern.compile(escapedString);
1800 patterns.add(pattern);
1801 }
1802 }
1803 return patterns;
1804 }
1805
1806
1807
1808
1809
1810
1811 public void refresh( boolean keepChanges ) throws RepositoryException {
1812 this.cache.refresh(this.nodeId, location.getPath(), keepChanges);
1813 }
1814
1815
1816
1817
1818
1819
1820 public void save() throws RepositoryException {
1821 session().checkReferentialIntegrityOfChanges();
1822 cache.save(nodeId, location.getPath());
1823 }
1824
1825 @Override
1826 public String toString() {
1827
1828 try {
1829 PropertyIterator iter = this.getProperties();
1830 StringBuffer propertyBuff = new StringBuffer();
1831 while (iter.hasNext()) {
1832 AbstractJcrProperty prop = (AbstractJcrProperty)iter.nextProperty();
1833 propertyBuff.append(prop).append(", ");
1834 }
1835 return this.getPath() + " {" + propertyBuff.toString() + "}";
1836 } catch (RepositoryException re) {
1837 return re.getMessage();
1838 }
1839 }
1840
1841
1842
1843
1844
1845
1846 @Override
1847 public boolean equals( Object obj ) {
1848 if (obj == this) return true;
1849 if (obj instanceof AbstractJcrNode) {
1850 AbstractJcrNode that = (AbstractJcrNode)obj;
1851 if (this.cache != that.cache) return false;
1852 return this.location.equals(that.location);
1853 }
1854 return false;
1855 }
1856 }