You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by to...@apache.org on 2016/05/17 14:43:30 UTC
svn commit: r1744284 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/
oak-core/src/test/java/org/apache/jackrabbit/oak/
oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/
oak-core/src/test/jav...
Author: tomekr
Date: Tue May 17 14:43:30 2016
New Revision: 1744284
URL: http://svn.apache.org/viewvc?rev=1744284&view=rev
Log:
OAK-4370: Unreferenced empty VersionHistories should be deleted automatically
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/OrphanedVersionCleaner.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionHook.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionableCollector.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/Utils.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditorProvider.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/OrphanedVersionCleaner.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/OrphanedVersionCleaner.java?rev=1744284&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/OrphanedVersionCleaner.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/OrphanedVersionCleaner.java Tue May 17 14:43:30 2016
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.version;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONSTORAGE;
+
+/**
+ * This editor removes empty version histories for nodes that are no longer versionable
+ * (eg. because were deleted). The class won't remove histories for nodes which
+ * UUIDs are present in the {@link OrphanedVersionCleaner#existingVersionables}.
+ * The set should be used to skip processing moved/renamed nodes and it can be
+ * filled by the related {@link VersionableCollector} editor.
+ */
+class OrphanedVersionCleaner extends DefaultEditor {
+
+ private final ReadWriteVersionManager vMgr;
+
+ private final Set<String> existingVersionables;
+
+ OrphanedVersionCleaner(ReadWriteVersionManager vMgr, Set<String> existingVersionables) {
+ this.vMgr = vMgr;
+ this.existingVersionables = existingVersionables;
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) throws CommitFailedException {
+ if (vMgr.isVersionable(before) && !vMgr.isVersionable(after)) {
+ String versionableUuid = Utils.uuidFromNode(before);
+ if (!existingVersionables.contains(versionableUuid)) {
+ vMgr.removeEmptyHistory(before);
+ }
+ }
+ }
+
+ @Override
+ public Editor childNodeAdded(String name, NodeState after) throws CommitFailedException {
+ return this;
+ }
+
+ @Override
+ public Editor childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException {
+ return this;
+ }
+
+ @Override
+ public Editor childNodeDeleted(String name, NodeState before) throws CommitFailedException {
+ return this;
+ }
+
+ static class Provider implements EditorProvider {
+
+ private final Set<String> existingVersionables;
+
+ Provider(Set<String> existingVersionables) {
+ this.existingVersionables = existingVersionables;
+ }
+
+ @Override
+ public Editor getRootEditor(NodeState before, NodeState after, NodeBuilder builder, CommitInfo info) throws CommitFailedException {
+ if (!builder.hasChildNode(JCR_SYSTEM)) {
+ return null;
+ }
+ NodeBuilder system = builder.child(JCR_SYSTEM);
+ if (!system.hasChildNode(JCR_VERSIONSTORAGE)) {
+ return null;
+ }
+ NodeBuilder versionStorage = system.child(JCR_VERSIONSTORAGE);
+ ReadWriteVersionManager vMgr = new ReadWriteVersionManager(versionStorage, builder);
+ return new OrphanedVersionCleaner(vMgr, existingVersionables);
+ }
+
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManager.java Tue May 17 14:43:30 2016
@@ -32,6 +32,8 @@ import org.apache.jackrabbit.oak.commons
import org.apache.jackrabbit.oak.namepath.NamePathMapper;
import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.util.TreeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -324,4 +326,18 @@ public abstract class ReadOnlyVersionMan
return getNodeTypeManager().isNodeType(
checkNotNull(tree), VersionConstants.MIX_VERSIONABLE);
}
+
+ /**
+ * Returns {@code true} if the given {@code versionableCandidate} is of type
+ * {@code mix:versionable}; {@code false} otherwise.
+ *
+ * @param versionableCandidate node state to check.
+ * @return whether the {@code versionableCandidate} is versionable.
+ */
+ boolean isVersionable(NodeState versionableCandidate) {
+ // this is not 100% correct, because t.getPath() will
+ // not return the correct path for node after, but is
+ // sufficient to check if it is versionable
+ return isVersionable(TreeFactory.createReadOnlyTree(versionableCandidate));
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/ReadWriteVersionManager.java Tue May 17 14:43:30 2016
@@ -42,9 +42,12 @@ import org.apache.jackrabbit.oak.namepat
import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
import org.apache.jackrabbit.oak.plugins.tree.RootFactory;
import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.util.ISO8601;
import org.apache.jackrabbit.util.Text;
@@ -78,12 +81,14 @@ public class ReadWriteVersionManager ext
private final NodeBuilder versionStorageNode;
private final NodeBuilder workspaceRoot;
+ private final TypePredicate isVersion;
private ReadOnlyNodeTypeManager ntMgr;
public ReadWriteVersionManager(NodeBuilder versionStorageNode,
NodeBuilder workspaceRoot) {
this.versionStorageNode = checkNotNull(versionStorageNode);
this.workspaceRoot = checkNotNull(workspaceRoot);
+ this.isVersion = new TypePredicate(workspaceRoot.getNodeState(), NT_VERSION);
}
@Nonnull
@@ -305,6 +310,18 @@ public class ReadWriteVersionManager ext
labels.removeProperty(label);
}
+ /**
+ * Removes the version history if it's empty.
+ *
+ * @param versionable the versionable node.
+ */
+ void removeEmptyHistory(@Nonnull NodeState versionable) {
+ NodeBuilder history = getVersionHistory(versionable);
+ if (isEmptyHistory(history.getNodeState())) {
+ history.remove();
+ }
+ }
+
// TODO: more methods that modify versions
//------------------------------< internal >--------------------------------
@@ -560,4 +577,55 @@ public class ReadWriteVersionManager ext
}
return null;
}
+
+ /**
+ * Gets the version history for the given
+ * {@code versionable} node.
+ *
+ * @param versionable the versionable node.
+ * @return the version history node.
+ * @throws IllegalArgumentException if the given node does not have a
+ * {@code jcr:uuid} property.
+ */
+ @Nonnull
+ private NodeBuilder getVersionHistory(@Nonnull NodeState versionable) {
+ checkNotNull(versionable);
+ String vUUID = uuidFromNode(versionable);
+ String relPath = getVersionHistoryPath(vUUID);
+ NodeBuilder node = versionStorageNode;
+ for (Iterator<String> it = PathUtils.elements(relPath).iterator(); it.hasNext(); ) {
+ String name = it.next();
+ node = node.getChildNode(name);
+ if (!node.exists()) {
+ throw new IllegalArgumentException("No version history for this node");
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Checks whether the passed node history hasn't been modified since its
+ * creation. It means that: (1) there's just one version, called jcr:rootVersion
+ * and (2) there are no custom labels.
+ *
+ * @param versionHistory to test
+ * @return {@code true} if the version history hasn't been changed yet
+ */
+ private boolean isEmptyHistory(NodeState versionHistory) {
+ for (ChildNodeEntry entry : versionHistory.getChildNodeEntries()) {
+ String name = entry.getName();
+ NodeState node = entry.getNodeState();
+ if (!JCR_ROOTVERSION.equals(name) && isVersion.apply(node)) {
+ return false; // a checked-in version
+ }
+ }
+ NodeState labels = versionHistory.getChildNode(JCR_VERSIONLABELS);
+ for (PropertyState prop : labels.getProperties()) {
+ if (prop.getType() == Type.REFERENCE) {
+ return false; // custom label
+ }
+ }
+ return true;
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/Utils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/Utils.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/Utils.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/Utils.java Tue May 17 14:43:30 2016
@@ -29,6 +29,7 @@ import org.apache.jackrabbit.oak.api.Com
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
/**
* {@code Utils} provide some utility methods.
@@ -47,6 +48,11 @@ public final class Utils {
@Nonnull
static String uuidFromNode(@Nonnull NodeBuilder node)
throws IllegalArgumentException {
+ return uuidFromNode(node.getNodeState());
+ }
+
+ @Nonnull
+ static String uuidFromNode(@Nonnull NodeState node) {
PropertyState p = checkNotNull(node).getProperty(JCR_UUID);
if (p == null) {
throw new IllegalArgumentException("Not referenceable");
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditor.java Tue May 17 14:43:30 2016
@@ -187,10 +187,7 @@ class VersionEditor implements Editor {
*/
private boolean isVersionable() {
if (isVersionable == null) {
- // this is not 100% correct, because t.getPath() will
- // not return the correct path for node after, but is
- // sufficient to check if it is versionable
- isVersionable = vMgr.isVersionable(TreeFactory.createReadOnlyTree(after));
+ isVersionable = vMgr.isVersionable(after);
}
return isVersionable;
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditorProvider.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionEditorProvider.java Tue May 17 14:43:30 2016
@@ -16,8 +16,6 @@
*/
package org.apache.jackrabbit.oak.plugins.version;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.CompositeEditor;
import org.apache.jackrabbit.oak.spi.commit.Editor;
@@ -30,9 +28,15 @@ import org.apache.jackrabbit.oak.spi.sta
import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_VERSIONSTORAGE;
-@Component
-@Service(EditorProvider.class)
-public class VersionEditorProvider implements EditorProvider {
+/**
+ * A provider creating two editors: {@link VersionEditor}
+ * {@link VersionStorageEditor}.
+ * <p>
+ * Historically, it has been used to initalize the Jcr repository. Now, the
+ * more general {@link VersionHook} should be passed there using the {@code with()}
+ * method.
+ */
+class VersionEditorProvider implements EditorProvider {
@Override
public Editor getRootEditor(
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionHook.java?rev=1744284&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionHook.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionHook.java Tue May 17 14:43:30 2016
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.version;
+
+import com.google.common.base.Function;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.collect.Collections2.transform;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.jackrabbit.oak.spi.commit.CompositeHook.compose;
+
+/**
+ * This class gathers together editors related to handling version storage:
+ * <ol>
+ * <li>
+ * {@link VersionEditorProvider}
+ * <ul>
+ * <li>
+ * {@link VersionEditor} - creates version history, handles
+ * checking-in, checking-out and restoring, prevents a
+ * checked-in node from being modified,
+ * </li>
+ * <li>
+ * {@link VersionStorageEditor} - validates changes on the
+ * version storage,
+ * </li>
+ * </ul>
+ * </li>
+ * <li>
+ * {@link VersionableCollector} - collects all existing versionable
+ * UUIDs, so assigned histories won't be removed in the next step,
+ * </li>
+ * <li>
+ * {@link OrphanedVersionCleaner} - removes all histories that are
+ * empty and have no longer a parent versionable node.
+ * </li>
+ * </ol>
+ *
+ */
+@Component
+@Service(CommitHook.class)
+public class VersionHook implements CommitHook {
+
+ @Nonnull
+ @Override
+ public NodeState processCommit(NodeState before, NodeState after, CommitInfo info) throws CommitFailedException {
+ Set<String> existingVersionables = newHashSet();
+
+ List<EditorProvider> providers = newArrayList();
+ providers.add(new VersionEditorProvider());
+ providers.add(new VersionableCollector.Provider(existingVersionables));
+ providers.add(new OrphanedVersionCleaner.Provider(existingVersionables));
+
+ return compose(transform(providers, new Function<EditorProvider, CommitHook>() {
+ @Nullable
+ @Override
+ public CommitHook apply(@Nullable EditorProvider input) {
+ return new EditorHook(input);
+ }
+ })).processCommit(before, after, info);
+ }
+}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionableCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionableCollector.java?rev=1744284&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionableCollector.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/version/VersionableCollector.java Tue May 17 14:43:30 2016
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.version;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import java.util.Set;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONSTORAGE;
+
+/**
+ * This editor puts UUIDs of all processed versionables into
+ * {@link VersionableCollector#existingVersionables} set. The main purpose
+ * is to handle moved/renamed versionable nodes in the {@link OrphanedVersionCleaner}.
+ */
+class VersionableCollector extends DefaultEditor {
+
+ private final ReadWriteVersionManager vMgr;
+
+ private final Set<String> existingVersionables;
+
+ VersionableCollector(ReadWriteVersionManager vMgr, Set<String> existingVersionables) {
+ this.vMgr = vMgr;
+ this.existingVersionables = existingVersionables;
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) throws CommitFailedException {
+ if (vMgr.isVersionable(after)) {
+ existingVersionables.add(Utils.uuidFromNode(after));
+ }
+ }
+
+ @Override
+ public Editor childNodeAdded(String name, NodeState after) throws CommitFailedException {
+ return this;
+ }
+
+ @Override
+ public Editor childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException {
+ return this;
+ }
+
+ @Override
+ public Editor childNodeDeleted(String name, NodeState before) throws CommitFailedException {
+ return this;
+ }
+
+ static class Provider implements EditorProvider {
+
+ private final Set<String> existingVersionables;
+
+ Provider(Set<String> existingVersionables) {
+ this.existingVersionables = existingVersionables;
+ }
+
+ @Override
+ public Editor getRootEditor(NodeState before, NodeState after, NodeBuilder builder, CommitInfo info) throws CommitFailedException {
+ if (!builder.hasChildNode(JCR_SYSTEM)) {
+ return null;
+ }
+ NodeBuilder system = builder.child(JCR_SYSTEM);
+ if (!system.hasChildNode(JCR_VERSIONSTORAGE)) {
+ return null;
+ }
+ NodeBuilder versionStorage = system.child(JCR_VERSIONSTORAGE);
+ ReadWriteVersionManager vMgr = new ReadWriteVersionManager(versionStorage, builder);
+ return new VersionableCollector(vMgr, existingVersionables);
+ }
+
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java Tue May 17 14:43:30 2016
@@ -52,7 +52,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
-import org.apache.jackrabbit.oak.plugins.version.VersionEditorProvider;
+import org.apache.jackrabbit.oak.plugins.version.VersionHook;
import org.apache.jackrabbit.oak.security.SecurityProviderImpl;
import org.apache.jackrabbit.oak.spi.commit.EditorHook;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
@@ -84,7 +84,7 @@ public abstract class AbstractSecurityTe
public void before() throws Exception {
Oak oak = new Oak()
.with(new InitialContent())
- .with(new EditorHook(new VersionEditorProvider()))
+ .with(new VersionHook())
.with(JcrConflictHandler.createJcrConflictHandler())
.with(new NamespaceEditorProvider())
.with(new ReferenceEditorProvider())
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/version/ReadOnlyVersionManagerTest.java Tue May 17 14:43:30 2016
@@ -17,9 +17,11 @@
package org.apache.jackrabbit.oak.plugins.version;
import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.namepath.NamePathMapper;
@@ -32,6 +34,7 @@ import org.junit.Test;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.JcrConstants.JCR_ISCHECKEDOUT;
+import static org.apache.jackrabbit.JcrConstants.JCR_UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -166,4 +169,50 @@ public class ReadOnlyVersionManagerTest
assertNotNull(t);
assertFalse(t.exists());
}
+
+ @Test
+ public void testRemoveEmptyHistoryAfterRemovingVersionable() throws RepositoryException, CommitFailedException {
+ NodeUtil node = new NodeUtil(root.getTree("/"));
+ NodeUtil testVersionable = node.addChild("testVersionable", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ TreeUtil.addMixin(testVersionable.getTree(), JcrConstants.MIX_VERSIONABLE, root.getTree(NodeTypeConstants.NODE_TYPES_PATH), null);
+ root.commit();
+
+ String historyPath = versionManager.getVersionHistory(testVersionable.getTree()).getPath();
+ assertTrue(root.getTree(historyPath).exists());
+
+ testVersionable.getTree().remove();
+ root.commit();
+
+ assertFalse(root.getTree(historyPath).exists());
+ }
+
+ @Test
+ public void testPreserveNonEmptyHistoryAfterRemovingVersionable() throws RepositoryException, CommitFailedException {
+ String historyPath = versionManager.getVersionHistory(versionable).getPath();
+ assertTrue(root.getTree(historyPath).exists());
+
+ versionable.remove();
+ root.commit();
+
+ assertTrue(root.getTree(historyPath).exists());
+ }
+
+ @Test
+ public void testPreserveHistoryAfterMovingVersionable() throws RepositoryException, CommitFailedException {
+ NodeUtil node = new NodeUtil(root.getTree("/"));
+ NodeUtil testVersionable = node.addChild("testVersionable", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ TreeUtil.addMixin(testVersionable.getTree(), JcrConstants.MIX_VERSIONABLE, root.getTree(NodeTypeConstants.NODE_TYPES_PATH), null);
+ root.commit();
+
+ Tree history = versionManager.getVersionHistory(testVersionable.getTree());
+ assertTrue(history.exists());
+ String historyUuid = history.getProperty(JCR_UUID).getValue(Type.STRING);
+
+ assertTrue(root.move("/testVersionable", "/testVersionable2"));
+ root.commit();
+
+ history = versionManager.getVersionHistory(root.getTree("/testVersionable2"));
+ assertTrue(history.exists());
+ assertEquals(historyUuid, history.getProperty(JCR_UUID).getValue(Type.STRING));
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/VersionStorageTest.java Tue May 17 14:43:30 2016
@@ -23,13 +23,11 @@ import javax.jcr.security.AccessControlM
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
-import org.apache.jackrabbit.oak.Oak;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
import org.apache.jackrabbit.oak.plugins.version.ReadOnlyVersionManager;
import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
-import org.apache.jackrabbit.oak.plugins.version.VersionEditorProvider;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
import org.apache.jackrabbit.oak.util.TreeUtil;
import org.junit.Test;
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java?rev=1744284&r1=1744283&r2=1744284&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java Tue May 17 14:43:30 2016
@@ -46,13 +46,12 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
import org.apache.jackrabbit.oak.plugins.observation.CommitRateLimiter;
-import org.apache.jackrabbit.oak.plugins.version.VersionEditorProvider;
+import org.apache.jackrabbit.oak.plugins.version.VersionHook;
import org.apache.jackrabbit.oak.query.QueryEngineSettings;
import org.apache.jackrabbit.oak.security.SecurityProviderImpl;
import org.apache.jackrabbit.oak.spi.commit.CommitHook;
import org.apache.jackrabbit.oak.spi.commit.CompositeConflictHandler;
import org.apache.jackrabbit.oak.spi.commit.Editor;
-import org.apache.jackrabbit.oak.spi.commit.EditorHook;
import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
import org.apache.jackrabbit.oak.spi.commit.Observer;
import org.apache.jackrabbit.oak.spi.commit.PartialConflictHandler;
@@ -112,7 +111,7 @@ public class Jcr {
if (initialize) {
with(new InitialContent());
- with(new EditorHook(new VersionEditorProvider()));
+ with(new VersionHook());
with(new SecurityProviderImpl());