docs: JcrPropertyDefinition findPropertyDefinition( JcrSession session,
                                                    Name primaryTypeName,
                                                    Collection<Name> mixinTypeNames,
                                                    Name propertyName,
                                                    Value[] values,
                                                    boolean skipProtected,
                                                    boolean checkTypeAndConstraints ) {
          boolean setToEmpty = values == null;
          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) {
                      if (!definition.isMandatory()) return definition;
                      // Otherwise this definition doesn't work, so continue with the next ...
                      continue;
                  }
                  assert values != null;
                  // We can use the definition if it matches the type and satisfies the constraints ...
                  int type = definition.getRequiredType();
                  boolean typeMatches = values.length == 0 || type == PropertyType.UNDEFINED || type == propertyType;
                  // Don't check constraints on reference properties
                  if (typeMatches) {
                      if (type == PropertyType.REFERENCE) return definition;
                      if (type == PropertyType.WEAKREFERENCE) return definition;
                      if (type == org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE) return definition;
                      if (!checkTypeAndConstraints) return definition;
                      if (definition.satisfiesConstraints(values, session)) 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;
                          // Don't check constraints on reference properties
                          if (definition.getRequiredType() == PropertyType.REFERENCE && definition.canCastToType(values)) return definition;
                          if (definition.getRequiredType() == PropertyType.WEAKREFERENCE && definition.canCastToType(values)) return definition;
                          if (definition.getRequiredType() == org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE
                              && definition.canCastToType(values)) return definition;
                          if (!checkTypeAndConstraints) return definition;
                          if (definition.canCastToTypeAndSatisfyConstraints(values, session)) return definition;
                      }
                  }
  
                  return null;
              }
          }
  
          // Look for a multi-value property definition on the mixin types that matches by name and type ...
          List<JcrNodeType> mixinTypes = null;
          if (mixinTypeNames != null) {
              mixinTypes = new LinkedList<JcrNodeType>();
              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) {
                          if (!definition.isMandatory()) return definition;
                          // Otherwise this definition doesn't work, so continue with the next ...
                          continue;
                      }
                      assert values != null;
                      // We can use the definition if it matches the type and satisfies the constraints ...
                      int type = definition.getRequiredType();
                      boolean typeMatches = values.length == 0 || type == PropertyType.UNDEFINED || type == propertyType;
                      // Don't check constraints on reference properties
                      if (typeMatches) {
                          if (type == PropertyType.REFERENCE) return definition;
                          if (type == PropertyType.WEAKREFERENCE) return definition;
                          if (type == org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE) return definition;
                          if (!checkTypeAndConstraints) return definition;
                          if (definition.satisfiesConstraints(values, session)) 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 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;
                              // Don't check constraints on reference properties
                              if (definition.getRequiredType() == PropertyType.REFERENCE && definition.canCastToType(values)) return definition;
                              if (definition.getRequiredType() == PropertyType.WEAKREFERENCE && definition.canCastToType(values)) return definition;
                              if (definition.getRequiredType() == org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE
                                  && definition.canCastToType(values)) return definition;
                              if (!checkTypeAndConstraints) return definition;
                              if (definition.canCastToTypeAndSatisfyConstraints(values, session)) return definition;
                          }
                      }
  
                      return null;
                  }
  
              }
          }
  
          // Nothing was found, so look for residual property definitions ...
          if (!propertyName.equals(JcrNodeType.RESIDUAL_NAME)) return findPropertyDefinition(session, primaryTypeName,
                                                                                             mixinTypeNames,
                                                                                             JcrNodeType.RESIDUAL_NAME, values,
                                                                                             skipProtected, checkTypeAndConstraints);
          return null;
      }