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 tr...@apache.org on 2013/11/14 23:34:28 UTC

svn commit: r1542109 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/ oak-core/src/main/java/org/apache/jackrabbit/oak/core/ oak-core/src/main/java/org/apache/jackrabbit/oak/util/ oak-jcr/src/main/java/org/apache/jackra...

Author: tripod
Date: Thu Nov 14 22:34:27 2013
New Revision: 1542109

URL: http://svn.apache.org/r1542109
Log:
OAK-1126: Same node and property name support

This reverts commit f3f78810e7eda7fe127a3f7f711b8fa28f88c5fd.

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Descriptors.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/GenericDescriptors.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/JcrDescriptorsImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java
Removed:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/Descriptors.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ContentRepository.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ContentRepository.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ContentRepository.java?rev=1542109&r1=1542108&r2=1542109&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ContentRepository.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/ContentRepository.java Thu Nov 14 22:34:27 2013
@@ -83,4 +83,12 @@ public interface ContentRepository {
     ContentSession login(@Nullable Credentials credentials, @Nullable String workspaceName)
             throws LoginException, NoSuchWorkspaceException;
 
+    /**
+     * Returns the repository descriptors which contain all or a subset of the descriptors defined in
+     * {@link javax.jcr.Repository}.
+     *
+     * @return the repository descriptors
+     */
+    @Nonnull
+    Descriptors getDescriptors();
 }

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Descriptors.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Descriptors.java?rev=1542109&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Descriptors.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Descriptors.java Thu Nov 14 22:34:27 2013
@@ -0,0 +1,86 @@
+/*
+ * 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.api;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.Value;
+
+/**
+ * Repository descriptors interface that is used to support providing the repository descriptors of
+ * {@link javax.jcr.Repository}
+ */
+public interface Descriptors {
+
+    /**
+     * Returns a string array holding all descriptor keys available for this
+     * implementation, both the standard descriptors defined by the string
+     * constants in this interface and any implementation-specific descriptors.
+     * Used in conjunction with {@link #getValue(String key)} and
+     * {@link #getValues(String key)} to query information about this
+     * repository implementation.
+     *
+     * @return a string array holding all descriptor keys.
+     */
+    @Nonnull
+    String[] getKeys();
+
+    /**
+     * Returns {@code true} if {@code key} is a standard descriptor
+     * defined by the string constants in this interface and {@code false}
+     * if it is either a valid implementation-specific key or not a valid key.
+     *
+     * @param key a descriptor key.
+     * @return whether <code>key</code> is a standard descriptor.
+     */
+    boolean isStandardDescriptor(@Nonnull String key);
+
+    /**
+     * Returns {@code true} if {@code key} is a valid single-value
+     * descriptor; otherwise returns {@code false}
+     *
+     * @param key a descriptor key.
+     * @return whether the specified descriptor is multi-valued.
+     * @since JCR 2.0
+     */
+    boolean isSingleValueDescriptor(@Nonnull String key);
+
+    /**
+     * The value of a single-value descriptor is found by passing the key for
+     * that descriptor to this method. If {@code key} is the key of a
+     * multi-value descriptor or not a valid key this method returns
+     * {@code null}.
+     *
+     * @param key a descriptor key.
+     * @return The value of the indicated descriptor
+     */
+    @CheckForNull
+    Value getValue(@Nonnull String key);
+
+    /**
+     * The value array of a multi-value descriptor is found by passing the key
+     * for that descriptor to this method. If {@code key} is the key of a
+     * single-value descriptor then this method returns that value as an array
+     * of size one. If {@code key} is not a valid key this method returns
+     * {@code null}.
+     *
+     * @param key a descriptor key.
+     * @return the value array for the indicated descriptor
+     */
+    @CheckForNull
+    Value[] getValues(@Nonnull String key);
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java?rev=1542109&r1=1542108&r2=1542109&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java Thu Nov 14 22:34:27 2013
@@ -16,16 +16,25 @@
  */
 package org.apache.jackrabbit.oak.core;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.jcr.Credentials;
 import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.PropertyType;
+import javax.jcr.Repository;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
 import javax.security.auth.login.LoginException;
 
+import org.apache.jackrabbit.commons.SimpleValueFactory;
 import org.apache.jackrabbit.oak.api.ContentRepository;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Descriptors;
+import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.query.CompositeQueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
@@ -34,6 +43,60 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.authentication.LoginContext;
 import org.apache.jackrabbit.oak.spi.security.authentication.LoginContextProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.util.GenericDescriptors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.jcr.Repository.IDENTIFIER_STABILITY;
+import static javax.jcr.Repository.LEVEL_1_SUPPORTED;
+import static javax.jcr.Repository.LEVEL_2_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_AUTOCREATED_DEFINITIONS_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_INHERITANCE;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_INHERITANCE_SINGLE;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_MULTIPLE_BINARY_PROPERTIES_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_MULTIVALUED_PROPERTIES_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_ORDERABLE_CHILD_NODES_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_OVERRIDES_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_PRIMARY_ITEM_NAME_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_PROPERTY_TYPES;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_RESIDUAL_DEFINITIONS_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_SAME_NAME_SIBLINGS_SUPPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_UPDATE_IN_USE_SUPORTED;
+import static javax.jcr.Repository.NODE_TYPE_MANAGEMENT_VALUE_CONSTRAINTS_SUPPORTED;
+import static javax.jcr.Repository.OPTION_ACCESS_CONTROL_SUPPORTED;
+import static javax.jcr.Repository.OPTION_ACTIVITIES_SUPPORTED;
+import static javax.jcr.Repository.OPTION_BASELINES_SUPPORTED;
+import static javax.jcr.Repository.OPTION_JOURNALED_OBSERVATION_SUPPORTED;
+import static javax.jcr.Repository.OPTION_LIFECYCLE_SUPPORTED;
+import static javax.jcr.Repository.OPTION_LOCKING_SUPPORTED;
+import static javax.jcr.Repository.OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED;
+import static javax.jcr.Repository.OPTION_NODE_TYPE_MANAGEMENT_SUPPORTED;
+import static javax.jcr.Repository.OPTION_OBSERVATION_SUPPORTED;
+import static javax.jcr.Repository.OPTION_QUERY_SQL_SUPPORTED;
+import static javax.jcr.Repository.OPTION_RETENTION_SUPPORTED;
+import static javax.jcr.Repository.OPTION_SHAREABLE_NODES_SUPPORTED;
+import static javax.jcr.Repository.OPTION_SIMPLE_VERSIONING_SUPPORTED;
+import static javax.jcr.Repository.OPTION_TRANSACTIONS_SUPPORTED;
+import static javax.jcr.Repository.OPTION_UNFILED_CONTENT_SUPPORTED;
+import static javax.jcr.Repository.OPTION_UPDATE_MIXIN_NODE_TYPES_SUPPORTED;
+import static javax.jcr.Repository.OPTION_UPDATE_PRIMARY_NODE_TYPE_SUPPORTED;
+import static javax.jcr.Repository.OPTION_VERSIONING_SUPPORTED;
+import static javax.jcr.Repository.OPTION_WORKSPACE_MANAGEMENT_SUPPORTED;
+import static javax.jcr.Repository.OPTION_XML_EXPORT_SUPPORTED;
+import static javax.jcr.Repository.OPTION_XML_IMPORT_SUPPORTED;
+import static javax.jcr.Repository.QUERY_FULL_TEXT_SEARCH_SUPPORTED;
+import static javax.jcr.Repository.QUERY_JOINS;
+import static javax.jcr.Repository.QUERY_JOINS_NONE;
+import static javax.jcr.Repository.QUERY_LANGUAGES;
+import static javax.jcr.Repository.QUERY_STORED_QUERIES_SUPPORTED;
+import static javax.jcr.Repository.QUERY_XPATH_DOC_ORDER;
+import static javax.jcr.Repository.QUERY_XPATH_POS_INDEX;
+import static javax.jcr.Repository.REP_NAME_DESC;
+import static javax.jcr.Repository.REP_VENDOR_DESC;
+import static javax.jcr.Repository.REP_VENDOR_URL_DESC;
+import static javax.jcr.Repository.REP_VERSION_DESC;
+import static javax.jcr.Repository.SPEC_NAME_DESC;
+import static javax.jcr.Repository.SPEC_VERSION_DESC;
+import static javax.jcr.Repository.WRITE_SUPPORTED;
 
 /**
  * {@code MicroKernel}-based implementation of
@@ -47,6 +110,8 @@ public class ContentRepositoryImpl imple
     private final SecurityProvider securityProvider;
     private final QueryIndexProvider indexProvider;
 
+    private GenericDescriptors descriptors;
+    
     /**
      * Creates an content repository instance based on the given, already
      * initialized components.
@@ -94,4 +159,125 @@ public class ContentRepositoryImpl imple
         return nodeStore;
     }
 
+    @Nonnull
+    @Override
+    public Descriptors getDescriptors() {
+        if (descriptors == null) {
+            descriptors = createDescriptors();
+        }
+        return descriptors;
+    }
+    
+    @SuppressWarnings("deprecation")
+    @Nonnull
+    protected GenericDescriptors createDescriptors() {
+        final ValueFactory valueFactory = new SimpleValueFactory();
+        final Value trueValue = valueFactory.createValue(true);
+        final Value falseValue = valueFactory.createValue(false);
+        return new GenericDescriptors()
+                .put(IDENTIFIER_STABILITY, valueFactory.createValue(Repository.IDENTIFIER_STABILITY_METHOD_DURATION), true, true)
+                .put(LEVEL_1_SUPPORTED, trueValue, true, true)
+                .put(LEVEL_2_SUPPORTED, trueValue, true, true)
+                .put(OPTION_NODE_TYPE_MANAGEMENT_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_AUTOCREATED_DEFINITIONS_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_INHERITANCE, valueFactory.createValue(NODE_TYPE_MANAGEMENT_INHERITANCE_SINGLE), true, true)
+                .put(NODE_TYPE_MANAGEMENT_MULTIPLE_BINARY_PROPERTIES_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_MULTIVALUED_PROPERTIES_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_ORDERABLE_CHILD_NODES_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_OVERRIDES_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_PRIMARY_ITEM_NAME_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_PROPERTY_TYPES,
+                new Value[]{
+                        valueFactory.createValue(PropertyType.TYPENAME_STRING),
+                        valueFactory.createValue(PropertyType.TYPENAME_BINARY),
+                        valueFactory.createValue(PropertyType.TYPENAME_LONG),
+                        valueFactory.createValue(PropertyType.TYPENAME_LONG),
+                        valueFactory.createValue(PropertyType.TYPENAME_DOUBLE),
+                        valueFactory.createValue(PropertyType.TYPENAME_DECIMAL),
+                        valueFactory.createValue(PropertyType.TYPENAME_DATE),
+                        valueFactory.createValue(PropertyType.TYPENAME_BOOLEAN),
+                        valueFactory.createValue(PropertyType.TYPENAME_NAME),
+                        valueFactory.createValue(PropertyType.TYPENAME_PATH),
+                        valueFactory.createValue(PropertyType.TYPENAME_REFERENCE),
+                        valueFactory.createValue(PropertyType.TYPENAME_WEAKREFERENCE),
+                        valueFactory.createValue(PropertyType.TYPENAME_URI),
+                        valueFactory.createValue(PropertyType.TYPENAME_UNDEFINED)
+                }, false, true)
+                .put(NODE_TYPE_MANAGEMENT_RESIDUAL_DEFINITIONS_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_SAME_NAME_SIBLINGS_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_VALUE_CONSTRAINTS_SUPPORTED, trueValue, true, true)
+                .put(NODE_TYPE_MANAGEMENT_UPDATE_IN_USE_SUPORTED, falseValue, true, true)
+                .put(OPTION_ACCESS_CONTROL_SUPPORTED, trueValue, true, true)
+                .put(OPTION_JOURNALED_OBSERVATION_SUPPORTED, falseValue, true, true)
+                .put(OPTION_LIFECYCLE_SUPPORTED, falseValue, true, true)
+                // locking support added via JCR layer
+                .put(OPTION_LOCKING_SUPPORTED, falseValue, true, true)
+                .put(OPTION_OBSERVATION_SUPPORTED, trueValue, true, true)
+                .put(OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED,
+                        supportsSameNameNodeAndProperties() ? trueValue : falseValue, true, true)
+                .put(OPTION_QUERY_SQL_SUPPORTED, falseValue, true, true)
+                .put(OPTION_RETENTION_SUPPORTED, falseValue, true, true)
+                .put(OPTION_SHAREABLE_NODES_SUPPORTED, falseValue, true, true)
+                 // todo: let plugin set the descriptor
+                .put(OPTION_SIMPLE_VERSIONING_SUPPORTED, falseValue, true, true)
+                .put(OPTION_TRANSACTIONS_SUPPORTED, falseValue, true, true)
+                .put(OPTION_UNFILED_CONTENT_SUPPORTED, falseValue, true, true)
+                .put(OPTION_UPDATE_MIXIN_NODE_TYPES_SUPPORTED, trueValue, true, true)
+                .put(OPTION_UPDATE_PRIMARY_NODE_TYPE_SUPPORTED, trueValue, true, true)
+                .put(OPTION_VERSIONING_SUPPORTED, trueValue, true, true)
+                .put(OPTION_WORKSPACE_MANAGEMENT_SUPPORTED, trueValue, true, true)
+                // xml export support added via JCR layer
+                .put(OPTION_XML_EXPORT_SUPPORTED, falseValue, true, true)
+                // xml import support added via JCR layer
+                .put(OPTION_XML_IMPORT_SUPPORTED, falseValue, true, true)
+                .put(OPTION_ACTIVITIES_SUPPORTED, falseValue, true, true)
+                .put(OPTION_BASELINES_SUPPORTED, falseValue, true, true)
+                .put(QUERY_FULL_TEXT_SEARCH_SUPPORTED, falseValue, true, true)
+                .put(QUERY_JOINS, valueFactory.createValue(QUERY_JOINS_NONE), true, true)
+                .put(QUERY_LANGUAGES, new Value[0], false, true)
+                .put(QUERY_STORED_QUERIES_SUPPORTED, falseValue, true, true)
+                .put(QUERY_XPATH_DOC_ORDER, falseValue, true, true)
+                .put(QUERY_XPATH_POS_INDEX, falseValue, true, true)
+                .put(REP_NAME_DESC, valueFactory.createValue("Apache Jackrabbit Oak"), true, true)
+                .put(REP_VERSION_DESC, valueFactory.createValue(getVersion()), true, true)
+                .put(REP_VENDOR_DESC, valueFactory.createValue("The Apache Software Foundation"), true, true)
+                .put(REP_VENDOR_URL_DESC, valueFactory.createValue("http://www.apache.org/"), true, true)
+                .put(SPEC_NAME_DESC, valueFactory.createValue("Content Repository for Java Technology API"), true, true)
+                .put(SPEC_VERSION_DESC, valueFactory.createValue("2.0"), true, true)
+                .put(WRITE_SUPPORTED, trueValue, true, true);
+    }
+
+    /**
+     * Checks if this repository supports same name node and properties. currently this is tied to the underlying
+     * node store implementation class.
+     *
+     * @return {@code true} if this repository supports SNNP.
+     */
+    private boolean supportsSameNameNodeAndProperties() {
+        return !(nodeStore instanceof KernelNodeStore);
+    }
+
+    /**
+     * Returns the version of this repository implementation.
+     * @return the version
+     */
+    @Nonnull
+    private static String getVersion() {
+        InputStream stream = ContentRepositoryImpl.class.getResourceAsStream(
+                "/META-INF/maven/org.apache.jackrabbit/oak-core/pom.properties");
+        if (stream != null) {
+            try {
+                try {
+                    Properties properties = new Properties();
+                    properties.load(stream);
+                    return properties.getProperty("version");
+                } finally {
+                    stream.close();
+                }
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+        return "SNAPSHOT";
+    }
 }

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/GenericDescriptors.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/GenericDescriptors.java?rev=1542109&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/GenericDescriptors.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/GenericDescriptors.java Thu Nov 14 22:34:27 2013
@@ -0,0 +1,173 @@
+/*
+ * 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.util;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.jcr.Value;
+
+import org.apache.jackrabbit.oak.api.Descriptors;
+
+/**
+ * Default implementation of the {@link Descriptors} interface. Supports overlying of given default descriptors.
+ */
+public class GenericDescriptors implements org.apache.jackrabbit.oak.api.Descriptors {
+
+    private final Descriptors base;
+
+    private final Map<String, Descriptor> descriptors = new ConcurrentHashMap<String, Descriptor>();
+
+    /**
+     * Constructs an empty descriptors set.
+     */
+    public GenericDescriptors() {
+        base = null;
+    }
+
+    /**
+     * Constructs a descriptors set that uses the given {@code base} descriptors as base.
+     * @param base the base descriptors or {@code null}
+     */
+    public GenericDescriptors(@Nullable Descriptors base) {
+        this.base = base;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Note: If this descriptors are based on default descriptors, the returns string array is a merge of this and the
+     * base's keys.
+     */
+    @Nonnull
+    @Override
+    public String[] getKeys() {
+        Set<String> keys = new HashSet<String>(descriptors.keySet());
+        if (base != null) {
+            Collections.addAll(keys, base.getKeys());
+        }
+        return keys.toArray(new String[keys.size()]);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Note: If the descriptor with {@code key} does not exist in this set, the call is delegated to the base descriptors.
+     */
+    @Override
+    public boolean isStandardDescriptor(@Nonnull String key) {
+        return descriptors.containsKey(key) && descriptors.get(key).standard
+                || base != null && base.isStandardDescriptor(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Note: If the descriptor with {@code key} does not exist in this set, the call is delegated to the base descriptors.
+     */
+    @Override
+    public boolean isSingleValueDescriptor(@Nonnull String key) {
+        return descriptors.containsKey(key) && descriptors.get(key).singleValued
+                || base != null && base.isSingleValueDescriptor(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Note: If the descriptor with {@code key} does not exist in this set, the call is delegated to the base descriptors.
+     */
+    @CheckForNull
+    @Override
+    public Value getValue(@Nonnull String key) {
+        Descriptor d = descriptors.get(key);
+        if (d == null) {
+            return base == null ? null : base.getValue(key);
+        }
+        return !d.singleValued ? null : d.values[0];
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Note: If the descriptor with {@code key} does not exist in this set, the call is delegated to the base descriptors.
+     */
+    @CheckForNull
+    @Override
+    public Value[] getValues(@Nonnull String key) {
+        Descriptor d = descriptors.get(key);
+        if (d == null) {
+            return base == null ? null : base.getValues(key);
+        }
+        return d.values;
+    }
+
+    /**
+     * Adds a new descriptor to this set of descriptors which overlay the ones from the base set.
+     *
+     * @param name descriptor name
+     * @param values array of descriptor values
+     * @param singleValued flag indicating if this is single valued descriptor. see {@link Descriptors#isSingleValueDescriptor(String)}
+     * @param standard flag indicating if this is a standard descriptor. see {@link Descriptors#isStandardDescriptor(String)}
+     * @return {@code this} suitable for chaining.
+     */
+    public GenericDescriptors put(@Nonnull String name, @Nonnull Value[] values, boolean singleValued, boolean standard) {
+        descriptors.put(name, new Descriptor(name, values, singleValued, standard));
+        return this;
+    }
+
+    /**
+     * Adds a new descriptor to this set of descriptors which overlay the ones from the base set.
+     *
+     * @param name descriptor name
+     * @param value descriptor value
+     * @param singleValued flag indicating if this is single valued descriptor. see {@link Descriptors#isSingleValueDescriptor(String)}
+     * @param standard flag indicating if this is a standard descriptor. see {@link Descriptors#isStandardDescriptor(String)}
+     * @return {@code this} suitable for chaining.
+     */
+    public GenericDescriptors put(@Nonnull String name, @Nonnull Value value, boolean singleValued, boolean standard) {
+        descriptors.put(name, new Descriptor(name, new Value[]{value}, singleValued, standard));
+        return this;
+    }
+
+    /**
+     * Internal Descriptor class
+     */
+    private static final class Descriptor {
+
+        final String name;
+        final Value[] values;
+        final boolean singleValued;
+        final boolean standard;
+
+        public Descriptor(String name, Value[] values, boolean singleValued, boolean standard) {
+            this.name = name;
+            this.values = values;
+            this.singleValued = singleValued;
+            this.standard = standard;
+        }
+    }
+
+}

Added: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/JcrDescriptorsImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/JcrDescriptorsImpl.java?rev=1542109&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/JcrDescriptorsImpl.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/JcrDescriptorsImpl.java Thu Nov 14 22:34:27 2013
@@ -0,0 +1,44 @@
+/*
+ * 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.jcr.repository;
+
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+import org.apache.jackrabbit.oak.api.Descriptors;
+import org.apache.jackrabbit.oak.util.GenericDescriptors;
+
+import static javax.jcr.Repository.OPTION_LOCKING_SUPPORTED;
+import static javax.jcr.Repository.OPTION_XML_EXPORT_SUPPORTED;
+import static javax.jcr.Repository.OPTION_XML_IMPORT_SUPPORTED;
+
+/**
+ * The {@code JcrDescriptorsImpl} extend the {@link org.apache.jackrabbit.oak.util.GenericDescriptors} by automatically marking some of the JCR
+ * features as supported.
+ */
+public class JcrDescriptorsImpl extends GenericDescriptors {
+
+    public JcrDescriptorsImpl(Descriptors base, ValueFactory valueFactory) {
+        super(base);
+
+        // add the descriptors of the features that are provided by the JCR layer
+        final Value trueValue = valueFactory.createValue(true);
+        put(OPTION_LOCKING_SUPPORTED, trueValue, true, true);
+        put(OPTION_XML_EXPORT_SUPPORTED, trueValue, true, true);
+        put(OPTION_XML_IMPORT_SUPPORTED, trueValue, true, true);
+   }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java?rev=1542109&r1=1542108&r2=1542109&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java Thu Nov 14 22:34:27 2013
@@ -16,8 +16,6 @@
  */
 package org.apache.jackrabbit.oak.jcr.repository;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import java.util.Collections;
 import java.util.Map;
 
@@ -37,18 +35,21 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.commons.SimpleValueFactory;
 import org.apache.jackrabbit.oak.api.ContentRepository;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
 import org.apache.jackrabbit.oak.jcr.session.RefreshStrategy;
 import org.apache.jackrabbit.oak.jcr.session.RefreshStrategy.LogOnce;
 import org.apache.jackrabbit.oak.jcr.session.RefreshStrategy.Once;
 import org.apache.jackrabbit.oak.jcr.session.RefreshStrategy.ThreadSynchronising;
 import org.apache.jackrabbit.oak.jcr.session.RefreshStrategy.Timed;
 import org.apache.jackrabbit.oak.jcr.session.SessionContext;
-import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.util.GenericDescriptors;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * TODO document
  */
@@ -67,7 +68,7 @@ public class RepositoryImpl implements J
      */
     public static final String REFRESH_INTERVAL = "oak.refresh-interval";
 
-    private final Descriptors descriptors;
+    private final GenericDescriptors descriptors;
     private final ContentRepository contentRepository;
     protected final Whiteboard whiteboard;
     private final SecurityProvider securityProvider;
@@ -239,15 +240,15 @@ public class RepositoryImpl implements J
      * by the subclasses to add more values to the descriptor
      * @return  repository descriptor
      */
-    protected Descriptors determineDescriptors() {
-        return new Descriptors(new SimpleValueFactory());
+    protected GenericDescriptors determineDescriptors() {
+        return new JcrDescriptorsImpl(contentRepository.getDescriptors(), new SimpleValueFactory());
     }
 
     /**
      * Returns the descriptors associated with the repository
      * @return repository descriptor
      */
-    protected Descriptors getDescriptors() {
+    protected GenericDescriptors getDescriptors() {
         return descriptors;
     }
 

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java?rev=1542109&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java Thu Nov 14 22:34:27 2013
@@ -0,0 +1,142 @@
+/*
+ * 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.jcr;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.junit.Test;
+
+public class SameNamePropertyNodeTest extends AbstractJCRTest {
+
+    private String sameName = "sameName";
+    private Node n;
+    private Property p;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        if (!getHelper().getRepository().getDescriptorValue(Repository.OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED).getBoolean()) {
+            throw new NotExecutableException("node and property with same name is not supported");
+        }
+
+        n = testRootNode.addNode(sameName);
+        p = testRootNode.setProperty(sameName, "value");
+        superuser.save();
+    }
+
+    @Test
+    public void testIsSame() throws Exception {
+        assertFalse(n.isSame(p));
+        assertFalse(p.isSame(n));
+    }
+
+    @Test
+    public void testNodeExists() throws Exception {
+        assertTrue(superuser.nodeExists(n.getPath()));
+    }
+
+    @Test
+    public void testSessionGetNode() throws Exception {
+        Node nn = superuser.getNode(n.getPath());
+        assertTrue(n.isSame(nn));
+    }
+
+    @Test
+    public void testHasNode() throws Exception {
+        assertTrue(testRootNode.hasNode(sameName));
+    }
+
+    @Test
+    public void testGetNode() throws Exception {
+        assertTrue(n.isSame(testRootNode.getNode(sameName)));
+        assertFalse(n.isSame(p));
+    }
+
+    @Test
+    public void testPropertyExists() throws Exception {
+        assertTrue(superuser.propertyExists(p.getPath()));
+    }
+
+    @Test
+    public void testSessionGetProperty() throws Exception {
+        Property pp = superuser.getProperty(p.getPath());
+        assertTrue(p.isSame(pp));
+    }
+
+    @Test
+    public void testHasProperty() throws Exception {
+        assertTrue(testRootNode.hasProperty(sameName));
+    }
+
+    @Test
+    public void testGetProperty() throws Exception {
+        assertTrue(p.isSame(testRootNode.getProperty(sameName)));
+        assertFalse(p.isSame(n));
+    }
+
+    @Test
+    public void testItemExists() throws Exception {
+        assertTrue(superuser.itemExists(n.getPath()));
+    }
+
+    @Test
+    public void testGetItem() throws Exception {
+        Item item = superuser.getItem(n.getPath());
+        if (item.isNode()) {
+            assertTrue(n.isSame(item));
+        } else {
+            assertTrue(p.isSame(item));
+        }
+    }
+
+    /**
+     * Tests if a microkernel fixture sets the SNNP repository descriptor to false.
+     */
+    @Test
+    public void testMicroKernelSupport() throws Exception {
+        NodeStore nodeStore = NodeStoreFixture.MK_IMPL.createNodeStore();
+        JackrabbitRepository repository  = (JackrabbitRepository) new Jcr(nodeStore).createRepository();
+        try {
+            assertFalse(repository.getDescriptorValue(Repository.OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED).getBoolean());
+        } finally {
+            repository.shutdown();
+        }
+    }
+
+    /**
+     * Tests if a nodestore fixture sets the SNNP repository descriptor to true.
+     */
+    @Test
+    public void testNodeStoreSupport() throws Exception {
+        NodeStore nodeStore = NodeStoreFixture.SEGMENT_MK.createNodeStore();
+        JackrabbitRepository repository  = (JackrabbitRepository) new Jcr(nodeStore).createRepository();
+        try {
+            assertTrue(repository.getDescriptorValue(Repository.OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED).getBoolean());
+        } finally {
+            repository.shutdown();
+        }
+
+    }
+}
\ No newline at end of file