private void addNode(ModelNodeInternal child, ModelRegistration registration) {
    ModelPath childPath = child.getPath();
    if (!getPath().isDirectChild(childPath)) {
      throw new IllegalArgumentException(
          String.format(
              "Element registration has a path (%s) which is not a child of this node (%s).",
              childPath, getPath()));
    }

    ModelNodeInternal currentChild = links.get(childPath.getName());
    if (currentChild != null) {
      if (!currentChild.isAtLeast(Created)) {
        throw new DuplicateModelException(
            String.format(
                "Cannot create '%s' using creation rule '%s' as the rule '%s' is already registered to create this model element.",
                childPath,
                describe(registration.getDescriptor()),
                describe(currentChild.getDescriptor())));
      }
      throw new DuplicateModelException(
          String.format(
              "Cannot create '%s' using creation rule '%s' as the rule '%s' has already been used to create this model element.",
              childPath,
              describe(registration.getDescriptor()),
              describe(currentChild.getDescriptor())));
    }
    if (!isMutable()) {
      throw new IllegalStateException(
          String.format(
              "Cannot create '%s' using creation rule '%s' as model element '%s' is no longer mutable.",
              childPath, describe(registration.getDescriptor()), getPath()));
    }
    links.put(child.getPath().getName(), child);
    modelRegistry.registerNode(child, registration.getActions());
  }
 @Override
 public void applyToLink(ModelActionRole type, ModelAction<?> action) {
   if (!getPath().isDirectChild(action.getSubject().getPath())) {
     throw new IllegalArgumentException(
         String.format(
             "Linked element action reference has a path (%s) which is not a child of this node (%s).",
             action.getSubject().getPath(), getPath()));
   }
   modelRegistry.bind(action.getSubject(), type, action, ModelPath.ROOT);
 }
 @Override
 public void ensureAtLeast(State state) {
   modelRegistry.transition(this, state, true);
 }
 @Override
 public void removeLink(String name) {
   if (links.remove(name) != null) {
     modelRegistry.remove(getPath().child(name));
   }
 }
 @Override
 public void applyTo(NodePredicate predicate, Class<? extends RuleSource> rules) {
   modelRegistry.configureMatching(predicate.scope(getPath()), rules);
 }
 @Override
 public void applyTo(NodePredicate predicate, ModelActionRole role, ModelAction<?> action) {
   modelRegistry.configureMatching(predicate.scope(getPath()), role, action);
 }
 @Override
 public void applyToSelf(Class<? extends RuleSource> rules) {
   modelRegistry.configure(rules, getPath());
 }
 @Override
 public void applyToSelf(ModelActionRole role, ModelAction<?> action) {
   DefaultModelRegistry.checkNodePath(this, action);
   modelRegistry.bind(action.getSubject(), role, action, ModelPath.ROOT);
 }