/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, 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;
import java.util.Set;
import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
/**
* Records information about capability reference information encoded in an attribute's value.
*
* @author Brian Stansberry (c) 2015 Red Hat Inc.
*/
public interface CapabilityReferenceRecorder {
/**
* Registers capability requirement information to the given context.
* @param context the context
* @param attributeName the name of the attribute
* @param attributeValues the values of the attribute, which may contain null
*/
void addCapabilityRequirements(OperationContext context, String attributeName, String... attributeValues);
/**
* Deregisters capability requirement information from the given context.
* @param context the context
* @param attributeName the name of the attribute
* @param attributeValues the values of the attribute, which may contain null
*/
void removeCapabilityRequirements(OperationContext context, String attributeName, String... attributeValues);
/**
* @return base name of dependant, usually name of the attribute that provides reference to capability
*
* @deprecated No longer required and may throw {@link java.lang.UnsupportedOperationException}
*/
@Deprecated
String getBaseDependentName();
/**
*
* @return requirement name of the capability this reference depends on
*/
String getBaseRequirementName();
/**
*
* @return tells is reference is dynamic or static, in case where it is dynamic it uses base name + name of
* dependent attribute to construct name of capability
*
* @deprecated No longer required and may throw {@link java.lang.UnsupportedOperationException}
*/
@Deprecated
boolean isDynamicDependent();
/**
* Default implementation of {@link org.jboss.as.controller.CapabilityReferenceRecorder}.
* Derives the required capability name from the {@code baseRequirementName} provided to the constructor and from
* the attribute value. Derives the dependent capability name from the {@code baseDependentName} provided to the
* constructor, and, if the dependent name is dynamic, from the address of the resource currently being processed.
*/
class DefaultCapabilityReferenceRecorder implements CapabilityReferenceRecorder {
private final String baseRequirementName;
private final String baseDependentName;
private final boolean dynamicDependent;
public DefaultCapabilityReferenceRecorder(String baseRequirementName, String baseDependentName, boolean dynamicDependent) {
this.baseRequirementName = baseRequirementName;
this.baseDependentName = baseDependentName;
this.dynamicDependent = dynamicDependent;
}
@Override
public final void addCapabilityRequirements(OperationContext context, String attributeName, String... attributeValues) {
processCapabilityRequirement(context, attributeName, false, attributeValues);
}
@Override
public final void removeCapabilityRequirements(OperationContext context, String attributeName, String... attributeValues) {
processCapabilityRequirement(context, attributeName, true, attributeValues);
}
private void processCapabilityRequirement(OperationContext context, String attributeName, boolean remove, String... attributeValues) {
String dependentName;
if (dynamicDependent) {
dependentName = RuntimeCapability.buildDynamicCapabilityName(baseDependentName, getDynamicDependentName(context.getCurrentAddress()));
} else {
dependentName = baseDependentName;
}
for (String attributeValue : attributeValues) {
// This implementation does not handle null attribute values
if (attributeValue != null) {
String requirementName = RuntimeCapability.buildDynamicCapabilityName(baseRequirementName, attributeValue);
if (remove) {
context.deregisterCapabilityRequirement(requirementName, dependentName);
} else {
context.registerAdditionalCapabilityRequirement(requirementName, dependentName, attributeName);
}
}
}
}
/**
* Determines the dynamic portion of the dependent capability's name. Only invoked if {@code dynamicDependent}
* is set to {@code true} in the constructor.
* <p>
* This base implementation returns the value of the last element in {@code currentAddress}. Subclasses that
* wish to extract the relevant name from some other element in the address may override this.
* </p>
* @param currentAddress the address of the resource currently being processed. Will not be {@code null}
* @return the dynamic portion of the dependenty capability name. Cannot be {@code null}
*/
protected String getDynamicDependentName(PathAddress currentAddress) {
return currentAddress.getLastElement().getValue();
}
@Override
public String getBaseDependentName() {
return baseDependentName;
}
@Override
public String getBaseRequirementName() {
return baseRequirementName;
}
@Override
public boolean isDynamicDependent() {
return dynamicDependent;
}
}
/**
* {@link CapabilityReferenceRecorder} that determines the dependent capability from
* the {@link OperationContext}. This assumes that the
* {@link OperationContext#getResourceRegistration() resource registration associated with currently executing step}
* will expose a {@link ImmutableManagementResourceRegistration#getCapabilities() capability set} including
* one and only one capability. <strong>This recorder cannot be used with attributes associated with resources
* that do not meet this requirement.</strong>
*/
class ContextDependencyRecorder implements CapabilityReferenceRecorder {
private final String baseRequirementName;
public ContextDependencyRecorder(String baseRequirementName) {
this.baseRequirementName = baseRequirementName;
}
/**
* {@inheritDoc}
*
* @throws AssertionError if the requirements discussed in the class javadoc are not fulfilled
*/
@Override
public final void addCapabilityRequirements(OperationContext context, String attributeName, String... attributeValues) {
processCapabilityRequirement(context, attributeName, false, attributeValues);
}
/**
* {@inheritDoc}
*
* @throws AssertionError if the requirements discussed in the class javadoc are not fulfilled
*/
@Override
public final void removeCapabilityRequirements(OperationContext context, String attributeName, String... attributeValues) {
processCapabilityRequirement(context, attributeName, true, attributeValues);
}
private void processCapabilityRequirement(OperationContext context, String attributeName, boolean remove, String... attributeValues) {
String dependentName = getDependentName(context);
for (String attributeValue : attributeValues) {
String requirementName = RuntimeCapability.buildDynamicCapabilityName(baseRequirementName, attributeValue);
if (remove) {
context.deregisterCapabilityRequirement(requirementName, dependentName);
} else {
context.registerAdditionalCapabilityRequirement(requirementName, dependentName, attributeName);
}
}
}
private String getDependentName(OperationContext context) {
ImmutableManagementResourceRegistration mrr = context.getResourceRegistration();
Set<RuntimeCapability> capabilities = mrr.getCapabilities();
assert capabilities != null && capabilities.size() == 1;
RuntimeCapability cap = capabilities.iterator().next();
if (cap.isDynamicallyNamed()) {
return cap.getDynamicName(context.getCurrentAddressValue());
} else {
return cap.getName();
}
}
/**
* Throws {@link UnsupportedOperationException}
*/
@Override
public String getBaseDependentName() {
throw new UnsupportedOperationException();
}
@Override
public String getBaseRequirementName() {
return baseRequirementName;
}
/**
* Throws {@link UnsupportedOperationException}
*/
@Override
public boolean isDynamicDependent() {
throw new UnsupportedOperationException();
}
}
}