@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();
    }
  }
 ConcreteResourceRegistration(
     final String valueString,
     final NodeSubregistry parent,
     final DescriptionProvider provider,
     final boolean runtimeOnly) {
   super(valueString, parent);
   childrenUpdater.clear(this);
   operationsUpdater.clear(this);
   attributesUpdater.clear(this);
   descriptionProviderUpdater.set(this, provider);
   this.runtimeOnly = runtimeOnly;
 }
 ConcreteResourceRegistration(
     final String valueString,
     final NodeSubregistry parent,
     final ResourceDefinition definition,
     AccessConstraintUtilizationRegistry constraintUtilizationRegistry,
     final boolean runtimeOnly) {
   super(valueString, parent);
   this.constraintUtilizationRegistry = constraintUtilizationRegistry;
   childrenUpdater.clear(this);
   operationsUpdater.clear(this);
   attributesUpdater.clear(this);
   this.resourceDefinition = definition;
   this.runtimeOnly.set(runtimeOnly);
   this.accessConstraintDefinitions = buildAccessConstraints();
 }
 @Override
 public void unregisterOperationHandler(final String operationName) {
   checkPermission();
   if (operationsUpdater.remove(this, operationName) == null) {
     throw operationNotRegisteredException(operationName, resourceDefinition.getPathElement());
   }
 }
  @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 getInheritedOperationEntries(final Map<String, OperationEntry> providers) {
   for (final Map.Entry<String, OperationEntry> entry : operationsUpdater.get(this).entrySet()) {
     if (entry.getValue().isInherited() && !providers.containsKey(entry.getKey())) {
       providers.put(entry.getKey(), entry.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);
 }
 @Override
 OperationEntry getInheritableOperationEntry(final String operationName) {
   final OperationEntry entry = operationsUpdater.get(this, operationName);
   if (entry != null && entry.isInherited()) {
     return entry;
   }
   return null;
 }
 @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());
   }
 }
 NodeSubregistry getOrCreateSubregistry(final String key) {
   for (; ; ) {
     final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
     final NodeSubregistry subregistry = snapshot.get(key);
     if (subregistry != null) {
       return subregistry;
     } else {
       final NodeSubregistry newRegistry = new NodeSubregistry(key, this);
       final NodeSubregistry appearing =
           childrenUpdater.putAtomic(this, key, newRegistry, snapshot);
       if (appearing == null) {
         return newRegistry;
       } else if (appearing != newRegistry) {
         // someone else added one
         return appearing;
       }
       // otherwise, retry the loop because the map changed
     }
   }
 }
 @Override
 public void registerReadOnlyAttribute(
     final String attributeName,
     final OperationStepHandler readHandler,
     AttributeAccess.Storage storage) {
   checkPermission();
   AttributeAccess aa =
       new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, null, null);
   if (attributesUpdater.putIfAbsent(this, attributeName, aa) != null) {
     throw alreadyRegistered("attribute", attributeName);
   }
 }
 @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();
   }
 }
 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
 public void registerOperationHandler(
     final String operationName,
     final OperationStepHandler handler,
     final DescriptionProvider descriptionProvider,
     final boolean inherited,
     EntryType entryType) {
   checkPermission();
   if (operationsUpdater.putIfAbsent(
           this,
           operationName,
           new OperationEntry(handler, descriptionProvider, inherited, entryType))
       != null) {
     throw alreadyRegistered("operation handler", operationName);
   }
 }
 @Override
 public void registerMetric(AttributeDefinition definition, OperationStepHandler metricHandler) {
   checkPermission();
   AttributeAccess aa =
       new AttributeAccess(
           AccessType.METRIC,
           AttributeAccess.Storage.RUNTIME,
           metricHandler,
           null,
           definition,
           definition.getFlags());
   if (attributesUpdater.putIfAbsent(this, definition.getName(), aa) != null) {
     throw alreadyRegistered("attribute", definition.getName());
   }
   registerAttributeAccessConstraints(definition);
 }
 @Override
 public void registerReadOnlyAttribute(
     final AttributeDefinition definition, final OperationStepHandler readHandler) {
   checkPermission();
   final EnumSet<AttributeAccess.Flag> flags = definition.getFlags();
   final String attributeName = definition.getName();
   AttributeAccess.Storage storage =
       (flags != null && flags.contains(AttributeAccess.Flag.STORAGE_RUNTIME))
           ? Storage.RUNTIME
           : Storage.CONFIGURATION;
   AttributeAccess aa =
       new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, definition, flags);
   if (attributesUpdater.putIfAbsent(this, attributeName, aa) != null) {
     throw alreadyRegistered("attribute", attributeName);
   }
   registerAttributeAccessConstraints(definition);
 }
 @Override
 public void registerReadOnlyAttribute(
     final String attributeName,
     final OperationStepHandler readHandler,
     AttributeAccess.Storage storage) {
   if (attributesUpdater.putIfAbsent(
           this,
           attributeName,
           new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, null))
       != null) {
     throw new IllegalArgumentException(
         "An attribute named '"
             + attributeName
             + "' is already registered at location '"
             + getLocationString()
             + "'");
   }
 }
 @Override
 public void registerOperationHandler(
     OperationDefinition definition, OperationStepHandler handler, boolean inherited) {
   checkPermission();
   if (operationsUpdater.putIfAbsent(
           this,
           definition.getName(),
           new OperationEntry(
               handler,
               definition.getDescriptionProvider(),
               inherited,
               definition.getEntryType(),
               definition.getFlags(),
               definition.getAccessConstraints()))
       != null) {
     throw alreadyRegistered("operation handler", definition.getName());
   }
   registerOperationAccessConstraints(definition);
 }
 @Override
 public void registerMetric(
     String attributeName,
     OperationStepHandler metricHandler,
     EnumSet<AttributeAccess.Flag> flags) {
   if (attributesUpdater.putIfAbsent(
           this,
           attributeName,
           new AttributeAccess(
               AccessType.METRIC, AttributeAccess.Storage.RUNTIME, metricHandler, null, flags))
       != null) {
     throw new IllegalArgumentException(
         "An attribute named '"
             + attributeName
             + "' is already registered at location '"
             + getLocationString()
             + "'");
   }
 }
 @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;
   }
 }
 @Override
 public void registerOperationHandler(
     final String operationName,
     final OperationStepHandler handler,
     final DescriptionProvider descriptionProvider,
     final boolean inherited,
     EntryType entryType) {
   if (operationsUpdater.putIfAbsent(
           this,
           operationName,
           new OperationEntry(handler, descriptionProvider, inherited, entryType))
       != null) {
     throw new IllegalArgumentException(
         "A handler named '"
             + operationName
             + "' is already registered at location '"
             + getLocationString()
             + "'");
   }
 }
  @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;
    }
  }
 @Override
 public void registerReadOnlyAttribute(
     final String attributeName,
     final OperationStepHandler readHandler,
     EnumSet<AttributeAccess.Flag> flags) {
   AttributeAccess.Storage storage =
       (flags != null && flags.contains(AttributeAccess.Flag.STORAGE_RUNTIME))
           ? Storage.RUNTIME
           : Storage.CONFIGURATION;
   if (attributesUpdater.putIfAbsent(
           this,
           attributeName,
           new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, null))
       != null) {
     throw new IllegalArgumentException(
         "An attribute named '"
             + attributeName
             + "' is already registered at location '"
             + getLocationString()
             + "'");
   }
 }
 @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);
     }
   }
 }
