@Override
  AttributeAccess getAttributeAccess(
      final ListIterator<PathElement> iterator, final String attributeName) {

    if (iterator.hasNext()) {
      final PathElement next = iterator.next();
      final NodeSubregistry subregistry = children.get(next.getKey());
      if (subregistry == null) {
        return null;
      }
      return subregistry.getAttributeAccess(iterator, next.getValue(), attributeName);
    } else {
      final Map<String, AttributeAccess> snapshot = attributesUpdater.get(this);
      AttributeAccess access = snapshot.get(attributeName);
      if (access == null) {
        // If there is metadata for an attribute but no AttributeAccess, assume RO. Can't
        // be writable without a registered handler. This opens the possibility that out-of-date
        // metadata
        // for attribute "foo" can lead to a read of non-existent-in-model "foo" with
        // an unexpected undefined value returned. But it removes the possibility of a
        // dev forgetting to call registry.registerReadOnlyAttribute("foo", null) resulting
        // in the valid attribute "foo" not being readable
        final ModelNode desc = descriptionProvider.getModelDescription(null);
        if (desc.has(ATTRIBUTES) && desc.get(ATTRIBUTES).keys().contains(attributeName)) {
          access =
              new AttributeAccess(AccessType.READ_ONLY, Storage.CONFIGURATION, null, null, null);
        }
      }
      return access;
    }
  }
  @Override
  void getOperationDescriptions(
      final ListIterator<PathElement> iterator,
      final Map<String, OperationEntry> providers,
      final boolean inherited) {

    if (!iterator.hasNext()) {
      checkPermission();
      providers.putAll(operationsUpdater.get(this));
      if (inherited) {
        getInheritedOperations(providers, true);
      }
      return;
    }
    final PathElement next = iterator.next();
    try {
      final String key = next.getKey();
      final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
      final NodeSubregistry subregistry = snapshot.get(key);
      if (subregistry != null) {
        subregistry.getHandlers(iterator, next.getValue(), providers, inherited);
      }
    } finally {
      iterator.previous();
    }
  }
  @Override
  public ManagementResourceRegistration registerOverrideModel(
      String name, OverrideDescriptionProvider descriptionProvider) {
    Assert.checkNotNullParam("name", name);
    Assert.checkNotNullParam("descriptionProvider", descriptionProvider);

    if (parent == null) {
      throw ControllerLogger.ROOT_LOGGER.cannotOverrideRootRegistration();
    }

    if (!PathElement.WILDCARD_VALUE.equals(valueString)) {
      throw ControllerLogger.ROOT_LOGGER.cannotOverrideNonWildCardRegistration(valueString);
    }
    PathElement pe = PathElement.pathElement(parent.getKeyName(), name);

    final SimpleResourceDefinition rd =
        new SimpleResourceDefinition(
            pe,
            new OverrideDescriptionCombiner(
                getModelDescription(PathAddress.EMPTY_ADDRESS), descriptionProvider)) {

          @Override
          public List<AccessConstraintDefinition> getAccessConstraints() {
            return AbstractResourceRegistration.this.getAccessConstraints();
          }
        };
    return parent.getParent().registerSubModel(rd);
  }
 @Override
 public void unregisterProxyController(final PathElement address) throws IllegalArgumentException {
   final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
   final NodeSubregistry subregistry = snapshot.get(address.getKey());
   if (subregistry != null) {
     subregistry.unregisterProxyController(address.getValue());
   }
 }
 @Override
 public void unregisterAlias(PathElement address) {
   final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
   final NodeSubregistry subregistry = snapshot.get(address.getKey());
   if (subregistry != null) {
     subregistry.unregisterAlias(address.getValue());
   }
 }
 public void unregisterSubModel(final PathElement address) throws IllegalArgumentException {
   final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
   final NodeSubregistry subregistry = snapshot.get(address.getKey());
   if (subregistry != null) {
     subregistry.unregisterSubModel(address.getValue());
   }
   unregisterAccessConstraints(address);
 }
 private List<AccessConstraintDefinition> buildAccessConstraints() {
   AbstractResourceRegistration reg = this;
   List<AccessConstraintDefinition> list = new ArrayList<AccessConstraintDefinition>();
   while (reg != null) {
     reg.addAccessConstraints(list);
     NodeSubregistry parent = reg.getParent();
     reg = parent == null ? null : parent.getParent();
   }
   return Collections.unmodifiableList(list);
 }
 @Override
 public void unregisterOverrideModel(String name) {
   Assert.checkNotNullParam("name", name);
   if (PathElement.WILDCARD_VALUE.equals(name)) {
     throw ControllerLogger.ROOT_LOGGER.wildcardRegistrationIsNotAnOverride();
   }
   if (parent == null) {
     throw ControllerLogger.ROOT_LOGGER.rootRegistrationIsNotOverridable();
   }
   PathElement pe = PathElement.pathElement(parent.getKeyName(), name);
   parent.getParent().unregisterSubModel(pe);
 }
 @Override
 DescriptionProvider getModelDescription(final Iterator<PathElement> iterator) {
   if (iterator.hasNext()) {
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return null;
     }
     return subregistry.getModelDescription(iterator, next.getValue());
   } else {
     return descriptionProvider;
   }
 }
 @Override
 ProxyController getProxyController(ListIterator<PathElement> iterator) {
   if (iterator.hasNext()) {
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return null;
     }
     return subregistry.getProxyController(iterator, next.getValue());
   } else {
     return null;
   }
 }
 @Override
 public void registerSubModel(
     final PathElement address, final ManagementResourceRegistration subModel) {
   if (address == null) {
     throw new IllegalArgumentException("address is null");
   }
   if (subModel == null) {
     throw new IllegalArgumentException("subModel is null");
   }
   final String key = address.getKey();
   final NodeSubregistry child = getOrCreateSubregistry(key);
   child.register(address.getValue(), subModel);
 }
 ManagementResourceRegistration getResourceRegistration(Iterator<PathElement> iterator) {
   if (!iterator.hasNext()) {
     return this;
   } else {
     final PathElement address = iterator.next();
     final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
     final NodeSubregistry subregistry = snapshot.get(address.getKey());
     if (subregistry != null) {
       return subregistry.getResourceRegistration(iterator, address.getValue());
     } else {
       return null;
     }
   }
 }
 @Override
 DescriptionProvider getModelDescription(final ListIterator<PathElement> iterator) {
   if (iterator.hasNext()) {
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return null;
     }
     return subregistry.getModelDescription(iterator, next.getValue());
   } else {
     checkPermission();
     return resourceDefinition.getDescriptionProvider(this);
   }
 }
 @Override
 Set<String> getAttributeNames(final Iterator<PathElement> iterator) {
   if (iterator.hasNext()) {
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return Collections.emptySet();
     }
     return subregistry.getAttributeNames(iterator, next.getValue());
   } else {
     final Map<String, AttributeAccess> snapshot = attributesUpdater.get(this);
     return snapshot.keySet();
   }
 }
 AbstractResourceRegistration(final String valueString, final NodeSubregistry parent) {
   checkPermission();
   this.valueString = valueString;
   this.parent = parent;
   this.pathAddress =
       parent == null ? PathAddress.EMPTY_ADDRESS : parent.getPathAddress(valueString);
 }
 @Override
 public ManagementResourceRegistration registerSubModel(
     final PathElement address, final DescriptionProvider descriptionProvider) {
   if (address == null) {
     throw new IllegalArgumentException("address is null");
   }
   if (descriptionProvider == null) {
     throw new IllegalArgumentException("descriptionProvider is null");
   }
   if (runtimeOnly) {
     throw new IllegalStateException(
         "Cannot register non-runtime-only submodels with a runtime-only parent");
   }
   final String key = address.getKey();
   final NodeSubregistry child = getOrCreateSubregistry(key);
   return child.register(address.getValue(), descriptionProvider, false);
 }
 @Override
 Set<String> getChildNames(final Iterator<PathElement> iterator) {
   if (iterator.hasNext()) {
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return Collections.emptySet();
     }
     return subregistry.getChildNames(iterator, next.getValue());
   } else {
     final Map<String, NodeSubregistry> children = this.children;
     if (children != null) {
       return Collections.unmodifiableSet(children.keySet());
     }
     return Collections.emptySet();
   }
 }
 final void getInheritedOperations(final Map<String, OperationEntry> providers, boolean skipSelf) {
   if (!skipSelf) {
     getInheritedOperationEntries(providers);
   }
   if (parent != null) {
     parent.getParent().getInheritedOperations(providers, false);
   }
 }
 @Override
 OperationEntry getOperationEntry(
     final ListIterator<PathElement> iterator,
     final String operationName,
     OperationEntry inherited) {
   if (iterator.hasNext()) {
     OperationEntry ourInherited = getInheritableOperationEntry(operationName);
     OperationEntry inheritance = ourInherited == null ? inherited : ourInherited;
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return null;
     }
     return subregistry.getOperationEntry(iterator, next.getValue(), operationName, inheritance);
   } else {
     final OperationEntry entry = operationsUpdater.get(this, operationName);
     return entry == null ? inherited : entry;
   }
 }
  /** {@inheritDoc} */
  @Override
  public final OperationEntry getOperationEntry(
      final PathAddress pathAddress, final String operationName) {

    if (parent != null) {
      RootInvocation ri = getRootInvocation();
      return ri.root.getOperationEntry(ri.pathAddress.append(pathAddress), operationName);
    }
    // else we are the root

    OperationEntry inheritable = getInheritableOperationEntry(operationName);
    OperationEntry result = getOperationEntry(pathAddress.iterator(), operationName, inheritable);
    NodeSubregistry ancestorSubregistry = parent;
    while (result == null && ancestorSubregistry != null) {
      AbstractResourceRegistration ancestor = ancestorSubregistry.getParent();
      result = ancestor.getInheritableOperationEntry(operationName);
      ancestorSubregistry = ancestor.parent;
    }
    return result;
  }
  @Override
  AttributeAccess getAttributeAccess(
      final ListIterator<PathElement> iterator, final String attributeName) {

    if (iterator.hasNext()) {
      final PathElement next = iterator.next();
      final NodeSubregistry subregistry = children.get(next.getKey());
      if (subregistry == null) {
        return null;
      }
      return subregistry.getAttributeAccess(iterator, next.getValue(), attributeName);
    } else {
      checkPermission();
      final Map<String, AttributeAccess> snapshot = attributesUpdater.get(this);
      AttributeAccess access = snapshot.get(attributeName);
      if (access == null && hasNoAlternativeWildcardRegistration()) {
        // If there is metadata for an attribute but no AttributeAccess, assume RO. Can't
        // be writable without a registered handler. This opens the possibility that out-of-date
        // metadata
        // for attribute "foo" can lead to a read of non-existent-in-model "foo" with
        // an unexpected undefined value returned. But it removes the possibility of a
        // dev forgetting to call registry.registerReadOnlyAttribute("foo", null) resulting
        // in the valid attribute "foo" not being readable
        DescriptionProvider provider = resourceDefinition.getDescriptionProvider(this);
        if (provider instanceof DefaultResourceDescriptionProvider) {
          return null; // attribute was not registered so it does not exist. no need to read
                       // resource description as we wont find anything and cause SO
        }
        // todo get rid of this fallback loop as with code cleanup we wont need it anymore.
        final ModelNode desc =
            resourceDefinition.getDescriptionProvider(this).getModelDescription(null);
        if (desc.has(ATTRIBUTES) && desc.get(ATTRIBUTES).keys().contains(attributeName)) {
          access =
              new AttributeAccess(
                  AccessType.READ_ONLY, Storage.CONFIGURATION, null, null, null, null);
        }
      }
      return access;
    }
  }
  /** {@inheritDoc} */
  @Override
  public final ManagementResourceRegistration getOverrideModel(String name) {

    Assert.checkNotNullParam("name", name);

    if (parent == null) {
      throw ControllerLogger.ROOT_LOGGER.cannotOverrideRootRegistration();
    }

    if (!PathElement.WILDCARD_VALUE.equals(valueString)) {
      throw ControllerLogger.ROOT_LOGGER.cannotOverrideNonWildCardRegistration(valueString);
    }
    PathElement pe = PathElement.pathElement(parent.getKeyName(), name);

    // TODO https://issues.jboss.org/browse/WFLY-2883
    //        ManagementResourceRegistration candidate =
    // parent.getParent().getSubModel(PathAddress.pathAddress(pe));
    //        // We may have gotten back the wildcard reg; detect this by checking for allowing
    // override
    //        return candidate.isAllowsOverride() ? null : candidate;
    return parent.getParent().getSubModel(PathAddress.pathAddress(pe));
  }
 private RootInvocation getRootInvocation() {
   RootInvocation result = null;
   if (parent != null) {
     synchronized (this) {
       if (rootInvocation == null) {
         NodeSubregistry ancestorSubregistry = parent;
         AbstractResourceRegistration ancestorReg = this;
         final List<PathElement> path = new ArrayList<PathElement>();
         while (ancestorSubregistry != null) {
           PathElement pe =
               PathElement.pathElement(ancestorSubregistry.getKeyName(), ancestorReg.valueString);
           path.add(0, pe);
           ancestorReg = ancestorSubregistry.getParent();
           ancestorSubregistry = ancestorReg.parent;
         }
         PathAddress pa = PathAddress.pathAddress(path);
         rootInvocation = new RootInvocation(ancestorReg, pa);
       }
       result = rootInvocation;
     }
   }
   return result;
 }
 @Override
 Set<PathElement> getChildAddresses(final Iterator<PathElement> iterator) {
   if (iterator.hasNext()) {
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return Collections.emptySet();
     }
     return subregistry.getChildAddresses(iterator, next.getValue());
   } else {
     final Map<String, NodeSubregistry> children = this.children;
     if (children != null) {
       final Set<PathElement> elements = new HashSet<PathElement>();
       for (final Map.Entry<String, NodeSubregistry> entry : children.entrySet()) {
         for (final String entryChild : entry.getValue().getChildNames()) {
           elements.add(PathElement.pathElement(entry.getKey(), entryChild));
         }
       }
       return elements;
     }
     return Collections.emptySet();
   }
 }
 @Override
 public ManagementResourceRegistration registerSubModel(
     final ResourceDefinition resourceDefinition) {
   if (resourceDefinition == null) {
     throw ControllerLogger.ROOT_LOGGER.nullVar("resourceDefinition");
   }
   final PathElement address = resourceDefinition.getPathElement();
   if (address == null) {
     throw ControllerLogger.ROOT_LOGGER.cannotRegisterSubmodelWithNullPath();
   }
   if (isRuntimeOnly()) {
     throw ControllerLogger.ROOT_LOGGER.cannotRegisterSubmodel();
   }
   final AbstractResourceRegistration existing =
       getSubRegistration(PathAddress.pathAddress(address));
   if (existing != null && existing.getValueString().equals(address.getValue())) {
     throw ControllerLogger.ROOT_LOGGER.nodeAlreadyRegistered(existing.getLocationString());
   }
   final String key = address.getKey();
   final NodeSubregistry child = getOrCreateSubregistry(key);
   final ManagementResourceRegistration resourceRegistration =
       child.register(address.getValue(), resourceDefinition, false);
   resourceDefinition.registerAttributes(resourceRegistration);
   resourceDefinition.registerOperations(resourceRegistration);
   resourceDefinition.registerChildren(resourceRegistration);
   if (constraintUtilizationRegistry != null
       && resourceDefinition instanceof ConstrainedResourceDefinition) {
     PathAddress childAddress = getPathAddress().append(address);
     List<AccessConstraintDefinition> constraintDefinitions =
         ((ConstrainedResourceDefinition) resourceDefinition).getAccessConstraints();
     for (AccessConstraintDefinition acd : constraintDefinitions) {
       constraintUtilizationRegistry.registerAccessConstraintResourceUtilization(
           acd.getKey(), childAddress);
     }
   }
   return resourceRegistration;
 }
 @Override
 void getProxyControllers(ListIterator<PathElement> iterator, Set<ProxyController> controllers) {
   if (iterator.hasNext()) {
     final PathElement next = iterator.next();
     final NodeSubregistry subregistry = children.get(next.getKey());
     if (subregistry == null) {
       return;
     }
     if (next.isWildcard()) {
       subregistry.getProxyControllers(iterator, null, controllers);
     } else if (next.isMultiTarget()) {
       for (final String value : next.getSegments()) {
         subregistry.getProxyControllers(iterator, value, controllers);
       }
     } else {
       subregistry.getProxyControllers(iterator, next.getValue(), controllers);
     }
   } else {
     final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
     for (NodeSubregistry subregistry : snapshot.values()) {
       subregistry.getProxyControllers(iterator, null, controllers);
     }
   }
 }
 @Override
 public ImmutableManagementResourceRegistration getParent() {
   return parent == null ? null : parent.getParent();
 }
 /** Gets whether this registration has an alternative wildcard registration */
 boolean hasNoAlternativeWildcardRegistration() {
   return parent == null
       || PathElement.WILDCARD_VALUE.equals(valueString)
       || !parent.getChildNames().contains(PathElement.WILDCARD_VALUE);
 }