Author: rombert
Date: Tue Sep  5 20:54:30 2017
New Revision: 1807403

URL: http://svn.apache.org/viewvc?rev=1807403&view=rev
Log:
OAK-6581 - Ensure mounts are consistent with the namespace registry

Added:
    
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreChecker.java
    
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreCheckerTest.java

Added: 
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreChecker.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreChecker.java?rev=1807403&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreChecker.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreChecker.java
 Tue Sep  5 20:54:30 2017
@@ -0,0 +1,96 @@
+/*
+ * 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.Set;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.composite.MountedNodeStore;
+import org.apache.jackrabbit.oak.plugins.name.ReadOnlyNamespaceRegistry;
+import org.apache.jackrabbit.oak.plugins.tree.RootFactory;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+
+import com.google.common.collect.Sets;
+
+@Component
+@Service(MountedNodeStoreChecker.class)
+public class NamespacePrefixNodestoreChecker implements 
MountedNodeStoreChecker<NamespacePrefixNodestoreChecker.Context> {
+
+    @Override
+    public Context createContext(NodeStore globalStore, MountInfoProvider mip) 
{
+
+        Root root = RootFactory.createReadOnlyRoot(globalStore.getRoot());
+        
+        ReadOnlyNamespaceRegistry registry = new 
ReadOnlyNamespaceRegistry(root);
+        
+        return new Context(registry.getPrefixes());
+    }
+
+    @Override
+    public boolean check(MountedNodeStore mountedStore, Tree tree, ErrorHolder 
errorHolder, Context context) {
+        
+        String name = tree.getName();
+        String path = tree.getPath();
+        
+        validate(mountedStore, errorHolder, context, name, path);
+        
+        for ( PropertyState prop : tree.getProperties() ) {
+            String propName = prop.getName();
+            validate(mountedStore, errorHolder, context, propName, 
PathUtils.concat(tree.getPath(), propName));
+        }
+        
+        return true;
+    }
+
+    private void validate(MountedNodeStore mountedStore, ErrorHolder 
errorHolder, Context context, String name,
+            String path) {
+        
+        String prefix = getPrefix(name);
+        if ( prefix != null && !context.validPrefixes.contains(prefix) ) {
+            errorHolder.report(mountedStore, path, "invalid namespace prefix " 
+ prefix + " , expected one of " + context.validPrefixes);
+        }
+    }
+    
+    private static String getPrefix(String name) {
+        int idx = name.indexOf(':');
+        if ( idx < 0 ) {
+            return null;
+        }
+        
+        // name will not start with a colon as it's an invalid JCR name
+        // and we assume the repositories to be well-formed
+        return name.substring(0, idx);
+    }
+    
+    static class Context {
+
+        private final Set<String> validPrefixes = Sets.newHashSet();
+        
+        public Context(String[] prefixes) {
+            for (String prefix : prefixes ) {
+                validPrefixes.add(prefix);
+            }
+        }
+    }
+
+}

Added: 
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreCheckerTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreCheckerTest.java?rev=1807403&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreCheckerTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/checks/NamespacePrefixNodestoreCheckerTest.java
 Tue Sep  5 20:54:30 2017
@@ -0,0 +1,123 @@
+/*
+ * 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.InitialContent;
+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.composite.checks.NamespacePrefixNodestoreChecker.Context;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+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.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class NamespacePrefixNodestoreCheckerTest {
+    
+    @Rule
+    public ExpectedException exception = ExpectedException.none();
+    
+    private MemoryNodeStore mount;
+    private NamespacePrefixNodestoreChecker checker;
+    private Context context;
+    private MountInfoProvider mip;
+    
+    @Before
+    public void prepareRepository() throws Exception {
+        MemoryNodeStore root = new MemoryNodeStore();
+        mount = new MemoryNodeStore();
+        
+        NodeBuilder rootBuilder = root.getRoot().builder();
+        new InitialContent().initialize(rootBuilder);
+        root.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+        
+        mip = Mounts.newBuilder()
+                .readOnlyMount("first", "/first")
+                .build();
+        
+        checker = new NamespacePrefixNodestoreChecker();
+        context = checker.createContext(root, mip);
+    }
+
+    @Test
+    public void invalidNamespacePrefix_node() throws Exception {
+        
+        NodeBuilder builder = mount.getRoot().builder();
+        builder.child("libs").child("foo:first");
+        
+        mount.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+        
+        exception.expect(IllegalRepositoryStateException.class);
+        exception.expectMessage("1 errors were found");
+        exception.expectMessage("invalid namespace prefix foo");
+        
+        check("/libs/foo:first");
+    }
+    
+    private void check(String path) {
+        
+        
+        Tree tree = 
TreeUtil.getTree(TreeFactory.createReadOnlyTree(mount.getRoot()), path);
+        
+        ErrorHolder errorHolder = new ErrorHolder();
+        checker.check(new MountedNodeStore(mip.getMountByName("first"), 
mount), tree, errorHolder, context);
+        errorHolder.end();
+    }
+    
+    @Test
+    public void invalidNamespacePrefix_property() throws Exception {
+        
+        NodeBuilder builder = mount.getRoot().builder();
+        builder.child("libs").setProperty("foo:prop", "value");
+        mount.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+        
+        exception.expect(IllegalRepositoryStateException.class);
+        exception.expectMessage("1 errors were found");
+        exception.expectMessage("invalid namespace prefix foo");
+        
+        check("/libs");
+    }
+    
+    @Test
+    public void validNamespacePrefix() throws Exception {
+        
+        NodeBuilder builder = mount.getRoot().builder();
+        builder.child("libs").setProperty("jcr:prop", "value");
+        mount.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        check("/libs/jcr:prop");
+    }
+    
+    @Test
+    public void noNamespacePrefix() throws Exception {
+        
+        NodeBuilder builder = mount.getRoot().builder();
+        builder.child("libs").setProperty("prop", "value");
+        mount.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        check("/libs");
+        
+    }
+}


Reply via email to