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.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.LinkedList;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import java.util.concurrent.locks.ReadWriteLock;
37 import java.util.concurrent.locks.ReentrantReadWriteLock;
38 import javax.jcr.PropertyType;
39 import javax.jcr.RepositoryException;
40 import javax.jcr.UnsupportedRepositoryOperationException;
41 import javax.jcr.Value;
42 import javax.jcr.ValueFormatException;
43 import javax.jcr.nodetype.NoSuchNodeTypeException;
44 import javax.jcr.nodetype.NodeDefinition;
45 import javax.jcr.nodetype.NodeType;
46 import javax.jcr.nodetype.NodeTypeDefinition;
47 import javax.jcr.nodetype.PropertyDefinition;
48 import javax.jcr.query.InvalidQueryException;
49 import javax.jcr.version.OnParentVersionAction;
50 import net.jcip.annotations.GuardedBy;
51 import net.jcip.annotations.ThreadSafe;
52 import org.modeshape.common.collection.Problems;
53 import org.modeshape.common.i18n.I18n;
54 import org.modeshape.common.text.TextEncoder;
55 import org.modeshape.common.text.XmlNameEncoder;
56 import org.modeshape.common.util.CheckArg;
57 import org.modeshape.common.util.Logger;
58 import org.modeshape.graph.ExecutionContext;
59 import org.modeshape.graph.Graph;
60 import org.modeshape.graph.Location;
61 import org.modeshape.graph.Subgraph;
62 import org.modeshape.graph.observe.Changes;
63 import org.modeshape.graph.property.Name;
64 import org.modeshape.graph.property.NameFactory;
65 import org.modeshape.graph.property.Path;
66 import org.modeshape.graph.property.PathFactory;
67 import org.modeshape.graph.property.PathNotFoundException;
68 import org.modeshape.graph.property.Property;
69 import org.modeshape.graph.property.PropertyFactory;
70 import org.modeshape.graph.query.QueryResults;
71 import org.modeshape.graph.query.model.QueryCommand;
72 import org.modeshape.graph.query.model.TypeSystem;
73 import org.modeshape.graph.query.parse.QueryParser;
74 import org.modeshape.graph.query.parse.SqlQueryParser;
75 import org.modeshape.graph.query.validate.Schemata;
76 import org.modeshape.graph.request.ChangeRequest;
77 import org.modeshape.jcr.nodetype.InvalidNodeTypeDefinitionException;
78 import org.modeshape.jcr.nodetype.NodeTypeExistsException;
79
80
81
82
83
84
85
86
87
88
89
90
91
92 @ThreadSafe
93 class RepositoryNodeTypeManager implements JcrSystemObserver {
94 private static final Logger LOGGER = Logger.getLogger(RepositoryNodeTypeManager.class);
95
96 private static final TextEncoder NAME_ENCODER = new XmlNameEncoder();
97
98 private final JcrRepository repository;
99 private final QueryParser queryParser;
100 private final ExecutionContext context;
101 private final Path nodeTypesPath;
102
103 @GuardedBy( "nodeTypeManagerLock" )
104 private final Map<Name, JcrNodeType> nodeTypes;
105 @GuardedBy( "nodeTypeManagerLock" )
106 private final Map<PropertyDefinitionId, JcrPropertyDefinition> propertyDefinitions;
107 @GuardedBy( "nodeTypeManagerLock" )
108 private final Map<NodeDefinitionId, JcrNodeDefinition> childNodeDefinitions;
109 @GuardedBy( "nodeTypeManagerLock" )
110 private NodeTypeSchemata schemata;
111 private final PropertyFactory propertyFactory;
112 private final PathFactory pathFactory;
113 private final NameFactory nameFactory;
114 private final ReadWriteLock nodeTypeManagerLock = new ReentrantReadWriteLock();
115 private final boolean includeColumnsForInheritedProperties;
116 private final boolean includePseudoColumnsInSelectStar;
117
118
119
120
121
122
123 private enum PropertyCardinality {
124 SINGLE_VALUED_ONLY,
125 MULTI_VALUED_ONLY,
126 ANY
127 }
128
129
130
131
132
133
134 private enum NodeCardinality {
135 NO_SAME_NAME_SIBLINGS,
136 SAME_NAME_SIBLINGS,
137 ANY
138 }
139
140 RepositoryNodeTypeManager( JcrRepository repository,
141 Path nodeTypesPath,
142 boolean includeColumnsForInheritedProperties,
143 boolean includePseudoColumnsInSelectStar ) {
144 this.repository = repository;
145 this.nodeTypesPath = nodeTypesPath;
146 this.context = repository.getExecutionContext();
147 this.includeColumnsForInheritedProperties = includeColumnsForInheritedProperties;
148 this.includePseudoColumnsInSelectStar = includePseudoColumnsInSelectStar;
149 this.propertyFactory = context.getPropertyFactory();
150 this.pathFactory = context.getValueFactories().getPathFactory();
151 this.nameFactory = context.getValueFactories().getNameFactory();
152
153 propertyDefinitions = new HashMap<PropertyDefinitionId, JcrPropertyDefinition>();
154 childNodeDefinitions = new HashMap<NodeDefinitionId, JcrNodeDefinition>();
155 nodeTypes = new HashMap<Name, JcrNodeType>(50);
156 queryParser = new SqlQueryParser();
157
158 if (nodeTypesPath != null) {
159 Graph systemGraph = repository.createSystemGraph(context);
160 try {
161 systemGraph.getNodeAt(nodeTypesPath);
162 } catch (PathNotFoundException pnfe) {
163 systemGraph.create(nodeTypesPath).with(JcrLexicon.PRIMARY_TYPE, ModeShapeLexicon.NODE_TYPES).and();
164 }
165 }
166 }
167
168
169
170
171
172
173 public Collection<JcrNodeType> getAllNodeTypes() {
174 try {
175 nodeTypeManagerLock.readLock().lock();
176 return Collections.unmodifiableCollection(new ArrayList<JcrNodeType>(nodeTypes.values()));
177 } finally {
178 nodeTypeManagerLock.readLock().unlock();
179 }
180 }
181
182
183
184
185
186
187
188 public Collection<JcrNodeType> getMixinNodeTypes() {
189 try {
190 nodeTypeManagerLock.readLock().lock();
191
192 List<JcrNodeType> types = new ArrayList<JcrNodeType>(nodeTypes.size());
193
194 for (JcrNodeType nodeType : nodeTypes.values()) {
195 if (nodeType.isMixin()) types.add(nodeType);
196 }
197
198 return types;
199 } finally {
200 nodeTypeManagerLock.readLock().unlock();
201 }
202 }
203
204
205
206
207
208
209
210 public Collection<JcrNodeType> getPrimaryNodeTypes() {
211 try {
212 nodeTypeManagerLock.readLock().lock();
213 List<JcrNodeType> types = new ArrayList<JcrNodeType>(nodeTypes.size());
214
215 for (JcrNodeType nodeType : nodeTypes.values()) {
216 if (!nodeType.isMixin()) types.add(nodeType);
217 }
218
219 return types;
220 } finally {
221 nodeTypeManagerLock.readLock().unlock();
222 }
223 }
224
225 public JcrPropertyDefinition getPropertyDefinition( PropertyDefinitionId id ) {
226 try {
227 nodeTypeManagerLock.readLock().lock();
228 return propertyDefinitions.get(id);
229 } finally {
230 nodeTypeManagerLock.readLock().unlock();
231 }
232 }
233
234 public JcrNodeDefinition getChildNodeDefinition( NodeDefinitionId id ) {
235 try {
236 nodeTypeManagerLock.readLock().lock();
237 return childNodeDefinitions.get(id);
238 } finally {
239 nodeTypeManagerLock.readLock().unlock();
240 }
241 }
242
243 NodeTypeSchemata getRepositorySchemata() {
244 try {
245 nodeTypeManagerLock.writeLock().lock();
246 if (schemata == null) {
247 schemata = new NodeTypeSchemata(context, nodeTypes, propertyDefinitions.values(),
248 includeColumnsForInheritedProperties, includePseudoColumnsInSelectStar);
249 }
250 return schemata;
251 } finally {
252 nodeTypeManagerLock.writeLock().unlock();
253 }
254 }
255
256 void signalNamespaceChanges() {
257 try {
258 nodeTypeManagerLock.writeLock().lock();
259 schemata = null;
260 } finally {
261 nodeTypeManagerLock.writeLock().unlock();
262 }
263 this.schemata = null;
264 }
265
266 JcrNodeType getNodeType( Name nodeTypeName ) {
267 try {
268 nodeTypeManagerLock.readLock().lock();
269 return nodeTypes.get(nodeTypeName);
270 } finally {
271 nodeTypeManagerLock.readLock().unlock();
272 }
273 }
274
275
276
277
278
279
280
281
282
283
284
285 boolean hasNodeType( Name nodeTypeName ) {
286 try {
287 nodeTypeManagerLock.readLock().lock();
288 return nodeTypes.containsKey(nodeTypeName);
289 } finally {
290 nodeTypeManagerLock.readLock().unlock();
291 }
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339 JcrPropertyDefinition findPropertyDefinition( Name primaryTypeName,
340 List<Name> mixinTypeNames,
341 Name propertyName,
342 Value value,
343 boolean checkMultiValuedDefinitions,
344 boolean skipProtected ) {
345 boolean setToEmpty = value == null;
346
347
348
349
350
351
352
353
354
355 boolean matchedOnName = false;
356
357
358 JcrNodeType primaryType = getNodeType(primaryTypeName);
359 if (primaryType != null) {
360 for (JcrPropertyDefinition definition : primaryType.allSingleValuePropertyDefinitions(propertyName)) {
361 matchedOnName = true;
362
363 if (skipProtected && definition.isProtected()) return null;
364 if (setToEmpty) {
365 if (!definition.isMandatory()) return definition;
366
367 continue;
368 }
369 assert value != null;
370
371 int type = definition.getRequiredType();
372
373 if (type == PropertyType.REFERENCE && type == value.getType()) return definition;
374 if (type == PropertyType.WEAKREFERENCE && type == value.getType()) return definition;
375 if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition;
376 }
377
378 if (matchedOnName) {
379 if (value != null) {
380 for (JcrPropertyDefinition definition : primaryType.allSingleValuePropertyDefinitions(propertyName)) {
381
382 if (skipProtected && definition.isProtected()) return null;
383
384 int type = definition.getRequiredType();
385 if (type == PropertyType.REFERENCE && definition.canCastToType(value)) {
386 return definition;
387 }
388 if (type == PropertyType.WEAKREFERENCE && definition.canCastToType(value)) {
389 return definition;
390 }
391 if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition;
392 }
393 }
394
395 if (checkMultiValuedDefinitions) {
396
397 for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) {
398
399 if (skipProtected && definition.isProtected()) return null;
400 if (setToEmpty) {
401 if (!definition.isMandatory()) return definition;
402
403 continue;
404 }
405 assert value != null;
406
407 int type = definition.getRequiredType();
408
409 if (type == PropertyType.REFERENCE && type == value.getType()) return definition;
410 if (type == PropertyType.WEAKREFERENCE && type == value.getType()) return definition;
411 if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition;
412 }
413 if (value != null) {
414 for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) {
415
416 if (skipProtected && definition.isProtected()) return null;
417 assert definition.getRequiredType() != PropertyType.UNDEFINED;
418
419 int type = definition.getRequiredType();
420 if (type == PropertyType.REFERENCE && definition.canCastToType(value)) {
421 return definition;
422 }
423 if (type == PropertyType.WEAKREFERENCE && definition.canCastToType(value)) {
424 return definition;
425 }
426 if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition;
427 }
428 }
429 }
430 return null;
431 }
432 }
433
434
435 List<JcrNodeType> mixinTypes = null;
436 if (mixinTypeNames != null && !mixinTypeNames.isEmpty()) {
437 mixinTypes = new LinkedList<JcrNodeType>();
438 for (Name mixinTypeName : mixinTypeNames) {
439 JcrNodeType mixinType = getNodeType(mixinTypeName);
440 if (mixinType == null) continue;
441 mixinTypes.add(mixinType);
442 for (JcrPropertyDefinition definition : mixinType.allSingleValuePropertyDefinitions(propertyName)) {
443 matchedOnName = true;
444
445 if (skipProtected && definition.isProtected()) return null;
446 if (setToEmpty) {
447 if (!definition.isMandatory()) return definition;
448
449 continue;
450 }
451 assert value != null;
452
453 int type = definition.getRequiredType();
454
455 if (type == PropertyType.REFERENCE && type == value.getType()) return definition;
456 if (type == PropertyType.WEAKREFERENCE && type == value.getType()) return definition;
457 if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition;
458 }
459 if (matchedOnName) {
460 if (value != null) {
461 for (JcrPropertyDefinition definition : mixinType.allSingleValuePropertyDefinitions(propertyName)) {
462
463 if (skipProtected && definition.isProtected()) return null;
464 assert definition.getRequiredType() != PropertyType.UNDEFINED;
465
466 int type = definition.getRequiredType();
467 if (type == PropertyType.REFERENCE && definition.canCastToType(value)) {
468 return definition;
469 }
470 if (type == PropertyType.WEAKREFERENCE && definition.canCastToType(value)) {
471 return definition;
472 }
473 if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition;
474 }
475 }
476
477 if (checkMultiValuedDefinitions) {
478 for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) {
479
480 if (skipProtected && definition.isProtected()) return null;
481 if (setToEmpty) {
482 if (!definition.isMandatory()) return definition;
483
484 continue;
485 }
486 assert value != null;
487
488 int type = definition.getRequiredType();
489
490 if (type == PropertyType.REFERENCE && type == value.getType()) return definition;
491 if (type == PropertyType.WEAKREFERENCE && type == value.getType()) return definition;
492 if ((type == PropertyType.UNDEFINED || type == value.getType())
493 && definition.satisfiesConstraints(value)) return definition;
494 }
495 if (value != null) {
496 for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) {
497 matchedOnName = true;
498
499 if (skipProtected && definition.isProtected()) return null;
500 assert definition.getRequiredType() != PropertyType.UNDEFINED;
501
502 int type = definition.getRequiredType();
503 if (type == PropertyType.REFERENCE && definition.canCastToType(value)) {
504 return definition;
505 }
506 if (type == PropertyType.WEAKREFERENCE && definition.canCastToType(value)) {
507 return definition;
508 }
509 if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition;
510
511 }
512 }
513 }
514
515 return null;
516 }
517 }
518 }
519
520 if (checkMultiValuedDefinitions) {
521 if (primaryType != null) {
522
523 for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) {
524 matchedOnName = true;
525
526 if (skipProtected && definition.isProtected()) return null;
527 if (setToEmpty) {
528 if (!definition.isMandatory()) return definition;
529
530 continue;
531 }
532 assert value != null;
533
534 int type = definition.getRequiredType();
535
536 if (type == PropertyType.REFERENCE && type == value.getType()) return definition;
537 if (type == PropertyType.WEAKREFERENCE && type == value.getType()) return definition;
538 if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition;
539 }
540 if (value != null) {
541 for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) {
542 matchedOnName = true;
543
544 if (skipProtected && definition.isProtected()) return null;
545 assert definition.getRequiredType() != PropertyType.UNDEFINED;
546
547 int type = definition.getRequiredType();
548 if (type == PropertyType.REFERENCE && definition.canCastToType(value)) {
549 return definition;
550 }
551 if (type == PropertyType.WEAKREFERENCE && definition.canCastToType(value)) {
552 return definition;
553 }
554 if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition;
555 }
556 }
557 }
558
559 if (matchedOnName) return null;
560
561 if (mixinTypeNames != null && !mixinTypeNames.isEmpty()) {
562 mixinTypes = new LinkedList<JcrNodeType>();
563 for (Name mixinTypeName : mixinTypeNames) {
564 JcrNodeType mixinType = getNodeType(mixinTypeName);
565 if (mixinType == null) continue;
566 mixinTypes.add(mixinType);
567 for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) {
568 matchedOnName = true;
569
570 if (skipProtected && definition.isProtected()) return null;
571 if (setToEmpty) {
572 if (!definition.isMandatory()) return definition;
573
574 continue;
575 }
576 assert value != null;
577
578 int type = definition.getRequiredType();
579
580 if (type == PropertyType.REFERENCE && type == value.getType()) return definition;
581 if (type == PropertyType.WEAKREFERENCE && type == value.getType()) return definition;
582 if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition;
583 }
584 if (value != null) {
585 for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) {
586 matchedOnName = true;
587
588 if (skipProtected && definition.isProtected()) return null;
589 assert definition.getRequiredType() != PropertyType.UNDEFINED;
590
591 int type = definition.getRequiredType();
592 if (type == PropertyType.REFERENCE && definition.canCastToType(value)) {
593 return definition;
594 }
595 if (type == PropertyType.WEAKREFERENCE && definition.canCastToType(value)) {
596 return definition;
597 }
598 if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition;
599 }
600 }
601 }
602 }
603 if (matchedOnName) return null;
604
605 }
606
607
608 if (!propertyName.equals(JcrNodeType.RESIDUAL_NAME)) return findPropertyDefinition(primaryTypeName,
609 mixinTypeNames,
610 JcrNodeType.RESIDUAL_NAME,
611 value,
612 checkMultiValuedDefinitions,
613 skipProtected);
614 return null;
615 }
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660 JcrPropertyDefinition findPropertyDefinition( Name primaryTypeName,
661 List<Name> mixinTypeNames,
662 Name propertyName,
663 Value[] values,
664 boolean skipProtected ) {
665 boolean setToEmpty = values == null;
666 int propertyType = values == null || values.length == 0 ? PropertyType.STRING : values[0].getType();
667
668
669
670
671
672
673
674
675
676 boolean matchedOnName = false;
677
678
679 JcrNodeType primaryType = getNodeType(primaryTypeName);
680 if (primaryType != null) {
681 for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) {
682 matchedOnName = true;
683
684 if (skipProtected && definition.isProtected()) return null;
685 if (setToEmpty) {
686 if (!definition.isMandatory()) return definition;
687
688 continue;
689 }
690 assert values != null;
691
692 int type = definition.getRequiredType();
693 boolean typeMatches = values.length == 0 || type == PropertyType.UNDEFINED || type == propertyType;
694
695 if (typeMatches && type == PropertyType.REFERENCE) return definition;
696 if (typeMatches && type == PropertyType.WEAKREFERENCE) return definition;
697 if (typeMatches && definition.satisfiesConstraints(values)) return definition;
698 }
699
700 if (matchedOnName) {
701 if (values != null && values.length != 0) {
702
703
704
705
706 for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) {
707
708 if (skipProtected && definition.isProtected()) return null;
709 assert definition.getRequiredType() != PropertyType.UNDEFINED;
710
711 if (definition.getRequiredType() == PropertyType.REFERENCE && definition.canCastToType(values)) return definition;
712 if (definition.getRequiredType() == PropertyType.WEAKREFERENCE && definition.canCastToType(values)) return definition;
713 if (definition.canCastToTypeAndSatisfyConstraints(values)) return definition;
714 }
715 }
716
717 return null;
718 }
719 }
720
721
722 List<JcrNodeType> mixinTypes = null;
723 if (mixinTypeNames != null && !mixinTypeNames.isEmpty()) {
724 mixinTypes = new LinkedList<JcrNodeType>();
725 for (Name mixinTypeName : mixinTypeNames) {
726 JcrNodeType mixinType = getNodeType(mixinTypeName);
727 if (mixinType == null) continue;
728 mixinTypes.add(mixinType);
729 for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) {
730 matchedOnName = true;
731
732 if (skipProtected && definition.isProtected()) return null;
733 if (setToEmpty) {
734 if (!definition.isMandatory()) return definition;
735
736 continue;
737 }
738 assert values != null;
739
740 int type = definition.getRequiredType();
741 boolean typeMatches = values.length == 0 || type == PropertyType.UNDEFINED || type == propertyType;
742
743 if (typeMatches && type == PropertyType.REFERENCE) return definition;
744 if (typeMatches && type == PropertyType.WEAKREFERENCE) return definition;
745 if (typeMatches && definition.satisfiesConstraints(values)) return definition;
746 }
747 if (matchedOnName) {
748 if (values != null && values.length != 0) {
749
750
751
752
753 for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) {
754
755 if (skipProtected && definition.isProtected()) return null;
756 assert definition.getRequiredType() != PropertyType.UNDEFINED;
757
758 if (definition.getRequiredType() == PropertyType.REFERENCE && definition.canCastToType(values)) return definition;
759 if (definition.getRequiredType() == PropertyType.WEAKREFERENCE && definition.canCastToType(values)) return definition;
760 if (definition.canCastToTypeAndSatisfyConstraints(values)) return definition;
761 }
762 }
763
764 return null;
765 }
766
767 }
768 }
769
770
771 if (!propertyName.equals(JcrNodeType.RESIDUAL_NAME)) return findPropertyDefinition(primaryTypeName,
772 mixinTypeNames,
773 JcrNodeType.RESIDUAL_NAME,
774 values,
775 skipProtected);
776 return null;
777 }
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792 private List<JcrPropertyDefinition> findPropertyDefinitions( List<Name> typeNamesToCheck,
793 Name propertyName,
794 PropertyCardinality typeToCheck,
795 List<JcrNodeType> pendingTypes ) {
796 assert typeNamesToCheck != null;
797
798 Collection<JcrPropertyDefinition> propDefs = null;
799 List<JcrPropertyDefinition> matchingDefs = new ArrayList<JcrPropertyDefinition>();
800
801
802 for (Name typeNameToCheck : typeNamesToCheck) {
803 JcrNodeType typeName = findTypeInMapOrList(typeNameToCheck, pendingTypes);
804 if (typeName == null) continue;
805
806 switch (typeToCheck) {
807 case SINGLE_VALUED_ONLY:
808 propDefs = typeName.allSingleValuePropertyDefinitions(propertyName);
809 break;
810 case MULTI_VALUED_ONLY:
811 propDefs = typeName.allMultiValuePropertyDefinitions(propertyName);
812 break;
813 case ANY:
814 propDefs = typeName.allPropertyDefinitions(propertyName);
815 break;
816 default:
817 throw new IllegalStateException("Should be unreachable: " + typeToCheck);
818 }
819
820 matchingDefs.addAll(propDefs);
821 }
822
823 return matchingDefs;
824 }
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839 boolean canRemoveProperty( Name primaryTypeNameOfParent,
840 List<Name> mixinTypeNamesOfParent,
841 Name propertyName,
842 boolean skipProtected ) {
843
844 JcrNodeType primaryType = getNodeType(primaryTypeNameOfParent);
845 if (primaryType != null) {
846 for (JcrPropertyDefinition definition : primaryType.allPropertyDefinitions(propertyName)) {
847
848 if (skipProtected && definition.isProtected()) continue;
849
850 return !definition.isMandatory();
851 }
852 }
853
854
855 if (mixinTypeNamesOfParent != null && !mixinTypeNamesOfParent.isEmpty()) {
856 for (Name mixinTypeName : mixinTypeNamesOfParent) {
857 JcrNodeType mixinType = getNodeType(mixinTypeName);
858 if (mixinType == null) continue;
859 for (JcrPropertyDefinition definition : mixinType.allPropertyDefinitions(propertyName)) {
860
861 if (skipProtected && definition.isProtected()) continue;
862
863 return !definition.isMandatory();
864 }
865 }
866 }
867
868
869 if (!propertyName.equals(JcrNodeType.RESIDUAL_NAME)) return canRemoveProperty(primaryTypeNameOfParent,
870 mixinTypeNamesOfParent,
871 JcrNodeType.RESIDUAL_NAME,
872 skipProtected);
873 return false;
874 }
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889 boolean canRemoveItem( Name primaryTypeNameOfParent,
890 List<Name> mixinTypeNamesOfParent,
891 Name itemName,
892 boolean skipProtected ) {
893
894 JcrNodeType primaryType = getNodeType(primaryTypeNameOfParent);
895 if (primaryType != null) {
896 for (JcrPropertyDefinition definition : primaryType.allPropertyDefinitions(itemName)) {
897
898 if (skipProtected && definition.isProtected()) continue;
899
900 return !definition.isMandatory();
901 }
902 }
903
904
905 if (primaryType != null) {
906 for (JcrNodeDefinition definition : primaryType.allChildNodeDefinitions(itemName)) {
907
908 if (skipProtected && definition.isProtected()) continue;
909
910 return !definition.isMandatory();
911 }
912 }
913
914
915 if (mixinTypeNamesOfParent != null && !mixinTypeNamesOfParent.isEmpty()) {
916 for (Name mixinTypeName : mixinTypeNamesOfParent) {
917 JcrNodeType mixinType = getNodeType(mixinTypeName);
918 if (mixinType == null) continue;
919 for (JcrPropertyDefinition definition : mixinType.allPropertyDefinitions(itemName)) {
920
921 if (skipProtected && definition.isProtected()) continue;
922
923 return !definition.isMandatory();
924 }
925 }
926 }
927
928
929 if (mixinTypeNamesOfParent != null && !mixinTypeNamesOfParent.isEmpty()) {
930 for (Name mixinTypeName : mixinTypeNamesOfParent) {
931 JcrNodeType mixinType = getNodeType(mixinTypeName);
932 if (mixinType == null) continue;
933 for (JcrNodeDefinition definition : mixinType.allChildNodeDefinitions(itemName)) {
934
935 if (skipProtected && definition.isProtected()) continue;
936
937 return !definition.isMandatory();
938 }
939 }
940 }
941
942
943 if (!itemName.equals(JcrNodeType.RESIDUAL_NAME)) return canRemoveItem(primaryTypeNameOfParent,
944 mixinTypeNamesOfParent,
945 JcrNodeType.RESIDUAL_NAME,
946 skipProtected);
947 return false;
948 }
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968 JcrNodeDefinition findChildNodeDefinition( Name primaryTypeNameOfParent,
969 List<Name> mixinTypeNamesOfParent,
970 Name childName,
971 Name childPrimaryNodeType,
972 int numberOfExistingChildrenWithSameName,
973 boolean skipProtected ) {
974 JcrNodeType childType = childPrimaryNodeType != null ? getNodeType(childPrimaryNodeType) : null;
975 boolean requireSns = numberOfExistingChildrenWithSameName > 1;
976
977
978 JcrNodeType primaryType = getNodeType(primaryTypeNameOfParent);
979 if (primaryType != null) {
980 for (JcrNodeDefinition definition : primaryType.allChildNodeDefinitions(childName, requireSns)) {
981
982 if (skipProtected && definition.isProtected()) return null;
983
984 if (definition.allowsChildWithType(childType)) return definition;
985 }
986 }
987
988
989 if (mixinTypeNamesOfParent != null && !mixinTypeNamesOfParent.isEmpty()) {
990 for (Name mixinTypeName : mixinTypeNamesOfParent) {
991 JcrNodeType mixinType = getNodeType(mixinTypeName);
992 if (mixinType == null) continue;
993 for (JcrNodeDefinition definition : mixinType.allChildNodeDefinitions(childName, requireSns)) {
994
995 if (skipProtected && definition.isProtected()) return null;
996
997 if (definition.allowsChildWithType(childType)) return definition;
998 }
999 }
1000 }
1001
1002
1003 if (!childName.equals(JcrNodeType.RESIDUAL_NAME)) return findChildNodeDefinition(primaryTypeNameOfParent,
1004 mixinTypeNamesOfParent,
1005 JcrNodeType.RESIDUAL_NAME,
1006 childPrimaryNodeType,
1007 numberOfExistingChildrenWithSameName,
1008 skipProtected);
1009 return null;
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 private List<JcrNodeDefinition> findChildNodeDefinitions( List<Name> typeNamesToCheck,
1026 Name childNodeName,
1027 NodeCardinality typesToCheck,
1028 List<JcrNodeType> pendingTypes ) {
1029 assert typeNamesToCheck != null;
1030 Collection<JcrNodeDefinition> nodeDefs = null;
1031 List<JcrNodeDefinition> matchingDefs = new ArrayList<JcrNodeDefinition>();
1032
1033 for (Name typeNameToCheck : typeNamesToCheck) {
1034 JcrNodeType typeName = findTypeInMapOrList(typeNameToCheck, pendingTypes);
1035 if (typeName == null) continue;
1036
1037 switch (typesToCheck) {
1038 case NO_SAME_NAME_SIBLINGS:
1039 nodeDefs = typeName.allChildNodeDefinitions(childNodeName, false);
1040 break;
1041 case SAME_NAME_SIBLINGS:
1042 nodeDefs = typeName.allChildNodeDefinitions(childNodeName, true);
1043 break;
1044 case ANY:
1045 nodeDefs = typeName.allChildNodeDefinitions(childNodeName);
1046 break;
1047 }
1048
1049 assert nodeDefs != null;
1050 for (JcrNodeDefinition definition : nodeDefs) {
1051 if (NodeCardinality.NO_SAME_NAME_SIBLINGS == typesToCheck && definition.allowsSameNameSiblings()) continue;
1052 matchingDefs.add(definition);
1053 }
1054 }
1055
1056 return matchingDefs;
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 boolean canRemoveAllChildren( Name primaryTypeNameOfParent,
1073 List<Name> mixinTypeNamesOfParent,
1074 Name childName,
1075 boolean skipProtected ) {
1076
1077 JcrNodeType primaryType = getNodeType(primaryTypeNameOfParent);
1078 if (primaryType != null) {
1079 for (JcrNodeDefinition definition : primaryType.allChildNodeDefinitions(childName)) {
1080
1081 if (skipProtected && definition.isProtected()) continue;
1082
1083 return !definition.isMandatory();
1084 }
1085 }
1086
1087
1088 if (mixinTypeNamesOfParent != null && !mixinTypeNamesOfParent.isEmpty()) {
1089 for (Name mixinTypeName : mixinTypeNamesOfParent) {
1090 JcrNodeType mixinType = getNodeType(mixinTypeName);
1091 if (mixinType == null) continue;
1092 for (JcrNodeDefinition definition : mixinType.allChildNodeDefinitions(childName)) {
1093
1094 if (skipProtected && definition.isProtected()) continue;
1095
1096 return !definition.isMandatory();
1097 }
1098 }
1099 }
1100
1101
1102 if (!childName.equals(JcrNodeType.RESIDUAL_NAME)) return canRemoveAllChildren(primaryTypeNameOfParent,
1103 mixinTypeNamesOfParent,
1104 JcrNodeType.RESIDUAL_NAME,
1105 skipProtected);
1106 return false;
1107 }
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128 void projectOnto( Graph graph,
1129 Path parentOfTypeNodes ) {
1130 assert graph != null;
1131 assert parentOfTypeNodes != null;
1132
1133
1134 try {
1135 graph.getNodeAt(parentOfTypeNodes);
1136 } catch (PathNotFoundException pnfe) {
1137 PropertyFactory propertyFactory = context.getPropertyFactory();
1138 graph.create(parentOfTypeNodes,
1139 propertyFactory.create(JcrLexicon.PRIMARY_TYPE,
1140 ModeShapeLexicon.NODE_TYPES.getString(context.getNamespaceRegistry()))).and();
1141 }
1142
1143 Graph.Batch batch = graph.batch();
1144
1145 for (JcrNodeType nodeType : getAllNodeTypes()) {
1146 projectNodeTypeOnto(nodeType, parentOfTypeNodes, batch);
1147 }
1148
1149 batch.execute();
1150 }
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 private void projectNodeTypeOnto( JcrNodeType nodeType,
1162 Path parentOfTypeNodes,
1163 Graph.Batch batch ) {
1164 assert nodeType != null;
1165 assert parentOfTypeNodes != null;
1166 assert batch != null;
1167
1168 Path nodeTypePath = pathFactory.create(parentOfTypeNodes, nodeType.getInternalName());
1169
1170 NodeType[] supertypes = nodeType.getDeclaredSupertypes();
1171 List<Name> supertypeNames = new ArrayList<Name>(supertypes.length);
1172 for (int i = 0; i < supertypes.length; i++) {
1173 supertypeNames.add(((JcrNodeType)supertypes[i]).getInternalName());
1174 }
1175
1176 List<Property> propsList = new ArrayList<Property>();
1177 propsList.add(propertyFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.NODE_TYPE));
1178 propsList.add(propertyFactory.create(JcrLexicon.IS_MIXIN, nodeType.isMixin()));
1179 propsList.add(propertyFactory.create(JcrLexicon.IS_ABSTRACT, nodeType.isAbstract()));
1180 propsList.add(propertyFactory.create(JcrLexicon.IS_QUERYABLE, nodeType.isQueryable()));
1181
1182 if (nodeType.getPrimaryItemName() != null) {
1183 propsList.add(propertyFactory.create(JcrLexicon.PRIMARY_ITEM_NAME, nodeType.getPrimaryItemName()));
1184 }
1185
1186 propsList.add(propertyFactory.create(JcrLexicon.NODE_TYPE_NAME, nodeType.getName()));
1187 propsList.add(propertyFactory.create(JcrLexicon.HAS_ORDERABLE_CHILD_NODES, nodeType.hasOrderableChildNodes()));
1188 propsList.add(propertyFactory.create(JcrLexicon.SUPERTYPES, supertypeNames));
1189
1190 batch.create(nodeTypePath).with(propsList).orReplace().and();
1191
1192 PropertyDefinition[] propertyDefs = nodeType.getDeclaredPropertyDefinitions();
1193 for (int i = 0; i < propertyDefs.length; i++) {
1194 projectPropertyDefinitionOnto(propertyDefs[i], nodeTypePath, batch);
1195 }
1196
1197 NodeDefinition[] childNodeDefs = nodeType.getDeclaredChildNodeDefinitions();
1198 for (int i = 0; i < childNodeDefs.length; i++) {
1199 projectChildNodeDefinitionOnto(childNodeDefs[i], nodeTypePath, batch);
1200 }
1201 }
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219 private void projectPropertyDefinitionOnto( PropertyDefinition propertyDef,
1220 Path nodeTypePath,
1221 Graph.Batch batch ) {
1222 assert propertyDef != null;
1223 assert nodeTypePath != null;
1224 assert batch != null;
1225
1226 JcrPropertyDefinition jcrPropDef = (JcrPropertyDefinition)propertyDef;
1227 String propName = jcrPropDef.getInternalName().getString(context.getNamespaceRegistry(), NAME_ENCODER);
1228 Path propDefPath = pathFactory.create(nodeTypePath, JcrLexicon.PROPERTY_DEFINITION);
1229
1230 List<Property> propsList = new ArrayList<Property>();
1231 propsList.add(propertyFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.PROPERTY_DEFINITION));
1232
1233 if (!JcrNodeType.RESIDUAL_ITEM_NAME.equals(jcrPropDef.getName())) {
1234 propsList.add(propertyFactory.create(JcrLexicon.NAME, propName));
1235 }
1236 propsList.add(propertyFactory.create(JcrLexicon.AUTO_CREATED, jcrPropDef.isAutoCreated()));
1237 propsList.add(propertyFactory.create(JcrLexicon.MANDATORY, jcrPropDef.isMandatory()));
1238 propsList.add(propertyFactory.create(JcrLexicon.MULTIPLE, jcrPropDef.isMultiple()));
1239 propsList.add(propertyFactory.create(JcrLexicon.PROTECTED, jcrPropDef.isProtected()));
1240 propsList.add(propertyFactory.create(JcrLexicon.ON_PARENT_VERSION,
1241 OnParentVersionAction.nameFromValue(jcrPropDef.getOnParentVersion())));
1242 propsList.add(propertyFactory.create(JcrLexicon.REQUIRED_TYPE, PropertyType.nameFromValue(jcrPropDef.getRequiredType())
1243 .toUpperCase()));
1244
1245 List<String> symbols = new ArrayList<String>();
1246 for (String value : jcrPropDef.getAvailableQueryOperators()) {
1247 if (value != null) symbols.add(value);
1248 }
1249 propsList.add(propertyFactory.create(JcrLexicon.QUERY_OPERATORS, symbols));
1250
1251 Value[] defaultValues = jcrPropDef.getDefaultValues();
1252 if (defaultValues.length > 0) {
1253 String[] defaultsAsString = new String[defaultValues.length];
1254
1255 for (int i = 0; i < defaultValues.length; i++) {
1256 try {
1257 defaultsAsString[i] = defaultValues[i].getString();
1258 } catch (RepositoryException re) {
1259
1260 throw new IllegalStateException(re);
1261 }
1262 }
1263 propsList.add(propertyFactory.create(JcrLexicon.DEFAULT_VALUES, (Object[])defaultsAsString));
1264 }
1265
1266 String[] valueConstraints = jcrPropDef.getValueConstraints();
1267 if (valueConstraints.length > 0) {
1268 propsList.add(propertyFactory.create(JcrLexicon.VALUE_CONSTRAINTS, (Object[])valueConstraints));
1269 }
1270 batch.create(propDefPath).with(propsList).and();
1271 }
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289 private void projectChildNodeDefinitionOnto( NodeDefinition childNodeDef,
1290 Path nodeTypePath,
1291 Graph.Batch batch ) {
1292 assert childNodeDef != null;
1293 assert nodeTypePath != null;
1294 assert batch != null;
1295
1296 JcrNodeDefinition jcrNodeDef = (JcrNodeDefinition)childNodeDef;
1297 String nodeName = jcrNodeDef.getInternalName().getString(context.getNamespaceRegistry(), NAME_ENCODER);
1298 Path nodeDefPath = pathFactory.create(nodeTypePath, JcrLexicon.CHILD_NODE_DEFINITION);
1299
1300 List<Property> propsList = new ArrayList<Property>();
1301 propsList.add(propertyFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.CHILD_NODE_DEFINITION));
1302
1303 if (!JcrNodeType.RESIDUAL_ITEM_NAME.equals(jcrNodeDef.getName())) {
1304 propsList.add(propertyFactory.create(JcrLexicon.NAME, nodeName));
1305 }
1306
1307 if (jcrNodeDef.getDefaultPrimaryType() != null) {
1308 propsList.add(propertyFactory.create(JcrLexicon.DEFAULT_PRIMARY_TYPE, jcrNodeDef.getDefaultPrimaryType().getName()));
1309 }
1310
1311 propsList.add(propertyFactory.create(JcrLexicon.REQUIRED_PRIMARY_TYPES, (Object[])jcrNodeDef.requiredPrimaryTypeNames()));
1312 propsList.add(propertyFactory.create(JcrLexicon.SAME_NAME_SIBLINGS, jcrNodeDef.allowsSameNameSiblings()));
1313 propsList.add(propertyFactory.create(JcrLexicon.ON_PARENT_VERSION,
1314 OnParentVersionAction.nameFromValue(jcrNodeDef.getOnParentVersion())));
1315 propsList.add(propertyFactory.create(JcrLexicon.AUTO_CREATED, jcrNodeDef.isAutoCreated()));
1316 propsList.add(propertyFactory.create(JcrLexicon.MANDATORY, jcrNodeDef.isMandatory()));
1317 propsList.add(propertyFactory.create(JcrLexicon.PROTECTED, jcrNodeDef.isProtected()));
1318
1319 batch.create(nodeDefPath).with(propsList).and();
1320 }
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337 void unregisterNodeType( Collection<Name> nodeTypeNames )
1338 throws NoSuchNodeTypeException, InvalidNodeTypeDefinitionException, RepositoryException {
1339 CheckArg.isNotNull(nodeTypeNames, "nodeTypeNames");
1340 try {
1341
1342
1343
1344 nodeTypeManagerLock.writeLock().lock();
1345
1346 for (Name nodeTypeName : nodeTypeNames) {
1347
1348
1349
1350 if (nodeTypeName == null) {
1351 throw new NoSuchNodeTypeException(JcrI18n.invalidNodeTypeName.text());
1352 }
1353 String name = nodeTypeName.getString(context.getNamespaceRegistry());
1354
1355 if (!this.nodeTypes.containsKey(nodeTypeName)) {
1356 throw new NoSuchNodeTypeException(JcrI18n.noSuchNodeType.text(name));
1357 }
1358
1359
1360
1361
1362 for (JcrNodeType nodeType : nodeTypes.values()) {
1363
1364 if (nodeTypeNames.contains(nodeType.getInternalName())) {
1365 continue;
1366 }
1367
1368 for (JcrNodeType supertype : nodeType.supertypes()) {
1369 if (nodeTypeName.equals(supertype.getInternalName())) {
1370 throw new InvalidNodeTypeDefinitionException(
1371 JcrI18n.cannotUnregisterSupertype.text(name,
1372 supertype.getName()));
1373 }
1374 }
1375
1376 for (JcrNodeDefinition childNode : nodeType.childNodeDefinitions()) {
1377 NodeType defaultPrimaryType = childNode.getDefaultPrimaryType();
1378 if (defaultPrimaryType != null && name.equals(defaultPrimaryType.getName())) {
1379 throw new InvalidNodeTypeDefinitionException(
1380 JcrI18n.cannotUnregisterDefaultPrimaryType.text(name,
1381 nodeType.getName(),
1382 childNode.getName()));
1383 }
1384 if (childNode.requiredPrimaryTypeNameSet().contains(nodeTypeName)) {
1385 throw new InvalidNodeTypeDefinitionException(
1386 JcrI18n.cannotUnregisterRequiredPrimaryType.text(name,
1387 nodeType.getName(),
1388 childNode.getName()));
1389 }
1390 }
1391
1392
1393
1394
1395 if (isNodeTypeInUse(nodeTypeName)) {
1396 throw new InvalidNodeTypeDefinitionException(JcrI18n.cannotUnregisterInUseType.text(name));
1397
1398 }
1399
1400 }
1401 }
1402
1403 this.nodeTypes.keySet().removeAll(nodeTypeNames);
1404
1405 if (nodeTypesPath != null) {
1406 Graph.Batch batch = repository.createSystemGraph(context).batch();
1407
1408 for (Name nodeTypeName : nodeTypeNames) {
1409 Path nodeTypePath = pathFactory.create(nodeTypesPath, nodeTypeName);
1410 batch.delete(nodeTypePath).and();
1411 }
1412
1413 batch.execute();
1414 }
1415 this.schemata = null;
1416
1417 } finally {
1418 nodeTypeManagerLock.writeLock().unlock();
1419 }
1420 }
1421
1422
1423
1424
1425
1426
1427
1428
1429 boolean isNodeTypeInUse( Name nodeTypeName ) throws InvalidQueryException {
1430 String nodeTypeString = nodeTypeName.getString(context.getNamespaceRegistry());
1431 String expression = "SELECT * from [" + nodeTypeString + "] LIMIT 1";
1432
1433 TypeSystem typeSystem = context.getValueFactories().getTypeSystem();
1434
1435 QueryCommand command = queryParser.parseQuery(expression, typeSystem);
1436 assert command != null : "Could not parse " + expression;
1437
1438 Schemata schemata = getRepositorySchemata();
1439
1440 Set<String> workspaceNames = repository.workspaceNames();
1441 for (String workspaceName : workspaceNames) {
1442 QueryResults result = repository.queryManager().query(workspaceName, command, schemata, null, null);
1443
1444 if (result.getRowCount() > 0) {
1445 return true;
1446 }
1447 }
1448
1449 return false;
1450 }
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466 JcrNodeType registerNodeType( NodeTypeDefinition ntd )
1467 throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException {
1468 assert ntd != null;
1469 List<JcrNodeType> result = registerNodeTypes(Collections.singletonList(ntd));
1470 return result.isEmpty() ? null : result.get(0);
1471 }
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485 List<JcrNodeType> registerNodeTypes( NodeTypeDefinition[] ntds )
1486 throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException {
1487 assert ntds != null;
1488 return registerNodeTypes(Arrays.asList(ntds));
1489 }
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564 List<JcrNodeType> registerNodeTypes( Iterable<NodeTypeDefinition> nodeTypeDefns )
1565 throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException {
1566
1567 if (nodeTypeDefns == null) {
1568 return Collections.emptyList();
1569 }
1570
1571 List<JcrNodeType> typesPendingRegistration = new ArrayList<JcrNodeType>();
1572
1573 try {
1574 nodeTypeManagerLock.writeLock().lock();
1575 for (NodeTypeDefinition nodeTypeDefn : nodeTypeDefns) {
1576 if (nodeTypeDefn instanceof JcrNodeTypeTemplate) {
1577
1578 nodeTypeDefn = ((JcrNodeTypeTemplate)nodeTypeDefn).with(context);
1579 }
1580 Name internalName = nameFactory.create(nodeTypeDefn.getName());
1581 if (internalName == null || internalName.getLocalName().length() == 0) {
1582 throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidNodeTypeName.text());
1583 }
1584
1585 if (nodeTypes.containsKey(internalName)) {
1586 String name = nodeTypeDefn.getName();
1587 throw new NodeTypeExistsException(internalName, JcrI18n.nodeTypeAlreadyExists.text(name));
1588 }
1589
1590 List<JcrNodeType> supertypes = supertypesFor(nodeTypeDefn, typesPendingRegistration);
1591 JcrNodeType nodeType = nodeTypeFrom(nodeTypeDefn, supertypes);
1592 validate(nodeType, supertypes, typesPendingRegistration);
1593
1594 typesPendingRegistration.add(nodeType);
1595 }
1596
1597
1598 for (JcrNodeType nodeType : typesPendingRegistration) {
1599 for (JcrNodeDefinition nodeDef : nodeType.getDeclaredChildNodeDefinitions()) {
1600 JcrNodeType[] requiredPrimaryTypes = new JcrNodeType[nodeDef.requiredPrimaryTypeNames().length];
1601 int i = 0;
1602 for (Name primaryTypeName : nodeDef.requiredPrimaryTypeNames()) {
1603 requiredPrimaryTypes[i] = findTypeInMapOrList(primaryTypeName, typesPendingRegistration);
1604
1605 if (requiredPrimaryTypes[i] == null) {
1606 throw new RepositoryException(
1607 JcrI18n.invalidPrimaryTypeName.text(primaryTypeName, nodeType.getName()));
1608 }
1609 i++;
1610 }
1611 }
1612 }
1613
1614 Graph.Batch batch = null;
1615 if (nodeTypesPath != null) batch = repository.createSystemGraph(context).batch();
1616
1617 for (JcrNodeType nodeType : typesPendingRegistration) {
1618
1619
1620
1621
1622
1623 Name name = nodeType.getInternalName();
1624 nodeTypes.put(name, nodeType);
1625 for (JcrNodeDefinition childDefinition : nodeType.childNodeDefinitions()) {
1626 childNodeDefinitions.put(childDefinition.getId(), childDefinition);
1627 }
1628 for (JcrPropertyDefinition propertyDefinition : nodeType.propertyDefinitions()) {
1629 propertyDefinitions.put(propertyDefinition.getId(), propertyDefinition);
1630 }
1631
1632 if (nodeTypesPath != null) projectNodeTypeOnto(nodeType, nodeTypesPath, batch);
1633 }
1634
1635
1636 this.schemata = null;
1637 if (nodeTypesPath != null) {
1638 assert batch != null;
1639 batch.execute();
1640 }
1641 } finally {
1642 nodeTypeManagerLock.writeLock().unlock();
1643 }
1644
1645 return typesPendingRegistration;
1646 }
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717 List<JcrNodeType> registerNodeTypes( Subgraph nodeTypeSubgraph,
1718 Location locationOfParentOfNodeTypes )
1719 throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, RepositoryException {
1720 assert nodeTypeSubgraph != null;
1721 assert locationOfParentOfNodeTypes != null;
1722 CndNodeTypeReader factory = new CndNodeTypeReader(this.context);
1723 factory.read(nodeTypeSubgraph, locationOfParentOfNodeTypes, nodeTypeSubgraph.getGraph().getSourceName());
1724 return registerNodeTypes(factory);
1725 }
1726
1727 private JcrNodeType nodeTypeFrom( NodeTypeDefinition nodeType,
1728 List<JcrNodeType> supertypes ) throws RepositoryException {
1729 PropertyDefinition[] propDefns = nodeType.getDeclaredPropertyDefinitions();
1730 NodeDefinition[] childDefns = nodeType.getDeclaredChildNodeDefinitions();
1731 List<JcrPropertyDefinition> properties = new ArrayList<JcrPropertyDefinition>();
1732 List<JcrNodeDefinition> childNodes = new ArrayList<JcrNodeDefinition>();
1733
1734 if (propDefns != null) {
1735 for (PropertyDefinition propDefn : propDefns) {
1736 properties.add(propertyDefinitionFrom(propDefn));
1737 }
1738 }
1739 if (childDefns != null) {
1740 for (NodeDefinition childNodeDefn : childDefns) {
1741 childNodes.add(childNodeDefinitionFrom(childNodeDefn));
1742 }
1743 }
1744
1745 Name name = nameFactory.create(nodeType.getName());
1746 Name primaryItemName = nameFactory.create(nodeType.getPrimaryItemName());
1747 boolean mixin = nodeType.isMixin();
1748 boolean isAbstract = nodeType.isAbstract();
1749 boolean queryable = nodeType.isQueryable();
1750 boolean orderableChildNodes = nodeType.hasOrderableChildNodes();
1751
1752 return new JcrNodeType(this.context, this, name, supertypes, primaryItemName, childNodes, properties, mixin, isAbstract,
1753 queryable, orderableChildNodes);
1754 }
1755
1756 private JcrPropertyDefinition propertyDefinitionFrom( PropertyDefinition propDefn ) throws RepositoryException {
1757 Name propertyName = nameFactory.create(propDefn.getName());
1758 int onParentVersionBehavior = propDefn.getOnParentVersion();
1759 int requiredType = propDefn.getRequiredType();
1760 boolean mandatory = propDefn.isMandatory();
1761 boolean multiple = propDefn.isMultiple();
1762 boolean autoCreated = propDefn.isAutoCreated();
1763 boolean isProtected = propDefn.isProtected();
1764 boolean fullTextSearchable = propDefn.isFullTextSearchable();
1765 boolean queryOrderable = propDefn.isQueryOrderable();
1766
1767 Value[] defaultValues = propDefn.getDefaultValues();
1768 if (defaultValues != null) {
1769 for (int i = 0; i != defaultValues.length; ++i) {
1770 Value value = defaultValues[i];
1771 defaultValues[i] = new JcrValue(this.context.getValueFactories(), null, value);
1772 }
1773 } else {
1774 defaultValues = new Value[0];
1775 }
1776
1777 String[] valueConstraints = propDefn.getValueConstraints();
1778 String[] queryOperators = propDefn.getAvailableQueryOperators();
1779 if (valueConstraints == null) valueConstraints = new String[0];
1780 return new JcrPropertyDefinition(this.context, null, propertyName, onParentVersionBehavior, autoCreated, mandatory,
1781 isProtected, defaultValues, requiredType, valueConstraints, multiple,
1782 fullTextSearchable, queryOrderable, queryOperators);
1783 }
1784
1785 private JcrNodeDefinition childNodeDefinitionFrom( NodeDefinition childNodeDefn ) {
1786 Name childNodeName = nameFactory.create(childNodeDefn.getName());
1787 Name defaultPrimaryTypeName = nameFactory.create(childNodeDefn.getDefaultPrimaryTypeName());
1788 int onParentVersion = childNodeDefn.getOnParentVersion();
1789
1790 boolean mandatory = childNodeDefn.isMandatory();
1791 boolean allowsSns = childNodeDefn.allowsSameNameSiblings();
1792 boolean autoCreated = childNodeDefn.isAutoCreated();
1793 boolean isProtected = childNodeDefn.isProtected();
1794
1795 Name[] requiredTypes;
1796 String[] requiredTypeNames = childNodeDefn.getRequiredPrimaryTypeNames();
1797 if (requiredTypeNames != null) {
1798 List<Name> names = new ArrayList<Name>(requiredTypeNames.length);
1799 for (String typeName : requiredTypeNames) {
1800 names.add(nameFactory.create(typeName));
1801 }
1802 requiredTypes = names.toArray(new Name[names.size()]);
1803 } else {
1804 requiredTypes = new Name[0];
1805 }
1806
1807 return new JcrNodeDefinition(this.context, null, childNodeName, onParentVersion, autoCreated, mandatory, isProtected,
1808 allowsSns, defaultPrimaryTypeName, requiredTypes);
1809 }
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820 private JcrNodeType findTypeInMapOrList( Name typeName,
1821 Collection<JcrNodeType> pendingList ) {
1822 for (JcrNodeType pendingNodeType : pendingList) {
1823 if (pendingNodeType.getInternalName().equals(typeName)) {
1824 return pendingNodeType;
1825 }
1826 }
1827
1828 return nodeTypes.get(typeName);
1829 }
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842 private List<JcrNodeType> supertypesFor( NodeTypeDefinition nodeType,
1843 Collection<JcrNodeType> pendingTypes ) throws RepositoryException {
1844 assert nodeType != null;
1845
1846 List<JcrNodeType> supertypes = new LinkedList<JcrNodeType>();
1847
1848 boolean isMixin = nodeType.isMixin();
1849 boolean needsPrimaryAncestor = !isMixin;
1850 String nodeTypeName = nodeType.getName();
1851
1852 for (String supertypeNameStr : nodeType.getDeclaredSupertypeNames()) {
1853 Name supertypeName = nameFactory.create(supertypeNameStr);
1854 JcrNodeType supertype = findTypeInMapOrList(supertypeName, pendingTypes);
1855 if (supertype == null) {
1856 throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidSupertypeName.text(supertypeNameStr, nodeTypeName));
1857 }
1858 needsPrimaryAncestor &= supertype.isMixin();
1859 supertypes.add(supertype);
1860 }
1861
1862
1863 if (needsPrimaryAncestor) {
1864 Name nodeName = nameFactory.create(nodeTypeName);
1865 if (!JcrNtLexicon.BASE.equals(nodeName)) {
1866 JcrNodeType ntBase = findTypeInMapOrList(JcrNtLexicon.BASE, pendingTypes);
1867 assert ntBase != null;
1868 supertypes.add(0, ntBase);
1869 }
1870 }
1871 return supertypes;
1872 }
1873
1874
1875
1876
1877
1878
1879
1880 final Collection<JcrNodeType> subtypesFor( JcrNodeType nodeType ) {
1881 CheckArg.isNotNull(nodeType, "nodeType");
1882
1883 try {
1884 nodeTypeManagerLock.readLock().lock();
1885
1886 List<JcrNodeType> subtypes = new LinkedList<JcrNodeType>();
1887 for (JcrNodeType type : this.nodeTypes.values()) {
1888 if (type.supertypes().contains(nodeType)) {
1889 subtypes.add(type);
1890 }
1891 }
1892
1893 return subtypes;
1894 } finally {
1895 nodeTypeManagerLock.readLock().unlock();
1896 }
1897 }
1898
1899
1900
1901
1902
1903
1904
1905 final Collection<JcrNodeType> declaredSubtypesFor( JcrNodeType nodeType ) {
1906 CheckArg.isNotNull(nodeType, "nodeType");
1907
1908 try {
1909 nodeTypeManagerLock.readLock().lock();
1910
1911 String nodeTypeName = nodeType.getName();
1912 List<JcrNodeType> subtypes = new LinkedList<JcrNodeType>();
1913 for (JcrNodeType type : this.nodeTypes.values()) {
1914 if (Arrays.asList(type.getDeclaredSupertypeNames()).contains(nodeTypeName)) {
1915 subtypes.add(type);
1916 }
1917 }
1918
1919 return subtypes;
1920 } finally {
1921 nodeTypeManagerLock.readLock().unlock();
1922 }
1923 }
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947 private void validate( List<JcrNodeType> supertypes,
1948 String nodeName ) throws RepositoryException {
1949 assert supertypes != null;
1950
1951 Map<PropertyDefinitionId, JcrPropertyDefinition> props = new HashMap<PropertyDefinitionId, JcrPropertyDefinition>();
1952
1953 for (JcrNodeType supertype : supertypes) {
1954 for (JcrPropertyDefinition property : supertype.propertyDefinitions()) {
1955 JcrPropertyDefinition oldProp = props.put(new PropertyDefinitionId(property.getInternalName(),
1956 property.getInternalName(),
1957 PropertyType.UNDEFINED, property.isMultiple()),
1958 property);
1959 if (oldProp != null) {
1960 String oldPropTypeName = oldProp.getDeclaringNodeType().getName();
1961 String propTypeName = property.getDeclaringNodeType().getName();
1962 if (!oldPropTypeName.equals(propTypeName)) {
1963 throw new InvalidNodeTypeDefinitionException(JcrI18n.supertypesConflict.text(oldPropTypeName,
1964 propTypeName,
1965 "property",
1966 property.getName()));
1967 }
1968 }
1969 }
1970 }
1971
1972 Map<NodeDefinitionId, JcrNodeDefinition> childNodes = new HashMap<NodeDefinitionId, JcrNodeDefinition>();
1973
1974 for (JcrNodeType supertype : supertypes) {
1975 for (JcrNodeDefinition childNode : supertype.childNodeDefinitions()) {
1976 JcrNodeDefinition oldNode = childNodes.put(new NodeDefinitionId(childNode.getInternalName(),
1977 childNode.getInternalName(), new Name[0]),
1978 childNode);
1979 if (oldNode != null) {
1980 String oldNodeTypeName = oldNode.getDeclaringNodeType().getName();
1981 String childNodeTypeName = childNode.getDeclaringNodeType().getName();
1982 if (!oldNodeTypeName.equals(childNodeTypeName)) {
1983 throw new InvalidNodeTypeDefinitionException(JcrI18n.supertypesConflict.text(oldNodeTypeName,
1984 childNodeTypeName,
1985 "child node",
1986 childNode.getName()));
1987 }
1988 }
1989 }
1990 }
1991 }
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004 private void validate( JcrNodeType nodeType,
2005 List<JcrNodeType> supertypes,
2006 List<JcrNodeType> pendingTypes ) throws RepositoryException {
2007 Name nodeTypeName = nodeType.getInternalName();
2008 validate(supertypes, nodeTypeName.getString(this.context.getNamespaceRegistry()));
2009
2010 List<Name> supertypeNames = new ArrayList<Name>(supertypes.size());
2011 for (JcrNodeType supertype : supertypes) {
2012 supertypeNames.add(supertype.getInternalName());
2013 }
2014
2015 boolean foundExact = false;
2016 boolean foundResidual = false;
2017 Name primaryItemName = nodeType.getInternalPrimaryItemName();
2018
2019 for (JcrNodeDefinition node : nodeType.getDeclaredChildNodeDefinitions()) {
2020 validate(node, supertypeNames, pendingTypes);
2021 if (node.isResidual()) foundResidual = true;
2022
2023 if (primaryItemName != null && primaryItemName.equals(node.getInternalName())) {
2024 foundExact = true;
2025 }
2026 }
2027
2028 for (JcrPropertyDefinition prop : nodeType.getDeclaredPropertyDefinitions()) {
2029 validate(prop, supertypeNames, pendingTypes);
2030 if (prop.isResidual()) foundResidual = true;
2031 if (primaryItemName != null && primaryItemName.equals(prop.getInternalName())) {
2032 if (foundExact) {
2033 throw new RepositoryException(JcrI18n.ambiguousPrimaryItemName.text(primaryItemName));
2034 }
2035 foundExact = true;
2036 }
2037 }
2038
2039 if (primaryItemName != null && !foundExact && !foundResidual) {
2040 throw new RepositoryException(JcrI18n.invalidPrimaryItemName.text(primaryItemName));
2041 }
2042 }
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068 private void validate( JcrNodeDefinition node,
2069 List<Name> supertypes,
2070 List<JcrNodeType> pendingTypes ) throws RepositoryException {
2071 if (node.isAutoCreated() && !node.isProtected() && node.defaultPrimaryTypeName() == null) {
2072 throw new InvalidNodeTypeDefinitionException(JcrI18n.autocreatedNodesNeedDefaults.text(node.getName()));
2073 }
2074 if (node.isMandatory() && JcrNodeType.RESIDUAL_ITEM_NAME.equals(node.getName())) {
2075 throw new InvalidNodeTypeDefinitionException(JcrI18n.residualDefinitionsCannotBeMandatory.text("child nodes"));
2076 }
2077
2078 Name nodeName = context.getValueFactories().getNameFactory().create(node.getName());
2079 nodeName = nodeName == null ? JcrNodeType.RESIDUAL_NAME : nodeName;
2080
2081 List<JcrNodeDefinition> ancestors = findChildNodeDefinitions(supertypes, nodeName, NodeCardinality.ANY, pendingTypes);
2082
2083 for (JcrNodeDefinition ancestor : ancestors) {
2084 if (ancestor.isProtected()) {
2085 throw new InvalidNodeTypeDefinitionException(
2086 JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType()
2087 .getName(),
2088 "child node"));
2089 }
2090
2091 if (ancestor.isMandatory() && !node.isMandatory()) {
2092 throw new InvalidNodeTypeDefinitionException(
2093 JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType()
2094 .getName(),
2095 "child node"));
2096
2097 }
2098
2099 Name[] requiredPrimaryTypeNames = ancestor.requiredPrimaryTypeNames();
2100 for (int i = 0; i < requiredPrimaryTypeNames.length; i++) {
2101 NodeType apt = findTypeInMapOrList(requiredPrimaryTypeNames[i], pendingTypes);
2102
2103 if (apt == null) {
2104 I18n msg = JcrI18n.couldNotFindDefinitionOfRequiredPrimaryType;
2105 throw new InvalidNodeTypeDefinitionException(msg.text(requiredPrimaryTypeNames[i],
2106 node.getName(),
2107 node.getDeclaringNodeType()));
2108
2109 }
2110
2111 boolean found = false;
2112
2113 for (Name name : node.requiredPrimaryTypeNames()) {
2114 JcrNodeType npt = findTypeInMapOrList(name, pendingTypes);
2115
2116 if (npt.isNodeType(apt.getName())) {
2117 found = true;
2118 break;
2119 }
2120 }
2121
2122
2123 if (!found && !JcrNodeType.RESIDUAL_NAME.equals(node.name)) {
2124 I18n msg = JcrI18n.cannotRedefineChildNodeWithIncompatibleDefinition;
2125 throw new InvalidNodeTypeDefinitionException(msg.text(nodeName, apt.getName(), node.getDeclaringNodeType()));
2126
2127 }
2128 }
2129 }
2130 }
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155 private void validate( JcrPropertyDefinition prop,
2156 List<Name> supertypes,
2157 List<JcrNodeType> pendingTypes ) throws RepositoryException {
2158 assert prop != null;
2159 assert supertypes != null;
2160 assert pendingTypes != null;
2161
2162 if (prop.isMandatory() && !prop.isProtected() && JcrNodeType.RESIDUAL_ITEM_NAME.equals(prop.getName())) {
2163 throw new InvalidNodeTypeDefinitionException(JcrI18n.residualDefinitionsCannotBeMandatory.text("properties"));
2164 }
2165
2166 Value[] defaultValues = prop.getDefaultValues();
2167 if (prop.isAutoCreated() && !prop.isProtected() && (defaultValues == null || defaultValues.length == 0)) {
2168 throw new InvalidNodeTypeDefinitionException(JcrI18n.autocreatedPropertyNeedsDefault.text(prop.getName(),
2169 prop.getDeclaringNodeType()
2170 .getName()));
2171 }
2172
2173 if (!prop.isMultiple() && (defaultValues != null && defaultValues.length > 1)) {
2174 throw new InvalidNodeTypeDefinitionException(
2175 JcrI18n.singleValuedPropertyNeedsSingleValuedDefault.text(prop.getName(),
2176 prop.getDeclaringNodeType()
2177 .getName()));
2178 }
2179
2180 Name propName = context.getValueFactories().getNameFactory().create(prop.getName());
2181 propName = propName == null ? JcrNodeType.RESIDUAL_NAME : propName;
2182
2183 List<JcrPropertyDefinition> ancestors = findPropertyDefinitions(supertypes,
2184 propName,
2185 prop.isMultiple() ? PropertyCardinality.MULTI_VALUED_ONLY : PropertyCardinality.SINGLE_VALUED_ONLY,
2186 pendingTypes);
2187
2188 for (JcrPropertyDefinition ancestor : ancestors) {
2189 if (ancestor.isProtected()) {
2190 throw new InvalidNodeTypeDefinitionException(
2191 JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType()
2192 .getName(),
2193 "property"));
2194 }
2195
2196 if (ancestor.isMandatory() && !prop.isMandatory()) {
2197 throw new InvalidNodeTypeDefinitionException(
2198 JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType()
2199 .getName(),
2200 "property"));
2201
2202 }
2203
2204
2205
2206 if (ancestor.getValueConstraints() != null
2207 && !Arrays.equals(ancestor.getValueConstraints(), prop.getValueConstraints())) {
2208 throw new InvalidNodeTypeDefinitionException(
2209 JcrI18n.constraintsChangedInSubtype.text(propName,
2210 ancestor.getDeclaringNodeType()
2211 .getName()));
2212 }
2213
2214 if (!isAlwaysSafeConversion(prop.getRequiredType(), ancestor.getRequiredType())) {
2215 throw new InvalidNodeTypeDefinitionException(
2216 JcrI18n.cannotRedefineProperty.text(propName,
2217 PropertyType.nameFromValue(prop.getRequiredType()),
2218 ancestor.getDeclaringNodeType()
2219 .getName(),
2220 PropertyType.nameFromValue(ancestor.getRequiredType())));
2221
2222 }
2223 }
2224 }
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239 private boolean isAlwaysSafeConversion( int fromType,
2240 int toType ) {
2241
2242 if (fromType == toType) return true;
2243
2244 switch (toType) {
2245 case PropertyType.BOOLEAN:
2246 return fromType == PropertyType.BINARY || fromType == PropertyType.STRING;
2247
2248 case PropertyType.DATE:
2249 return fromType == PropertyType.DOUBLE || fromType == PropertyType.LONG;
2250
2251 case PropertyType.DOUBLE:
2252
2253 return fromType == PropertyType.LONG;
2254 case PropertyType.LONG:
2255
2256 return fromType == PropertyType.DOUBLE;
2257
2258 case PropertyType.PATH:
2259 return fromType == PropertyType.NAME;
2260
2261
2262 case PropertyType.NAME:
2263 case PropertyType.REFERENCE:
2264 case PropertyType.WEAKREFERENCE:
2265 return false;
2266
2267
2268 case PropertyType.BINARY:
2269 case PropertyType.STRING:
2270 case PropertyType.UNDEFINED:
2271 return true;
2272
2273 default:
2274 throw new IllegalStateException("Unexpected state: " + toType);
2275 }
2276 }
2277
2278 @Override
2279 public Path getObservedPath() {
2280 return this.nodeTypesPath;
2281 }
2282
2283 @Override
2284 public void notify( Changes changes ) {
2285 Collection<Name> createdNodeTypeNames = new HashSet<Name>();
2286 Collection<Name> deletedNodeTypeNames = new HashSet<Name>();
2287
2288 for (ChangeRequest change : changes.getChangeRequests()) {
2289 assert change.changedLocation().hasPath();
2290
2291 Path changedPath = change.changedLocation().getPath();
2292 if (changedPath.equals(nodeTypesPath)) {
2293
2294 continue;
2295 }
2296 assert nodeTypesPath.isAncestorOf(changedPath);
2297
2298
2299
2300
2301
2302 Path relativePath = changedPath.relativeTo(nodeTypesPath);
2303 Name changedNodeTypeName = relativePath.getSegment(0).getName();
2304
2305 switch (change.getType()) {
2306 case CREATE_NODE:
2307
2308
2309
2310
2311
2312
2313
2314 if (!createdNodeTypeNames.contains(changedNodeTypeName)) {
2315 createdNodeTypeNames.add(changedNodeTypeName);
2316 }
2317 break;
2318
2319 case DELETE_BRANCH:
2320 deletedNodeTypeNames.add(changedNodeTypeName);
2321
2322 break;
2323 default:
2324 assert false : "Unexpected change request: " + change;
2325 }
2326 }
2327
2328 if (createdNodeTypeNames.isEmpty() && deletedNodeTypeNames.isEmpty()) return;
2329
2330 this.nodeTypeManagerLock.writeLock().lock();
2331 try {
2332 GraphNodeTypeReader reader = new GraphNodeTypeReader(this.context);
2333 Graph systemGraph = repository.createSystemGraph(this.context);
2334
2335 reader.read(systemGraph, nodeTypesPath, createdNodeTypeNames, null);
2336
2337 Problems readerProblems = reader.getProblems();
2338 if (readerProblems.hasProblems()) {
2339 if (readerProblems.hasErrors()) {
2340 LOGGER.error(JcrI18n.errorReadingNodeTypesFromRemote, reader.getProblems());
2341 return;
2342 }
2343
2344 LOGGER.warn(JcrI18n.problemReadingNodeTypesFromRemote, reader.getProblems());
2345 }
2346
2347 Map<Name, JcrNodeType> newNodeTypeMap = new HashMap<Name, JcrNodeType>();
2348 try {
2349 for (NodeTypeDefinition nodeTypeDefn : reader.getNodeTypeDefinitions()) {
2350 List<JcrNodeType> supertypes = supertypesFor(nodeTypeDefn, newNodeTypeMap.values());
2351 JcrNodeType nodeType = nodeTypeFrom(nodeTypeDefn, supertypes);
2352
2353 newNodeTypeMap.put(nodeType.getInternalName(), nodeType);
2354 }
2355 } catch (Throwable re) {
2356 LOGGER.error(JcrI18n.errorSynchronizingNodeTypes, re);
2357 }
2358
2359 assert this.nodeTypes.get(ModeShapeLexicon.ROOT) != null;
2360 assert !deletedNodeTypeNames.contains(ModeShapeLexicon.ROOT);
2361
2362 nodeTypes.keySet().removeAll(deletedNodeTypeNames);
2363 this.nodeTypes.putAll(newNodeTypeMap);
2364
2365 assert this.nodeTypes.get(ModeShapeLexicon.ROOT) != null;
2366
2367 for (JcrSession activeSession : repository.activeSessions()) {
2368 JcrWorkspace workspace = activeSession.workspace();
2369 if (workspace == null) continue;
2370
2371 JcrNodeTypeManager nodeTypeManager = workspace.nodeTypeManager();
2372 if (nodeTypeManager == null) continue;
2373
2374 nodeTypeManager.signalExternalNodeTypeChanges();
2375 }
2376
2377 } finally {
2378 this.schemata = null;
2379 this.nodeTypeManagerLock.writeLock().unlock();
2380 }
2381
2382 }
2383 }