Index: dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java (working copy) @@ -26,6 +26,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Calendar; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; @@ -48,6 +49,7 @@ import javax.jcr.version.VersionHistory; import net.jcip.annotations.NotThreadSafe; import org.jboss.dna.common.util.CheckArg; +import org.jboss.dna.graph.ExecutionContext; import org.jboss.dna.graph.property.Name; import org.jboss.dna.graph.property.Path.Segment; @@ -225,8 +227,20 @@ * @throws UnsupportedOperationException always * @see javax.jcr.Node#getMixinNodeTypes() */ - public NodeType[] getMixinNodeTypes() { - throw new UnsupportedOperationException(); + public NodeType[] getMixinNodeTypes() throws RepositoryException { + PropertyIterator mixinProperties = getProperties(JcrLexicon.MIXIN_TYPES.getString(session.getExecutionContext().getNamespaceRegistry())); + List mixinNodeTypes = new ArrayList((int)mixinProperties.getSize()); + + while (mixinProperties.hasNext()) { + Property property = mixinProperties.nextProperty(); + + String nodeTypeName = property.getValue().getString(); + NodeType nodeType = session.getWorkspace().getNodeTypeManager().getNodeType(nodeTypeName); + + mixinNodeTypes.add(nodeType); + } + + return mixinNodeTypes.toArray(new NodeType[0]); } /** @@ -308,8 +322,16 @@ * @throws UnsupportedOperationException always * @see javax.jcr.Node#getPrimaryNodeType() */ - public NodeType getPrimaryNodeType() { - throw new UnsupportedOperationException(); + public NodeType getPrimaryNodeType() throws RepositoryException { + String primaryTypeName = JcrLexicon.PRIMARY_TYPE.getString(session.getExecutionContext().getNamespaceRegistry()); + Property primaryNodeTypeProperty = getProperty(primaryTypeName); + Value nodeValue = primaryNodeTypeProperty.getValue(); + + ExecutionContext context = session.getExecutionContext(); + Name nodeValueAsName = context.getValueFactories().getNameFactory().create(nodeValue.getString()); + + String nodeTypeName = nodeValueAsName.getString(context.getNamespaceRegistry()); + return session.getWorkspace().getNodeTypeManager().getNodeType(nodeTypeName); } /** @@ -324,12 +346,19 @@ /** * {@inheritDoc} * - * @throws UnsupportedOperationException always * @see javax.jcr.Node#getProperties(java.lang.String) */ - public PropertyIterator getProperties( String namePattern ) { + public PropertyIterator getProperties( String namePattern ) throws RepositoryException { // TODO: Implement after changing impl to delegate to Graph API - throw new UnsupportedOperationException(); + + // Implementing exact-matching only for now to prototype types as properties + Set matchingProps = new HashSet(); + for (Property prop : properties) { + String propName = prop.getName(); + if (propName.equals(namePattern)) matchingProps.add(prop); + } + + return new JcrPropertyIterator(matchingProps); } /** @@ -522,7 +551,20 @@ * @return false * @see javax.jcr.Node#isNodeType(java.lang.String) */ - public boolean isNodeType( String nodeTypeName ) { + public boolean isNodeType( String nodeTypeName ) throws RepositoryException { + NodeType nodeType = getPrimaryNodeType(); + + if (nodeType.isNodeType(nodeTypeName)) { + return true; + } + + NodeType[] mixinNodeTypes = getMixinNodeTypes(); + for (int i = 0; i < mixinNodeTypes.length; i++) { + if (mixinNodeTypes[i].isNodeType(nodeTypeName)) { + return true; + } + } + return false; } Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrBuiltinNodeTypeSource.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrBuiltinNodeTypeSource.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrBuiltinNodeTypeSource.java (revision 0) @@ -0,0 +1,636 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import javax.jcr.PropertyType; +import javax.jcr.Value; +import javax.jcr.nodetype.NodeType; +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.basic.BasicName; + +/** + * {@link JcrNodeTypeSource} that provides built-in node types per the 1.0 specification. + */ +class JcrBuiltinNodeTypeSource implements JcrNodeTypeSource { + + // Convenience constants to help improve readability + private static final Value[] NO_DEFAULT_VALUES = new Value[0]; + private static final String[] NO_CONSTRAINTS = new String[0]; + private static final List NO_SUPERTYPES = Collections.emptyList(); + private static final List NO_CHILD_NODES = Collections.emptyList(); + private static final List NO_PROPERTIES = Collections.emptyList(); + + // Indicates that the node type has no primary item name - added for readability + private static final Name NO_PRIMARY_ITEM_NAME = null; + // Indicates that the definition should apply to all property definition or child node definitions - added for readability + private static final Name ALL_NODES = null; + + // Indicates whether or not the node type is a mixin - added for readability + private static final boolean IS_A_MIXIN = true; + private static final boolean NOT_MIXIN = false; + + // Indicates whether or not the node type has orderable children - added for readability + private static final boolean ORDERABLE_CHILD_NODES = true; + private static final boolean UNORDERABLE_CHILD_NODES = false; + + /** The list of primary node types. */ + private final List primaryNodeTypes; + /** The list of mixin node types. */ + private final List mixinNodeTypes; + + JcrBuiltinNodeTypeSource( JcrSession session ) { + primaryNodeTypes = new ArrayList(); + + Value trueValue = new JcrValue(session.getExecutionContext().getValueFactories(), PropertyType.BOOLEAN, + Boolean.TRUE); + Value ntBaseValue = new JcrValue(session.getExecutionContext().getValueFactories(), PropertyType.NAME, + JcrNtLexicon.BASE); + + // Stubbing in child node and property definitions for now + JcrNodeType base = new JcrNodeType(session, JcrNtLexicon.BASE, NO_SUPERTYPES, NO_PRIMARY_ITEM_NAME, NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.PRIMARY_TYPE, + OnParentVersionBehavior.COMPUTE.getJcrValue(), true, + true, true, NO_DEFAULT_VALUES, PropertyType.NAME, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.MIXIN_TYPES, + OnParentVersionBehavior.COMPUTE.getJcrValue(), false, + false, true, NO_DEFAULT_VALUES, PropertyType.NAME, + NO_CONSTRAINTS, true)}), NOT_MIXIN, + UNORDERABLE_CHILD_NODES); + + // This needs to be declared early, as some of the primary types reference it + JcrNodeType referenceable = new JcrNodeType( + session, + JcrMixLexicon.REFERENCEABLE, + NO_SUPERTYPES, + NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition( + session, + null, + JcrLexicon.UUID, + OnParentVersionBehavior.INITIALIZE.getJcrValue(), + true, + true, + true, + NO_DEFAULT_VALUES, + PropertyType.STRING, + NO_CONSTRAINTS, + false),}), + IS_A_MIXIN, UNORDERABLE_CHILD_NODES); + + JcrNodeType childNodeDefinition = new JcrNodeType( + session, + JcrNtLexicon.CHILD_NODE_DEFINITION, + Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition( + session, + null, + JcrLexicon.AUTO_CREATED, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.DEFAULT_PRIMARY_TYPE, + OnParentVersionBehavior.COPY.getJcrValue(), + false, false, false, NO_DEFAULT_VALUES, + PropertyType.NAME, NO_CONSTRAINTS, false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.MANDATORY, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.NAME, + OnParentVersionBehavior.COPY.getJcrValue(), + false, false, false, NO_DEFAULT_VALUES, + PropertyType.NAME, NO_CONSTRAINTS, false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.ON_PARENT_VERSION, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.STRING, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.PROTECTED, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.REQUIRED_PRIMARY_TYPES, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, + new Value[] {ntBaseValue}, + PropertyType.NAME, NO_CONSTRAINTS, true), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.SAME_NAME_SIBLINGS, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false)}), NOT_MIXIN, + UNORDERABLE_CHILD_NODES); + + JcrNodeType hierarchyNode = new JcrNodeType( + session, + JcrNtLexicon.HIERARCHY_NODE, + Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition( + session, + null, + JcrLexicon.CREATED, + OnParentVersionBehavior.INITIALIZE.getJcrValue(), + true, + false, + true, + NO_DEFAULT_VALUES, + PropertyType.DATE, + NO_CONSTRAINTS, + false),}), + NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + JcrNodeType file = new JcrNodeType( + session, + JcrNtLexicon.FILE, + Arrays.asList(new NodeType[] {hierarchyNode}), + JcrLexicon.CONTENT, + Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition( + session, + null, + JcrLexicon.CONTENT, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, + false, null, + new NodeType[] {base})}), + NO_PROPERTIES, NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + JcrNodeType folder = new JcrNodeType( + session, + JcrNtLexicon.FOLDER, + Arrays.asList(new NodeType[] {hierarchyNode}), + NO_PRIMARY_ITEM_NAME, + Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition( + session, + null, + null, + OnParentVersionBehavior.VERSION.getJcrValue(), + false, + false, + false, + false, + null, + new NodeType[] {hierarchyNode})}), + NO_PROPERTIES, NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + JcrNodeType frozenNode = new JcrNodeType( + session, + JcrNtLexicon.FROZEN_NODE, + Arrays.asList(new NodeType[] {base, referenceable}), + NO_PRIMARY_ITEM_NAME, + Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition( + session, + null, + ALL_NODES, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, + false, + true, + true, + null, + new NodeType[] {base})}), + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.FROZEN_MIXIN_TYPES, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, false, true, NO_DEFAULT_VALUES, + PropertyType.NAME, NO_CONSTRAINTS, true), + new JcrPropertyDefinition(session, null, JcrLexicon.FROZEN_PRIMARY_TYPE, + OnParentVersionBehavior.ABORT.getJcrValue(), true, + true, true, NO_DEFAULT_VALUES, PropertyType.NAME, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.FROZEN_UUID, + OnParentVersionBehavior.ABORT.getJcrValue(), true, + true, true, NO_DEFAULT_VALUES, + PropertyType.STRING, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, ALL_NODES, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, false, true, NO_DEFAULT_VALUES, + PropertyType.UNDEFINED, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, ALL_NODES, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, false, true, NO_DEFAULT_VALUES, + PropertyType.UNDEFINED, NO_CONSTRAINTS, true),}), + NOT_MIXIN, ORDERABLE_CHILD_NODES); + + JcrNodeType linkedFile = new JcrNodeType( + session, + JcrNtLexicon.LINKED_FILE, + Arrays.asList(new NodeType[] {hierarchyNode}), + JcrLexicon.CONTENT, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition( + session, + null, + JcrLexicon.CONTENT, + OnParentVersionBehavior.COPY.getJcrValue(), + false, + true, + false, + NO_DEFAULT_VALUES, + PropertyType.REFERENCE, + NO_CONSTRAINTS, + false),}), + NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + // Had to be moved above nodeType due to dependency + JcrNodeType propertyDefinition = new JcrNodeType( + session, + JcrNtLexicon.PROPERTY_DEFINITION, + Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition( + session, + null, + JcrLexicon.AUTO_CREATED, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.DEFAULT_VALUES, + OnParentVersionBehavior.COPY.getJcrValue(), + false, false, false, NO_DEFAULT_VALUES, + PropertyType.UNDEFINED, NO_CONSTRAINTS, + true), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.MANDATORY, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.MULTIPLE, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.NAME, + OnParentVersionBehavior.COPY.getJcrValue(), + false, false, false, NO_DEFAULT_VALUES, + PropertyType.NAME, NO_CONSTRAINTS, false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.ON_PARENT_VERSION, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.STRING, NO_CONSTRAINTS, false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.PROTECTED, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, + false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.REQUIRED_TYPE, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, false, NO_DEFAULT_VALUES, + PropertyType.STRING, NO_CONSTRAINTS, false), + new JcrPropertyDefinition( + session, + null, + JcrLexicon.VALUE_CONSTRAINTS, + OnParentVersionBehavior.COPY.getJcrValue(), + false, false, false, NO_DEFAULT_VALUES, + PropertyType.STRING, NO_CONSTRAINTS, true)}), + NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + JcrNodeType nodeType = new JcrNodeType(session, JcrNtLexicon.NODE_TYPE, Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, Arrays.asList(new JcrNodeDefinition[] { + new JcrNodeDefinition(session, null, JcrLexicon.CHILD_NODE_DEFINITION, + OnParentVersionBehavior.VERSION.getJcrValue(), false, + false, false, true, JcrNtLexicon.CHILD_NODE_DEFINITION, + new NodeType[] {childNodeDefinition}), + new JcrNodeDefinition(session, null, JcrLexicon.PROPERTY_DEFINITION, + OnParentVersionBehavior.VERSION.getJcrValue(), false, + false, false, true, JcrNtLexicon.PROPERTY_DEFINITION, + new NodeType[] {propertyDefinition})}), + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.HAS_ORDERABLE_CHILD_NODES, + OnParentVersionBehavior.COPY.getJcrValue(), false, + true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.IS_MIXIN, + OnParentVersionBehavior.COPY.getJcrValue(), false, + true, false, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.NODE_TYPE_NAME, + OnParentVersionBehavior.COPY.getJcrValue(), false, + true, false, NO_DEFAULT_VALUES, PropertyType.NAME, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.PRIMARY_ITEM_NAME, + OnParentVersionBehavior.COPY.getJcrValue(), false, + false, false, NO_DEFAULT_VALUES, PropertyType.NAME, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.SUPERTYPES, + OnParentVersionBehavior.COPY.getJcrValue(), false, + false, false, NO_DEFAULT_VALUES, PropertyType.NAME, + NO_CONSTRAINTS, true),}), NOT_MIXIN, + UNORDERABLE_CHILD_NODES); + + JcrNodeType query = new JcrNodeType(session, JcrNtLexicon.QUERY, Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, NO_CHILD_NODES, Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.LANGUAGE, + OnParentVersionBehavior.COPY.getJcrValue(), false, + false, false, NO_DEFAULT_VALUES, PropertyType.STRING, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.STATEMENT, + OnParentVersionBehavior.COPY.getJcrValue(), false, + false, false, NO_DEFAULT_VALUES, PropertyType.STRING, + NO_CONSTRAINTS, false),}), NOT_MIXIN, + UNORDERABLE_CHILD_NODES); + + JcrNodeType resource = new JcrNodeType(session, JcrNtLexicon.RESOURCE, + Arrays.asList(new NodeType[] {base, referenceable}), JcrLexicon.DATA, + NO_CHILD_NODES, Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.DATA, + OnParentVersionBehavior.COPY.getJcrValue(), false, + true, false, NO_DEFAULT_VALUES, PropertyType.BINARY, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.ENCODING, + OnParentVersionBehavior.COPY.getJcrValue(), false, + false, false, NO_DEFAULT_VALUES, + PropertyType.STRING, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.LAST_MODIFIED, + OnParentVersionBehavior.IGNORE.getJcrValue(), false, + true, false, NO_DEFAULT_VALUES, PropertyType.DATE, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.MIME_TYPE, + OnParentVersionBehavior.COPY.getJcrValue(), false, + true, false, NO_DEFAULT_VALUES, PropertyType.STRING, + NO_CONSTRAINTS, false),}), NOT_MIXIN, + UNORDERABLE_CHILD_NODES); + + JcrNodeType unstructured = new JcrNodeType( + session, + JcrNtLexicon.UNSTRUCTURED, + Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, + Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition( + session, + null, + ALL_NODES, + OnParentVersionBehavior.VERSION.getJcrValue(), + false, + false, + false, + true, + JcrNtLexicon.UNSTRUCTURED, + new NodeType[] {base}),}), + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, ALL_NODES, + OnParentVersionBehavior.COPY.getJcrValue(), + false, false, false, NO_DEFAULT_VALUES, + PropertyType.UNDEFINED, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, ALL_NODES, + OnParentVersionBehavior.COPY.getJcrValue(), + false, false, false, NO_DEFAULT_VALUES, + PropertyType.UNDEFINED, NO_CONSTRAINTS, true),}), + NOT_MIXIN, ORDERABLE_CHILD_NODES); + + JcrNodeType version = new JcrNodeType( + session, + JcrNtLexicon.VERSION, + Arrays.asList(new NodeType[] {base, referenceable}), + NO_PRIMARY_ITEM_NAME, + Arrays.asList(new JcrNodeDefinition[] {new JcrNodeDefinition( + session, + null, + JcrLexicon.FROZEN_NODE, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, + false, + true, + false, + null, + new NodeType[] {frozenNode}),}), + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.CREATED, + OnParentVersionBehavior.ABORT.getJcrValue(), true, + true, true, NO_DEFAULT_VALUES, PropertyType.DATE, + NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.PREDECESSORS, + OnParentVersionBehavior.ABORT.getJcrValue(), false, + false, true, NO_DEFAULT_VALUES, + PropertyType.REFERENCE, NO_CONSTRAINTS, true), + new JcrPropertyDefinition(session, null, JcrLexicon.SUCCESSORS, + OnParentVersionBehavior.ABORT.getJcrValue(), false, + false, true, NO_DEFAULT_VALUES, + PropertyType.REFERENCE, NO_CONSTRAINTS, true),}), + NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + JcrNodeType versionLabels = new JcrNodeType( + session, + JcrNtLexicon.VERSION_LABELS, + Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition( + session, + null, + ALL_NODES, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, + false, + true, + NO_DEFAULT_VALUES, + PropertyType.REFERENCE, + NO_CONSTRAINTS, + false),}), + NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + JcrNodeType versionHistory = new JcrNodeType( + session, + JcrNtLexicon.VERSION_HISTORY, + Arrays.asList(new NodeType[] {base, referenceable}), + NO_PRIMARY_ITEM_NAME, + Arrays.asList(new JcrNodeDefinition[] { + new JcrNodeDefinition(session, null, JcrLexicon.ROOT_VERSION, + OnParentVersionBehavior.ABORT.getJcrValue(), true, + true, true, false, JcrNtLexicon.VERSION, + new NodeType[] {version}), + new JcrNodeDefinition(session, null, JcrLexicon.VERSION_LABELS, + OnParentVersionBehavior.ABORT.getJcrValue(), true, + true, true, false, JcrNtLexicon.VERSION_LABELS, + new NodeType[] {versionLabels}), + new JcrNodeDefinition(session, null, ALL_NODES, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, false, true, false, JcrNtLexicon.VERSION, + new NodeType[] {version}),}), + Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition( + session, + null, + JcrLexicon.VERSIONABLE_UUID, + OnParentVersionBehavior.ABORT.getJcrValue(), + true, + true, + true, + NO_DEFAULT_VALUES, + PropertyType.STRING, + NO_CONSTRAINTS, + false),}), + NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + Name CHILD_VERSION_HISTORY = new BasicName(JcrLexicon.Namespace.URI, "childVersionHistory"); + JcrNodeType versionedChild = new JcrNodeType( + session, + JcrNtLexicon.VERSIONED_CHILD, + Arrays.asList(new NodeType[] {base}), + NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] {new JcrPropertyDefinition( + session, + null, + CHILD_VERSION_HISTORY, + OnParentVersionBehavior.ABORT.getJcrValue(), + true, + true, + true, + NO_DEFAULT_VALUES, + PropertyType.REFERENCE, + NO_CONSTRAINTS, + false),}), + NOT_MIXIN, UNORDERABLE_CHILD_NODES); + + primaryNodeTypes.addAll(Arrays.asList(new JcrNodeType[] {base, unstructured, childNodeDefinition, file, folder, + frozenNode, hierarchyNode, linkedFile, nodeType, propertyDefinition, query, resource, nodeType, version, + versionHistory, versionLabels, versionedChild})); + + mixinNodeTypes = new ArrayList(); + + JcrNodeType lockable = new JcrNodeType(session, JcrMixLexicon.LOCKABLE, NO_SUPERTYPES, NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.LOCK_IS_DEEP, + OnParentVersionBehavior.IGNORE.getJcrValue(), false, + false, true, NO_DEFAULT_VALUES, + PropertyType.BOOLEAN, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.LOCK_OWNER, + OnParentVersionBehavior.IGNORE.getJcrValue(), false, + false, true, NO_DEFAULT_VALUES, PropertyType.STRING, + NO_CONSTRAINTS, false)}), IS_A_MIXIN, + UNORDERABLE_CHILD_NODES); + + JcrNodeType versionable = new JcrNodeType( + session, + JcrMixLexicon.VERSIONABLE, + Arrays.asList(new NodeType[] {referenceable}), + NO_PRIMARY_ITEM_NAME, + NO_CHILD_NODES, + Arrays.asList(new JcrPropertyDefinition[] { + new JcrPropertyDefinition(session, null, JcrLexicon.BASE_VERSION, + OnParentVersionBehavior.IGNORE.getJcrValue(), + false, true, true, NO_DEFAULT_VALUES, + PropertyType.REFERENCE, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.IS_CHECKED_OUT, + OnParentVersionBehavior.IGNORE.getJcrValue(), + true, true, true, new Value[] {trueValue}, + PropertyType.BOOLEAN, NO_CONSTRAINTS, false), + new JcrPropertyDefinition(session, null, JcrLexicon.MERGE_FAILED, + OnParentVersionBehavior.ABORT.getJcrValue(), + false, false, true, NO_DEFAULT_VALUES, + PropertyType.REFERENCE, NO_CONSTRAINTS, true), + new JcrPropertyDefinition(session, null, JcrLexicon.PREDECESSORS, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, true, NO_DEFAULT_VALUES, + PropertyType.REFERENCE, NO_CONSTRAINTS, true), + new JcrPropertyDefinition(session, null, JcrLexicon.VERSION_HISTORY, + OnParentVersionBehavior.COPY.getJcrValue(), + false, true, true, NO_DEFAULT_VALUES, + PropertyType.REFERENCE, NO_CONSTRAINTS, false),}), + IS_A_MIXIN, UNORDERABLE_CHILD_NODES); + + mixinNodeTypes.addAll(Arrays.asList(new JcrNodeType[] {lockable, referenceable, versionable})); + + } + + /** + * {@inheritDoc} + * + * @see org.jboss.dna.jcr.JcrNodeTypeSource#getMixinNodeTypes() + */ + public Collection getMixinNodeTypes() { + return mixinNodeTypes; + } + + /** + * {@inheritDoc} + * + * @see org.jboss.dna.jcr.JcrNodeTypeSource#getPrimaryNodeTypes() + */ + public Collection getPrimaryNodeTypes() { + return primaryNodeTypes; + } + +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java (working copy) @@ -57,7 +57,9 @@ public static I18n errorWhileInitializingTheNamespaceRegistry; public static I18n invalidPathParameter; - + + public static I18n typeNotFound; + public static I18n REP_NAME_DESC; public static I18n REP_VENDOR_DESC; public static I18n SPEC_NAME_DESC; Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrItemDefinition.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrItemDefinition.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrItemDefinition.java (revision 0) @@ -0,0 +1,122 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import javax.jcr.nodetype.ItemDefinition; +import javax.jcr.nodetype.NodeType; +import net.jcip.annotations.Immutable; +import org.jboss.dna.graph.property.Name; + +/** + * DNA implementation of the {@link ItemDefinition} interface. This implementation is immutable and has all fields initialized + * through its constructor. + */ +@Immutable +class JcrItemDefinition implements ItemDefinition { + + protected final JcrSession session; + + private final NodeType declaringNodeType; + protected final Name name; + private final int onParentVersion; + private final boolean autoCreated; + private final boolean mandatory; + private final boolean protectedItem; + + JcrItemDefinition( JcrSession session, + NodeType declaringNodeType, + Name name, + int onParentVersion, + boolean autoCreated, + boolean mandatory, + boolean protectedItem ) { + super(); + this.session = session; + this.declaringNodeType = declaringNodeType; + this.name = name; + this.onParentVersion = onParentVersion; + this.autoCreated = autoCreated; + this.mandatory = mandatory; + this.protectedItem = protectedItem; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#getDeclaringNodeType() + */ + public NodeType getDeclaringNodeType() { + return declaringNodeType; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#getName() + */ + public String getName() { + if (name == null) { + return "*"; + } + + return name.getString(session.getExecutionContext().getNamespaceRegistry()); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#getOnParentVersion() + */ + public int getOnParentVersion() { + return onParentVersion; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#isAutoCreated() + */ + public boolean isAutoCreated() { + return autoCreated; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#isMandatory() + */ + public boolean isMandatory() { + return mandatory; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#isProtected() + */ + public boolean isProtected() { + return protectedItem; + } + +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java (working copy) @@ -31,6 +31,48 @@ */ class JcrLexicon extends org.jboss.dna.graph.JcrLexicon { + public static final Name AUTO_CREATED = new BasicName(Namespace.URI, "autoCreated"); + public static final Name BASE_VERSION = new BasicName(Namespace.URI, "baseVersion"); + public static final Name CHILD_NODE_DEFINITION = new BasicName(Namespace.URI, "childNodeDefinition"); + public static final Name CONTENT = new BasicName(Namespace.URI, "content"); + public static final Name CREATED = new BasicName(Namespace.URI, "created"); + public static final Name DATA = new BasicName(Namespace.URI, "data"); + public static final Name DEFAULT_PRIMARY_TYPE = new BasicName(Namespace.URI, "defaultPrimaryType"); + public static final Name DEFAULT_VALUES = new BasicName(Namespace.URI, "defaultValues"); + public static final Name ENCODING = new BasicName(Namespace.URI, "encoding"); + public static final Name FROZEN_MIXIN_TYPES = new BasicName(Namespace.URI, "frozenMixinTypes"); + public static final Name FROZEN_NODE = new BasicName(Namespace.URI, "frozenNode"); + public static final Name FROZEN_PRIMARY_TYPE = new BasicName(Namespace.URI, "frozenPrimaryType"); + public static final Name FROZEN_UUID = new BasicName(Namespace.URI, "frozenUuid"); + public static final Name HAS_ORDERABLE_CHILD_NODES = new BasicName(Namespace.URI, "hasOrderableChildNodes"); + public static final Name IS_CHECKED_OUT = new BasicName(Namespace.URI, "isCheckedOut"); + public static final Name IS_MIXIN = new BasicName(Namespace.URI, "isMixin"); + public static final Name LANGUAGE = new BasicName(Namespace.URI, "language"); + public static final Name LAST_MODIFIED = new BasicName(Namespace.URI, "lastModified"); + public static final Name LOCK_IS_DEEP = new BasicName(Namespace.URI, "lockIsDeep"); + public static final Name LOCK_OWNER = new BasicName(Namespace.URI, "lockOwner"); + public static final Name MANDATORY = new BasicName(Namespace.URI, "mandatory"); + public static final Name MERGE_FAILED = new BasicName(Namespace.URI, "mergeFailed"); + public static final Name MIME_TYPE = new BasicName(Namespace.URI, "mimeType"); + public static final Name MULTIPLE = new BasicName(Namespace.URI, "multiple"); + public static final Name NAME = new BasicName(Namespace.URI, "name"); + public static final Name NODE_TYPE_NAME = new BasicName(Namespace.URI, "nodeTypeName"); + public static final Name ON_PARENT_VERSION = new BasicName(Namespace.URI, "onParentVersion"); + public static final Name PREDECESSORS = new BasicName(Namespace.URI, "predecessors"); + public static final Name PRIMARY_ITEM_NAME = new BasicName(Namespace.URI, "primaryItemName"); + public static final Name PROPERTY_DEFINITION = new BasicName(Namespace.URI, "propertyDefinition"); + public static final Name PROTECTED = new BasicName(Namespace.URI, "protected"); + public static final Name REQUIRED_PRIMARY_TYPES = new BasicName(Namespace.URI, "requiredPrimaryTypes"); + public static final Name REQUIRED_TYPE = new BasicName(Namespace.URI, "requiredType"); + public static final Name ROOT_VERSION = new BasicName(Namespace.URI, "rootVersion"); + public static final Name SAME_NAME_SIBLINGS = new BasicName(Namespace.URI, "sameNameSiblings"); + public static final Name STATEMENT = new BasicName(Namespace.URI, "statement"); + public static final Name SUCCESSORS = new BasicName(Namespace.URI, "successors"); + public static final Name SUPERTYPES = new BasicName(Namespace.URI, "supertypes"); public static final Name SYSTEM = new BasicName(Namespace.URI, "system"); + public static final Name VALUE_CONSTRAINTS = new BasicName(Namespace.URI, "valueConstraints"); + public static final Name VERSIONABLE_UUID = new BasicName(Namespace.URI, "versionableUuid"); + public static final Name VERSION_HISTORY = new BasicName(Namespace.URI, "versionHistory"); + public static final Name VERSION_LABELS = new BasicName(Namespace.URI, "versionLabels"); } Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMixLexicon.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMixLexicon.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMixLexicon.java (revision 0) @@ -0,0 +1,5 @@ +package org.jboss.dna.jcr; + +public class JcrMixLexicon extends org.jboss.dna.graph.JcrMixLexicon { + +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeDefinition.java (revision 0) @@ -0,0 +1,124 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeDefinition; +import javax.jcr.nodetype.NodeType; +import net.jcip.annotations.Immutable; +import org.jboss.dna.graph.property.Name; + +/** + * DNA implementation of the {@link NodeDefinition} class. + */ +@Immutable +class JcrNodeDefinition extends JcrItemDefinition implements NodeDefinition { + + /** @see NodeDefinition#allowsSameNameSiblings() */ + private final boolean allowsSameNameSiblings; + + /** + * The name of the default primary type (if any). The name is used instead of the raw node type to allow circular references a + * la nt:unstructured. + */ + private final Name defaultPrimaryTypeName; + + /** @see NodeDefinition#getRequiredPrimaryTypes() */ + private final NodeType[] requiredPrimaryTypes; + + JcrNodeDefinition( JcrSession session, + NodeType declaringNodeType, + Name name, + int onParentVersion, + boolean autoCreated, + boolean mandatory, + boolean protectedItem, + boolean allowsSameNameSiblings, + Name defaultPrimaryTypeName, + NodeType[] requiredPrimaryTypes ) { + super(session, declaringNodeType, name, onParentVersion, autoCreated, mandatory, protectedItem); + this.allowsSameNameSiblings = allowsSameNameSiblings; + this.defaultPrimaryTypeName = defaultPrimaryTypeName; + this.requiredPrimaryTypes = requiredPrimaryTypes; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeDefinition#allowsSameNameSiblings() + */ + public boolean allowsSameNameSiblings() { + return allowsSameNameSiblings; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeDefinition#getDefaultPrimaryType() + */ + public NodeType getDefaultPrimaryType() { + // It is valid for this field to be null. + if (defaultPrimaryTypeName == null) { + return null; + } + + /* + * Translate the name to a prefixed type based on the current transient (session) and persistent (workspace) + * prefix to URI mappings. + */ + String mappedTypeName = defaultPrimaryTypeName.getString(session.getExecutionContext().getNamespaceRegistry()); + + try { + return session.getWorkspace().getNodeTypeManager().getNodeType(mappedTypeName); + } catch (RepositoryException re) { + /* + * The spec doesn't allow us to throw a checked exception at this point, but a corrupted namespace mapping + * would be pretty severe. + */ + throw new IllegalStateException(JcrI18n.typeNotFound.text(mappedTypeName)); + } + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeDefinition#getRequiredPrimaryTypes() + */ + public NodeType[] getRequiredPrimaryTypes() { + return requiredPrimaryTypes; + } + + /** + * Creates a new JcrNodeDefinition that is identical to the current object, but with the given + * declaringNodeType. Provided to support immutable pattern for this class. + * + * @param declaringNodeType the declaring node type for the new JcrNodeDefinition + * @return a new JcrNodeDefinition that is identical to the current object, but with the given + * declaringNodeType. + */ + JcrNodeDefinition with( NodeType declaringNodeType ) { + return new JcrNodeDefinition(session, declaringNodeType, name, getOnParentVersion(), isAutoCreated(), isMandatory(), + isProtected(), allowsSameNameSiblings(), defaultPrimaryTypeName, requiredPrimaryTypes); + } +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java (revision 0) @@ -0,0 +1,598 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.nodetype.NodeDefinition; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.PropertyDefinition; +import net.jcip.annotations.Immutable; +import org.jboss.dna.common.util.CheckArg; +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.Path; +import org.jboss.dna.graph.property.ValueFormatException; +import org.jboss.dna.graph.property.Path.Segment; + +/** + * DNA implementation of JCR {@link NodeType}s. + */ +@Immutable +class JcrNodeType implements NodeType { + + /** The name of the node type (e.g., {http://www.jcp.org/jcr/nt/1.0}base) */ + private final Name name; + /** The name of the node's primary item */ + private final Name primaryItemName; + + /** The set of child node definitions for nodes of this type (possibly empty). */ + private final Set childNodeDefinitions; + /** The set of property definitions for nodes of this type (possibly empty). */ + private final Set propertyDefinitions; + /** The supertypes for this node. */ + private final List declaredSupertypes; + + /** Indicates whether this node type is a mixin type (as opposed to a primary type). */ + private boolean mixin; + /** Indicates whether the child nodes of nodes of this type can be ordered. */ + private boolean orderableChildNodes; + + /** + * A reference to the session in which this node type exists, used to remap the internal names to their appropriate prefixed + * version (e.g., {http://www.jcp.org/jcr/nt/1.0}base to "nt:base".). + */ + private JcrSession session; + + JcrNodeType( JcrSession session, + Name name, + List declaredSupertypes, + Name primaryItemName, + Collection childNodeDefinitions, + Collection propertyDefinitions, + boolean mixin, + boolean orderableChildNodes ) { + this.session = session; + this.name = name; + this.primaryItemName = primaryItemName; + this.declaredSupertypes = declaredSupertypes != null ? declaredSupertypes : Collections.emptyList(); + this.mixin = mixin; + this.orderableChildNodes = orderableChildNodes; + this.propertyDefinitions = new HashSet(propertyDefinitions.size()); + for (JcrPropertyDefinition property : propertyDefinitions) { + this.propertyDefinitions.add(property.with(this)); + } + + this.childNodeDefinitions = new HashSet(childNodeDefinitions.size()); + for (JcrNodeDefinition childNode : childNodeDefinitions) { + this.childNodeDefinitions.add(childNode.with(this)); + } + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#canAddChildNode(java.lang.String) + */ + public boolean canAddChildNode( String childNodeName ) { + + CheckArg.isNotNull(childNodeName, "childNodeName"); + + JcrNodeDefinition residual = null; + + // First, try to find a child node definition with the given name + for (JcrNodeDefinition childNode : childNodeDefinitions) { + if (childNodeName.equals(childNode.getName())) { + NodeType defaultType = childNode.getDefaultPrimaryType(); + // If there's no default type, the child node can't be created + if (defaultType == null) { + return false; + } + + // Check if the node can be added with the named child node definition + return checkTypeAgainstDefinition(defaultType, childNode); + // If we run into a residual (*) definition, save it just in case + } else if (childNode.name == null) { + residual = childNode; + } + } + + // If there's no matching child node definition for the name and no residual definition, the node cannot be added + if (residual == null) { + return false; + } + + NodeType defaultType = residual.getDefaultPrimaryType(); + + // If there's no default type, the child node can't be created + if (defaultType == null) { + return false; + } + + // Check if the node can be added with the default type of the residual child node definition + return checkTypeAgainstDefinition(defaultType, residual); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#canAddChildNode(java.lang.String, java.lang.String) + */ + public boolean canAddChildNode( String childNodeName, + String primaryNodeTypeName ) { + + CheckArg.isNotNull(childNodeName, "childNodeName"); + CheckArg.isNotNull(primaryNodeTypeName, "primaryNodeTypeName"); + + NodeType primaryNodeType; + try { + primaryNodeType = session.getWorkspace().getNodeTypeManager().getNodeType(primaryNodeTypeName); + } catch (RepositoryException re) { + // If the node type doesn't exist, you can't add a child node with that type + return false; + } + + JcrNodeDefinition residual = null; + + // First, try to find a child node definition with the given name + for (JcrNodeDefinition childNode : childNodeDefinitions) { + if (childNodeName.equals(childNode.getName())) { + return checkTypeAgainstDefinition(primaryNodeType, childNode); + // If we run into a residual (*) definition, save it just in case + } else if (childNode.name == null) { + residual = childNode; + } + } + + // If there's no matching child node definition for the name and no residual definition, the node cannot be added + if (residual == null) { + return false; + } + + return checkTypeAgainstDefinition(primaryNodeType, residual); + } + + /** + * Checks whether the given type is the same type or a subtype of each of the required primary types for the given node + * definition. + * + * @param typeToCheck the type to check + * @param definition the node definition to check against + * @return true if and only if the given type is the same type or extends each of the required primary types in + * the given definition + */ + private boolean checkTypeAgainstDefinition( NodeType typeToCheck, + NodeDefinition definition ) { + NodeType[] requiredPrimaryTypes = definition.getRequiredPrimaryTypes(); + for (int i = 0; i < requiredPrimaryTypes.length; i++) { + // See if the given type for the node matches all of the required primary types + if (!typeToCheck.isNodeType(requiredPrimaryTypes[i].getName())) { + return false; + } + } + // The node can be added with the given type based on the given child node definition + return true; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#canRemoveItem(java.lang.String) + */ + public boolean canRemoveItem( String itemName ) { + CheckArg.isNotNull(itemName, "itemName"); + + for (PropertyDefinition item : propertyDefinitions) { + if (itemName.equals(item.getName())) { + return !item.isMandatory() && !item.isProtected(); + } + } + + for (NodeDefinition item : childNodeDefinitions) { + if (itemName.equals(item.getName())) { + return !item.isMandatory() && !item.isProtected(); + } + } + + return true; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#canSetProperty(java.lang.String, javax.jcr.Value) + */ + public boolean canSetProperty( String propertyName, + Value value ) { + CheckArg.isNotNull(propertyName, "propertyName"); + + JcrPropertyDefinition residual = null; + + for (JcrPropertyDefinition property : propertyDefinitions) { + if (propertyName.equals(property.getName())) { + if (property.isMultiple()) { + return false; + } + + return canSetProperty(property, value); + } else if (property.name == null && !property.isMultiple()) { + residual = property; + } + } + + return canSetProperty(residual, value); + } + + /** + * Internal method to validate that a value can be set on a given property. The values are set according to the following + * rules: + *
    + *
  1. If value is null, return the value of {@link JcrNodeType#canRemoveItem(String)}
  2. + *
  3. If property.isProtected() is true, return false
  4. + *
  5. If property.getRequiredType() is {@link PropertyType#UNDEFINED}, return true
  6. + *
  7. Compare the type of the given value to the required type and see if they are compatible based on the rules in the JCR + * 1.0 spec.
  8. + *
+ * + * @param property the property to be set + * @param value the value to set (may be null) + * @return whether the property can be set to the value based on the described rules + */ + private boolean canSetProperty( JcrPropertyDefinition property, + Value value ) { + assert property != null; + + if (value == null) { + return !property.isProtected() && !property.isMandatory(); + } + + if (property.isProtected()) { + return false; + } + + int valueType = value.getType(); + + switch (property.getRequiredType()) { + case PropertyType.BINARY: + return true; + case PropertyType.BOOLEAN: + if (valueType == PropertyType.BOOLEAN || valueType == PropertyType.STRING) { + return true; + } + + // If the binary can be converted to a UTF-8 string, it can be set onto a boolean property + if (valueType == PropertyType.BINARY) { + try { + value.getString(); + return true; + } catch (RepositoryException re) { + return false; + } + } + return false; + + case PropertyType.DATE: + if (valueType == PropertyType.DATE || valueType == PropertyType.DOUBLE || valueType == PropertyType.LONG) { + return true; + } + + if (valueType == PropertyType.STRING || valueType == PropertyType.BINARY) { + try { + value.getDate(); + return true; + } catch (RepositoryException re) { + return false; + } + } + return false; + + case PropertyType.DOUBLE: + return value.getType() == PropertyType.DOUBLE; + case PropertyType.LONG: + return value.getType() == PropertyType.LONG; + case PropertyType.NAME: + if (value.getType() == PropertyType.NAME) { + return true; + } + + try { + if (valueType == PropertyType.STRING || valueType == PropertyType.BINARY) { + session.getExecutionContext().getValueFactories().getNameFactory().create(value.getString()); + return true; + } + + if (valueType == PropertyType.PATH) { + Path path = session.getExecutionContext().getValueFactories().getPathFactory().create(value.getString()); + + Segment[] segments = path.getSegmentsArray(); + return !path.isAbsolute() && segments.length == 1 && !segments[0].hasIndex(); + } + } catch (ValueFormatException re) { + return false; + } catch (RepositoryException re) { + return false; + } + + return false; + + case PropertyType.PATH: + return value.getType() == PropertyType.PATH || value.getType() == PropertyType.STRING; + case PropertyType.REFERENCE: + return value.getType() == PropertyType.REFERENCE; + + // Anything can be converted to these types + case PropertyType.STRING: + case PropertyType.UNDEFINED: + return true; + default: + throw new IllegalStateException("Invalid required property type " + property.getRequiredType() + " for property " + + property.getName()); + } + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#canSetProperty(java.lang.String, javax.jcr.Value[]) + */ + public boolean canSetProperty( String propertyName, + Value[] values ) { + CheckArg.isNotNull(propertyName, "propertyName"); + + JcrPropertyDefinition residual = null; + + for (JcrPropertyDefinition property : propertyDefinitions) { + if (propertyName.equals(property.getName())) { + if (!property.isMultiple()) { + return false; + } + + return canSetProperty(property, values); + } else if (property.name == null && property.isMultiple()) { + residual = property; + } + } + + return canSetProperty(residual, values); + } + + /** + * Internal method to validate that an array of values can be set on a given property. This method returns true + * if the following algorithm would return true when applied to each non-null value in values: + *
    + *
  1. If the value is null, return the value of {@link JcrNodeType#canRemoveItem(String)}
  2. + *
  3. If the property definition has a no required type ({@link PropertyType#UNDEFINED}), return true
  4. + *
  5. Compare the type of the given value to the required type and see if they are compatible
  6. + *
+ * + * @param property the property to be set + * @param values the array of values to set (may be null) + * @return whether the property can be set to the value based on the described rules + */ + private boolean canSetProperty( JcrPropertyDefinition property, + Value[] values ) { + if (values != null) { + for (int i = 0; i < values.length; i++) { + if (values[i] != null) { + if (!canSetProperty(property, values[i])) { + return false; + } + } + } + } + + return !property.isProtected(); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getDeclaredChildNodeDefinitions() + */ + public NodeDefinition[] getDeclaredChildNodeDefinitions() { + return childNodeDefinitions.toArray(new JcrNodeDefinition[childNodeDefinitions.size()]); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getChildNodeDefinitions() + */ + public NodeDefinition[] getChildNodeDefinitions() { + Set nodeDefs = new HashSet(); + NodeType[] supertypes = getSupertypes(); + + // TODO: This could be cached after being calculated once + for (int i = 0; i < supertypes.length; i++) { + NodeDefinition[] childNodeDefinitions = supertypes[i].getChildNodeDefinitions(); + for (int j = 0; j < childNodeDefinitions.length; i++) { + + // TODO: Could add sanity check here (assertion?) that definitions of the same child node in multiple supertypes + // are consistent + nodeDefs.add(childNodeDefinitions[j]); + } + } + + nodeDefs.addAll(childNodeDefinitions); + + return nodeDefs.toArray(new JcrNodeDefinition[nodeDefs.size()]); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getPropertyDefinitions() + */ + public PropertyDefinition[] getPropertyDefinitions() { + Set propDefs = new HashSet(); + NodeType[] supertypes = getSupertypes(); + + // TODO: This could be cached after being calculated once + for (int i = 0; i < supertypes.length; i++) { + PropertyDefinition[] childPropertyDefinitions = supertypes[i].getPropertyDefinitions(); + for (int j = 0; j < childPropertyDefinitions.length; j++) { + + // TODO: Could add sanity check here (assertion?) that definitions of the same child node in multiple supertypes + // are consistent + propDefs.add(childPropertyDefinitions[j]); + } + } + propDefs.addAll(propertyDefinitions); + + return propDefs.toArray(new JcrPropertyDefinition[propDefs.size()]); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getDeclaredSupertypes() + */ + public NodeType[] getDeclaredSupertypes() { + return declaredSupertypes.toArray(new NodeType[declaredSupertypes.size()]); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getName() + */ + public String getName() { + // Translate the name to the correct prefix. Need to check the session to support url-remapping. + return name.getString(session.getExecutionContext().getNamespaceRegistry()); + } + + /** + * Returns the internal {@link Name} object for the note type. This method exists outside the JCR API and should not be + * exposed outside of the package. + * + * @return the internal {@link Name} object for the note type. + */ + Name getInternalName() { + return name; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getPrimaryItemName() + */ + public String getPrimaryItemName() { + if (primaryItemName == null) { + return null; + } + + // Translate the name to the correct prefix. Need to check the session to support url-remapping. + return primaryItemName.getString(session.getExecutionContext().getNamespaceRegistry()); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getDeclaredPropertyDefinitions() + */ + public PropertyDefinition[] getDeclaredPropertyDefinitions() { + return propertyDefinitions.toArray(new JcrPropertyDefinition[propertyDefinitions.size()]); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#getSupertypes() + */ + public NodeType[] getSupertypes() { + Set supertypes = new HashSet(); + Stack unvisitedSupertypes = new Stack(); + + assert declaredSupertypes != null; + unvisitedSupertypes.addAll(declaredSupertypes); + + // TODO: If this ends up getting called frequently, it should probably be executed once in the constructor and have the + // results cached. + while (!unvisitedSupertypes.isEmpty()) { + NodeType nodeType = unvisitedSupertypes.pop(); + + /* + * If we haven't already visited this nodeType (which we can + * infer by whether or not it was already added to the return set), + * then add the supertypes of this new node to the unvisited set for + * further inspection. + */ + if (!supertypes.contains(nodeType)) { + supertypes.add(nodeType); + // Violating encapsulation to avoid going from List to array back to List + unvisitedSupertypes.addAll(((JcrNodeType)nodeType).declaredSupertypes); + } + } + + return supertypes.toArray(new NodeType[0]); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#hasOrderableChildNodes() + */ + public boolean hasOrderableChildNodes() { + return orderableChildNodes; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#isMixin() + */ + public boolean isMixin() { + return mixin; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeType#isNodeType(java.lang.String) + */ + public boolean isNodeType( String nodeTypeName ) { + if (this.getName().equals(nodeTypeName)) return true; + + // TODO: This could be optimized + NodeType[] supertypes = getSupertypes(); + for (int i = 0; i < supertypes.length; i++) { + if (supertypes[i].isNodeType(nodeTypeName)) { + return true; + } + } + + return false; + } + + @Override + public String toString() { + return getName(); + } +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeIterator.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeIterator.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeIterator.java (revision 0) @@ -0,0 +1,116 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.NodeTypeIterator; + +/** + * Type-safe {@link Iterator} implementation for NodeTypes, as per the JCR specification. + */ +final class JcrNodeTypeIterator implements NodeTypeIterator { + + private int size; + private int position; + private Iterator iterator; + + JcrNodeTypeIterator( Collection values ) { + this.iterator = Collections.unmodifiableCollection(values).iterator(); + this.size = values.size(); + this.position = 0; + + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeTypeIterator#nextNodeType() + */ + public NodeType nextNodeType() { + // TODO: Does this really need to return a copy of the node type to prevent manipulation? + position++; + return iterator.next(); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.RangeIterator#getPosition() + */ + public long getPosition() { + return position; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.RangeIterator#getSize() + */ + public long getSize() { + return size; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.RangeIterator#skip(long) + */ + public void skip( long count ) { + position += count; + while (count-- > 0) + iterator.next(); + } + + /** + * {@inheritDoc} + * + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext() { + return iterator.hasNext(); + } + + /** + * {@inheritDoc} + * + * @see java.util.Iterator#next() + */ + public Object next() { + position++; + return iterator.next(); + } + + /** + * {@inheritDoc} + * + * @see java.util.Iterator#remove() + */ + public void remove() { + throw new UnsupportedOperationException("Node types cannot be removed through their iterator"); + } + +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeSource.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeSource.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeSource.java (revision 0) @@ -0,0 +1,26 @@ +package org.jboss.dna.jcr; + +import java.util.Collection; +import javax.jcr.nodetype.NodeType; + +/** + * Interface for any potential provider of {@link JcrNodeType} definitions, the DNA implementation of {@link NodeType}. Possible + * sources of node type definitions include CND files, repository metadata, and mock types for testing. + * + * @see JcrWorkspace#getNodeTypeManager() + */ +public interface JcrNodeTypeSource { + + /** + * Returns the list of primary node types provided by this source + * @return the list of primary node types provided by this source + */ + public Collection getPrimaryNodeTypes(); + + /** + * Returns the list of mixin node types provided by this source + * @return the list of mixin node types provided by this source + */ + public Collection getMixinNodeTypes(); + +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNtLexicon.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNtLexicon.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNtLexicon.java (revision 0) @@ -0,0 +1,43 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.basic.BasicName; + +public class JcrNtLexicon extends org.jboss.dna.graph.JcrNtLexicon { + + public static final Name CHILD_NODE_DEFINITION = new BasicName(Namespace.URI, "childNodeDefinition"); + public static final Name FROZEN_NODE = new BasicName(Namespace.URI, "frozenNode"); + public static final Name HIERARCHY_NODE = new BasicName(Namespace.URI, "hierarchyNode"); + public static final Name LINKED_FILE = new BasicName(Namespace.URI, "linkedFile"); + public static final Name NODE_TYPE = new BasicName(Namespace.URI, "nodeType"); + public static final Name PROPERTY_DEFINITION = new BasicName(Namespace.URI, "propertyDefinition"); + public static final Name QUERY = new BasicName(Namespace.URI, "query"); + public static final Name VERSION = new BasicName(Namespace.URI, "version"); + public static final Name VERSIONED_CHILD = new BasicName(Namespace.URI, "versionedChild"); + public static final Name VERSION_HISTORY = new BasicName(Namespace.URI, "versionHistory"); + public static final Name VERSION_LABELS = new BasicName(Namespace.URI, "versionLabels"); + +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrProperty.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrProperty.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrProperty.java (working copy) @@ -131,7 +131,7 @@ /** * {@inheritDoc} - * + * * @see javax.jcr.Property#getString() */ public String getString() throws RepositoryException { @@ -163,7 +163,8 @@ * @see javax.jcr.Property#getValues() */ public Value[] getValues() throws ValueFormatException { - throw new ValueFormatException(); + + return new Value[] {jcrValue}; } /* Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java (revision 0) @@ -0,0 +1,112 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import javax.jcr.Value; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.PropertyDefinition; +import net.jcip.annotations.Immutable; +import org.jboss.dna.graph.property.Name; + + +/** + * DNA implementation of the {@link PropertyDefinition} interface. This implementation is immutable and has all fields initialized + * through its constructor. + */ +@Immutable +class JcrPropertyDefinition extends JcrItemDefinition implements PropertyDefinition { + + private final Value[] defaultValues; + private final int requiredType; + private final String[] valueConstraints; + private final boolean multiple; + + JcrPropertyDefinition( JcrSession session, + NodeType declaringNodeType, + Name name, + int onParentVersion, + boolean autoCreated, + boolean mandatory, + boolean protectedItem, + Value[] defaultValues, + int requiredType, + String[] valueConstraints, + boolean multiple ) { + super(session, declaringNodeType, name, onParentVersion, autoCreated, mandatory, protectedItem); + this.defaultValues = defaultValues; + this.requiredType = requiredType; + this.valueConstraints = valueConstraints; + this.multiple = multiple; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#getDefaultValues() + */ + public Value[] getDefaultValues() { + return defaultValues; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#getRequiredType() + */ + public int getRequiredType() { + return requiredType; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#getValueConstraints() + */ + public String[] getValueConstraints() { + return valueConstraints; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#isMultiple() + */ + public boolean isMultiple() { + return multiple; + } + + /** + * Creates a new JcrPropertyDefinition that is identical to the current object, but with the given + * declaringNodeType. Provided to support immutable pattern for this class. + * + * @param declaringNodeType the declaring node type for the new JcrPropertyDefinition + * @return a new JcrPropertyDefinition that is identical to the current object, but with the given + * declaringNodeType. + */ + JcrPropertyDefinition with( NodeType declaringNodeType ) { + return new JcrPropertyDefinition(this.session, declaringNodeType, this.name, this.getOnParentVersion(), + this.isAutoCreated(), this.isMandatory(), this.isProtected(), this.getDefaultValues(), + this.getRequiredType(), this.getValueConstraints(), this.isMultiple()); + } +} Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyIterator.java (working copy) @@ -36,10 +36,12 @@ private final Iterator iterator; private int ndx; + private int size; JcrPropertyIterator( Set properties ) { assert properties != null; iterator = properties.iterator(); + size = properties.size(); } /** @@ -54,11 +56,10 @@ /** * {@inheritDoc} * - * @return -1L * @see javax.jcr.RangeIterator#getSize() */ public long getSize() { - return -1L; + return size; } /** Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java (working copy) @@ -423,6 +423,15 @@ rootNode = new JcrRootNode(this); // Get root node from source populateNode(rootNode, graph.getNodeAt(executionContext.getValueFactories().getPathFactory().createRootPath())); + + // Root nodes need to have a type in JCR land + // JcrProperty primaryType = new JcrProperty(rootNode, getExecutionContext(), JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.BASE); + String typeValue = JcrNtLexicon.BASE.getString(executionContext.getNamespaceRegistry()); + JcrProperty primaryType = new JcrProperty(rootNode, executionContext, JcrLexicon.PRIMARY_TYPE, typeValue); + + // TODO: Not liking the hard-code + rootNode.properties.add(primaryType); + return rootNode; } @@ -594,8 +603,7 @@ if (uuid == null && DnaLexicon.UUID.equals(name)) uuid = uuidFactory.create(dnaProp.getValues()).next(); else if (jcrUuidName.equals(name)) dnaUuidProp = dnaProp; else if (jcrMixinTypesName.equals(name)) { - org.jboss.dna.graph.property.ValueFactory stringFactory = executionContext.getValueFactories() - .getStringFactory(); + org.jboss.dna.graph.property.ValueFactory stringFactory = executionContext.getValueFactories().getStringFactory(); for (String mixin : stringFactory.create(dnaProp)) { if ("mix:referenceable".equals(mixin)) referenceable = true; } Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java (working copy) @@ -4,13 +4,13 @@ * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * See the AUTHORS.txt file in the distribution for a full listing of - * individual contributors. + * individual contributors. * * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA * is licensed to you under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. - * + * * JBoss DNA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -23,9 +23,11 @@ */ package org.jboss.dna.jcr; +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.basic.BasicName; /** - * @author Randall Hauch + * */ public class JcrSvLexicon { @@ -34,4 +36,9 @@ public static final String PREFIX = "sv"; } + public static final Name NODE = new BasicName(Namespace.URI, "node"); + public static final Name PROPERTY = new BasicName(Namespace.URI, "property"); + public static final Name NAME = new BasicName(Namespace.URI, "name"); + public static final Name TYPE = new BasicName(Namespace.URI, "type"); + public static final Name VALUE = new BasicName(Namespace.URI, "value"); } Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java (revision 738) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java (working copy) @@ -25,6 +25,10 @@ import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import javax.jcr.AccessDeniedException; @@ -37,6 +41,9 @@ import javax.jcr.Workspace; import javax.jcr.lock.LockException; import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.NodeTypeIterator; import javax.jcr.nodetype.NodeTypeManager; import javax.jcr.observation.ObservationManager; import javax.jcr.query.QueryManager; @@ -101,10 +108,16 @@ private final JcrNamespaceRegistry workspaceRegistry; /** + * Reference to the JCR type manager for this workspace. + */ + private final NodeTypeManager nodeTypeManager; + + /** * The {@link Session} instance that this corresponds with this workspace. */ private final JcrSession session; + @SuppressWarnings( "synthetic-access" ) JcrWorkspace( JcrRepository repository, String workspaceName, ExecutionContext context, @@ -141,6 +154,10 @@ // Set up the session for this workspace ... this.session = new JcrSession(this.repository, this, this.context, sessionAttributes); + + // This must be initialized after the session + this.nodeTypeManager = new JcrNodeTypeManager(new JcrBuiltinNodeTypeSource(session)); + } String getSourceName() { @@ -186,7 +203,7 @@ * {@inheritDoc} */ public NodeTypeManager getNodeTypeManager() { - throw new UnsupportedOperationException(); + return nodeTypeManager; } /** @@ -331,4 +348,95 @@ boolean removeExisting ) { throw new UnsupportedOperationException(); } + + /** + * Local implementation of @{link NodeTypeManager}. Initialized with {@link NodeType} source data when it is created (in the + * {@link JcrWorkspace} constructor. + */ + private class JcrNodeTypeManager implements NodeTypeManager { + + private final Map primaryNodeTypes; + private final Map mixinNodeTypes; + + private JcrNodeTypeManager( JcrNodeTypeSource source ) { + Collection primary = source.getPrimaryNodeTypes(); + Collection mixins = source.getMixinNodeTypes(); + + primaryNodeTypes = new HashMap(primary.size()); + for (JcrNodeType nodeType : primary) { + primaryNodeTypes.put(nodeType.getInternalName(), nodeType); + } + + mixinNodeTypes = new HashMap(mixins.size()); + for (JcrNodeType nodeType : mixins) { + mixinNodeTypes.put(nodeType.getInternalName(), nodeType); + } + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeTypeManager#getAllNodeTypes() + */ + public NodeTypeIterator getAllNodeTypes() { + + // TODO: Can revisit this approach later if it becomes a performance issue + /* + * Note also that this creates a subtle difference in behavior for concurrent modification + * between this method and the specific get*NodeTypes methods. That is, if a type is added + * while an iterator from the corresponding specific get*NodeType method is being traversed, + * a ConcurrentModificationException will be thrown. Because this iterator is based on a copy + * of the underlying maps, no exception would be thrown in the same case. + */ + + List allTypes = new ArrayList(primaryNodeTypes.size() + mixinNodeTypes.size()); + allTypes.addAll(primaryNodeTypes.values()); + allTypes.addAll(mixinNodeTypes.values()); + return new JcrNodeTypeIterator(allTypes); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeTypeManager#getMixinNodeTypes() + */ + public NodeTypeIterator getMixinNodeTypes() { + return new JcrNodeTypeIterator(mixinNodeTypes.values()); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeTypeManager#getNodeType(java.lang.String) + */ + @SuppressWarnings( "synthetic-access" ) + public NodeType getNodeType( String nodeTypeName ) throws NoSuchNodeTypeException, RepositoryException { + Name ntName = session.getExecutionContext().getValueFactories().getNameFactory().create(nodeTypeName); + + NodeType nodeType = primaryNodeTypes.get(ntName); + + if (nodeType != null) { + return nodeType; + } + + nodeType = mixinNodeTypes.get(ntName); + + if (nodeType != null) { + return nodeType; + } + + throw new NoSuchNodeTypeException(JcrI18n.typeNotFound.text(nodeTypeName)); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.NodeTypeManager#getPrimaryNodeTypes() + */ + public NodeTypeIterator getPrimaryNodeTypes() { + return new JcrNodeTypeIterator(primaryNodeTypes.values()); + } + + } + } Index: dna-jcr/src/main/java/org/jboss/dna/jcr/OnParentVersionBehavior.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/OnParentVersionBehavior.java (revision 0) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/OnParentVersionBehavior.java (revision 0) @@ -0,0 +1,71 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.jcr; + +import javax.jcr.version.OnParentVersionAction; + +/** + * Enumeration of possible behaviors for on-parent-version setting of properties and child nodes in JCR specification. + */ +public enum OnParentVersionBehavior { + /** @see OnParentVersionAction#ABORT */ + ABORT(OnParentVersionAction.ABORT, OnParentVersionAction.ACTIONNAME_ABORT), + /** @see OnParentVersionAction#COMPUTE */ + COMPUTE(OnParentVersionAction.COMPUTE, OnParentVersionAction.ACTIONNAME_COMPUTE), + /** @see OnParentVersionAction#COPY */ + COPY(OnParentVersionAction.COPY, OnParentVersionAction.ACTIONNAME_COPY), + /** @see OnParentVersionAction#IGNORE */ + IGNORE(OnParentVersionAction.IGNORE, OnParentVersionAction.ACTIONNAME_IGNORE), + /** @see OnParentVersionAction#INITIALIZE */ + INITIALIZE(OnParentVersionAction.INITIALIZE, OnParentVersionAction.ACTIONNAME_INITIALIZE), + /** @see OnParentVersionAction#VERSION */ + VERSION(OnParentVersionAction.VERSION, OnParentVersionAction.ACTIONNAME_VERSION); + + private final int jcrValue; + private final String name; + + OnParentVersionBehavior( int jcrValue, + String name ) { + this.jcrValue = jcrValue; + this.name = name; + } + + public int getJcrValue() { + return jcrValue; + } + + public String getName() { + return name; + } + + public static OnParentVersionBehavior fromValue( int onParentVersionAction ) { + for (OnParentVersionBehavior opvb : OnParentVersionBehavior.values()) { + if (opvb.jcrValue == onParentVersionAction) { + return opvb; + } + } + + throw new IllegalStateException("No matching version for value: " + onParentVersionAction); + } +} Index: dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties =================================================================== --- dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties (revision 738) +++ dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties (working copy) @@ -55,4 +55,5 @@ errorObtainingWorkspaceNames = Error while obtaining the workspace names for the "{0}" repository: {1} errorObtainingDefaultWorkspaceName = Error while obtaining the default workspace names for the "{0}" repository: {1} workspaceNameIsInvalid = "{1}" is not a valid workspace name for the "{0}" repository -errorVerifyingWorkspaceName = Error validating the workspace name "{1}" for the "{0}" repository: {2} \ No newline at end of file +errorVerifyingWorkspaceName =Error validating the workspace name "{1}" for the "{0}" repository\: {2} +typeNotFound=No type exists with name "{0}" Index: dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java =================================================================== --- dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java (revision 738) +++ dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyIteratorTest.java (working copy) @@ -63,7 +63,7 @@ properties.add(Mockito.mock(Property.class)); PropertyIterator iter = node.getProperties(); assertThat(iter, notNullValue()); - assertThat(iter.getSize(), is(-1L)); + assertThat(iter.getSize(), is(4L)); assertThat(iter.getPosition(), is(0L)); assertThat(iter.hasNext(), is(true)); assertThat(iter.next(), notNullValue()); Index: dna-jcr/src/test/resources/repositoryJackRabbitTck.xml =================================================================== --- dna-jcr/src/test/resources/repositoryJackRabbitTck.xml (revision 738) +++ dna-jcr/src/test/resources/repositoryJackRabbitTck.xml (working copy) @@ -24,9 +24,11 @@ ~ 51 Franklin Street, Fifth Floor ~ Boston, MA 02110-1301 USA --> - - - - - + + + + + \ No newline at end of file