commit 6bcdf62097f898d48b7ded8f78497123241da830 Author: Randall Hauch Date: Wed Nov 14 09:58:48 2012 -0600 MODE-1188 Preliminary support for connectors that support versioning diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrVersionManager.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrVersionManager.java index 5f7b606..772de31 100644 --- a/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrVersionManager.java +++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrVersionManager.java @@ -106,6 +106,7 @@ final class JcrVersionManager implements VersionManager { private final Path versionStoragePath; private final PathAlgorithm versionHistoryPathAlgorithm; private final SystemContent readableSystem; + private final SystemVersionStore systemVersionStore; public JcrVersionManager( JcrSession session ) { super(); @@ -114,6 +115,7 @@ final class JcrVersionManager implements VersionManager { ExecutionContext context = session.context(); versionHistoryPathAlgorithm = new HiearchicalPathAlgorithm(versionStoragePath, context); readableSystem = new SystemContent(this.session.cache()); + this.systemVersionStore = new SystemVersionStore(this.session); } final ExecutionContext context() { @@ -192,6 +194,7 @@ final class JcrVersionManager implements VersionManager { * a node exists at the returned path. In fact, this method will return null for every node that is and has never been * versionable, or every node that is versionable but not checked in. */ + @Deprecated Path versionHistoryPathFor( NodeKey key ) { return versionHistoryPathAlgorithm.versionHistoryPathFor(key.getIdentifierHash()); } @@ -205,7 +208,7 @@ final class JcrVersionManager implements VersionManager { checkVersionable(node); // Try to look up the version history by its key ... - NodeKey historyKey = readableSystem.versionHistoryNodeKeyFor(node.key()); + NodeKey historyKey = systemVersionStore.getVersionHistoryNodeKeyForVersionable(node.key()); SessionCache cache = session.cache(); CachedNode historyNode = cache.getNode(historyKey); if (historyNode != null) { @@ -250,26 +253,16 @@ final class JcrVersionManager implements VersionManager { return (JcrVersionHistoryNode)session.node(historyNode, Type.VERSION_HISTORY); } + @Deprecated private void initializeVersionHistoryFor( AbstractJcrNode node, NodeKey historyKey, SessionCache cache ) throws RepositoryException { - SystemContent content = new SystemContent(session.createSystemCache(false)); CachedNode cachedNode = node.node(); Name primaryTypeName = cachedNode.getPrimaryType(cache); Set mixinTypeNames = cachedNode.getMixinTypes(cache); NodeKey versionedKey = cachedNode.getKey(); - Path versionHistoryPath = versionHistoryPathFor(versionedKey); DateTime now = session().dateFactory().create(); - - content.initializeVersionStorage(versionedKey, - historyKey, - null, - primaryTypeName, - mixinTypeNames, - versionHistoryPath, - null, - now); - content.save(); + systemVersionStore.initializeVersionStorage(versionedKey, historyKey, null, primaryTypeName, mixinTypeNames, null, now); } /** diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/SystemVersionStore.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/SystemVersionStore.java new file mode 100644 index 0000000..d6276b2 --- /dev/null +++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/SystemVersionStore.java @@ -0,0 +1,113 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr; + +import java.util.Set; +import org.modeshape.jcr.JcrVersionManager.HiearchicalPathAlgorithm; +import org.modeshape.jcr.JcrVersionManager.PathAlgorithm; +import org.modeshape.jcr.api.value.DateTime; +import org.modeshape.jcr.cache.NodeKey; +import org.modeshape.jcr.value.Name; +import org.modeshape.jcr.value.Path; +import org.modeshape.jcr.versioning.VersionStore; + +/** + * + */ +public class SystemVersionStore implements VersionStore { + + private final JcrSession session; + private final SystemContent readableSystem; + private final Path versionStoragePath; + private final PathAlgorithm versionHistoryPathAlgorithm; + + public SystemVersionStore( JcrSession session ) { + this.session = session; + ExecutionContext context = session.context(); + versionStoragePath = absolutePath(JcrLexicon.SYSTEM, JcrLexicon.VERSION_STORAGE); + versionHistoryPathAlgorithm = new HiearchicalPathAlgorithm(versionStoragePath, context); + readableSystem = new SystemContent(this.session.cache()); + } + + final Path absolutePath( Name... absolutePathSegments ) { + return session.pathFactory().createAbsolutePath(absolutePathSegments); + } + + /** + * Return the path to the nt:versionHistory node for the node with the supplied NodeKey. + *

+ * This method uses one of two algorithms, both of which operate upon the {@link NodeKey#getIdentifierHash() SHA-1 hash of the + * identifier part} of the versionable node's {@link NodeKey key}. In the following descriptions, "{sha1}" is hex string form + * of the SHA-1 hash of the identifier part of the versionable node's key. + *

+ *

+ * + * @param key the key for the node for which the path to the version history should be returned + * @return the path to the version history node that corresponds to the node with the given key. This does not guarantee that + * a node exists at the returned path. In fact, this method will return null for every node that is and has never been + * versionable, or every node that is versionable but not checked in. + */ + Path versionHistoryPathFor( NodeKey key ) { + return versionHistoryPathAlgorithm.versionHistoryPathFor(key.getIdentifierHash()); + } + + @Override + public NodeKey getVersionHistoryNodeKeyForVersionable( NodeKey key ) { + return readableSystem.versionHistoryNodeKeyFor(key); + } + + @Override + public void initializeVersionStorage( NodeKey versionableNodeKey, + NodeKey versionHistoryKey, + NodeKey versionKey, + Name primaryTypeName, + Set mixinTypeNames, + NodeKey originalVersionKey, + DateTime now ) { + Path versionHistoryPath = versionHistoryPathFor(versionableNodeKey); + SystemContent content = new SystemContent(session.createSystemCache(false)); + content.initializeVersionStorage(versionableNodeKey, + versionHistoryKey, + null, + primaryTypeName, + mixinTypeNames, + versionHistoryPath, + null, + now); + content.save(); + } + +} diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/versioning/VersionStore.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/versioning/VersionStore.java new file mode 100644 index 0000000..584f47c --- /dev/null +++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/versioning/VersionStore.java @@ -0,0 +1,105 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr.versioning; + +import java.util.Collection; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import org.modeshape.jcr.api.value.DateTime; +import org.modeshape.jcr.cache.CachedNode; +import org.modeshape.jcr.cache.NodeKey; +import org.modeshape.jcr.cache.SessionCache; +import org.modeshape.jcr.value.Name; +import org.modeshape.jcr.value.Path; +import org.modeshape.jcr.value.Property; + +/** + * + */ +public interface VersionStore { + + NodeKey getVersionHistoryNodeKeyForVersionable( NodeKey key ); + + /** + * Create and initialize the version history structure for a versionable node with the supplied UUID. This method assumes that + * the version history node does not exist. + *

+ * Given a NodeKey for a node that has an identifier part of "fae2b929-c5ef-4ce5-9fa1-514779ca0ae3", the SHA-1 hash of this + * identifier part is "b46dde8905f76361779339fa3ccacc4f47664255". The path to the version history for this node is as follows: + * + *

+     *    + 298905f76361779339fa3ccacc4f47664255   {jcr:primaryType = nt:versionHistory}
+     *      + jcr:versionLabels  {jcr:primaryType = nt:versionLabels}
+     *      + jcr:rootVersion  {jcr:primaryType = nt:version}
+     *        - jcr:uuid = ...
+     *        - jcr:created = ...
+     *        + jcr:frozenNode  {jcr:primaryType = nt:frozenNode}
+     *          - jcr:frozenUuid
+     *          - jcr:frozenPrimaryType
+     *          - jcr:frozenMixinTypes
+     * 
+ * + * @param versionableNodeKey the identifier of the versionable node for which the history is to be created; may not be null + * @param versionHistoryKey the key to the version history node; may not be null + * @param versionKey the key to be used for the initial version; may be null if the key should be generated + * @param primaryTypeName the name of the primary type of the versionable node; may not be null + * @param mixinTypeNames the names of the mixin types for the versionable node; may be null or empty + * @param originalVersionKey the key of the original node from which the new versionable node was copied; may be null + * @param now the current date time; may not be null + */ + void initializeVersionStorage( NodeKey versionableNodeKey, + NodeKey versionHistoryKey, + NodeKey versionKey, + Name primaryTypeName, + Set mixinTypeNames, + NodeKey originalVersionKey, + DateTime now ); + + /** + * The method efficiently updates the JCR version history and storage with a new version of a node being checked in. However, + * it does not update the versionable node with the "mix:versionable" properties. + *

+ * Note that this method should initialize the version history for the node if the version history does not already exist. + *

+ * + * @param versionableNode the versionable node for which a new version is to be created in the node's version history; may not + * be null + * @param cacheForVersionableNode the cache used to access the versionable node and any descendants; may not be null + * @param versionHistoryPath the path of the version history node; may not be null + * @param originalVersionKey the key of the original node from which the new versionable node was copied; may be null + * @param versionableProperties the versionable node's properties that should be record in the version history (on the frozen + * node); may be null or empty + * @param now the current date time; may not be null + * @param frozenNodeOutput the reference that should be set upon successful completion to the frozen node created under the + * new version; may not be null + * @return the node key for the new version node in the version history; never null + */ + public NodeKey recordNewVersion( CachedNode versionableNode, + SessionCache cacheForVersionableNode, + Path versionHistoryPath, + NodeKey originalVersionKey, + Collection versionableProperties, + DateTime now, + AtomicReference frozenNodeOutput ); +}