@SuppressWarnings("deprecation")
final class ConcreteResourceRegistration extends AbstractResourceRegistration {

  @SuppressWarnings("unused")
  private volatile Map<String, NodeSubregistry> children;

  @SuppressWarnings("unused")
  private volatile Map<String, OperationEntry> operations;

  private final ResourceDefinition resourceDefinition;
  private final List<AccessConstraintDefinition> accessConstraintDefinitions;

  @SuppressWarnings("unused")
  private volatile Map<String, AttributeAccess> attributes;

  private final AtomicBoolean runtimeOnly = new AtomicBoolean();
  private final AccessConstraintUtilizationRegistry constraintUtilizationRegistry;

  private static final AtomicMapFieldUpdater<ConcreteResourceRegistration, String, NodeSubregistry>
      childrenUpdater =
          AtomicMapFieldUpdater.newMapUpdater(
              AtomicReferenceFieldUpdater.newUpdater(
                  ConcreteResourceRegistration.class, Map.class, "children"));
  private static final AtomicMapFieldUpdater<ConcreteResourceRegistration, String, OperationEntry>
      operationsUpdater =
          AtomicMapFieldUpdater.newMapUpdater(
              AtomicReferenceFieldUpdater.newUpdater(
                  ConcreteResourceRegistration.class, Map.class, "operations"));
  private static final AtomicMapFieldUpdater<ConcreteResourceRegistration, String, AttributeAccess>
      attributesUpdater =
          AtomicMapFieldUpdater.newMapUpdater(
              AtomicReferenceFieldUpdater.newUpdater(
                  ConcreteResourceRegistration.class, Map.class, "attributes"));

