ModeShape/modeshape — pull request #745 by rhauch (2013-03-14 22:18:20+00:00)
Title: MODE-1857 Added support for overriding property definitions

It is now possible to define a node type that overrides a property definition of a supertype, as long as the new definition is as-constrained or more-constrained than that of the supertype.

For example, a property definition in a supertype N might define constraints on a STRING property definition, with enumerated values of "A", "B", "C" and "D". A subtype N' can override this property definition with constraints that are a subset of this (e.g., "A", "C"), ensuring that any node of type N' is also still a valid node of type N. However, not all nodes of type N are valid nodes of type N'.

ModeShape determines which property definitions are "as- or more-constrained than" another property definition using rules that are dependent upon the property type of the definitions. If the property types are the same, the rules are as follows:

- STRING and URI: the constraint literal strings (which are regular expressions) in the overriding definition must also appear exactly as a constraint literal string in the overridden definition.
- LONG, DOUBLE, DECIMAL, DATE: the constraints are ranges, and each of the ranges in the overriding definition must be equal to or wholly contained within one of the ranges in the overridden definition.
- BINARY: the constraints are ranges for the binary value sizes, and each of the size ranges in the overriding definition must be equal to or wholly contained within one of the size ranges in the overridden definition.
- NAME: the constrained names in the overriding definition must be a subset of those found in the overridden definition.
- PATH: the constrained paths (including an optional '*' descendant wildcard) in the overriding definition must either exactly match a path in the overridden definition, or if the optional '*' descendant wildcard is used a path that is below one of the paths in the overridden definition
- REFERENCE: the constrained node type names in the overriding definition must be
a subset of those found in the overridden definition.

If the property types of the overriding and overridden property definitions are different, then a simple string comparison is used to ensure that each of the constraint literal strings of the overriding definition are also constraint literal strings for the overridden definition.

A number of unit tests were added to verify that determining whether a property definition is as- or more-constrained than another property definition. Also, several unit tests were added to check that nodes that used overridden definitions are properly validated.

Note that even when the node type has residual property definitions, if a non-residual property definition applies but is not constrained, the residual property defintiions are **NOT** used. Thus, a property "foo" on a node with a (primary or mixin) node type that has a "foo" property definition will be validated with the "foo" property definition; if the property value does not satisfy the constraints, then a ConstraintViolationException is thrown despite the fact that a residual property definition might theoretically apply. This behavior is indeed compliant with the specification.