Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java (revision 768998) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java (working copy) @@ -20,6 +20,7 @@ import org.apache.jackrabbit.core.cluster.NamespaceEventListener; import org.apache.jackrabbit.core.fs.FileSystem; import org.apache.jackrabbit.core.fs.FileSystemResource; +import org.apache.jackrabbit.core.util.DefaultNamespaceUtil; import org.apache.jackrabbit.core.util.StringIndex; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.util.XMLChar; @@ -56,7 +57,8 @@ static { // reserved prefixes reservedPrefixes.add(Name.NS_XML_PREFIX); - reservedPrefixes.add(Name.NS_XMLNS_PREFIX); + reservedPrefixes.add(Name.NS_XMLNS_PREFIX); + reservedPrefixes.add(Name.NS_DEFAULT_CONV_VALUE); // predefined (e.g. built-in) prefixes reservedPrefixes.add(Name.NS_REP_PREFIX); reservedPrefixes.add(Name.NS_JCR_PREFIX); @@ -66,6 +68,7 @@ // reserved namespace URI's reservedURIs.add(Name.NS_XML_URI); reservedURIs.add(Name.NS_XMLNS_URI); + reservedURIs.add(Name.NS_DEFAULT_CONV_VALUE); // predefined (e.g. built-in) namespace URI's reservedURIs.add(Name.NS_REP_URI); reservedURIs.add(Name.NS_JCR_URI); @@ -128,7 +131,9 @@ * @param uri the namespace uri * @param idx the index or null. */ - private void map(String prefix, String uri, Integer idx) { + private void map(String prefix, String uri, Integer idx) { + prefix = DefaultNamespaceUtil.convertToDefaultIfRequired(prefix); + uri = DefaultNamespaceUtil.convertToDefaultIfRequired(uri); prefixToURI.put(prefix, uri); uriToPrefix.put(uri, prefix); if (!uriToIndex.containsKey(uri)) { @@ -207,6 +212,9 @@ map(prefix, uri); } } + + addDefaultNamespaceIfNotFound(); + } finally { in.close(); } @@ -220,6 +228,18 @@ } } + /** + * Verify that the default (empty) namespace exists. If it does + * not, add it. This can happen if the existing namespace + * property file has been created with the empty prefix and + * not the 'converted' value. + */ + private void addDefaultNamespaceIfNotFound() { + if (!prefixToURI.containsKey(Name.NS_EMPTY_PREFIX)) { + map(Name.NS_EMPTY_PREFIX, Name.NS_DEFAULT_URI); + } + } + private void store() throws RepositoryException { FileSystemResource propFile = new FileSystemResource(nsRegStore, NS_REG_RESOURCE); @@ -233,7 +253,7 @@ while (iter.hasNext()) { String prefix = (String) iter.next(); String uri = (String) prefixToURI.get(prefix); - props.setProperty(prefix, uri); + setProperty(props, prefix, uri); } try { @@ -260,7 +280,7 @@ while (iter.hasNext()) { String uri = (String) iter.next(); String index = uriToIndex.get(uri).toString(); - props.setProperty(uri, index); + setProperty(props, uri, index); } try { @@ -277,6 +297,23 @@ } /** + * Adds a specific key/value pair into the properties object. If the key/value + * pair represents the default namespace, the values will be converted into a + * different representation before storing in the properties. The method + * {@link DefaultNamespaceUtil#convertToDefaultIfRequired(String)} should be called when reading + * information from a property object to properly 'undo' this conversion. + * + * @param props Property object to store the key/value pair + * @param key Key that will be used when setting the property + * @param value Value of the property that is being set + */ + private void setProperty(Properties props, String key, String value) { + key = DefaultNamespaceUtil.convertToValueIfDefault(key); + value = DefaultNamespaceUtil.convertToValueIfDefault(value); + props.setProperty(key, value); + } + + /** * Set an event channel to inform about changes. * * @param eventChannel event channel Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DefaultNamespaceUtil.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DefaultNamespaceUtil.java (revision 0) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/DefaultNamespaceUtil.java (revision 0) @@ -0,0 +1,66 @@ +/* + * 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.core.util; + + +import org.apache.jackrabbit.spi.Name; + +/** + * Simple utility class that converts the default namespace/uri into a value + * that can be used when storing information into property files. Added to + * resolve issues on IBM JDK 1.6 (see JIRA issue JCR-888). + */ +public class DefaultNamespaceUtil { + + /** + * Converts the value into a non-empty string representation if the value + * provided is {@link Name#NS_DEFAULT_URI} or {@link Name#NS_EMPTY_PREFIX}. + * + * @param value URI or prefix to convert if default. + * @return If the value is default, a non-empty string representation that + * should be used when storing into property files. If not, the value + * will be returned. + */ + public static String convertToValueIfDefault(String value) { + if (Name.NS_DEFAULT_URI.equals(value) || + Name.NS_EMPTY_PREFIX.equals(value)) { + return Name.NS_DEFAULT_CONV_VALUE; + } + + return value; + } + + /** + * Converts the value back into the empty string representing + * {@link Name#NS_DEFAULT_URI} or {@link Name#NS_EMPTY_PREFIX} if the + * value is equal to the converted string returned from the + * {@link #convertToValueIfDefault(String)} method. If the value is not + * equal, it will be returned without modification. + * + * @param value Value to check if it is the converted default namespace + * value. + * @return The default uri/empty prefix if the value provided was converted + * by this class previously. + */ + public static String convertToDefaultIfRequired(String value) { + if (Name.NS_DEFAULT_CONV_VALUE.equals(value)) { + return Name.NS_DEFAULT_URI; + } + + return value; + } +} Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/DefaultNamespaceUtilTest.java =================================================================== --- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/DefaultNamespaceUtilTest.java (revision 0) +++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/DefaultNamespaceUtilTest.java (revision 0) @@ -0,0 +1,105 @@ +/* + * 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.core.util; + +import org.apache.jackrabbit.spi.Name; + +import junit.framework.TestCase; + +/** + * Unit test class to verify that the DefaultNamespaceUtil class properly + * converts the default URI/Namespace value "" into a constant and vice-versa + */ +public class DefaultNamespaceUtilTest extends TestCase { + + /** + * Test that a non-default value sent to the utility class will not be + * modified. + */ + public void testResolveNonDefaultToValue() { + String value = "testValue"; + + String actualValue = DefaultNamespaceUtil.convertToValueIfDefault(value); + + assertEquals("Value should not be changed if it is not the default" + + " URI/Namepace", value, actualValue); + } + + /** + * Test that the default URI will be converted into a different + * value. + */ + public void testResolveDefaultUriToValue() { + String value = Name.NS_DEFAULT_URI; + String actualValue = DefaultNamespaceUtil.convertToValueIfDefault(value); + + assertEquals("Default URI should be changed", + Name.NS_DEFAULT_CONV_VALUE, actualValue); + } + + /** + * Test that the default prefix will be converted into a different + * value. + */ + public void testResolveDefaultPrefixToValue() { + String value = Name.NS_EMPTY_PREFIX; + String actualValue = DefaultNamespaceUtil.convertToValueIfDefault(value); + + assertEquals("Default value should be changed", + Name.NS_DEFAULT_CONV_VALUE, actualValue); + } + + /** + * Test that a value that wasn't converted from the default namespace/uri + * isn't changed when restoring from a property. + */ + public void testResolveNonDefaultFromValue() { + String value = "testValue"; + + String actualValue = DefaultNamespaceUtil.convertToDefaultIfRequired(value); + + assertEquals("A non-default value should not be modified", value, actualValue); + } + + /** + * Test that the default URI value is provided when converting from the + * modified value. + */ + public void testResolveDefaultUriFromValue() { + String value = Name.NS_DEFAULT_CONV_VALUE; + String expValue = Name.NS_DEFAULT_URI; + + String actualValue = DefaultNamespaceUtil.convertToDefaultIfRequired(value); + + assertEquals("The value should be converted back into the default URI", + expValue, actualValue); + } + + /** + * Test that the empty prefix value is provided when converting from the + * modified value. + */ + public void testResolveDefaultPrefixFromValue() { + String value = Name.NS_DEFAULT_CONV_VALUE; + String expValue = Name.NS_EMPTY_PREFIX; + + String actualValue = DefaultNamespaceUtil.convertToDefaultIfRequired(value); + + assertEquals("The value should be converted back into the default URI", + expValue, actualValue); + } +} Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java =================================================================== --- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java (revision 768998) +++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java (working copy) @@ -33,6 +33,7 @@ public static Test suite() { TestSuite suite = new TestSuite("Utility tests"); suite.addTestSuite(RepositoryLockTest.class); + suite.addTestSuite(DefaultNamespaceUtilTest.class); return suite; } } Index: jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/Name.java =================================================================== --- jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/Name.java (revision 768998) +++ jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/Name.java (working copy) @@ -36,8 +36,10 @@ // default namespace (empty uri) public static final String NS_EMPTY_PREFIX = ""; - public static final String NS_DEFAULT_URI = ""; - + public static final String NS_DEFAULT_URI = ""; + // converted string denoting the default uri/prefix (JCR-888) + public static final String NS_DEFAULT_CONV_VALUE = "jcrDefaultNamespace"; + // reserved namespace for repository internal node types public static final String NS_REP_PREFIX = "rep"; public static final String NS_REP_URI = "internal"; @@ -68,6 +70,7 @@ * Empty array of Name */ public static final Name[] EMPTY_ARRAY = new Name[0]; + /** * Returns the local part of this Name object.