  ConcreteResourceRegistration(
      final String valueString,
      final NodeSubregistry parent,
      final ResourceDefinition definition,
      AccessConstraintUtilizationRegistry constraintUtilizationRegistry,
      final boolean runtimeOnly) {
    super(valueString, parent);
    this.constraintUtilizationRegistry = constraintUtilizationRegistry;
    childrenUpdater.clear(this);
    operationsUpdater.clear(this);
    attributesUpdater.clear(this);
    this.resourceDefinition = definition;
    this.runtimeOnly.set(runtimeOnly);
    this.accessConstraintDefinitions = buildAccessConstraints();
  }

  @Override
  public boolean isRuntimeOnly() {
    checkPermission();
    return runtimeOnly.get();
  }

  @Override
  public void setRuntimeOnly(final boolean runtimeOnly) {
    checkPermission();
    this.runtimeOnly.set(runtimeOnly);
  }

  @Override
  public boolean isRemote() {
    checkPermission();
    return false;
  }

  @Override
  public List<AccessConstraintDefinition> getAccessConstraints() {
    checkPermission();
    return accessConstraintDefinitions;
  }

  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
  void addAccessConstraints(List<AccessConstraintDefinition> list) {
    if (resourceDefinition instanceof ConstrainedResourceDefinition) {
      list.addAll(((ConstrainedResourceDefinition) resourceDefinition).getAccessConstraints());
    }
  }

