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