/* * JBoss, Home of Professional Open Source. * Copyright 2011, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.controller.registry; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.jboss.as.controller.CapabilityRegistry; import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.PathElement; import org.jboss.as.controller.ProxyController; import org.jboss.as.controller.ResourceDefinition; import org.jboss.as.controller.access.management.AccessConstraintDefinition; import org.jboss.as.controller.access.management.AccessConstraintUtilizationRegistry; import org.jboss.as.controller.capability.Capability; import org.jboss.as.controller.capability.RuntimeCapability; import org.jboss.as.controller.descriptions.DescriptionProvider; import org.jboss.as.controller.logging.ControllerLogger; /** * A registry of values within a specific key type. */ final class NodeSubregistry { private static void checkPermission() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(ImmutableManagementResourceRegistration.ACCESS_PERMISSION); } } private static final ListIterator<PathElement> EMPTY_ITERATOR = PathAddress.EMPTY_ADDRESS.iterator(); private static final String WILDCARD_VALUE = PathElement.WILDCARD_VALUE; private final String keyName; private final ConcreteResourceRegistration parent; private final AccessConstraintUtilizationRegistry constraintUtilizationRegistry; private final CapabilityRegistry capabilityRegistry; @SuppressWarnings( { "unused" }) private volatile Map<String, AbstractResourceRegistration> childRegistries; private static final AtomicMapFieldUpdater<NodeSubregistry, String, AbstractResourceRegistration> childRegistriesUpdater = AtomicMapFieldUpdater.newMapUpdater(AtomicReferenceFieldUpdater.newUpdater(NodeSubregistry.class, Map.class, "childRegistries")); NodeSubregistry(final String keyName, final ConcreteResourceRegistration parent, AccessConstraintUtilizationRegistry constraintUtilizationRegistry, CapabilityRegistry capabilityRegistry) { this.keyName = keyName; this.parent = parent; this.constraintUtilizationRegistry = constraintUtilizationRegistry; this.capabilityRegistry = capabilityRegistry; childRegistriesUpdater.clear(this); } AbstractResourceRegistration getParent() { return parent; } Set<String> getChildNames(){ final Map<String, AbstractResourceRegistration> snapshot = this.childRegistries; if (snapshot == null) { return Collections.emptySet(); } return new HashSet<String>(snapshot.keySet()); } ManagementResourceRegistration registerChild(final String elementValue, final ResourceDefinition provider) { boolean ordered = provider.isOrderedChild(); final ConcreteResourceRegistration newRegistry = new ConcreteResourceRegistration(elementValue, this, provider, constraintUtilizationRegistry, ordered, capabilityRegistry, parent.processType); newRegistry.beginInitialization(); try { final AbstractResourceRegistration existingRegistry = childRegistriesUpdater.putIfAbsent(this, elementValue, newRegistry); if (existingRegistry != null) { throw ControllerLogger.ROOT_LOGGER.nodeAlreadyRegistered(getLocationString(elementValue)); } provider.registerAttributes(newRegistry); provider.registerOperations(newRegistry); provider.registerNotifications(newRegistry); provider.registerChildren(newRegistry); provider.registerCapabilities(newRegistry); if (constraintUtilizationRegistry != null) { PathAddress childAddress = newRegistry.getPathAddress(); List<AccessConstraintDefinition> constraintDefinitions = provider.getAccessConstraints(); for (AccessConstraintDefinition acd : constraintDefinitions) { constraintUtilizationRegistry.registerAccessConstraintResourceUtilization(acd.getKey(), childAddress); } } } finally { newRegistry.initialized(); } if (ordered) { AbstractResourceRegistration parentRegistration = getParent(); parentRegistration.setOrderedChild(keyName); } return newRegistry; } ProxyControllerRegistration registerProxyController(final String elementValue, final ProxyController proxyController) { final ProxyControllerRegistration newRegistry = new ProxyControllerRegistration(elementValue, this, proxyController); final AbstractResourceRegistration appearingRegistry = childRegistriesUpdater.putIfAbsent(this, elementValue, newRegistry); if (appearingRegistry != null) { throw ControllerLogger.ROOT_LOGGER.nodeAlreadyRegistered(getLocationString(elementValue)); } //register(elementValue, newRegistry); return newRegistry; } void unregisterProxyController(final String elementValue) { checkPermission(); childRegistriesUpdater.remove(this, elementValue); } public AliasResourceRegistration registerAlias(final String elementValue, AliasEntry aliasEntry, AbstractResourceRegistration target) { final AliasResourceRegistration newRegistry = new AliasResourceRegistration(elementValue, this, aliasEntry, target); final AbstractResourceRegistration existingRegistry = childRegistriesUpdater.putIfAbsent(this, elementValue, newRegistry); if (existingRegistry != null) { throw ControllerLogger.ROOT_LOGGER.nodeAlreadyRegistered(getLocationString(elementValue)); } return newRegistry; } public void unregisterAlias(final String elementValue) { checkPermission(); childRegistriesUpdater.remove(this, elementValue); } void unregisterSubModel(final String elementValue) { checkPermission(); AbstractResourceRegistration rr = childRegistriesUpdater.remove(this, elementValue); if (rr != null) { // We want to remove the possible capabilities. // We've removed the MRR so the normal getCapabilities() won't work as it // relies on walking the tree from the root. So we just use the local call // with a iterator whose hasNext() returns false PathAddress pa = getPathAddress(elementValue); for (Capability c : rr.getCapabilities(EMPTY_ITERATOR)) { capabilityRegistry.removePossibleCapability(c, pa); } } } OperationEntry getOperationEntry(final ListIterator<PathElement> iterator, final String child, final String operationName, OperationEntry inherited) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the non-wildcard child; if not found, search the wildcard child OperationEntry result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getOperationEntry(searchControl.getIterator(), operationName, inherited); } if (result == null && searchControl.getWildCardRegistry() != null) { result = searchControl.getWildCardRegistry().getOperationEntry(searchControl.getIterator(), operationName, inherited); } // If there is no concrete registry and wildcard query if (result == null && child.equals("*")) { return inherited; } return result; } void getHandlers(final ListIterator<PathElement> iterator, final String child, final Map<String, OperationEntry> providers, final boolean inherited) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the wildcard child, then if there is a non-wildcard child search it // Non-wildcard goes second so its description overwrites in case of duplicates if (searchControl.getWildCardRegistry() != null) { searchControl.getWildCardRegistry().getOperationDescriptions(searchControl.getIterator(), providers, inherited); } if (searchControl.getSpecifiedRegistry() != null) { searchControl.getSpecifiedRegistry().getOperationDescriptions(searchControl.getIterator(), providers, inherited); } } void getNotificationDescriptions(final ListIterator<PathElement> iterator, final String child, final Map<String, NotificationEntry> providers, final boolean inherited) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the wildcard child, then if there is a non-wildcard child search it // Non-wildcard goes second so its description overwrites in case of duplicates if (searchControl.getWildCardRegistry() != null) { searchControl.getWildCardRegistry().getNotificationDescriptions(searchControl.getIterator(), providers, inherited); } if (searchControl.getSpecifiedRegistry() != null) { searchControl.getSpecifiedRegistry().getNotificationDescriptions(searchControl.getIterator(), providers, inherited); } } private String getLocationString(String value) { return parent.getPathAddress().append(keyName, value).toCLIStyleString(); } DescriptionProvider getModelDescription(final ListIterator<PathElement> iterator, final String child) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the non-wildcard child; if not found, search the wildcard child DescriptionProvider result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getModelDescription(searchControl.getIterator()); } if (result == null && searchControl.getWildCardRegistry() != null) { result = searchControl.getWildCardRegistry().getModelDescription(searchControl.getIterator()); } return result; } Set<String> getChildNames(final ListIterator<PathElement> iterator, final String child){ final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); Set<String> result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getChildNames(searchControl.getIterator()); } if (searchControl.getWildCardRegistry() != null) { final Set<String> wildCardChildren = searchControl.getWildCardRegistry().getChildNames(searchControl.getIterator()); if (result == null) { result = wildCardChildren; } else if (wildCardChildren != null) { // Merge result = new HashSet<String>(result); result.addAll(wildCardChildren); } } return result; } Set<String> getAttributeNames(final ListIterator<PathElement> iterator, final String child){ final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); Set<String> result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getAttributeNames(searchControl.getIterator()); } if (searchControl.getWildCardRegistry() != null) { final Set<String> wildCardChildren = searchControl.getWildCardRegistry().getAttributeNames(searchControl.getIterator()); if (result == null) { result = wildCardChildren; } else if (wildCardChildren != null) { // Merge result = new HashSet<String>(result); result.addAll(wildCardChildren); } } return result; } AttributeAccess getAttributeAccess(final ListIterator<PathElement> iterator, final String child, final String attributeName) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the non-wildcard child; if not found, search the wildcard child AttributeAccess result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getAttributeAccess(searchControl.getIterator(), attributeName); } if (result == null && searchControl.getWildCardRegistry() != null) { result = searchControl.getWildCardRegistry().getAttributeAccess(searchControl.getIterator(), attributeName); } return result; } Set<PathElement> getChildAddresses(final ListIterator<PathElement> iterator, final String child){ final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); Set<PathElement> result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getChildAddresses(searchControl.getIterator()); } if (searchControl.getWildCardRegistry() != null) { final Set<PathElement> wildCardChildren = searchControl.getWildCardRegistry().getChildAddresses(searchControl.getIterator()); if (result == null) { result = wildCardChildren; } else if (wildCardChildren != null) { // Merge result = new HashSet<PathElement>(result); result.addAll(wildCardChildren); } } return result; } ProxyController getProxyController(final ListIterator<PathElement> iterator, final String child) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the non-wildcard child; if not found, search the wildcard child ProxyController result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getProxyController(searchControl.getIterator()); } if (result == null && searchControl.getWildCardRegistry() != null) { result = searchControl.getWildCardRegistry().getProxyController(searchControl.getIterator()); } return result; } ManagementResourceRegistration getResourceRegistration(final ListIterator<PathElement> iterator, final String child) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the non-wildcard child; if not found, search the wildcard child ManagementResourceRegistration result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getResourceRegistration(searchControl.getIterator()); } if (result == null && searchControl.getWildCardRegistry() != null) { result = searchControl.getWildCardRegistry().getResourceRegistration(searchControl.getIterator()); } return result; } void getProxyControllers(final ListIterator<PathElement> iterator, final String child, Set<ProxyController> controllers) { if (child != null) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); // First search the wildcard child, then if there is a non-wildcard child search it if (searchControl.getWildCardRegistry() != null) { searchControl.getWildCardRegistry().getProxyControllers(searchControl.getIterator(), controllers); } if (searchControl.getSpecifiedRegistry() != null) { searchControl.getSpecifiedRegistry().getProxyControllers(searchControl.getIterator(), controllers); } } else { final Map<String, AbstractResourceRegistration> snapshot = childRegistriesUpdater.get(NodeSubregistry.this); for (AbstractResourceRegistration childRegistry : snapshot.values()) { childRegistry.getProxyControllers(iterator, controllers); } } } PathAddress getPathAddress(String valueString) { return parent.getPathAddress().append(PathElement.pathElement(keyName, valueString)); } Set<RuntimeCapability> getCapabilities(ListIterator<PathElement> iterator, String child) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); Set<RuntimeCapability> result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getCapabilities(searchControl.getIterator()); } if (searchControl.getWildCardRegistry() != null) { final Set<RuntimeCapability> wildCardChildren = searchControl.getWildCardRegistry().getCapabilities(searchControl.getIterator()); if (result == null) { result = wildCardChildren; } else if (wildCardChildren != null) { // Merge result = new HashSet<RuntimeCapability>(result); result.addAll(wildCardChildren); } } return result; } Set<RuntimeCapability> getIncorporatingCapabilities(ListIterator<PathElement> iterator, String child) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); Set<RuntimeCapability> result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getIncorporatingCapabilities(searchControl.getIterator()); } if (searchControl.getWildCardRegistry() != null) { final Set<RuntimeCapability> wildCardChildren = searchControl.getWildCardRegistry().getIncorporatingCapabilities(searchControl.getIterator()); if (result == null) { result = wildCardChildren; } else if (wildCardChildren != null) { // Merge result = new HashSet<RuntimeCapability>(result); result.addAll(wildCardChildren); } } return result; } Set<String> getOrderedChildTypes(ListIterator<PathElement> iterator, String child) { final RegistrySearchControl searchControl = new RegistrySearchControl(iterator, child); Set<String> result = null; if (searchControl.getSpecifiedRegistry() != null) { result = searchControl.getSpecifiedRegistry().getOrderedChildTypes(searchControl.getIterator()); } if (searchControl.getWildCardRegistry() != null) { final Set<String> wildCardChildren = searchControl.getWildCardRegistry().getOrderedChildTypes(searchControl.getIterator()); if (result == null) { result = wildCardChildren; } else if (wildCardChildren != null) { // Merge result = new HashSet<String>(result); result.addAll(wildCardChildren); } } return result; } /** * Encapsulates data and behavior to help with searches in both a specified child and in the wildcard child if * it exists and is different from the specified child */ private class RegistrySearchControl { private final AbstractResourceRegistration specifiedRegistry; private final AbstractResourceRegistration wildCardRegistry; private final ListIterator<PathElement> iterator; private final int restoreIndex; private boolean backupRequired; private RegistrySearchControl(final ListIterator<PathElement> iterator, final String childName) { final Map<String, AbstractResourceRegistration> snapshot = childRegistriesUpdater.get(NodeSubregistry.this); this.specifiedRegistry = snapshot.get(childName); this.wildCardRegistry = WILDCARD_VALUE.equals(childName) ? null : snapshot.get(WILDCARD_VALUE); this.iterator = iterator; this.restoreIndex = (specifiedRegistry != null && wildCardRegistry != null) ? iterator.nextIndex() : -1; } private AbstractResourceRegistration getSpecifiedRegistry() { return specifiedRegistry; } private AbstractResourceRegistration getWildCardRegistry() { return wildCardRegistry; } private ListIterator<PathElement> getIterator() { if (backupRequired) { if (restoreIndex == -1) { // Coding mistake; someone wants to search twice for no reason, since we only have a single registration throw new IllegalStateException("Multiple iterator requests are not supported since both " + "named and wildcard entries were not present"); } // Back the iterator to the restore index while (iterator.nextIndex() > restoreIndex) { iterator.previous(); } } backupRequired = true; return iterator; } } String getKeyName() { return keyName; } }