  @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
  public void registerOperationHandler(
      OperationDefinition definition, OperationStepHandler handler, boolean inherited) {
    checkPermission();
    if (operationsUpdater.putIfAbsent(
            this,
            definition.getName(),
            new OperationEntry(
                handler,
                definition.getDescriptionProvider(),
                inherited,
                definition.getEntryType(),
                definition.getFlags(),
                definition.getAccessConstraints()))
        != null) {
      throw alreadyRegistered("operation handler", definition.getName());
    }
    registerOperationAccessConstraints(definition);
  }

  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);
  }

  @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 {
      checkPermission();
      final OperationEntry entry = operationsUpdater.get(this, operationName);
      return entry == null ? inherited : entry;
    }
  }

  @Override
  OperationEntry getInheritableOperationEntry(final String operationName) {
    checkPermission();
    final OperationEntry entry = operationsUpdater.get(this, operationName);
    if (entry != null && entry.isInherited()) {
      return entry;
    }
    return null;
  }

  @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
  void getInheritedOperationEntries(final Map<String, OperationEntry> providers) {
    checkPermission();
    for (final Map.Entry<String, OperationEntry> entry : operationsUpdater.get(this).entrySet()) {
      if (entry.getValue().isInherited() && !providers.containsKey(entry.getKey())) {
        providers.put(entry.getKey(), entry.getValue());
      }
    }
  }

  @Override
  public void registerOperationHandler(
      final String operationName,
      final OperationStepHandler handler,
      final DescriptionProvider descriptionProvider,
      final boolean inherited,
      EntryType entryType) {
    checkPermission();
    if (operationsUpdater.putIfAbsent(
            this,
            operationName,
            new OperationEntry(handler, descriptionProvider, inherited, entryType))
        != null) {
      throw alreadyRegistered("operation handler", operationName);
    }
  }

  @Override
  public void registerOperationHandler(
      final String operationName,
      final OperationStepHandler handler,
      final DescriptionProvider descriptionProvider,
      final boolean inherited,
      EntryType entryType,
      EnumSet<OperationEntry.Flag> flags) {
    checkPermission();
    if (operationsUpdater.putIfAbsent(
            this,
            operationName,
            new OperationEntry(handler, descriptionProvider, inherited, entryType, flags, null))
        != null) {
      throw alreadyRegistered("operation handler", operationName);
    }
  }

  @Override
  public void unregisterOperationHandler(final String operationName) {
    checkPermission();
    if (operationsUpdater.remove(this, operationName) == null) {
      throw operationNotRegisteredException(operationName, resourceDefinition.getPathElement());
    }
  }

  @Override
  public void registerReadWriteAttribute(
      final AttributeDefinition definition,
      final OperationStepHandler readHandler,
      final OperationStepHandler writeHandler) {
    checkPermission();
    final EnumSet<AttributeAccess.Flag> flags = definition.getFlags();
    final String attributeName = definition.getName();
    AttributeAccess.Storage storage =
        (flags != null && flags.contains(AttributeAccess.Flag.STORAGE_RUNTIME))
            ? Storage.RUNTIME
            : Storage.CONFIGURATION;
    AttributeAccess aa =
        new AttributeAccess(
            AccessType.READ_WRITE, storage, readHandler, writeHandler, definition, flags);
    if (attributesUpdater.putIfAbsent(this, attributeName, aa) != null) {
      throw alreadyRegistered("attribute", attributeName);
    }
    registerAttributeAccessConstraints(definition);
  }

  @Override
  public void registerReadOnlyAttribute(
      final String attributeName,
      final OperationStepHandler readHandler,
      AttributeAccess.Storage storage) {
    checkPermission();
    AttributeAccess aa =
        new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, null, null);
    if (attributesUpdater.putIfAbsent(this, attributeName, aa) != null) {
      throw alreadyRegistered("attribute", attributeName);
    }
  }

  @Override
  public void registerReadOnlyAttribute(
      final AttributeDefinition definition, final OperationStepHandler readHandler) {
    checkPermission();
    final EnumSet<AttributeAccess.Flag> flags = definition.getFlags();
    final String attributeName = definition.getName();
    AttributeAccess.Storage storage =
        (flags != null && flags.contains(AttributeAccess.Flag.STORAGE_RUNTIME))
            ? Storage.RUNTIME
            : Storage.CONFIGURATION;
    AttributeAccess aa =
        new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, definition, flags);
    if (attributesUpdater.putIfAbsent(this, attributeName, aa) != null) {
      throw alreadyRegistered("attribute", attributeName);
    }
    registerAttributeAccessConstraints(definition);
  }

  @Override
  public void unregisterAttribute(String attributeName) {
    checkPermission();
    attributesUpdater.remove(this, attributeName);
  }

  @Override
  public void registerMetric(AttributeDefinition definition, OperationStepHandler metricHandler) {
    checkPermission();
    AttributeAccess aa =
        new AttributeAccess(
            AccessType.METRIC,
            AttributeAccess.Storage.RUNTIME,
            metricHandler,
            null,
            definition,
            definition.getFlags());
    if (attributesUpdater.putIfAbsent(this, definition.getName(), aa) != null) {
      throw alreadyRegistered("attribute", definition.getName());
    }
    registerAttributeAccessConstraints(definition);
  }

  private void registerAttributeAccessConstraints(AttributeDefinition ad) {
    if (constraintUtilizationRegistry != null) {
      for (AccessConstraintDefinition acd : ad.getAccessConstraints()) {
        constraintUtilizationRegistry.registerAccessConstraintAttributeUtilization(
            acd.getKey(), getPathAddress(), ad.getName());
      }
    }
  }

  private void registerOperationAccessConstraints(OperationDefinition od) {
    if (constraintUtilizationRegistry != null) {
      for (AccessConstraintDefinition acd : od.getAccessConstraints()) {
        constraintUtilizationRegistry.registerAccessConstraintOperationUtilization(
            acd.getKey(), getPathAddress(), od.getName());
      }
    }
  }

  private void unregisterAccessConstraints(PathElement childAddress) {
    if (constraintUtilizationRegistry != null) {
      constraintUtilizationRegistry.unregisterAccessConstraintUtilizations(
          getPathAddress().append(childAddress));
    }
  }

  @Override
  public void registerProxyController(final PathElement address, final ProxyController controller)
      throws IllegalArgumentException {
    final AbstractResourceRegistration existing =
        getSubRegistration(PathAddress.pathAddress(address));
    if (existing != null && existing.getValueString().equals(address.getValue())) {
      throw ControllerLogger.ROOT_LOGGER.nodeAlreadyRegistered(existing.getLocationString());
    }
    getOrCreateSubregistry(address.getKey())
        .registerProxyController(address.getValue(), controller);
  }

  @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 registerAlias(
      PathElement address, AliasEntry alias, AbstractResourceRegistration target) {
    getOrCreateSubregistry(address.getKey()).registerAlias(address.getValue(), alias, target);
  }

  @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());
    }
  }

  NodeSubregistry getOrCreateSubregistry(final String key) {
    for (; ; ) {
      final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
      final NodeSubregistry subregistry = snapshot.get(key);
      if (subregistry != null) {
        return subregistry;
      } else {
        checkPermission();
        final NodeSubregistry newRegistry =
            new NodeSubregistry(key, this, constraintUtilizationRegistry);
        final NodeSubregistry appearing =
            childrenUpdater.putAtomic(this, key, newRegistry, snapshot);
        if (appearing == null) {
          return newRegistry;
        } else if (appearing != newRegistry) {
          // someone else added one
          return appearing;
        }
        // otherwise, retry the loop because the map changed
      }
    }
  }

  @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 ListIterator<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 {
      checkPermission();
      final Map<String, AttributeAccess> snapshot = attributesUpdater.get(this);
      return snapshot.keySet();
    }
  }

  @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;
    }
  }

  @Override
  Set<String> getChildNames(final ListIterator<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 {
      checkPermission();
      final Map<String, NodeSubregistry> children = this.children;
      if (children != null) {
        return Collections.unmodifiableSet(children.keySet());
      }
      return Collections.emptySet();
    }
  }

  @Override
  Set<PathElement> getChildAddresses(final ListIterator<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 {
      checkPermission();
      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
  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
  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
  AbstractResourceRegistration getResourceRegistration(ListIterator<PathElement> iterator) {
    if (!iterator.hasNext()) {
      checkPermission();
      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;
      }
    }
  }

  private IllegalArgumentException alreadyRegistered(final String type, final String name) {
    return ControllerLogger.ROOT_LOGGER.alreadyRegistered(type, name, getLocationString());
  }

  private IllegalArgumentException operationNotRegisteredException(String op, PathElement address) {
    return ControllerLogger.ROOT_LOGGER.operationNotRegisteredException(
        op, PathAddress.pathAddress(address));
  }

  @Override
  public AliasEntry getAliasEntry() {
    checkPermission();
    return null;
  }
}
final class ConcreteResourceRegistration extends AbstractResourceRegistration {

