Index: modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/Repository.java new file mode 100644 =================================================================== --- /dev/null (revision 1812) +++ modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/Repository.java (working copy) @@ -0,0 +1,464 @@ +package org.modeshape.jcr.api; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.jcr.Value; + +/** + * Replicates JCR 2.0's Repository interface. + */ +public interface Repository extends javax.jcr.Repository { + + /** + * Key to a boolean descriptor. Returns true if and only if repository content can be updated + * through the JCR API (as opposed to having read-only access). + * + * @since JCR 2.0 + */ + public static final String WRITE_SUPPORTED = "write.supported"; + + /** + * Key to a String descriptor. Returns one of the following javax.jcr.Repository constants + * indicating the stability of identifiers: + *
+ *

+ *

IDENTIFIER_STABILITY_METHOD_DURATION
+ *
Identifiers may change between method calls.
+ *

+ *

IDENTIFIER_STABILITY_SAVE_DURATION
+ *
Identifiers are guaranteed stable within a single save/refresh cycle.
+ *

+ *

IDENTIFIER_STABILITY_SESSION_DURATION
+ *
Identifiers are guaranteed stable within a single session.
+ *

+ *

IDENTIFIER_STABILITY_INDEFINITE_DURATION
+ *
Identifiers are guaranteed to be stable forever.
+ *

+ *

+ * + * @since JCR 2.0 + */ + public static final String IDENTIFIER_STABILITY = "identifier.stability"; + + /** + * One of four possible values for the descriptor IDENTIFIER_STABILITY. Indicates that identifiers may change + * between method calls. + * + * @since JCR 2.0 + */ + public static final String IDENTIFIER_STABILITY_METHOD_DURATION = "identifier.stability.method.duration"; + + /** + * One of four possible values for the descriptor IDENTIFIER_STABILITY. Indicates that identifiers are guaranteed + * stable within a single save/refresh cycle. + * + * @since JCR 2.0 + */ + public static final String IDENTIFIER_STABILITY_SAVE_DURATION = "identifier.stability.save.duration"; + + /** + * One of four possible values for the descriptor IDENTIFIER_STABILITY. Indicates that identifiers are guaranteed + * stable within a single session. + * + * @since JCR 2.0 + */ + public static final String IDENTIFIER_STABILITY_SESSION_DURATION = "identifier.stability.session.duration"; + + /** + * One of four possible values for the descriptor IDENTIFIER_STABILITY. Indicates that identifiers are guaranteed + * to be stable forever. + * + * @since JCR 2.0 + */ + public static final String IDENTIFIER_STABILITY_INDEFINITE_DURATION = "identifier.stability.indefinite.duration"; + + /** + * Key to a boolean descriptor. Returns true if and only if XML export is supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_XML_EXPORT_SUPPORTED = "option.xml.export.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if XML import is supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_XML_IMPORT_SUPPORTED = "option.xml.import.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if unfiled content is supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_UNFILED_CONTENT_SUPPORTED = "option.unfiled.content.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if full versioning is supported. + */ + public static final String OPTION_VERSIONING_SUPPORTED = "option.versioning.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if simple versioning is supported. + */ + public static final String OPTION_SIMPLE_VERSIONING_SUPPORTED = "option.simple.versioning.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if activities are supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_ACTIVITIES_SUPPORTED = "option.activities.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if configurations and baselines are + * supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_BASELINES_SUPPORTED = "option.baselines.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if access control is supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_ACCESS_CONTROL_SUPPORTED = "option.access.control.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if journaled observation is supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_JOURNALED_OBSERVATION_SUPPORTED = "option.journaled.observation.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if retention and hold are supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_RETENTION_SUPPORTED = "option.retention.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if lifecycles are supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_LIFECYCLE_SUPPORTED = "option.lifecycle.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if workspace management is supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_WORKSPACE_MANAGEMENT_SUPPORTED = "option.workspace.management.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if the primary node type of an existing + * node can be updated. + * + * @since JCR 2.0 + */ + public static final String OPTION_UPDATE_PRIMARY_NODE_TYPE_SUPPORTED = "option.update.primary.node.type.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if the mixin node types of an existing node + * can be added and removed. + * + * @since JCR 2.0 + */ + public static final String OPTION_UPDATE_MIXIN_NODE_TYPES_SUPPORTED = "option.update.mixin.node.types.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if the creation of shareable nodes is + * supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_SHAREABLE_NODES_SUPPORTED = "option.shareable.nodes.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if node type management is supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_NODE_TYPE_MANAGEMENT_SUPPORTED = "option.node.type.management.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if node and property with same name is + * supported. + * + * @since JCR 2.0 + */ + public static final String OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED = "option.node.and.property.with.same.name.supported"; + + /** + * Key to String descriptor. Returns one of the following javax.jcr.Repository constants indicating + * the level of support for node type inheritance: + *
+ *
NODE_TYPE_MANAGEMENT_INHERITANCE_MINIMAL
+ *
Registration of primary node types is limited to those which have only nt:base as supertype. Registration of mixin node + * types is limited to those without any supertypes.
+ *
NODE_TYPE_MANAGEMENT_INHERITANCE_SINGLE
+ *
Registration of primary node types is limited to those with exactly one supertype. Registration of mixin node types is + * limited to those with at most one supertype.
+ *
NODE_TYPE_MANAGEMENT_INHERITANCE_MULTIPLE
+ *
Primary node types can be registered with one or more supertypes. Mixin node types can be registered with zero or more + * supertypes.
+ *
+ * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_INHERITANCE = "node.type.management.inheritance"; + + /** + * One of three possible values for the descriptor NODE_TYPE_MANAGEMENT_INHERITANCE. Indicates that registration + * of primary node types is limited to those which have only nt:base as supertype. Registration of mixin node types is limited + * to those without any supertypes. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_INHERITANCE_MINIMAL = "node.type.management.inheritance.minimal"; + + /** + * One of three possible values for the descriptor NODE_TYPE_MANAGEMENT_INHERITANCE. Indicates that registration + * of primary node types is limited to those with exactly one supertype. Registration of mixin node types is limited to those + * with at most one supertype. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_INHERITANCE_SINGLE = "node.type.management.inheritance.single"; + + /** + * One of three possible values for the descriptor NODE_TYPE_MANAGEMENT_INHERITANCE. Indicates that primary node + * types can be registered with one or more supertypes. Mixin node types can be registered with zero or more supertypes. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_INHERITANCE_MULTIPLE = "node.type.management.inheritance.multiple"; + + /** + * Key to a boolean descriptor. Returns true if and only if override of inherited property or child + * node definitions is supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_OVERRIDES_SUPPORTED = "node.type.management.overrides.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if primary items are supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_PRIMARY_ITEM_NAME_SUPPORTED = "node.type.management.primary.item.name.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if preservation of child node ordering is + * supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_ORDERABLE_CHILD_NODES_SUPPORTED = "node.type.management.orderable.child.nodes.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if residual property and child node + * definitions are supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_RESIDUAL_DEFINITIONS_SUPPORTED = "node.type.management.residual.definitions.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if autocreated properties and child nodes + * are supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_AUTOCREATED_DEFINITIONS_SUPPORTED = "node.type.management.autocreated.definitions.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if same-name sibling child nodes are + * supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_SAME_NAME_SIBLINGS_SUPPORTED = "node.type.management.same.name.siblings.supported"; + + /** + * Key to a long[] descriptor. Returns an array holding the javax.jcr.PropertyType constants for the + * property types (including UNDEFINED, if supported) that a registered node type can specify, or a zero-length + * array if registered node types cannot specify property definitions. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_PROPERTY_TYPES = "node.type.management.property.types"; + + /** + * Key to a boolean descriptor. Returns true if and only if multivalue properties are supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_MULTIVALUED_PROPERTIES_SUPPORTED = "node.type.management.multivalued.properties.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if registration of a node types with more + * than one BINARY property is permitted. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_MULTIPLE_BINARY_PROPERTIES_SUPPORTED = "node.type.management.multiple.binary.properties.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only value-constraints are supported. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_VALUE_CONSTRAINTS_SUPPORTED = "node.type.management.value.constraints.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only the update of node types is supported for node types + * currently in use as the type of an existing node in the repository. + * + * @since JCR 2.0 + */ + public static final String NODE_TYPE_MANAGEMENT_UPDATE_IN_USE_SUPORTED = "node.type.management.update.in.use.suported"; + + /** + * Key to a String[] descriptor. Returns an array holding the constants representing the supported query + * languages, or a zero-length if query is not supported. + * + * @since JCR 2.0 + */ + public static final String QUERY_LANGUAGES = "query.languages"; + + /** + * Key to a boolean descriptor. Returns true if and only if stored queries are supported. + * + * @since JCR 2.0 + */ + public static final String QUERY_STORED_QUERIES_SUPPORTED = "query.stored.queries.supported"; + + /** + * Key to a boolean descriptor. Returns true if and only if full-text search is supported. + * + * @since JCR 2.0 + */ + public static final String QUERY_FULL_TEXT_SEARCH_SUPPORTED = "query.full.text.search.supported"; + + /** + * Key to String descriptor. Returns one of the following javax.jcr.Repository constants indicating + * the level of support for joins in queries: + *
+ *
QUERY_JOINS_NONE
+ *
Joins are not supported. Queries are limited to a single selector.
+ *
QUERY_JOINS_INNER
+ *
Inner joins are supported.
+ *
QUERY_JOINS_INNER_OUTER
+ *
Inner and outer joins are supported.
+ *
+ * + * @since JCR 2.0 + */ + public static final String QUERY_JOINS = "query.joins"; + + /** + * One of three possible values for the descriptor QUERY_JOINS + * . Indicates that joins are not supported. Queries are limited to a + * single selector. + * + * @since JCR 2.0 + */ + public static final String QUERY_JOINS_NONE = "query.joins.none"; + + /** + * One of three possible values for the descriptor QUERY_JOINS + * . Indicates that inner joins are supported. + * + * @since JCR 2.0 + */ + public static final String QUERY_JOINS_INNER = "query.joins.inner"; + + /** + * One of three possible values for the descriptor QUERY_JOINS + * . Indicates that inner and outer joins are supported. + * + * @since JCR 2.0 + */ + public static final String QUERY_JOINS_INNER_OUTER = "query.joins.inner.outer"; + + /** + * 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 #getDescriptorValue(String key)} and {@link #getDescriptorValues(String key)} to query information about this + * repository implementation. + * + * @return a string array holding all descriptor keys. + */ + public String[] getDescriptorKeys(); + + /** + * Returns true if key is a standard descriptor defined by the string constants in this interface + * and false if it is either a valid implementation-specific key or not a valid key. + * + * @param key a descriptor key. + * @return whether key is a standard descriptor. + * @since JCR 2.0 + */ + public boolean isStandardDescriptor( String key ); + + /** + * Returns true if key is a valid single-value descriptor; otherwise returns false. + * + * @param key a descriptor key. + * @return whether the specified desdfriptor is multi-valued. + * @since JCR 2.0 + */ + public boolean isSingleValueDescriptor( String key ); + + /** + * The value of a single-value descriptor is found by passing the key for that descriptor to this method. If key + * is the key of a multi-value descriptor or not a valid key this method returns null. + * + * @param key a descriptor key. + * @return The value of the indicated descriptor + * @since JCR 2.0 + */ + public Value getDescriptorValue( String key ); + + /** + * The value array of a multi-value descriptor is found by passing the key for that descriptor to this method. If + * key is the key of a single-value descriptor then this method returns that value as an array of size one. If + * key is not a valid key this method returns null. + * + * @param key a descriptor key. + * @return the value array for the indicated descriptor + * @since JCR 2.0 + */ + public Value[] getDescriptorValues( String key ); + + /** + * A collection of "standard" descriptors, as defined in the JSR-283 specification. + */ + public static final Set STANDARD_DESCRIPTORS = new HashSet(Arrays.asList(new String[] {LEVEL_1_SUPPORTED, + LEVEL_2_SUPPORTED, OPTION_LOCKING_SUPPORTED, OPTION_OBSERVATION_SUPPORTED, OPTION_QUERY_SQL_SUPPORTED, + OPTION_TRANSACTIONS_SUPPORTED, OPTION_VERSIONING_SUPPORTED, QUERY_XPATH_DOC_ORDER, QUERY_XPATH_POS_INDEX, + WRITE_SUPPORTED, IDENTIFIER_STABILITY, OPTION_XML_IMPORT_SUPPORTED, OPTION_XML_EXPORT_SUPPORTED, + OPTION_UNFILED_CONTENT_SUPPORTED, OPTION_SIMPLE_VERSIONING_SUPPORTED, OPTION_ACTIVITIES_SUPPORTED, + OPTION_BASELINES_SUPPORTED, OPTION_ACCESS_CONTROL_SUPPORTED, OPTION_LOCKING_SUPPORTED, OPTION_OBSERVATION_SUPPORTED, + OPTION_JOURNALED_OBSERVATION_SUPPORTED, OPTION_RETENTION_SUPPORTED, OPTION_LIFECYCLE_SUPPORTED, + OPTION_TRANSACTIONS_SUPPORTED, OPTION_WORKSPACE_MANAGEMENT_SUPPORTED, OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED, + OPTION_UPDATE_PRIMARY_NODE_TYPE_SUPPORTED, OPTION_UPDATE_MIXIN_NODE_TYPES_SUPPORTED, OPTION_SHAREABLE_NODES_SUPPORTED, + OPTION_NODE_TYPE_MANAGEMENT_SUPPORTED, NODE_TYPE_MANAGEMENT_INHERITANCE, + NODE_TYPE_MANAGEMENT_PRIMARY_ITEM_NAME_SUPPORTED, NODE_TYPE_MANAGEMENT_ORDERABLE_CHILD_NODES_SUPPORTED, + NODE_TYPE_MANAGEMENT_RESIDUAL_DEFINITIONS_SUPPORTED, NODE_TYPE_MANAGEMENT_AUTOCREATED_DEFINITIONS_SUPPORTED, + NODE_TYPE_MANAGEMENT_SAME_NAME_SIBLINGS_SUPPORTED, NODE_TYPE_MANAGEMENT_PROPERTY_TYPES, + NODE_TYPE_MANAGEMENT_OVERRIDES_SUPPORTED, NODE_TYPE_MANAGEMENT_MULTIVALUED_PROPERTIES_SUPPORTED, + NODE_TYPE_MANAGEMENT_MULTIPLE_BINARY_PROPERTIES_SUPPORTED, NODE_TYPE_MANAGEMENT_VALUE_CONSTRAINTS_SUPPORTED, + NODE_TYPE_MANAGEMENT_UPDATE_IN_USE_SUPORTED, QUERY_LANGUAGES, QUERY_STORED_QUERIES_SUPPORTED, + QUERY_FULL_TEXT_SEARCH_SUPPORTED, QUERY_JOINS, SPEC_NAME_DESC, SPEC_VERSION_DESC, REP_NAME_DESC, REP_VENDOR_DESC, + REP_VENDOR_URL_DESC, REP_VERSION_DESC, + + })); + +} Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (revision 1812) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (working copy) @@ -49,7 +49,6 @@ import javax.jcr.Credentials; import javax.jcr.LoginException; import javax.jcr.NoSuchWorkspaceException; import javax.jcr.PropertyType; -import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.SimpleCredentials; @@ -94,11 +93,13 @@ import org.modeshape.graph.property.PathFactory; import org.modeshape.graph.property.PathNotFoundException; import org.modeshape.graph.property.Property; import org.modeshape.graph.property.PropertyFactory; +import org.modeshape.graph.property.ValueFactories; import org.modeshape.graph.property.ValueFactory; import org.modeshape.graph.property.basic.GraphNamespaceRegistry; import org.modeshape.graph.query.parse.QueryParsers; import org.modeshape.graph.request.InvalidWorkspaceException; import org.modeshape.jcr.RepositoryQueryManager.PushDown; +import org.modeshape.jcr.api.Repository; import org.modeshape.jcr.xpath.XPathQueryParser; /** @@ -399,7 +400,7 @@ public class JcrRepository implements Repository { } private final String sourceName; - private final Map descriptors; + private final Map descriptors; private final ExecutionContext executionContext; private final RepositoryConnectionFactory connectionFactory; private final RepositoryNodeTypeManager repositoryTypeManager; @@ -449,41 +450,8 @@ public class JcrRepository implements Repository { CheckArg.isNotNull(repositorySourceName, "repositorySourceName"); CheckArg.isNotNull(repositoryObservable, "repositoryObservable"); - Map modifiableDescriptors; - if (descriptors == null) { - modifiableDescriptors = new HashMap(); - } else { - modifiableDescriptors = new HashMap(descriptors); - } // Initialize required JCR descriptors. - modifiableDescriptors.put(Repository.LEVEL_1_SUPPORTED, "true"); - modifiableDescriptors.put(Repository.LEVEL_2_SUPPORTED, "true"); - modifiableDescriptors.put(Repository.OPTION_LOCKING_SUPPORTED, "true"); - modifiableDescriptors.put(Repository.OPTION_OBSERVATION_SUPPORTED, "true"); - modifiableDescriptors.put(Repository.OPTION_QUERY_SQL_SUPPORTED, "true"); - modifiableDescriptors.put(Repository.OPTION_TRANSACTIONS_SUPPORTED, "false"); - modifiableDescriptors.put(Repository.OPTION_VERSIONING_SUPPORTED, "true"); - modifiableDescriptors.put(Repository.QUERY_XPATH_DOC_ORDER, "false"); // see MODE-613 - if (!modifiableDescriptors.containsKey(Repository.QUERY_XPATH_POS_INDEX)) { - // don't override what was supplied ... - modifiableDescriptors.put(Repository.QUERY_XPATH_POS_INDEX, "true"); - } - // Vendor-specific descriptors (REP_XXX) will only be initialized if not already present, allowing for customer branding. - if (!modifiableDescriptors.containsKey(Repository.REP_NAME_DESC)) { - modifiableDescriptors.put(Repository.REP_NAME_DESC, getBundleProperty(Repository.REP_NAME_DESC, true)); - } - if (!modifiableDescriptors.containsKey(Repository.REP_VENDOR_DESC)) { - modifiableDescriptors.put(Repository.REP_VENDOR_DESC, getBundleProperty(Repository.REP_VENDOR_DESC, true)); - } - if (!modifiableDescriptors.containsKey(Repository.REP_VENDOR_URL_DESC)) { - modifiableDescriptors.put(Repository.REP_VENDOR_URL_DESC, getBundleProperty(Repository.REP_VENDOR_URL_DESC, true)); - } - if (!modifiableDescriptors.containsKey(Repository.REP_VERSION_DESC)) { - modifiableDescriptors.put(Repository.REP_VERSION_DESC, getBundleProperty(Repository.REP_VERSION_DESC, true)); - } - modifiableDescriptors.put(Repository.SPEC_NAME_DESC, JcrI18n.SPEC_NAME_DESC.text()); - modifiableDescriptors.put(Repository.SPEC_VERSION_DESC, "1.0"); - this.descriptors = Collections.unmodifiableMap(modifiableDescriptors); + this.descriptors = initializeDescriptors(executionContext.getValueFactories(), descriptors); // Set up the options ... if (options == null) { @@ -814,11 +782,66 @@ public class JcrRepository implements Repository { * {@inheritDoc} * * @throws IllegalArgumentException if key is null. - * @see javax.jcr.Repository#getDescriptor(java.lang.String) + * @see Repository#getDescriptor(java.lang.String) */ public String getDescriptor( String key ) { + if (!isSingleValueDescriptor(key)) return null; + + JcrValue value = (JcrValue)descriptors.get(key); + try { + return value.getString(); + } catch (RepositoryException re) { + throw new IllegalStateException(re); + } + } + + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if {@code key} is null or empty + * @see Repository#getDescriptorValue(String) + */ + public JcrValue getDescriptorValue( String key ) { + if (!isSingleValueDescriptor(key)) return null; + return (JcrValue)descriptors.get(key); + } + + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if {@code key} is null or empty + * @see Repository#getDescriptorValues(String) + */ + public JcrValue[] getDescriptorValues( String key ) { + Object value = descriptors.get(key); + if (value instanceof JcrValue[]) { + return (JcrValue[])value; + } + if (value instanceof JcrValue) { + return new JcrValue[] {(JcrValue)value}; + } + return null; + } + + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if {@code key} is null or empty + * @see Repository#isSingleValueDescriptor(String) + */ + public boolean isSingleValueDescriptor( String key ) { CheckArg.isNotEmpty(key, "key"); - return descriptors.get(key); + return descriptors.get(key) instanceof JcrValue; + } + + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if {@code key} is null or empty + * @see Repository#isStandardDescriptor(String) + */ + public boolean isStandardDescriptor( String key ) { + return STANDARD_DESCRIPTORS.contains(key); } /** @@ -1157,7 +1180,7 @@ public class JcrRepository implements Repository { } } - protected static Properties getBundleProperties() throws RepositoryException { + protected static Properties getBundleProperties() { if (bundleProperties == null) { // This is idempotent, so we don't need to lock ... InputStream stream = null; @@ -1168,7 +1191,7 @@ public class JcrRepository implements Repository { props.load(stream); bundleProperties = new UnmodifiableProperties(props); } catch (IOException e) { - throw new RepositoryException(JcrI18n.failedToReadPropertiesFromManifest.text(e.getLocalizedMessage()), e); + throw new IllegalStateException(JcrI18n.failedToReadPropertiesFromManifest.text(e.getLocalizedMessage()), e); } finally { if (stream != null) { try { @@ -1184,14 +1207,121 @@ public class JcrRepository implements Repository { } protected static String getBundleProperty( String propertyName, - boolean required ) throws RepositoryException { + boolean required ) { String value = getBundleProperties().getProperty(propertyName); if (value == null && required) { - throw new RepositoryException(JcrI18n.failedToReadPropertyFromManifest.text(propertyName)); + throw new IllegalStateException(JcrI18n.failedToReadPropertyFromManifest.text(propertyName)); } return value; } + /** + * Combines the given custom descriptors with the default repository descriptors. + * + * @param factories the value factories to use to create the descriptor values + * @param customDescriptors the custom descriptors; may be null + * @return the custom descriptors (if any) combined with the default repository descriptors; never null or empty + */ + private static Map initializeDescriptors( ValueFactories factories, + Map customDescriptors ) { + if (customDescriptors == null) customDescriptors = Collections.emptyMap(); + Map repoDescriptors = new HashMap(customDescriptors.size() + 60); + + for (Map.Entry entry : customDescriptors.entrySet()) { + repoDescriptors.put(entry.getKey(), valueFor(factories, entry.getValue())); + } + + repoDescriptors.put(Repository.LEVEL_1_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.LEVEL_2_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_LOCKING_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_OBSERVATION_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_QUERY_SQL_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_TRANSACTIONS_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_VERSIONING_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.QUERY_XPATH_DOC_ORDER, valueFor(factories, false)); // see MODE-613 + repoDescriptors.put(Repository.QUERY_XPATH_POS_INDEX, valueFor(factories, true)); + + repoDescriptors.put(Repository.WRITE_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.IDENTIFIER_STABILITY, valueFor(factories, + Repository.IDENTIFIER_STABILITY_METHOD_DURATION)); + repoDescriptors.put(Repository.OPTION_XML_IMPORT_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_XML_EXPORT_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_UNFILED_CONTENT_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_SIMPLE_VERSIONING_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_ACTIVITIES_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_BASELINES_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_ACCESS_CONTROL_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_JOURNALED_OBSERVATION_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_RETENTION_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_LIFECYCLE_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_TRANSACTIONS_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_WORKSPACE_MANAGEMENT_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_UPDATE_PRIMARY_NODE_TYPE_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_UPDATE_MIXIN_NODE_TYPES_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.OPTION_SHAREABLE_NODES_SUPPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.OPTION_NODE_TYPE_MANAGEMENT_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_INHERITANCE, + valueFor(factories, Repository.NODE_TYPE_MANAGEMENT_INHERITANCE_MULTIPLE)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_PRIMARY_ITEM_NAME_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_ORDERABLE_CHILD_NODES_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_RESIDUAL_DEFINITIONS_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_AUTOCREATED_DEFINITIONS_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_SAME_NAME_SIBLINGS_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_PROPERTY_TYPES, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_OVERRIDES_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_MULTIVALUED_PROPERTIES_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_MULTIPLE_BINARY_PROPERTIES_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_VALUE_CONSTRAINTS_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.NODE_TYPE_MANAGEMENT_UPDATE_IN_USE_SUPORTED, valueFor(factories, false)); + repoDescriptors.put(Repository.QUERY_LANGUAGES, new JcrValue[] {valueFor(factories, Query.XPATH), + valueFor(factories, JcrSql2QueryParser.LANGUAGE), valueFor(factories, Query.SQL)}); + repoDescriptors.put(Repository.QUERY_STORED_QUERIES_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.QUERY_FULL_TEXT_SEARCH_SUPPORTED, valueFor(factories, true)); + repoDescriptors.put(Repository.QUERY_JOINS, valueFor(factories, Repository.QUERY_JOINS_INNER)); + repoDescriptors.put(Repository.SPEC_NAME_DESC, valueFor(factories, JcrI18n.SPEC_NAME_DESC.text())); + repoDescriptors.put(Repository.SPEC_VERSION_DESC, valueFor(factories, "1.0")); + + if (!repoDescriptors.containsKey(Repository.REP_NAME_DESC)) { + repoDescriptors.put(Repository.REP_NAME_DESC, + valueFor(factories, + JcrRepository.getBundleProperty(Repository.REP_NAME_DESC, true))); + } + if (!repoDescriptors.containsKey(Repository.REP_VENDOR_DESC)) { + repoDescriptors.put(Repository.REP_VENDOR_DESC, valueFor(factories, + JcrRepository.getBundleProperty(Repository.REP_VENDOR_DESC, + true))); + } + if (!repoDescriptors.containsKey(Repository.REP_VENDOR_URL_DESC)) { + repoDescriptors.put(Repository.REP_VENDOR_URL_DESC, + valueFor(factories, JcrRepository.getBundleProperty(Repository.REP_VENDOR_URL_DESC, true))); + } + if (!repoDescriptors.containsKey(Repository.REP_VERSION_DESC)) { + repoDescriptors.put(Repository.REP_VERSION_DESC, + valueFor(factories, + JcrRepository.getBundleProperty(Repository.REP_VERSION_DESC, + true))); + } + + return Collections.unmodifiableMap(repoDescriptors); + } + + private static JcrValue valueFor( ValueFactories valueFactories, + int type, + Object value ) { + return new JcrValue(valueFactories, null, type, value); + } + + private static JcrValue valueFor( ValueFactories valueFactories, + String value ) { + return valueFor(valueFactories, PropertyType.STRING, value); + } + + private static JcrValue valueFor( ValueFactories valueFactories, + boolean value ) { + return valueFor(valueFactories, PropertyType.BOOLEAN, value); + } + protected class FederatedRepositoryContext implements RepositoryContext { private final RepositoryConnectionFactory connectionFactory;