TreeUtil { public static void addMixin(@NotNull Tree tree, @NotNull String mixinName, @NotNull Tree typeRoot, @Nullable String userID) throws RepositoryException { Tree type = typeRoot.getChild(mixinName); if (!type.exists()) { throw new NoSuchNodeTypeException( "Node type " + mixinName + " does not exist"); } else if (getBoolean(type, JCR_IS_ABSTRACT)) { throw new ConstraintViolationException( "Node type " + mixinName + " is abstract"); } else if (!getBoolean(type, JCR_ISMIXIN)) { throw new ConstraintViolationException( "Node type " + mixinName + " is a not a mixin type"); } List<String> mixins = Lists.newArrayList(); String primary = getName(tree, JCR_PRIMARYTYPE); if (primary != null && Iterables.contains(getNames(type, NodeTypeConstants.REP_PRIMARY_SUBTYPES), primary)) { return; } Set<String> subMixins = Sets.newHashSet(getNames(type, NodeTypeConstants.REP_MIXIN_SUBTYPES)); for (String mixin : getNames(tree, NodeTypeConstants.JCR_MIXINTYPES)) { if (mixinName.equals(mixin) || subMixins.contains(mixin)) { return; } mixins.add(mixin); } mixins.add(mixinName); tree.setProperty(JcrConstants.JCR_MIXINTYPES, mixins, NAMES); autoCreateItems(tree, type, typeRoot, userID); } private  TreeUtil(); @Nullable static String getPrimaryTypeName(@NotNull Tree tree); @Nullable static String getPrimaryTypeName(@NotNull Tree tree, @NotNull LazyValue<Tree> readOnlyTree); @NotNull static Iterable<String> getMixinTypeNames(@NotNull Tree tree); @NotNull static Iterable<String> getMixinTypeNames(@NotNull Tree tree, @NotNull LazyValue<Tree> readOnlyTree); @Nullable static Iterable<String> getStrings(@NotNull Tree tree, @NotNull String propertyName); @Nullable static String getString(@NotNull Tree tree, @NotNull String propertyName); @Nullable static String getString(@NotNull Tree tree, @NotNull String name, @Nullable String defaultValue); static boolean getBoolean(@NotNull Tree tree, @NotNull String propertyName); @Nullable static String getName(@NotNull Tree tree, @NotNull String name); @NotNull static Iterable<String> getNames(@NotNull Tree tree, @NotNull String name); static long getLong(@NotNull Tree tree, @NotNull String name, long defaultValue); @Nullable static Tree getTree(@NotNull Tree tree, @NotNull String path); static Tree addChild(
            @NotNull Tree parent, @NotNull String name,
            @Nullable String typeName, @NotNull Tree typeRoot,
            @Nullable String userID); @NotNull static Tree addChild(@NotNull Tree tree, @NotNull String childName, @NotNull String primaryTypeName); @NotNull static Tree getOrAddChild(@NotNull Tree tree, @NotNull String childName, @NotNull String primaryTypeName); static void addMixin(@NotNull Tree tree, @NotNull String mixinName, @NotNull Tree typeRoot, @Nullable String userID); static void autoCreateItems(@NotNull Tree tree, @NotNull Tree type, @NotNull Tree typeRoot, @Nullable String userID); static PropertyState autoCreateProperty(@NotNull String name,
                                                   @NotNull Tree definition,
                                                   @Nullable String userID); static String getDefaultChildType(
            Tree typeRoot, Tree parent, String childName); static List<Tree> getEffectiveType(Tree tree, Tree typeRoot); static String findDefaultPrimaryType(Tree definitions, boolean sns); static boolean isNodeType(Tree tree, String typeName, Tree typeRoot); static boolean isReadOnlyTree(@NotNull Tree tree);  }
