TreeUtil { public static Tree addChild( @NotNull Tree parent, @NotNull String name, @Nullable String typeName, @NotNull Tree typeRoot, @Nullable String userID) throws RepositoryException { if (typeName == null) { typeName = getDefaultChildType(typeRoot, parent, name); if (typeName == null) { String path = PathUtils.concat(parent.getPath(), name); throw new ConstraintViolationException( "No default node type available for " + path); } } Tree type = typeRoot.getChild(typeName); if (!type.exists()) { throw new NoSuchNodeTypeException( "Node type " + typeName + " does not exist"); } else if (getBoolean(type, JCR_IS_ABSTRACT) && !typeName.equals(getDefaultChildType(typeRoot, parent, name))) { throw new ConstraintViolationException( "Node type " + typeName + " is abstract"); } else if (getBoolean(type, JCR_ISMIXIN)) { throw new ConstraintViolationException( "Node type " + typeName + " is a mixin type"); } Tree child = parent.addChild(name); child.setProperty(JCR_PRIMARYTYPE, typeName, NAME); if (getBoolean(type, JCR_HASORDERABLECHILDNODES)) { child.setOrderableChildren(true); } autoCreateItems(child, type, typeRoot, userID); return child; } 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 = ConstraintViolationException.class) public void testAddChildNullTypeNameNoDefault() throws Exception { Tree parent = mockTree("/some/tree", true); TreeUtil.addChild(parent, "grandChild", null, typeRoot, "userid"); }
@Test(expected = NoSuchNodeTypeException.class) public void testAddChildWithNonExistingTypeName() throws Exception { Tree parent = mockTree("/some/tree", true); TreeUtil.addChild(parent, "name", "rep:NonExistingType", typeRoot, "userid"); }
@Test(expected = ConstraintViolationException.class) public void testAddChildWithMixinName() throws Exception { Tree parent = mockTree("/some/tree", true); when(ntDef.getProperty(JCR_ISMIXIN)).thenReturn(PropertyStates.createProperty(JCR_ISMIXIN, true, Type.BOOLEAN)); TreeUtil.addChild(parent, "name", MIX_LOCKABLE, typeRoot, "userid"); }
@Test(expected = ConstraintViolationException.class) public void testAddChildWithAbstractName() throws Exception { Tree parent = mockTree("/some/tree", true); when(ntDef.getProperty(JCR_IS_ABSTRACT)).thenReturn(PropertyStates.createProperty(JCR_IS_ABSTRACT, true, Type.BOOLEAN)); TreeUtil.addChild(parent, "name", MIX_LOCKABLE, typeRoot, "userid"); }
@Test public void testAddChildWithOrderableChildren() throws Exception { Tree t = mock(Tree.class); Tree parent = when(mockTree("/some/tree", true).addChild("name")).thenReturn(t).getMock(); when(ntDef.getProperty(JCR_HASORDERABLECHILDNODES)).thenReturn(PropertyStates.createProperty(JCR_HASORDERABLECHILDNODES, true, Type.BOOLEAN)); Tree defWithoutChildren = when(mock(Tree.class).getChildren()).thenReturn(ImmutableList.of()).getMock(); when(ntDef.getChild(REP_NAMED_PROPERTY_DEFINITIONS)).thenReturn(defWithoutChildren); when(ntDef.getChild(REP_NAMED_CHILD_NODE_DEFINITIONS)).thenReturn(defWithoutChildren); TreeUtil.addChild(parent, "name", NT_OAK_UNSTRUCTURED, typeRoot, "userid"); verify(t, times(1)).setOrderableChildren(true); }
@Test public void testAddChild() throws Exception { assertEquals(z.getPath(), TreeUtil.addChild(rootTree, z.getName(), NT_OAK_UNSTRUCTURED).getPath()); }