code: private NodeImpl doAddNode(NodeImpl parentNode, InternalQName name, InternalQName primaryTypeName,
        NodeDefinitionData nodeDef) throws ItemExistsException, RepositoryException, ConstraintViolationException,
        VersionException, LockException
     {
        validateChildNode(parentNode, name, primaryTypeName, nodeDef);
  
        // Initialize data
        InternalQName[] mixinTypeNames = new InternalQName[0];
        String identifier = IdGenerator.generate();
  
        int orderNum = parentNode.getNextChildOrderNum();
        int index = parentNode.getNextChildIndex(name, primaryTypeName, parentNode.nodeData(), nodeDef);
  
        QPath path = QPath.makeChildPath(parentNode.getInternalPath(), name, index);
  
        AccessControlList acl = parentNode.getACL();
  
        // create new nodedata, [PN] fix of use index as persisted version
        NodeData nodeData =
           new TransientNodeData(path, identifier, -1, primaryTypeName, mixinTypeNames, orderNum, parentNode
              .getInternalIdentifier(), acl);
  
        // Create new Node
        ItemState state = ItemState.createAddedState(nodeData, false);
        NodeImpl node = (NodeImpl)dataManager.update(state, true);
  
        NodeTypeDataManager ntmanager = session.getWorkspace().getNodeTypesHolder();
        ItemAutocreator itemAutocreator = new ItemAutocreator(ntmanager, valueFactory, dataManager, true);
  
        PlainChangesLog changes =
           itemAutocreator.makeAutoCreatedItems(node.nodeData(), primaryTypeName, dataManager, session.getUserID());
        for (ItemState autoCreatedState : changes.getAllStates())
        {
           dataManager.updateItemState(autoCreatedState);
        }
  
        session.getActionHandler().postAddNode(node);
  
        return node;
     }
docs: Do add node internally. If nodeDef not null it is used in getNextChildIndex() method to
  avoid double calculation.