  @SuppressWarnings("unused")
  private volatile Map<String, NodeSubregistry> children;

  @SuppressWarnings("unused")
  private volatile Map<String, OperationEntry> operations;

  @SuppressWarnings("unused")
  private volatile DescriptionProvider descriptionProvider;

  @SuppressWarnings("unused")
  private volatile Map<String, AttributeAccess> attributes;

  private final boolean runtimeOnly;

  private static final AtomicMapFieldUpdater<ConcreteResourceRegistration, String, NodeSubregistry>
      childrenUpdater =
          AtomicMapFieldUpdater.newMapUpdater(
              AtomicReferenceFieldUpdater.newUpdater(
                  ConcreteResourceRegistration.class, Map.class, "children"));
  private static final AtomicMapFieldUpdater<ConcreteResourceRegistration, String, OperationEntry>
      operationsUpdater =
          AtomicMapFieldUpdater.newMapUpdater(
              AtomicReferenceFieldUpdater.newUpdater(
                  ConcreteResourceRegistration.class, Map.class, "operations"));
  private static final AtomicMapFieldUpdater<ConcreteResourceRegistration, String, AttributeAccess>
      attributesUpdater =
          AtomicMapFieldUpdater.newMapUpdater(
              AtomicReferenceFieldUpdater.newUpdater(
                  ConcreteResourceRegistration.class, Map.class, "attributes"));
  private static final AtomicReferenceFieldUpdater<
          ConcreteResourceRegistration, DescriptionProvider>
      descriptionProviderUpdater =
          AtomicReferenceFieldUpdater.newUpdater(
              ConcreteResourceRegistration.class, DescriptionProvider.class, "descriptionProvider");

