Index: dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java (revision 938) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java (working copy) @@ -283,10 +283,21 @@ boolean skipProtected ) { boolean setToEmpty = value == null; + /* + * We use this flag to indicate that there was a definition encountered with the same name. If + * a named definition (or definitions - for example the same node type could define a LONG and BOOLEAN + * version of the same property) is encountered and no match is found for the name, then processing should not + * proceed. If processing did proceed, a residual definition might be found and matched. This would + * lead to a situation where a node defined a type for a named property, but contained a property with + * the same name and the wrong type. + */ + boolean matchedOnName = false; + // Look for a single-value property definition on the primary type that matches by name and type ... JcrNodeType primaryType = getNodeType(primaryTypeName); if (primaryType != null) { for (JcrPropertyDefinition definition : primaryType.allSingleValuePropertyDefinitions(propertyName)) { + matchedOnName = true; // See if the definition allows the value ... if (skipProtected && definition.isProtected()) return null; if (setToEmpty) { @@ -299,6 +310,42 @@ int type = definition.getRequiredType(); if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition; } + + if (matchedOnName) { + if (value != null) { + for (JcrPropertyDefinition definition : primaryType.allSingleValuePropertyDefinitions(propertyName)) { + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; + } + } + + if (checkMultiValuedDefinitions) { + // Look for a multi-value property definition on the primary type that matches by name and type ... + for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + if (setToEmpty) { + if (!definition.isMandatory()) return definition; + // Otherwise this definition doesn't work, so continue with the next ... + continue; + } + assert value != null; + // We can use the definition if it matches the type and satisfies the constraints ... + int type = definition.getRequiredType(); + if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition; + } + if (value != null) { + for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + assert definition.getRequiredType() != PropertyType.UNDEFINED; + if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; + } + } + } + return null; + } } // Look for a single-value property definition on the mixin types that matches by name and type ... @@ -310,6 +357,7 @@ if (mixinType == null) continue; mixinTypes.add(mixinType); for (JcrPropertyDefinition definition : mixinType.allSingleValuePropertyDefinitions(propertyName)) { + matchedOnName = true; // See if the definition allows the value ... if (skipProtected && definition.isProtected()) return null; if (setToEmpty) { @@ -322,31 +370,84 @@ int type = definition.getRequiredType(); if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition; } + if (matchedOnName) { + if (value != null) { + for (JcrPropertyDefinition definition : mixinType.allSingleValuePropertyDefinitions(propertyName)) { + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + assert definition.getRequiredType() != PropertyType.UNDEFINED; + if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; + } + } + + if (checkMultiValuedDefinitions) { + for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) { + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + if (setToEmpty) { + if (!definition.isMandatory()) return definition; + // Otherwise this definition doesn't work, so continue with the next ... + continue; + } + assert value != null; + // We can use the definition if it matches the type and satisfies the constraints ... + int type = definition.getRequiredType(); + if ((type == PropertyType.UNDEFINED || type == value.getType()) + && definition.satisfiesConstraints(value)) return definition; + } + if (value != null) { + for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) { + matchedOnName = true; + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + assert definition.getRequiredType() != PropertyType.UNDEFINED; + if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; + + } + } + } + + return null; + } } } if (checkMultiValuedDefinitions) { // Look for a multi-value property definition on the primary type that matches by name and type ... - if (primaryType != null) { + for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { + matchedOnName = true; + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + if (setToEmpty) { + if (!definition.isMandatory()) return definition; + // Otherwise this definition doesn't work, so continue with the next ... + continue; + } + assert value != null; + // We can use the definition if it matches the type and satisfies the constraints ... + int type = definition.getRequiredType(); + if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition; + } + if (value != null) { for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { + matchedOnName = true; // See if the definition allows the value ... if (skipProtected && definition.isProtected()) return null; - if (setToEmpty) { - if (!definition.isMandatory()) return definition; - // Otherwise this definition doesn't work, so continue with the next ... - continue; - } - assert value != null; - // We can use the definition if it matches the type and satisfies the constraints ... - int type = definition.getRequiredType(); - if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition; + assert definition.getRequiredType() != PropertyType.UNDEFINED; + if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; } } - // Look for a multi-value property definition on the mixin types that matches by name and type ... - if (mixinTypes != null) { - for (JcrNodeType mixinType : mixinTypes) { + if (matchedOnName) return null; + + if (mixinTypeNames != null && !mixinTypeNames.isEmpty()) { + mixinTypes = new LinkedList(); + for (Name mixinTypeName : mixinTypeNames) { + JcrNodeType mixinType = getNodeType(mixinTypeName); + if (mixinType == null) continue; + mixinTypes.add(mixinType); for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) { + matchedOnName = true; // See if the definition allows the value ... if (skipProtected && definition.isProtected()) return null; if (setToEmpty) { @@ -359,59 +460,20 @@ int type = definition.getRequiredType(); if ((type == PropertyType.UNDEFINED || type == value.getType()) && definition.satisfiesConstraints(value)) return definition; } - } - } - } - - if (value != null) { - // Nothing was found with matching name and type, so look for definitions with - // matching name and an undefined or castable type ... - - // Look for a single-value property definition on the primary type that matches by name ... - if (primaryType != null) { - for (JcrPropertyDefinition definition : primaryType.allSingleValuePropertyDefinitions(propertyName)) { - // See if the definition allows the value ... - if (skipProtected && definition.isProtected()) return null; - assert definition.getRequiredType() != PropertyType.UNDEFINED; - if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; - } - } - - // Look for a single-value property definition on the mixin types that matches by name ... - if (mixinTypes != null) { - for (JcrNodeType mixinType : mixinTypes) { - for (JcrPropertyDefinition definition : mixinType.allSingleValuePropertyDefinitions(propertyName)) { - // See if the definition allows the value ... - if (skipProtected && definition.isProtected()) return null; - assert definition.getRequiredType() != PropertyType.UNDEFINED; - if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; - } - } - } - - if (checkMultiValuedDefinitions) { - // Look for a multi-value property definition on the primary type that matches by name ... - if (primaryType != null) { - for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { - // See if the definition allows the value ... - if (skipProtected && definition.isProtected()) return null; - assert definition.getRequiredType() != PropertyType.UNDEFINED; - if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; - } - } - - // Look for a multi-value property definition on the mixin types that matches by name ... - if (mixinTypes != null) { - for (JcrNodeType mixinType : mixinTypes) { + if (value != null) { for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) { + matchedOnName = true; // See if the definition allows the value ... if (skipProtected && definition.isProtected()) return null; assert definition.getRequiredType() != PropertyType.UNDEFINED; if (definition.canCastToTypeAndSatisfyConstraints(value)) return definition; + } } } } + if (matchedOnName) return null; + } // Nothing was found, so look for residual property definitions ... @@ -475,10 +537,21 @@ boolean setToEmpty = values == null || values.length == 0; int propertyType = values == null || values.length == 0 ? PropertyType.STRING : values[0].getType(); + /* + * We use this flag to indicate that there was a definition encountered with the same name. If + * a named definition (or definitions - for example the same node type could define a LONG and BOOLEAN + * version of the same property) is encountered and no match is found for the name, then processing should not + * proceed. If processing did proceed, a residual definition might be found and matched. This would + * lead to a situation where a node defined a type for a named property, but contained a property with + * the same name and the wrong type. + */ + boolean matchedOnName = false; + // Look for a multi-value property definition on the primary type that matches by name and type ... JcrNodeType primaryType = getNodeType(primaryTypeName); if (primaryType != null) { for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { + matchedOnName = true; // See if the definition allows the value ... if (skipProtected && definition.isProtected()) return null; if (setToEmpty) { @@ -492,6 +565,23 @@ int type = definition.getRequiredType(); if ((type == PropertyType.UNDEFINED || type == propertyType) && definition.satisfiesConstraints(values)) return definition; } + + if (matchedOnName) { + if (values != null && values.length != 0) { + // Nothing was found with matching name and type, so look for definitions with + // matching name and an undefined or castable type ... + + // Look for a multi-value property definition on the primary type that matches by name and type ... + for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + assert definition.getRequiredType() != PropertyType.UNDEFINED; + if (definition.canCastToTypeAndSatisfyConstraints(values)) return definition; + } + } + + return null; + } } // Look for a multi-value property definition on the mixin types that matches by name and type ... @@ -503,6 +593,7 @@ if (mixinType == null) continue; mixinTypes.add(mixinType); for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) { + matchedOnName = true; // See if the definition allows the value ... if (skipProtected && definition.isProtected()) return null; if (setToEmpty) { @@ -516,33 +607,23 @@ int type = definition.getRequiredType(); if ((type == PropertyType.UNDEFINED || type == propertyType) && definition.satisfiesConstraints(values)) return definition; } - } - } + if (matchedOnName) { + if (values != null && values.length != 0) { + // Nothing was found with matching name and type, so look for definitions with + // matching name and an undefined or castable type ... - if (values != null && values.length != 0) { - // Nothing was found with matching name and type, so look for definitions with - // matching name and an undefined or castable type ... + // Look for a multi-value property definition on the mixin type that matches by name and type ... + for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) { + // See if the definition allows the value ... + if (skipProtected && definition.isProtected()) return null; + assert definition.getRequiredType() != PropertyType.UNDEFINED; + if (definition.canCastToTypeAndSatisfyConstraints(values)) return definition; + } + } - // Look for a multi-value property definition on the primary type that matches by name and type ... - if (primaryType != null) { - for (JcrPropertyDefinition definition : primaryType.allMultiValuePropertyDefinitions(propertyName)) { - // See if the definition allows the value ... - if (skipProtected && definition.isProtected()) return null; - assert definition.getRequiredType() != PropertyType.UNDEFINED; - if (definition.canCastToTypeAndSatisfyConstraints(values)) return definition; + return null; } - } - // Look for a multi-value property definition on the mixin types that matches by name and type ... - if (mixinTypes != null) { - for (JcrNodeType mixinType : mixinTypes) { - for (JcrPropertyDefinition definition : mixinType.allMultiValuePropertyDefinitions(propertyName)) { - // See if the definition allows the value ... - if (skipProtected && definition.isProtected()) return null; - assert definition.getRequiredType() != PropertyType.UNDEFINED; - if (definition.canCastToTypeAndSatisfyConstraints(values)) return definition; - } - } } } Index: dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java =================================================================== --- dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java (revision 940) +++ dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java (working copy) @@ -43,6 +43,7 @@ import org.apache.jackrabbit.test.api.SerializationTest; import org.apache.jackrabbit.test.api.SessionTest; import org.apache.jackrabbit.test.api.SessionUUIDTest; +import org.apache.jackrabbit.test.api.SetPropertyAssumeTypeTest; import org.apache.jackrabbit.test.api.SetPropertyBooleanTest; import org.apache.jackrabbit.test.api.SetPropertyCalendarTest; import org.apache.jackrabbit.test.api.SetPropertyConstraintViolationExceptionTest; @@ -200,7 +201,7 @@ addTestSuite(SetPropertyStringTest.class); addTestSuite(SetPropertyValueTest.class); addTestSuite(SetPropertyConstraintViolationExceptionTest.class); - // addTestSuite(SetPropertyAssumeTypeTest.class); + addTestSuite(SetPropertyAssumeTypeTest.class); addTestSuite(NodeItemIsModifiedTest.class); addTestSuite(NodeItemIsNewTest.class); Index: dna-jcr/src/test/resources/repositoryStubImpl.properties =================================================================== --- dna-jcr/src/test/resources/repositoryStubImpl.properties (revision 938) +++ dna-jcr/src/test/resources/repositoryStubImpl.properties (working copy) @@ -46,6 +46,8 @@ # For some reason, this test assumes testNodeType doesn't allow children - most other tests assume that it does javax.jcr.tck.SaveTest.nodetype=nt\:query +javax.jcr.tck.SetPropertyAssumeTypeTest.nodetype=dnatest\:setPropertyAssumeTypeTest + # Test users javax.jcr.tck.superuser.name=superuser javax.jcr.tck.superuser.pwd=superuser Index: dna-jcr/src/test/resources/tck_test_types.cnd =================================================================== --- dna-jcr/src/test/resources/tck_test_types.cnd (revision 938) +++ dna-jcr/src/test/resources/tck_test_types.cnd (working copy) @@ -20,4 +20,9 @@ [dnatest:unorderableUnstructured] - * (*) copy - * (*) multiple copy -+ * (nt:base) = dnatest:unorderableUnstructured multiple version \ No newline at end of file ++ * (nt:base) = dnatest:unorderableUnstructured multiple version + +[dnatest:setPropertyAssumeTypeTest] +- prop1 (PATH) copy +- * (*) copy +- * (*) multiple copy