code: boolean canRemoveProperty( Name primaryTypeNameOfParent,
                                 List<Name> mixinTypeNamesOfParent,
                                 Name propertyName,
                                 boolean skipProtected ) {
          // First look in the primary type ...
          JcrNodeType primaryType = getNodeType(primaryTypeNameOfParent);
          if (primaryType != null) {
              for (JcrPropertyDefinition definition : primaryType.allPropertyDefinitions(propertyName)) {
                  // Skip protected definitions ...
                  if (skipProtected && definition.isProtected()) continue;
                  // If this definition is not mandatory, then we have found that we CAN remove the property ...
                  return !definition.isMandatory();
              }
          }
  
          // Then, look in the mixin types ...
          if (mixinTypeNamesOfParent != null && !mixinTypeNamesOfParent.isEmpty()) {
              for (Name mixinTypeName : mixinTypeNamesOfParent) {
                  JcrNodeType mixinType = getNodeType(mixinTypeName);
                  if (mixinType == null) continue;
                  for (JcrPropertyDefinition definition : mixinType.allPropertyDefinitions(propertyName)) {
                      // Skip protected definitions ...
                      if (skipProtected && definition.isProtected()) continue;
                      // If this definition is not mandatory, then we have found that we CAN remove the property ...
                      return !definition.isMandatory();
                  }
              }
          }
  
          // Nothing was found, so look for residual node definitions ...
          if (!propertyName.equals(JcrNodeType.RESIDUAL_NAME)) return canRemoveProperty(primaryTypeNameOfParent,
                                                                                        mixinTypeNamesOfParent,
                                                                                        JcrNodeType.RESIDUAL_NAME, skipProtected);
          return false;
      }
docs: Determine if the property definitions of the supplied primary type and mixin types allow the property with the supplied
  name to be removed.
  
  @param primaryTypeNameOfParent the name of the primary type for the parent node; may not be null
  @param mixinTypeNamesOfParent the names of the mixin types for the parent node; may be null or empty if there are no mixins
  to include in the search
  @param propertyName the name of the property to be removed; may not be null
  @param skipProtected true if this operation is being done from within the public JCR node and property API, or false if
  this operation is being done from within internal implementations
  @return true if at least one child node definition does not require children with the supplied name to exist, or false
  otherwise