@Test(expected = NoSuchNodeTypeException.class) public void testAddMixinNonExisting() throws Exception { TreeUtil.addMixin(child, "rep:NonExistingType", typeRoot, "userId"); }
@Test(expected = ConstraintViolationException.class) public void testAddMixinAbstract() throws Exception { when(ntDef.getProperty(JCR_IS_ABSTRACT)).thenReturn(PropertyStates.createProperty(JCR_IS_ABSTRACT, true, Type.BOOLEAN)); TreeUtil.addMixin(child, NT_OAK_UNSTRUCTURED, typeRoot, "userId"); }
@Test(expected = ConstraintViolationException.class) public void testAddMixinNotMixin() throws Exception { when(ntDef.getProperty(JCR_ISMIXIN)).thenReturn(PropertyStates.createProperty(JCR_ISMIXIN, false, Type.BOOLEAN)); TreeUtil.addMixin(child, NT_OAK_UNSTRUCTURED, typeRoot, "userId"); }
@Test public void testAddMixinAlreadyContained() throws Exception { when(ntDef.getProperty(JCR_ISMIXIN)).thenReturn(PropertyStates.createProperty(JCR_ISMIXIN, true, Type.BOOLEAN)); TreeUtil.addMixin(child, MIX_LOCKABLE, typeRoot, "userId"); verify(child, times(1)).getProperty(JcrConstants.JCR_MIXINTYPES); verify(child, never()).setProperty(JcrConstants.JCR_MIXINTYPES, Lists.newArrayList(MIX_LOCKABLE, MIX_VERSIONABLE, MIX_CREATED), Type.NAMES); }
@Test public void testAddMixinAlreadyContainedNoPrimary() throws Exception { when(ntDef.getProperty(JCR_ISMIXIN)).thenReturn(PropertyStates.createProperty(JCR_ISMIXIN, true, Type.BOOLEAN)); when(child.getProperty(JCR_PRIMARYTYPE)).thenReturn(null); TreeUtil.addMixin(child, MIX_LOCKABLE, typeRoot, "userId"); verify(child, times(1)).getProperty(JcrConstants.JCR_MIXINTYPES); verify(child, never()).setProperty(JcrConstants.JCR_MIXINTYPES, Lists.newArrayList(MIX_LOCKABLE, MIX_VERSIONABLE, MIX_CREATED), Type.NAMES); }
@Test public void testAddMixinSuPrimary() throws Exception { when(ntDef.getProperty(JCR_ISMIXIN)).thenReturn(PropertyStates.createProperty(JCR_ISMIXIN, true, Type.BOOLEAN)); when(ntDef.getProperty(REP_PRIMARY_SUBTYPES)).thenReturn(PropertyStates.createProperty(REP_PRIMARY_SUBTYPES, ImmutableList.of(NT_OAK_UNSTRUCTURED), Type.NAMES)); when(typeRoot.getChild("containsSubPrimary")).thenReturn(ntDef); TreeUtil.addMixin(child, "containsSubPrimary", typeRoot, "userId"); verify(child, times(1)).getProperty(JcrConstants.JCR_PRIMARYTYPE); verify(child, never()).setProperty(anyString(), any(), any(Type.class)); }
@Test public void testAddMixinSubMixin() throws Exception { when(ntDef.getProperty(JCR_ISMIXIN)).thenReturn(PropertyStates.createProperty(JCR_ISMIXIN, true, Type.BOOLEAN)); when(ntDef.getProperty(REP_MIXIN_SUBTYPES)).thenReturn(PropertyStates.createProperty(REP_MIXIN_SUBTYPES, ImmutableList.of(MIX_VERSIONABLE), Type.NAMES)); when(typeRoot.getChild("containsSubMixin")).thenReturn(ntDef); TreeUtil.addMixin(child, "containsSubMixin", typeRoot, "userId"); verify(child, times(1)).getProperty(JcrConstants.JCR_MIXINTYPES); verify(child, never()).setProperty(anyString(), any(), any(Type.class)); }
@Test public void testAddMixin() throws Exception { Tree defWithoutChildren = when(mock(Tree.class).getChildren()).thenReturn(ImmutableList.of()).getMock(); when(ntDef.getProperty(JCR_ISMIXIN)).thenReturn(PropertyStates.createProperty(JCR_ISMIXIN, true, Type.BOOLEAN)); when(ntDef.getChild(REP_NAMED_PROPERTY_DEFINITIONS)).thenReturn(defWithoutChildren); when(ntDef.getChild(REP_NAMED_CHILD_NODE_DEFINITIONS)).thenReturn(defWithoutChildren); when(typeRoot.getChild(MIX_CREATED)).thenReturn(ntDef); TreeUtil.addMixin(child, MIX_CREATED, typeRoot, "userId"); verify(child, times(1)).getProperty(JcrConstants.JCR_MIXINTYPES); verify(child, times(1)).setProperty(JcrConstants.JCR_MIXINTYPES, Lists.newArrayList(MIX_LOCKABLE, MIX_VERSIONABLE, MIX_CREATED), Type.NAMES); }