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/07/31 10:02:07 UTC
svn commit: r1803501 - 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/
oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/chec...
Author: rombert
Date: Mon Jul 31 10:02:06 2017
New Revision: 1803501
URL: http://svn.apache.org/viewvc?rev=1803501&view=rev
Log:
OAK-6445 - Ensure mounted node stores don't contain versionable nodes
Added:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/ErrorHolder.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/MountedNodeStoreChecker.java
- copied, changed from r1803272, jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecks.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksService.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/VersionableNodesMountedNodeStoreChecker.java
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksServiceTest.java
Modified:
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreBuilderTest.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreServiceTest.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=1803501&r1=1803500&r2=1803501&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 Mon Jul 31 10:02:06 2017
@@ -18,9 +18,21 @@
*/
package org.apache.jackrabbit.oak.composite;
+import java.util.Collections;
+
+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.checks.NodeStoreChecksService;
+import org.apache.jackrabbit.oak.composite.checks.VersionableNodesMountedNodeStoreChecker;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+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 CompositeNodeStoreBuilderTest {
@@ -82,4 +94,29 @@ public class CompositeNodeStoreBuilderTe
.addMount("not-temp", new MemoryNodeStore())
.build();
}
+
+ @Test(expected = IllegalRepositoryStateException.class)
+ public void versionableNode() throws CommitFailedException {
+
+ MemoryNodeStore root = new MemoryNodeStore();
+ MemoryNodeStore mount = new MemoryNodeStore();
+
+ // create a child node that is versionable
+ // note that we won't cover all checks here, we are only interested in seeing that at least one check is triggered
+ NodeBuilder rootBuilder = mount.getRoot().builder();
+ NodeBuilder childNode = rootBuilder.setChildNode("readOnly").setChildNode("second").setChildNode("third");
+ childNode.setProperty(JcrConstants.JCR_ISCHECKEDOUT, false);
+ childNode.setProperty(PropertyStates.createProperty(JcrConstants.JCR_MIXINTYPES , Collections.singletonList(JcrConstants.MIX_VERSIONABLE), Type.NAMES));
+ mount.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ MountInfoProvider mip = Mounts.newBuilder()
+ .readOnlyMount("readOnly", "/readOnly")
+ .build();
+
+ new CompositeNodeStore.Builder(mip, root)
+ .addMount("readOnly", mount)
+ .with(new NodeStoreChecksService(Collections.singletonList(new VersionableNodesMountedNodeStoreChecker())))
+ .build();
+
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java?rev=1803501&r1=1803500&r2=1803501&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java Mon Jul 31 10:02:06 2017
@@ -25,6 +25,7 @@ import org.apache.jackrabbit.oak.api.Blo
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.composite.checks.NodeStoreChecks;
import org.apache.jackrabbit.oak.spi.commit.CommitHook;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
@@ -461,10 +462,17 @@ public class CompositeNodeStore implemen
private boolean partialReadOnly = true;
+ private NodeStoreChecks checks;
+
public Builder(MountInfoProvider mip, NodeStore globalStore) {
this.mip = checkNotNull(mip, "mountInfoProvider");
this.globalStore = checkNotNull(globalStore, "globalStore");
}
+
+ public Builder with(NodeStoreChecks checks) {
+ this.checks = checks;
+ return this;
+ }
public Builder addMount(String mountName, NodeStore store) {
checkNotNull(store, "store");
@@ -490,6 +498,9 @@ public class CompositeNodeStore implemen
if (partialReadOnly) {
assertPartialMountsAreReadOnly();
}
+ if ( checks != null ) {
+ nonDefaultStores.forEach( s -> checks.check(globalStore, s));
+ }
return new CompositeNodeStore(mip, globalStore, nonDefaultStores, ignoreReadOnlyWritePaths);
}
Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java?rev=1803501&r1=1803500&r2=1803501&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java Mon Jul 31 10:02:06 2017
@@ -27,6 +27,7 @@ import org.apache.felix.scr.annotations.
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.jackrabbit.oak.api.jmx.CheckpointMBean;
import org.apache.jackrabbit.oak.commons.PropertiesUtil;
+import org.apache.jackrabbit.oak.composite.checks.NodeStoreChecks;
import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
import org.apache.jackrabbit.oak.spi.commit.ObserverTracker;
import org.apache.jackrabbit.oak.spi.mount.Mount;
@@ -67,6 +68,9 @@ public class CompositeNodeStoreService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC, bind = "bindNodeStore", unbind = "unbindNodeStore", referenceInterface = NodeStoreProvider.class, target="(!(service.pid=org.apache.jackrabbit.oak.composite.CompositeNodeStore))")
private List<NodeStoreWithProps> nodeStores = new ArrayList<>();
+
+ @Reference
+ private NodeStoreChecks checks;
@Property(label = "Ignore read only writes",
unbounded = PropertyUnbounded.ARRAY,
@@ -126,7 +130,7 @@ public class CompositeNodeStoreService {
LOG.info("Composite node store registration is deferred until there's a global node store registered in OSGi");
return;
} else {
- LOG.info("Found global node store: {}", getDescription(globalNs));
+ LOG.info("Found global node store: {}", globalNs.getDescription());
}
for (Mount m : mountInfoProvider.getNonDefaultMounts()) {
@@ -140,6 +144,7 @@ public class CompositeNodeStoreService {
CompositeNodeStore.Builder builder = new CompositeNodeStore.Builder(mountInfoProvider, globalNs.getNodeStoreProvider().getNodeStore());
nodeStoresInUse.add(globalNs.getNodeStoreProvider());
+ builder.with(checks);
builder.setPartialReadOnly(partialReadOnly);
for (String p : ignoreReadOnlyWritePaths) {
builder.addIgnoredReadOnlyWritePath(p);
@@ -152,7 +157,7 @@ public class CompositeNodeStoreService {
String mountName = getMountName(ns);
if (mountName != null) {
builder.addMount(mountName, ns.getNodeStoreProvider().getNodeStore());
- LOG.info("Mounting {} as {}", getDescription(ns), mountName);
+ LOG.info("Mounting {} as {}", ns.getDescription(), mountName);
nodeStoresInUse.add(ns.getNodeStoreProvider());
}
}
@@ -197,10 +202,6 @@ public class CompositeNodeStoreService {
return role.substring(MOUNT_ROLE_PREFIX.length());
}
- private String getDescription(NodeStoreWithProps ns) {
- return PropertiesUtil.toString(ns.getProps().get("oak.nodestore.description"), ns.getNodeStoreProvider().getClass().toString());
- }
-
private void unregisterCompositeNodeStore() {
if (nsReg != null) {
LOG.info("Unregistering the composite node store");
@@ -272,5 +273,10 @@ public class CompositeNodeStoreService {
public String getRole() {
return PropertiesUtil.toString(props.get(NodeStoreProvider.ROLE), null);
}
+
+ public String getDescription() {
+ return PropertiesUtil.toString(getProps().get("oak.nodestore.description"),
+ getNodeStoreProvider().getClass().toString());
+ }
}
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java?rev=1803501&r1=1803500&r2=1803501&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java Mon Jul 31 10:02:06 2017
@@ -21,7 +21,7 @@ package org.apache.jackrabbit.oak.compos
import org.apache.jackrabbit.oak.spi.mount.Mount;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
-class MountedNodeStore {
+public class MountedNodeStore {
private final Mount mount;
Added: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/ErrorHolder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/ErrorHolder.java?rev=1803501&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/ErrorHolder.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/ErrorHolder.java Mon Jul 31 10:02:06 2017
@@ -0,0 +1,47 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jackrabbit.oak.api.IllegalRepositoryStateException;
+import org.apache.jackrabbit.oak.composite.MountedNodeStore;
+
+class ErrorHolder {
+
+ private static final int FAIL_IMMEDIATELY_THRESHOLD = 100;
+ private final List<String> errors = new ArrayList<>();
+
+ public void report(MountedNodeStore mountedStore, String path, String error) {
+ errors.add(String.format("For NodeStore mount %s, path %s, encountered the following problem: '%s'", mountedStore.getMount().getName(), path, error));
+ if ( errors.size() == FAIL_IMMEDIATELY_THRESHOLD ) {
+ end();
+ }
+ }
+
+ public void end() {
+ if ( errors.isEmpty() ) {
+ return;
+ }
+ StringBuilder out = new StringBuilder();
+ out.append(errors.size()).append(" errors were found: \n");
+ errors.forEach( e -> out.append(e).append('\n'));
+
+ throw new IllegalRepositoryStateException(out.toString());
+ }
+}
\ No newline at end of file
Copied: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/MountedNodeStoreChecker.java (from r1803272, jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/MountedNodeStoreChecker.java?p2=jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/MountedNodeStoreChecker.java&p1=jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java&r1=1803272&r2=1803501&rev=1803501&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/MountedNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/MountedNodeStoreChecker.java Mon Jul 31 10:02:06 2017
@@ -16,40 +16,25 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.jackrabbit.oak.composite;
-import org.apache.jackrabbit.oak.spi.mount.Mount;
-import org.apache.jackrabbit.oak.spi.state.NodeStore;
-
-class MountedNodeStore {
-
- private final Mount mount;
-
- private final NodeStore nodeStore;
+package org.apache.jackrabbit.oak.composite.checks;
- public MountedNodeStore(Mount mount, NodeStore nodeStore) {
- this.mount = mount;
- this.nodeStore = nodeStore;
- }
-
- public Mount getMount() {
- return mount;
- }
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.composite.MountedNodeStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
- public NodeStore getNodeStore() {
- return nodeStore;
- }
+/**
+ * Applies a category of consistence checks specific to <tt>NodeStore</tt> mounts
+ *
+ * <p>Checks are only performed on non-default mounts.</p>
+ *
+ * <p>Named 'Checker' to clarify that it is not a Validator in the Oak sense.</p>
+ *
+ */
+public interface MountedNodeStoreChecker<T> {
+
+ public T createContext(NodeStore globalStore);
+
+ void check(MountedNodeStore mountedStore, Tree tree, ErrorHolder errorHolder, T context);
- @Override
- public String toString() {
- StringBuilder result = new StringBuilder(super.toString());
- result.append('[');
- if (mount.isDefault()) {
- result.append("default");
- } else {
- result.append(mount.getName());
- }
- result.append(']');
- return result.toString();
- }
-}
\ No newline at end of file
+}
Added: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecks.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecks.java?rev=1803501&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecks.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecks.java Mon Jul 31 10:02:06 2017
@@ -0,0 +1,26 @@
+/*
+ * 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 org.apache.jackrabbit.oak.composite.MountedNodeStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+
+public interface NodeStoreChecks {
+
+ void check(NodeStore globalStore, MountedNodeStore mountedStore);
+
+}
Added: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksService.java?rev=1803501&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksService.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksService.java Mon Jul 31 10:02:06 2017
@@ -0,0 +1,108 @@
+/*
+ * 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 java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.composite.MountedNodeStore;
+import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
+import org.apache.jackrabbit.oak.spi.mount.Mount;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service(NodeStoreChecks.class)
+public class NodeStoreChecksService implements NodeStoreChecks {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
+ bind = "bindChecker",
+ unbind = "unbindChecker",
+ referenceInterface = MountedNodeStoreChecker.class)
+ private List<MountedNodeStoreChecker<?>> checkers = new CopyOnWriteArrayList<>();
+
+ // used by SCR
+ public NodeStoreChecksService() {
+
+ }
+
+ // visible for testing
+ public NodeStoreChecksService(List<MountedNodeStoreChecker<?>> checkers) {
+ this.checkers = checkers;
+ }
+
+ @Override
+ public void check(NodeStore globalStore, MountedNodeStore mountedStore) {
+
+ ErrorHolder errorHolder = new ErrorHolder();
+
+ checkers.forEach( c -> {
+ log.info("Checking NodeStore from mount {} with {}", mountedStore.getMount().getName(), c );
+
+ check(mountedStore, errorHolder, globalStore, c);
+
+ log.info("Check complete");
+ });
+
+ errorHolder.end();
+ }
+
+ private <T> void check(MountedNodeStore mountedStore, ErrorHolder errorHolder, NodeStore globalStore,
+ MountedNodeStoreChecker<T> c) {
+
+ T context = c.createContext(globalStore);
+ Tree mountRoot = TreeFactory.createReadOnlyTree(mountedStore.getNodeStore().getRoot());
+
+ visit(mountRoot, mountedStore, errorHolder, context, c);
+ }
+
+ private <T> void visit(Tree tree, MountedNodeStore mountedStore, ErrorHolder errorHolder, T context, MountedNodeStoreChecker<T> c) {
+
+
+ // a mounted NodeStore may contain more paths than what it owns, but since these are not accessible
+ // through the CompositeNodeStore skip them
+ Mount mount = mountedStore.getMount();
+
+ boolean under = mount.isUnder(tree.getPath());
+ boolean mounted = mount.isMounted(tree.getPath());
+
+
+ if ( mounted ) {
+ c.check(mountedStore, tree, errorHolder, context);
+ }
+
+ if ( mounted || under ) {
+ tree.getChildren().forEach( child -> visit(child, mountedStore, errorHolder, context, c));
+ }
+ }
+
+ protected void bindChecker(MountedNodeStoreChecker<?> checker) {
+ checkers.add(checker);
+ }
+
+ protected void unbindChecker(MountedNodeStoreChecker<?> checker) {
+ checkers.remove(checker);
+ }
+}
Added: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/VersionableNodesMountedNodeStoreChecker.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/VersionableNodesMountedNodeStoreChecker.java?rev=1803501&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/VersionableNodesMountedNodeStoreChecker.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/VersionableNodesMountedNodeStoreChecker.java Mon Jul 31 10:02:06 2017
@@ -0,0 +1,67 @@
+/*
+ * 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 org.apache.felix.scr.annotations.Component;
+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.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.plugins.version.VersionConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+
+/**
+ * Checks that no <tt>versionable</tt> nodes are present in a non-default <tt>NodeStore</tt>
+ */
+@Component
+@Service(MountedNodeStoreChecker.class)
+public class VersionableNodesMountedNodeStoreChecker implements MountedNodeStoreChecker<VersionableNodesMountedNodeStoreChecker.Context> {
+
+ @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, VersionConstants.MIX_VERSIONABLE) ) {
+ errorHolder.report(mountedStore, tree.getPath(), "versionable node");
+ }
+ }
+
+ static class Context {
+
+ private final ReadOnlyNodeTypeManager typeManager;
+
+ Context(ReadOnlyNodeTypeManager typeManager) {
+ this.typeManager = typeManager;
+ }
+
+ public ReadOnlyNodeTypeManager getTypeManager() {
+ return typeManager;
+ }
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreServiceTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreServiceTest.java?rev=1803501&r1=1803500&r2=1803501&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreServiceTest.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreServiceTest.java Mon Jul 31 10:02:06 2017
@@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.notN
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
+import org.apache.jackrabbit.oak.composite.checks.NodeStoreChecksService;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
import org.apache.jackrabbit.oak.spi.mount.Mounts;
@@ -50,9 +51,11 @@ public class CompositeNodeStoreServiceTe
ctx.registerService(MountInfoProvider.class, mip);
ctx.registerService(NodeStoreProvider.class, new SimpleNodeStoreProvider(global), ImmutableMap.of("role", "composite:global", "registerDescriptors", Boolean.TRUE));
ctx.registerService(NodeStoreProvider.class, new SimpleNodeStoreProvider(mount), ImmutableMap.of("role", "composite:mount:libs"));
+ ctx.registerInjectActivateService(new NodeStoreChecksService());
ctx.registerInjectActivateService(new CompositeNodeStoreService());
-
+
+
assertThat("No NodeStore registered", ctx.getService(NodeStore.class), notNullValue());
}
@@ -70,6 +73,7 @@ public class CompositeNodeStoreServiceTe
ctx.registerService(MountInfoProvider.class, mip);
ctx.registerService(NodeStoreProvider.class, new SimpleNodeStoreProvider(global), ImmutableMap.of("role", "composite:global", "registerDescriptors", Boolean.TRUE));
ctx.registerService(NodeStoreProvider.class, new SimpleNodeStoreProvider(mount), ImmutableMap.of("role", "composite:mount:libs"));
+ ctx.registerInjectActivateService(new NodeStoreChecksService());
ctx.registerInjectActivateService(new CompositeNodeStoreService());
@@ -88,6 +92,7 @@ public class CompositeNodeStoreServiceTe
ctx.registerService(MountInfoProvider.class, mip);
ctx.registerService(NodeStoreProvider.class, new SimpleNodeStoreProvider(mount), ImmutableMap.of("role", "composite:mount:libs"));
+ ctx.registerInjectActivateService(new NodeStoreChecksService());
ctx.registerInjectActivateService(new CompositeNodeStoreService());
Added: jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksServiceTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksServiceTest.java?rev=1803501&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksServiceTest.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NodeStoreChecksServiceTest.java Mon Jul 31 10:02:06 2017
@@ -0,0 +1,106 @@
+/*
+ * 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.Arrays;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.IllegalRepositoryStateException;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.composite.MountedNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.mount.Mount;
+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.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NodeStoreChecksServiceTest {
+
+ private MemoryNodeStore globalStore;
+ private MemoryNodeStore mountedStore;
+ private MountInfoProvider mip;
+ private Mount mount;
+
+ @Before
+ public void createFixture() throws CommitFailedException {
+ globalStore = new MemoryNodeStore();
+ mountedStore = new MemoryNodeStore();
+
+ NodeBuilder rootBuilder = mountedStore.getRoot().builder();
+ rootBuilder.setChildNode("first").setChildNode("second").setChildNode("third");
+ rootBuilder.setChildNode("not-covered");
+ mountedStore.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ mip = Mounts.newBuilder()
+ .readOnlyMount("first", "/first")
+ .build();
+
+ mount = mip.getMountByName("first");
+ }
+
+ @Test
+ public void noCheckers() throws CommitFailedException {
+
+ NodeStoreChecksService checks = new NodeStoreChecksService();
+
+ checks.check(globalStore, new MountedNodeStore(mount, mountedStore));
+ }
+
+ @Test(expected = IllegalRepositoryStateException.class)
+ public void failOnNodeCoveredByMount() {
+
+ NodeStoreChecksService checks = new NodeStoreChecksService(Arrays.asList(new FailOnTreeNameChecker("third")));
+
+ checks.check(globalStore, new MountedNodeStore(mount, mountedStore));
+ }
+
+ @Test
+ public void doNotFailOnNodeNotCoveredByMount() {
+
+ NodeStoreChecksService checks = new NodeStoreChecksService(Arrays.asList(new FailOnTreeNameChecker("not-covered")));
+
+ checks.check(globalStore, new MountedNodeStore(mount, mountedStore));
+ }
+
+ static class FailOnTreeNameChecker implements MountedNodeStoreChecker<Void> {
+
+ private final String name;
+
+ private FailOnTreeNameChecker(String name) {
+ this.name = checkNotNull(name, "name shold not be null");
+ }
+
+ @Override
+ public Void createContext(NodeStore globalStore) {
+ return null;
+ }
+
+ @Override
+ public void check(MountedNodeStore mountedStore, Tree tree, ErrorHolder errorHolder, Void context) {
+ if ( name.equals(tree.getName()))
+ errorHolder.report(mountedStore, tree.getPath(), "test failure");
+ }
+
+ }
+}