Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 61719C50C for ; Thu, 31 May 2012 23:18:38 +0000 (UTC) Received: (qmail 73747 invoked by uid 500); 31 May 2012 23:18:38 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 73718 invoked by uid 500); 31 May 2012 23:18:38 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-commits@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 73705 invoked by uid 99); 31 May 2012 23:18:38 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 31 May 2012 23:18:38 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 31 May 2012 23:18:33 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 88BC9238890B; Thu, 31 May 2012 23:18:11 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1344937 - in /jackrabbit/oak/trunk/oak-core: ./ src/main/java/org/apache/jackrabbit/oak/kernel/ src/main/java/org/apache/jackrabbit/oak/plugins/name/ src/test/java/org/apache/jackrabbit/oak/plugins/name/ Date: Thu, 31 May 2012 23:18:11 -0000 To: oak-commits@jackrabbit.apache.org From: jukka@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120531231811.88BC9238890B@eris.apache.org> Author: jukka Date: Thu May 31 23:18:10 2012 New Revision: 1344937 URL: http://svn.apache.org/viewvc?rev=1344937&view=rev Log: OAK-125: Improved namespace registry Use the registered namespaces also in the validator. + various smaller improvements Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorTest.java Modified: jackrabbit/oak/trunk/oak-core/pom.xml jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/PropertyStateImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java Modified: jackrabbit/oak/trunk/oak-core/pom.xml URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/pom.xml?rev=1344937&r1=1344936&r2=1344937&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/pom.xml (original) +++ jackrabbit/oak/trunk/oak-core/pom.xml Thu May 31 23:18:10 2012 @@ -90,6 +90,11 @@ bndlib provided + + org.apache.felix + org.apache.felix.scr.annotations + provided + org.apache.jackrabbit Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/PropertyStateImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/PropertyStateImpl.java?rev=1344937&r1=1344936&r2=1344937&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/PropertyStateImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/PropertyStateImpl.java Thu May 31 23:18:10 2012 @@ -25,6 +25,8 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import javax.jcr.PropertyType; + public class PropertyStateImpl implements PropertyState { private final String name; @@ -47,6 +49,10 @@ public class PropertyStateImpl implement this(name, null, Collections.unmodifiableList(values)); } + public PropertyStateImpl(String name, String value) { + this(name, new CoreValueImpl(value, PropertyType.STRING)); + } + @Override public String getName() { return name; Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java?rev=1344937&r1=1344936&r2=1344937&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java Thu May 31 23:18:10 2012 @@ -17,12 +17,15 @@ package org.apache.jackrabbit.oak.plugins.name; import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.api.CoreValue; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.spi.commit.Validator; import org.apache.jackrabbit.oak.spi.state.NodeState; import java.util.Set; +import javax.jcr.PropertyType; + class NameValidator implements Validator { private final Set prefixes; @@ -32,36 +35,37 @@ class NameValidator implements Validator } protected void checkValidName(String name) throws CommitFailedException { - String prefix = null; - String local = name; - int colon = name.indexOf(':'); - if (colon == name.length() - 1) { - throw new CommitFailedException("Local name most not be empty"); - } if (colon != -1) { - prefix = name.substring(0, colon); - local = name.substring(colon + 1); + String prefix = name.substring(0, colon); + if (prefix.length() == 0 || !prefixes.contains(prefix)) { + throw new CommitFailedException( + "Invalid namespace prefix: " + name); + } } - if ((prefix != null && !prefixes.contains(prefix)) || !isValidLocalName(local)) { + String local = name.substring(colon + 1); + if (!Namespaces.isValidLocalName(local)) { throw new CommitFailedException("Invalid name: " + name); } } - private static boolean isValidLocalName(String local) { - if (".".equals(local) || "..".equals(local)) { - return false; - } - - for (int i = 0; i < local.length(); i++) { - char ch = local.charAt(i); - if ("/:[]|*".indexOf(ch) != -1) { // TODO: XMLChar check - return false; + protected void checkValidValue(PropertyState property) + throws CommitFailedException { + if (property.isArray()) { + for (CoreValue value : property.getValues()) { + checkValidValue(value); } + } else { + checkValidValue(property.getValue()); } + } - return true; + protected void checkValidValue(CoreValue value) + throws CommitFailedException { + if (value.getType() == PropertyType.NAME) { + checkValidName(value.getString()); + } } //-------------------------------------------------------< NodeValidator > @@ -70,11 +74,13 @@ class NameValidator implements Validator public void propertyAdded(PropertyState after) throws CommitFailedException { checkValidName(after.getName()); + checkValidValue(after); } @Override - public void propertyChanged(PropertyState before, PropertyState after) { - // do nothing + public void propertyChanged(PropertyState before, PropertyState after) + throws CommitFailedException { + checkValidValue(after); } @Override @@ -91,8 +97,7 @@ class NameValidator implements Validator @Override public Validator childNodeChanged( - String name, NodeState before, NodeState after) - throws CommitFailedException { + String name, NodeState before, NodeState after) { return this; } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java?rev=1344937&r1=1344936&r2=1344937&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java Thu May 31 23:18:10 2012 @@ -16,45 +16,24 @@ */ package org.apache.jackrabbit.oak.plugins.name; -import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; import org.apache.jackrabbit.oak.spi.commit.Validator; import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider; import org.apache.jackrabbit.oak.spi.state.NodeState; -import java.util.HashSet; -import java.util.Set; - +/** + * Validator service that checks that all node and property names as well + * as any name values are syntactically valid and that any namespace prefixes + * are properly registered. + */ +@Component +@Service(ValidatorProvider.class) public class NameValidatorProvider implements ValidatorProvider { @Override public Validator getRootValidator(NodeState before, NodeState after) { - Set prefixes = new HashSet(); - - // FIXME don't hardcode these here but fetch them from the ns registry - // Default JCR prefixes are always available - prefixes.add("jcr"); - prefixes.add("nt"); - prefixes.add("mix"); - prefixes.add("sv"); - - // Jackrabbit 2.x prefixes are always available - prefixes.add("rep"); - - prefixes.add("tst"); - prefixes.add("test"); - - // Find any extra prefixes from /jcr:system/jcr:namespaces - NodeState system = after.getChildNode("jcr:system"); - if (system != null) { - NodeState registry = system.getChildNode("jcr:namespaces"); - if (registry != null) { - for (PropertyState property : registry.getProperties()) { - prefixes.add(property.getName()); - } - } - } - - return new NameValidator(prefixes); + return new NameValidator(Namespaces.getNamespaceMap(after).keySet()); } } Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java?rev=1344937&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java (added) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java Thu May 31 23:18:10 2012 @@ -0,0 +1,97 @@ +/* +* 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.name; + +import java.util.HashMap; +import java.util.Map; + +import javax.jcr.PropertyType; + +import org.apache.jackrabbit.oak.api.CoreValue; +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.spi.state.NodeState; + +/** + * Internal static utility class for managing the persisted namespace registry. + */ +class Namespaces { + + private static final Map defaults = + new HashMap(); + + static { + // Standard namespace specified by JCR (default one not included) + defaults.put("", ""); + defaults.put("jcr", "http://www.jcp.org/jcr/1.0"); + defaults.put("nt", "http://www.jcp.org/jcr/nt/1.0"); + defaults.put("mix", "http://www.jcp.org/jcr/mix/1.0"); + defaults.put("xml", "http://www.w3.org/XML/1998/namespace"); + + // Namespace included in Jackrabbit 2.x + defaults.put("sv", "http://www.jcp.org/jcr/sv/1.0"); + + // TODO: see OAK-74 + defaults.put("rep", "internal"); + + // test prefix TODO: remove again. + defaults.put("test", "http://apache.jackrabbit.org/oak/0.1"); + } + + public static Map getNamespaceMap(NodeState root) { + Map map = new HashMap(defaults); + + NodeState system = root.getChildNode("jcr:system"); + if (system != null) { + NodeState namespaces = system.getChildNode("jcr:namespaces"); + if (namespaces != null) { + for (PropertyState property : namespaces.getProperties()) { + String prefix = property.getName(); + if (!property.isArray() && isValidPrefix(prefix)) { + CoreValue value = property.getValue(); + if (value.getType() == PropertyType.STRING) { + map.put(prefix, value.getString()); + } + } + } + } + } + + return map; + } + + public static boolean isValidPrefix(String prefix) { + // TODO: Other prefix rules? + return prefix.length() > 0 && prefix.indexOf(':') == -1; + } + + public static boolean isValidLocalName(String local) { + if (local.length() == 0 || ".".equals(local) || "..".equals(local)) { + return false; + } + + for (int i = 0; i < local.length(); i++) { + char ch = local.charAt(i); + if ("/:[]|*".indexOf(ch) != -1) { // TODO: XMLChar check + return false; + } + } + + // TODO: Other name rules? + return true; + } + +} Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorTest.java?rev=1344937&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorTest.java Thu May 31 23:18:10 2012 @@ -0,0 +1,80 @@ +/* + * 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.name; + +import java.util.Collections; + +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState; +import org.apache.jackrabbit.oak.spi.commit.Validator; +import org.junit.Test; + +public class NameValidatorTest { + + private final Validator validator = + new NameValidator(Collections.singleton("valid")); + + @Test(expected = CommitFailedException.class) + public void testCurrentPath() throws CommitFailedException { + validator.childNodeAdded(".", MemoryNodeState.EMPTY_NODE); + } + + @Test(expected = CommitFailedException.class) + public void testParentPath() throws CommitFailedException { + validator.childNodeAdded(".", MemoryNodeState.EMPTY_NODE); + } + + @Test(expected = CommitFailedException.class) + public void testEmptyPrefix() throws CommitFailedException { + validator.childNodeAdded(":name", MemoryNodeState.EMPTY_NODE); + } + + @Test(expected = CommitFailedException.class) + public void testInvalidPrefix() throws CommitFailedException { + validator.childNodeAdded("invalid:name", MemoryNodeState.EMPTY_NODE); + } + + @Test + public void testValidPrefix() throws CommitFailedException { + validator.childNodeAdded("valid:name", MemoryNodeState.EMPTY_NODE); + } + + @Test(expected = CommitFailedException.class) + public void testSlashName() throws CommitFailedException { + validator.childNodeAdded("invalid/name", MemoryNodeState.EMPTY_NODE); + } + + @Test(expected = CommitFailedException.class) + public void testIndexInName() throws CommitFailedException { + validator.childNodeAdded("name[1]", MemoryNodeState.EMPTY_NODE); + } + + @Test + public void testValidName() throws CommitFailedException { + validator.childNodeAdded("name", MemoryNodeState.EMPTY_NODE); + } + + @Test + public void testDeleted() throws CommitFailedException { + validator.childNodeDeleted(".", MemoryNodeState.EMPTY_NODE); + validator.childNodeDeleted("..", MemoryNodeState.EMPTY_NODE); + validator.childNodeDeleted("valid:name", MemoryNodeState.EMPTY_NODE); + validator.childNodeDeleted("invalid:name", MemoryNodeState.EMPTY_NODE); + validator.childNodeDeleted("invalid/name", MemoryNodeState.EMPTY_NODE); + } + +}