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.
+ *
+ * - The flat algorithm just returns the path
/jcr:system/jcr:versionStorage/{sha1}
. For example, given a node
+ * key with an identifier part of "fae2b929-c5ef-4ce5-9fa1-514779ca0ae3", the SHA-1 hash of the identifier is
+ * "b46dde8905f76361779339fa3ccacc4f47664255", so the path to the node's version history would be
+ * /jcr:system/jcr:versionStorage/b46dde8905f76361779339fa3ccacc4f47664255
.
+ * - The hierarchical algorithm creates a hiearchical path based upon the first 6 characters of the "{sha1}" hash:
+ *
/jcr:system/jcr:versionStorage/{part1}/{part2}/{part3}/{part4}
, where "{part1}" consists of the 1st and 2nd
+ * hex characters of the "{sha1}" string, "{part2}" consists of the 3rd and 4th hex characters of the "{sha1}" string,
+ * "{part3}" consists of the 5th and 6th characters of the "{sha1}" string, "{part4}" consists of the remaining characters.
+ * For example, given a node key with an identifier part of "fae2b929-c5ef-4ce5-9fa1-514779ca0ae3", the SHA-1 hash of the
+ * identifier is "b46dde8905f76361779339fa3ccacc4f47664255", so the path to the node's version history would be
+ * /jcr:system/jcr:versionStorage/b4/6d/de/298905f76361779339fa3ccacc4f47664255
.
+ *
+ *
+ *
+ * @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 );
+}