@SuppressWarnings( "fallthrough" )
    private void versionNodeAt( AbstractJcrNode node,
                                Name nodeName, 
                                MutableCachedNode parentInVersionHistory,
                                boolean forceCopy,
                                SessionCache nodeCache,
                                SessionCache versionHistoryCache ) throws RepositoryException {
        int onParentVersion = 0;
        if (forceCopy) {
            onParentVersion = OnParentVersionAction.COPY;
        } else {
            onParentVersion = node.getDefinition().getOnParentVersion();
        }

        NodeKey key = parentInVersionHistory.getKey().withRandomId();

        switch (onParentVersion) {
            case OnParentVersionAction.ABORT:
                throw new VersionException(JcrI18n.cannotCheckinNodeWithAbortChildNode.text(nodeName, 
                                                                                            node.getParent().getName()));
            case OnParentVersionAction.VERSION:
                if (node.isNodeType(JcrMixLexicon.VERSIONABLE)) {
                    // The frozen node should reference the version history of the node ...
                    JcrVersionHistoryNode history = node.getVersionHistory();
                    org.modeshape.jcr.value.Property primaryType = propertyFactory().create(JcrLexicon.PRIMARY_TYPE,
                                                                                            JcrNtLexicon.VERSIONED_CHILD);
                    Reference childVersionHistoryValue = session.referenceFactory().create(history.key(), true);                    
                    org.modeshape.jcr.value.Property childVersionHistory = propertyFactory().create(
                            JcrLexicon.CHILD_VERSION_HISTORY,
                            childVersionHistoryValue);
                    parentInVersionHistory.createChild(versionHistoryCache, key, nodeName, primaryType, childVersionHistory);
                    return;
                }

                // Otherwise, treat it as a copy, as per section 3.13.9 bullet item 5 in JSR-283, so DO NOT break ...
            case OnParentVersionAction.COPY:
                // Per section 3.13.9 item 5 in JSR-283, an OPV of COPY or VERSION (if not versionable)
                // results in COPY behavior "regardless of the OPV values of the sub-items".
                // We can achieve this by making the onParentVersionAction always COPY for the
                // recursive call ...
                forceCopy = true;

                PropertyFactory factory = propertyFactory();
                List<Property> props = new LinkedList<Property>();

                if (node.isShared()) {
                    // This is a shared node, so we should store a proxy to the shareable node ...
                    props.add(factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FROZEN_NODE));
                    props.add(factory.create(JcrLexicon.FROZEN_PRIMARY_TYPE, ModeShapeLexicon.SHARE));
                    props.add(factory.create(JcrLexicon.FROZEN_UUID, node.getIdentifier()));
                    props.add(factory.create(JcrLexicon.UUID, key));
                    parentInVersionHistory.createChild(versionHistoryCache, key, nodeName, props);

                    // The proxies to shareable nodes never have children (nor versionable properties), so we're done ...
                    return;
                }

                // But the copy needs to be a 'nt:frozenNode', so that it doesn't compete with the actual node
                // (outside of version history) ...
                Name primaryTypeName = node.getPrimaryTypeName();
                Set<Name> mixinTypeNames = node.getMixinTypeNames();
                props.add(factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FROZEN_NODE));
                props.add(factory.create(JcrLexicon.FROZEN_PRIMARY_TYPE, primaryTypeName));
                props.add(factory.create(JcrLexicon.FROZEN_MIXIN_TYPES, mixinTypeNames));
                props.add(factory.create(JcrLexicon.FROZEN_UUID, node.getIdentifier()));
                props.add(factory.create(JcrLexicon.UUID, key));
                addVersionedPropertiesFor(node, forceCopy, props);
                MutableCachedNode newCopy = parentInVersionHistory.createChild(versionHistoryCache, key, nodeName, props);

                // Now process the children of the versionable node ...
                NodeKey parentKey = node.key();
                for (ChildReference childRef : node.node().getChildReferences(nodeCache)) {
                    AbstractJcrNode child = session.node(childRef.getKey(), null, parentKey);
                    versionNodeAt(child, childRef.getName(), newCopy, forceCopy, nodeCache, versionHistoryCache);
                }
                return;
            case OnParentVersionAction.INITIALIZE:
            case OnParentVersionAction.COMPUTE:
            case OnParentVersionAction.IGNORE:
                // Do nothing for these. No built-in types require initialize or compute for child nodes.
                return;
            default:
                throw new IllegalStateException("Unexpected value: " + onParentVersion);
        }
    }