  ConcreteResourceRegistration(
      final String valueString,
      final NodeSubregistry parent,
      final DescriptionProvider provider,
      final boolean runtimeOnly) {
    super(valueString, parent);
    childrenUpdater.clear(this);
    operationsUpdater.clear(this);
    attributesUpdater.clear(this);
    descriptionProviderUpdater.set(this, provider);
    this.runtimeOnly = runtimeOnly;
  }

  @Override
  public boolean isRuntimeOnly() {
    return runtimeOnly;
  }

  @Override
  public boolean isRemote() {
    return false;
  }

  @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
  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);
  }

  @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;
    }
  }

  @Override
  OperationEntry getInheritableOperationEntry(final String operationName) {
    final OperationEntry entry = operationsUpdater.get(this, operationName);
    if (entry != null && entry.isInherited()) {
      return entry;
    }
    return null;
  }

  @Override
  void getOperationDescriptions(
      final ListIterator<PathElement> iterator,
      final Map<String, OperationEntry> providers,
      final boolean inherited) {

    if (!iterator.hasNext()) {
      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
  void getInheritedOperationEntries(final Map<String, OperationEntry> providers) {
    for (final Map.Entry<String, OperationEntry> entry : operationsUpdater.get(this).entrySet()) {
      if (entry.getValue().isInherited() && !providers.containsKey(entry.getKey())) {
        providers.put(entry.getKey(), entry.getValue());
      }
    }
  }

  @Override
  public void registerOperationHandler(
      final String operationName,
      final OperationStepHandler handler,
      final DescriptionProvider descriptionProvider,
      final boolean inherited,
      EntryType entryType) {
    if (operationsUpdater.putIfAbsent(
            this,
            operationName,
            new OperationEntry(handler, descriptionProvider, inherited, entryType))
        != null) {
      throw new IllegalArgumentException(
          "A handler named '"
              + operationName
              + "' is already registered at location '"
              + getLocationString()
              + "'");
    }
  }

  @Override
  public void registerOperationHandler(
      final String operationName,
      final OperationStepHandler handler,
      final DescriptionProvider descriptionProvider,
      final boolean inherited,
      EntryType entryType,
      EnumSet<OperationEntry.Flag> flags) {
    if (operationsUpdater.putIfAbsent(
            this,
            operationName,
            new OperationEntry(handler, descriptionProvider, inherited, entryType, flags))
        != null) {
      throw new IllegalArgumentException(
          "A handler named '"
              + operationName
              + "' is already registered at location '"
              + getLocationString()
              + "'");
    }
  }

  @Override
  public void registerReadWriteAttribute(
      final String attributeName,
      final OperationStepHandler readHandler,
      final OperationStepHandler writeHandler,
      AttributeAccess.Storage storage) {
    if (attributesUpdater.putIfAbsent(
            this,
            attributeName,
            new AttributeAccess(AccessType.READ_WRITE, storage, readHandler, writeHandler, null))
        != null) {
      throw new IllegalArgumentException(
          "An attribute named '"
              + attributeName
              + "' is already registered at location '"
              + getLocationString()
              + "'");
    }
  }

  @Override
  public void registerReadWriteAttribute(
      final String attributeName,
      final OperationStepHandler readHandler,
      final OperationStepHandler writeHandler,
      EnumSet<AttributeAccess.Flag> flags) {
    AttributeAccess.Storage storage =
        (flags != null && flags.contains(AttributeAccess.Flag.STORAGE_RUNTIME))
            ? Storage.RUNTIME
            : Storage.CONFIGURATION;
    if (attributesUpdater.putIfAbsent(
            this,
            attributeName,
            new AttributeAccess(AccessType.READ_WRITE, storage, readHandler, writeHandler, flags))
        != null) {
      throw new IllegalArgumentException(
          "An attribute named '"
              + attributeName
              + "' is already registered at location '"
              + getLocationString()
              + "'");
    }
  }

  @Override
  public void registerReadOnlyAttribute(
      final String attributeName,
      final OperationStepHandler readHandler,
      AttributeAccess.Storage storage) {
    if (attributesUpdater.putIfAbsent(
            this,
            attributeName,
            new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, null))
        != null) {
      throw new IllegalArgumentException(
          "An attribute named '"
              + attributeName
              + "' is already registered at location '"
              + getLocationString()
              + "'");
    }
  }

  @Override
  public void registerReadOnlyAttribute(
      final String attributeName,
      final OperationStepHandler readHandler,
      EnumSet<AttributeAccess.Flag> flags) {
    AttributeAccess.Storage storage =
        (flags != null && flags.contains(AttributeAccess.Flag.STORAGE_RUNTIME))
            ? Storage.RUNTIME
            : Storage.CONFIGURATION;
    if (attributesUpdater.putIfAbsent(
            this,
            attributeName,
            new AttributeAccess(AccessType.READ_ONLY, storage, readHandler, null, null))
        != null) {
      throw new IllegalArgumentException(
          "An attribute named '"
              + attributeName
              + "' is already registered at location '"
              + getLocationString()
              + "'");
    }
  }

  @Override
  public void registerMetric(String attributeName, OperationStepHandler metricHandler) {
    registerMetric(attributeName, metricHandler, null);
  }

  @Override
  public void registerMetric(
      String attributeName,
      OperationStepHandler metricHandler,
      EnumSet<AttributeAccess.Flag> flags) {
    if (attributesUpdater.putIfAbsent(
            this,
            attributeName,
            new AttributeAccess(
                AccessType.METRIC, AttributeAccess.Storage.RUNTIME, metricHandler, null, flags))
        != null) {
      throw new IllegalArgumentException(
          "An attribute named '"
              + attributeName
              + "' is already registered at location '"
              + getLocationString()
              + "'");
    }
  }

  @Override
  public void registerProxyController(final PathElement address, final ProxyController controller)
      throws IllegalArgumentException {
    getOrCreateSubregistry(address.getKey())
        .registerProxyController(address.getValue(), controller);
  }

  @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());
    }
  }

  NodeSubregistry getOrCreateSubregistry(final String key) {
    for (; ; ) {
      final Map<String, NodeSubregistry> snapshot = childrenUpdater.get(this);
      final NodeSubregistry subregistry = snapshot.get(key);
      if (subregistry != null) {
        return subregistry;
      } else {
        final NodeSubregistry newRegistry = new NodeSubregistry(key, this);
        final NodeSubregistry appearing =
            childrenUpdater.putAtomic(this, key, newRegistry, snapshot);
        if (appearing == null) {
          return newRegistry;
        } else if (appearing != newRegistry) {
          // someone else added one
          return appearing;
        }
        // otherwise, retry the loop because the map changed
      }
    }
  }

  @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
  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();
    }
  }

  @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
  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();
    }
  }

  @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
  ProxyController getProxyController(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.getProxyController(iterator, next.getValue());
    } else {
      return null;
    }
  }

  @Override
  void getProxyControllers(Iterator<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);
      }
    }
  }

  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
 public void unregisterAttribute(String attributeName) {
   checkPermission();
   attributesUpdater.remove(this, attributeName);
 }