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 ro...@apache.org on 2017/08/02 12:19:07 UTC
svn commit: r1803812 - in /jackrabbit/oak/trunk:
oak-it/src/test/java/org/apache/jackrabbit/oak/composite/
oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/
oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composi...
Author: rombert
Date: Wed Aug 2 12:19:07 2017
New Revision: 1803812
URL: http://svn.apache.org/viewvc?rev=1803812&view=rev
Log:
OAK-6505 - Ensure mounted node stores don't contain referenceable nodes
Create an OSGi service that performs checks based on node types for a
certain tree. The service allow skipping certain node types from the
check, to allow transitioning existing instances in a more streamlined
way.
Added:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreChecker.java
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreCheckerTest.java
Removed:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/VersionableNodesMountedNodeStoreChecker.java
Modified:
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreBuilderTest.java
Modified: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreBuilderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreBuilderTest.java?rev=1803812&r1=1803811&r2=1803812&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreBuilderTest.java (original)
+++ jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreBuilderTest.java Wed Aug 2 12:19:07 2017
@@ -25,7 +25,7 @@ import org.apache.jackrabbit.oak.api.Com
import org.apache.jackrabbit.oak.api.IllegalRepositoryStateException;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.composite.checks.NodeStoreChecksService;
-import org.apache.jackrabbit.oak.composite.checks.VersionableNodesMountedNodeStoreChecker;
+import org.apache.jackrabbit.oak.composite.checks.NodeTypeMountedNodeStoreChecker;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
@@ -115,7 +115,7 @@ public class CompositeNodeStoreBuilderTe
new CompositeNodeStore.Builder(mip, root)
.addMount("readOnly", mount)
- .with(new NodeStoreChecksService(Collections.singletonList(new VersionableNodesMountedNodeStoreChecker())))
+ .with(new NodeStoreChecksService(Collections.singletonList(new NodeTypeMountedNodeStoreChecker(JcrConstants.MIX_VERSIONABLE, "test error"))))
.build();
}
Added: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreChecker.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreChecker.java?rev=1803812&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreChecker.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreChecker.java Wed Aug 2 12:19:07 2017
@@ -0,0 +1,129 @@
+/*
+ * 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.composite.checks;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PropertiesUtil;
+import org.apache.jackrabbit.oak.composite.MountedNodeStore;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.plugins.tree.RootFactory;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+
+@Component(configurationFactory=true,
+ policy = ConfigurationPolicy.REQUIRE)
+@Service(MountedNodeStoreChecker.class)
+public class NodeTypeMountedNodeStoreChecker implements
+ MountedNodeStoreChecker<NodeTypeMountedNodeStoreChecker.Context> {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Property(label = "The name of a node type that is invalid and will be rejected when found")
+ private static final String INVALID_NODE_TYPE = "invalidNodeType";
+ @Property(label = "The error label to use when rejecting an invalid node type")
+ private static final String ERROR_LABEL = "errorLabel";
+
+ @Property(label="Node types that will cause the check to succeeed, even in the invalid node type is also found.",
+ cardinality = Integer.MAX_VALUE)
+ private static final String EXCLUDED_NODE_TYPES = "excludedNodeTypes";
+
+ private String invalidNodeType;
+ private String errorLabel;
+ private Set<String> excludedNodeTypes;
+
+ // used by SCR
+ public NodeTypeMountedNodeStoreChecker() {
+
+ }
+
+ // visible for testing
+ public NodeTypeMountedNodeStoreChecker(String invalidNodeType, String errorLabel, String... excludedNodeTypes) {
+ this.invalidNodeType = invalidNodeType;
+ this.errorLabel = errorLabel;
+ this.excludedNodeTypes = ImmutableSet.copyOf(excludedNodeTypes);
+ }
+
+ protected void activate(ComponentContext ctx) {
+ invalidNodeType = checkNotNull(PropertiesUtil.toString(ctx.getProperties().get(INVALID_NODE_TYPE), null), INVALID_NODE_TYPE);
+ errorLabel = checkNotNull(PropertiesUtil.toString(ctx.getProperties().get(ERROR_LABEL), null), ERROR_LABEL);
+ excludedNodeTypes = ImmutableSet.copyOf(PropertiesUtil.toStringArray(ctx.getProperties().get(EXCLUDED_NODE_TYPES), new String[0]));
+ }
+
+ @Override
+ public Context createContext(NodeStore globalStore) {
+
+ Root globalRoot = RootFactory.createReadOnlyRoot(globalStore.getRoot());
+ ReadOnlyNodeTypeManager typeManager = ReadOnlyNodeTypeManager.getInstance(globalRoot, NamePathMapper.DEFAULT);
+
+ return new Context(typeManager);
+ }
+
+ @Override
+ public void check(MountedNodeStore mountedStore, Tree tree, ErrorHolder errorHolder, Context context) {
+
+ if ( context.getTypeManager().isNodeType(tree, invalidNodeType) &&
+ !isExcluded(mountedStore, tree, context) ) {
+ errorHolder.report(mountedStore, tree.getPath(), errorLabel);
+ }
+ }
+
+ private boolean isExcluded(MountedNodeStore mountedStore, Tree tree, Context context) {
+
+ for ( String excludedNodeType : excludedNodeTypes ) {
+ if ( context.getTypeManager().isNodeType(tree, excludedNodeType ) ) {
+ log.warn("Not failing check for tree at path {}, mount {} due to matching excluded node type {}",
+ tree.getPath(), mountedStore.getMount().getName(), excludedNodeType);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName()+ ": [ invalidNodeType: " + invalidNodeType +
+ ", excludedNodeTypes: " + excludedNodeTypes + " ]";
+ }
+
+ protected static class Context {
+
+ private final ReadOnlyNodeTypeManager typeManager;
+
+ Context(ReadOnlyNodeTypeManager typeManager) {
+ this.typeManager = typeManager;
+ }
+
+ public ReadOnlyNodeTypeManager getTypeManager() {
+ return typeManager;
+ }
+ }
+
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreCheckerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreCheckerTest.java?rev=1803812&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreCheckerTest.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeTypeMountedNodeStoreCheckerTest.java Wed Aug 2 12:19:07 2017
@@ -0,0 +1,80 @@
+package org.apache.jackrabbit.oak.composite.checks;
+
+import java.util.Collections;
+import java.util.UUID;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.IllegalRepositoryStateException;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.composite.MountedNodeStore;
+import org.apache.jackrabbit.oak.composite.checks.NodeTypeMountedNodeStoreChecker.Context;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.junit.Test;
+
+public class NodeTypeMountedNodeStoreCheckerTest {
+
+ @Test(expected = IllegalRepositoryStateException.class)
+ public void referenceableNodeIsDetected() throws CommitFailedException {
+
+ MemoryNodeStore root = new MemoryNodeStore();
+ MemoryNodeStore mount = new MemoryNodeStore();
+
+ NodeBuilder builder = mount.getRoot().builder();
+ builder.child("first")
+ .setProperty(PropertyStates.createProperty(JcrConstants.JCR_MIXINTYPES,
+ Collections.singletonList(JcrConstants.MIX_REFERENCEABLE), Type.NAMES))
+ .setProperty(JcrConstants.JCR_UUID, UUID.randomUUID().toString());
+
+ mount.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ MountInfoProvider mip = Mounts.newBuilder()
+ .readOnlyMount("first", "/first")
+ .build();
+
+ NodeTypeMountedNodeStoreChecker checker = new NodeTypeMountedNodeStoreChecker(JcrConstants.MIX_REFERENCEABLE, "test error");
+ Context context = checker.createContext(root);
+ ErrorHolder errorHolder = new ErrorHolder();
+
+ checker.check(new MountedNodeStore(mip.getMountByName("first"), mount), TreeFactory.createReadOnlyTree(mount.getRoot()).getChild("first"), errorHolder, context);
+
+ errorHolder.end();
+ }
+
+ @Test
+ public void referenceableNodeInWhitelistIsSkipped() throws CommitFailedException {
+
+ MemoryNodeStore root = new MemoryNodeStore();
+ MemoryNodeStore mount = new MemoryNodeStore();
+
+ NodeBuilder builder = mount.getRoot().builder();
+ builder.child("first")
+ .setProperty(PropertyStates.createProperty(JcrConstants.JCR_PRIMARYTYPE,
+ JcrConstants.NT_RESOURCE, Type.NAME))
+ .setProperty(PropertyStates.createProperty(JcrConstants.JCR_MIXINTYPES,
+ Collections.singletonList(JcrConstants.MIX_REFERENCEABLE), Type.NAMES))
+ .setProperty(JcrConstants.JCR_UUID, UUID.randomUUID().toString());
+
+ mount.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ MountInfoProvider mip = Mounts.newBuilder()
+ .readOnlyMount("first", "/first")
+ .build();
+
+ NodeTypeMountedNodeStoreChecker checker = new NodeTypeMountedNodeStoreChecker(JcrConstants.MIX_REFERENCEABLE, "test error",
+ JcrConstants.NT_RESOURCE);
+ Context context = checker.createContext(root);
+ ErrorHolder errorHolder = new ErrorHolder();
+
+ checker.check(new MountedNodeStore(mip.getMountByName("first"), mount), TreeFactory.createReadOnlyTree(mount.getRoot()).getChild("first"), errorHolder, context);
+
+ errorHolder.end();
+ }
+}