@ SuppressWarnings ( "fallthrough" ) private void versionNodeAt ( AbstractJcrNode node , Name nodeName , MutableCachedNode parentInVersionHistory , boolean forceCopy , SessionCache nodeCache , SessionCache versionHistoryCache ) throws RepositoryException { int onParentVersion = 0 ; if ( forceCopy ) { onParentVersion = OnParentVersionAction . COPY ; } else { onParentVersion = node . getDefinition ( ) . getOnParentVersion ( ) ; } NodeKey key = parentInVersionHistory . getKey ( ) . withRandomId ( ) ; switch ( onParentVersion ) { case OnParentVersionAction . ABORT : throw new VersionException ( JcrI18n . cannotCheckinNodeWithAbortChildNode . text ( nodeName , node . getParent ( ) . getName ( ) ) ) ; case OnParentVersionAction . VERSION : if ( node . isNodeType ( JcrMixLexicon . VERSIONABLE ) ) { JcrVersionHistoryNode history = node . getVersionHistory ( ) ; org . modeshape . jcr . value . Property primaryType = propertyFactory ( ) . create ( JcrLexicon . PRIMARY_TYPE , JcrNtLexicon . VERSIONED_CHILD ) ; Reference childVersionHistoryValue = session . referenceFactory ( ) . create ( history . key ( ) , true ) ; org . modeshape . jcr . value . Property childVersionHistory = propertyFactory ( ) . create ( JcrLexicon . CHILD_VERSION_HISTORY , childVersionHistoryValue ) ; parentInVersionHistory . createChild ( versionHistoryCache , key , nodeName , primaryType , childVersionHistory ) ; return ; } case OnParentVersionAction . COPY : forceCopy = true ; PropertyFactory factory = propertyFactory ( ) ; List < Property > props = new LinkedList < Property > ( ) ; if ( node . isShared ( ) ) { props . add ( factory . create ( JcrLexicon . PRIMARY_TYPE , JcrNtLexicon . FROZEN_NODE ) ) ; props . add ( factory . create ( JcrLexicon . FROZEN_PRIMARY_TYPE , ModeShapeLexicon . SHARE ) ) ; props . add ( factory . create ( JcrLexicon . FROZEN_UUID , node . getIdentifier ( ) ) ) ; props . add ( factory . create ( JcrLexicon . UUID , key ) ) ; parentInVersionHistory . createChild ( versionHistoryCache , key , nodeName , props ) ; return ; } Name primaryTypeName = node . getPrimaryTypeName ( ) ; Set < Name > mixinTypeNames = node . getMixinTypeNames ( ) ; props . add ( factory . create ( JcrLexicon . PRIMARY_TYPE , JcrNtLexicon . FROZEN_NODE ) ) ; props . add ( factory . create ( JcrLexicon . FROZEN_PRIMARY_TYPE , primaryTypeName ) ) ; props . add ( factory . create ( JcrLexicon . FROZEN_MIXIN_TYPES , mixinTypeNames ) ) ; props . add ( factory . create ( JcrLexicon . FROZEN_UUID , node . getIdentifier ( ) ) ) ; props . add ( factory . create ( JcrLexicon . UUID , key ) ) ; addVersionedPropertiesFor ( node , forceCopy , props ) ; MutableCachedNode newCopy = parentInVersionHistory . createChild ( versionHistoryCache , key , nodeName , props ) ; NodeKey parentKey = node . key ( ) ; for ( ChildReference childRef : node . node ( ) . getChildReferences ( nodeCache ) ) { AbstractJcrNode child = session . node ( childRef . getKey ( ) , null , parentKey ) ; versionNodeAt ( child , childRef . getName ( ) , newCopy , forceCopy , nodeCache , versionHistoryCache ) ; } return ; case OnParentVersionAction . INITIALIZE : case OnParentVersionAction . COMPUTE : case OnParentVersionAction . IGNORE : return ; default : throw new IllegalStateException ( "Unexpected value: " + onParentVersion ) ; } }
Create a version record for the given node under the given parent path with the given batch.

@param node the node for which the frozen version record should be created
@param nodeName the name of the node which we're versioning
@param parentInVersionHistory the node in the version history under which the frozen version should be recorded
@param forceCopy true if the OPV should be ignored and a COPY is to be performed, or false if the OPV should be used
@param nodeCache the session cache used to access the node information; may not be null
@param versionHistoryCache the session cache used to create nodes in the version history; may not be null     @throws RepositoryException if an error occurs accessing the repository