/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat Middleware LLC, 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.jmx.model;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ACCESS_MECHANISM;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ATTRIBUTES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OPERATION_HEADERS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_ATTRIBUTE_OPERATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REPLY_PROPERTIES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REQUEST_PROPERTIES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.WRITE_ATTRIBUTE_OPERATION;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMRuntimeException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.QueryEval;
import javax.management.QueryExp;
import javax.management.ReflectionException;
import org.jboss.as.controller.ExpressionResolver;
import org.jboss.as.controller.ModelController;
import org.jboss.as.controller.ModelController.OperationTransactionControl;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.descriptions.DescriptionProvider;
import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
import org.jboss.as.controller.registry.OperationEntry.Flag;
import org.jboss.as.core.security.AccessMechanism;
import org.jboss.as.jmx.logging.JmxLogger;
import org.jboss.as.jmx.model.ChildAddOperationFinder.ChildAddOperationEntry;
import org.jboss.as.jmx.model.ResourceAccessControlUtil.ResourceAccessControl;
import org.jboss.as.jmx.model.RootResourceIterator.ResourceAction;
import org.jboss.dmr.ModelNode;
import org.wildfly.common.Assert;
/**
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
*/
public class ModelControllerMBeanHelper {
static final String CLASS_NAME = ModelController.class.getName();
private static final String AUTHORIZED_ERROR = "WFLYCTL0313";
private final MutabilityChecker mutabilityChecker;
private final ModelController controller;
private final ResourceAccessControlUtil accessControlUtil;
private final PathAddress CORE_SERVICE_PLATFORM_MBEAN = PathAddress.pathAddress(PathElement.pathElement("core-service", "platform-mbean"));
private final TypeConverters converters;
private final ConfiguredDomains configuredDomains;
private final String domain;
private final ManagementModelIntegration.ManagementModelProvider managementModelProvider;
ModelControllerMBeanHelper(TypeConverters converters, ConfiguredDomains configuredDomains, String domain,
ModelController controller, MutabilityChecker mutabilityChecker,
ManagementModelIntegration.ManagementModelProvider managementModelProvider) {
this.converters = converters;
this.configuredDomains = configuredDomains;
this.domain = domain;
this.controller = controller;
this.accessControlUtil = new ResourceAccessControlUtil(controller);
this.mutabilityChecker = mutabilityChecker;
this.managementModelProvider = managementModelProvider;
}
int getMBeanCount() {
return new RootResourceIterator<Integer>(accessControlUtil, getRootResourceAndRegistration().getResource(), new ResourceAction<Integer>() {
int count;
@Override
public ObjectName onAddress(PathAddress address) {
return isExcludeAddress(address) ? null : ObjectNameAddressUtil.createObjectName(domain, address);
}
public boolean onResource(ObjectName address) {
count++;
return true;
}
public Integer getResult() {
return count;
}
}).iterate();
}
Set<ObjectInstance> queryMBeans(final MBeanServer mbeanServer, final ObjectName name, final QueryExp query) {
Set<ObjectInstance> basic = new RootResourceIterator<Set<ObjectInstance>>(accessControlUtil, getRootResourceAndRegistration().getResource(),
new ObjectNameMatchResourceAction<Set<ObjectInstance>>(name) {
Set<ObjectInstance> set = new HashSet<ObjectInstance>();
@Override
public boolean onResource(ObjectName resourceName) {
if (name == null || name.apply(resourceName)) {
set.add(new ObjectInstance(resourceName, CLASS_NAME));
}
return true;
}
@Override
public Set<ObjectInstance> getResult() {
if (set.size() == 1 && set.contains(ModelControllerMBeanHelper.createRootObjectInstance(domain))) {
return Collections.emptySet();
}
return set;
}
}).iterate();
// Handle any 'query' outside the RootResourceIterator so if the query calls back
// into us it's not a recursive kind of thing in the ModelController
Set<ObjectInstance> result;
if (query == null || basic.isEmpty()) {
result = basic;
} else {
result = new HashSet<>(basic.size());
for (ObjectInstance oi : basic) {
MBeanServer oldServer = setQueryExpServer(query, mbeanServer);
try {
if (query.apply(oi.getObjectName())) {
result.add(oi);
}
} catch (Exception ignored) {
// we just don't add it
} finally {
setQueryExpServer(query, oldServer);
}
}
}
return result;
}
Set<ObjectName> queryNames(MBeanServer mbeanServer, final ObjectName name, final QueryExp query) {
Set<ObjectName> basic = new RootResourceIterator<Set<ObjectName>>(accessControlUtil, getRootResourceAndRegistration().getResource(),
new ObjectNameMatchResourceAction<Set<ObjectName>>(name) {
Set<ObjectName> set = new HashSet<ObjectName>();
@Override
public boolean onResource(ObjectName resourceName) {
if (name == null || name.apply(resourceName)) {
set.add(resourceName);
}
return true;
}
@Override
public Set<ObjectName> getResult() {
if (set.size() == 1 && set.contains(ModelControllerMBeanHelper.createRootObjectName(domain))) {
return Collections.emptySet();
}
return set;
}
}).iterate();
// Handle any 'query' outside the RootResourceIterator so if the query calls back
// into us it's not a recursive kind of thing in the ModelController
Set<ObjectName> result;
if (query == null || basic.isEmpty()) {
result = basic;
} else {
result = new HashSet<>(basic.size());
for (ObjectName on : basic) {
MBeanServer oldServer = setQueryExpServer(query, mbeanServer);
try {
if (query.apply(on)) {
result.add(on);
}
} catch (Exception ignored) {
// we just don't add it
} finally {
setQueryExpServer(query, oldServer);
}
}
}
return result;
}
/** Set the mbean server on the QueryExp and try and pass back any previously set one */
private static MBeanServer setQueryExpServer(QueryExp query, MBeanServer toSet) {
// We assume the QueryExp is a QueryEval subclass or uses the QueryEval thread local
// mechanism to store any existing MBeanServer. If that's not the case we have no
// way to access the old mbeanserver to let us restore it
MBeanServer result = QueryEval.getMBeanServer();
query.setMBeanServer(toSet);
return result;
}
PathAddress resolvePathAddress(final ObjectName name) {
return ObjectNameAddressUtil.resolvePathAddress(domain, getRootResourceAndRegistration().getResource(), name);
}
PathAddress resolvePathAddress(final ObjectName name, ManagementModelIntegration.ResourceAndRegistration reg) {
return ObjectNameAddressUtil.resolvePathAddress(domain, reg.getResource(), name);
}
/**
* Convert an ObjectName to a PathAddress.
*
* Patterns are supported: there may not be a resource at the returned PathAddress but a resource model <strong>MUST</strong>
* must be registered.
*/
PathAddress toPathAddress(final ObjectName name) {
return ObjectNameAddressUtil.toPathAddress(domain, getRootResourceAndRegistration().getRegistration(), name);
}
MBeanInfo getMBeanInfo(final ObjectName name) throws InstanceNotFoundException {
final ManagementModelIntegration.ResourceAndRegistration reg = getRootResourceAndRegistration();
final PathAddress address = resolvePathAddress(name, reg);
if (address == null) {
throw JmxLogger.ROOT_LOGGER.mbeanNotFound(name);
}
final ResourceAccessControl accessControl = accessControlUtil.getResourceAccessWithInstanceNotFoundExceptionIfNotAccessible(name, address, true);
return MBeanInfoFactory.createMBeanInfo(name, converters, configuredDomains, mutabilityChecker, address, getMBeanRegistration(address, reg));
}
Object getAttribute(final ObjectName name, final String attribute) throws AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
final ManagementModelIntegration.ResourceAndRegistration reg = getRootResourceAndRegistration();
final PathAddress address = resolvePathAddress(name, reg);
if (address == null) {
throw JmxLogger.ROOT_LOGGER.mbeanNotFound(name);
}
final ResourceAccessControl accessControl = accessControlUtil.getResourceAccessWithInstanceNotFoundExceptionIfNotAccessible(name, address, false);
return getAttribute(reg, address, name, attribute, accessControl);
}
AttributeList getAttributes(ObjectName name, String[] attributes) throws InstanceNotFoundException, ReflectionException {
final ManagementModelIntegration.ResourceAndRegistration reg = getRootResourceAndRegistration();
final PathAddress address = resolvePathAddress(name, reg);
if (address == null) {
throw JmxLogger.ROOT_LOGGER.mbeanNotFound(name);
}
final ResourceAccessControl accessControl = accessControlUtil.getResourceAccessWithInstanceNotFoundExceptionIfNotAccessible(name, address, false);
AttributeList list = new AttributeList();
for (String attribute : attributes) {
try {
list.add(new Attribute(attribute, getAttribute(reg, address, name, attribute, accessControl)));
} catch (AttributeNotFoundException e) {
throw new ReflectionException(e);
}
}
return list;
}
private Object getAttribute(final ManagementModelIntegration.ResourceAndRegistration reg, final PathAddress address, final ObjectName name, final String attribute, final ResourceAccessControl accessControl) throws ReflectionException, AttributeNotFoundException, InstanceNotFoundException {
final ImmutableManagementResourceRegistration registration = getMBeanRegistration(address, reg);
final DescriptionProvider provider = registration.getModelDescription(PathAddress.EMPTY_ADDRESS);
if (provider == null) {
throw JmxLogger.ROOT_LOGGER.descriptionProviderNotFound(address);
}
final ModelNode description = provider.getModelDescription(null);
final String attributeName = findAttributeName(description.get(ATTRIBUTES), attribute);
if (!accessControl.isReadableAttribute(attributeName)) {
throw JmxLogger.ROOT_LOGGER.notAuthorizedToReadAttribute(attributeName);
}
ModelNode op = new ModelNode();
op.get(OP).set(READ_ATTRIBUTE_OPERATION);
op.get(OP_ADDR).set(address.toModelNode());
op.get(NAME).set(attributeName);
ModelNode result = execute(op);
String error = getFailureDescription(result);
if (error != null) {
throw new AttributeNotFoundException(error);
}
return converters.fromModelNode(description.require(ATTRIBUTES).require(attributeName), result.get(RESULT));
}
void setAttribute(ObjectName name, Attribute attribute) throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException {
final ManagementModelIntegration.ResourceAndRegistration reg = getRootResourceAndRegistration();
final PathAddress address = resolvePathAddress(name, reg);
if (address == null) {
throw JmxLogger.ROOT_LOGGER.mbeanNotFound(name);
}
final ResourceAccessControl accessControl = accessControlUtil.getResourceAccessWithInstanceNotFoundExceptionIfNotAccessible(name, address, false);
setAttribute(reg, address, name, attribute, accessControl);
}
AttributeList setAttributes(ObjectName name, AttributeList attributes) throws InstanceNotFoundException, ReflectionException {
final ManagementModelIntegration.ResourceAndRegistration reg = getRootResourceAndRegistration();
final PathAddress address = resolvePathAddress(name, reg);
if (address == null) {
throw JmxLogger.ROOT_LOGGER.mbeanNotFound(name);
}
final ResourceAccessControl accessControl = accessControlUtil.getResourceAccessWithInstanceNotFoundExceptionIfNotAccessible(name, address, false);
for (Attribute attribute : attributes.asList()) {
try {
setAttribute(reg, address, name, attribute, accessControl);
} catch (JMRuntimeException e) {
//Propagate the JMRuntimeException thrown from authorization
throw e;
} catch (Exception e) {
throw JmxLogger.ROOT_LOGGER.cannotSetAttribute(e, attribute.getName());
}
}
return attributes;
}
private void setAttribute(final ManagementModelIntegration.ResourceAndRegistration reg, final PathAddress address, final ObjectName name, final Attribute attribute, ResourceAccessControl accessControl) throws InvalidAttributeValueException, AttributeNotFoundException, InstanceNotFoundException {
final ImmutableManagementResourceRegistration registration = getMBeanRegistration(address, reg);
final DescriptionProvider provider = registration.getModelDescription(PathAddress.EMPTY_ADDRESS);
if (provider == null) {
throw JmxLogger.ROOT_LOGGER.descriptionProviderNotFound(address);
}
final ModelNode description = provider.getModelDescription(null);
final String attributeName = findAttributeName(description.get(ATTRIBUTES), attribute.getName());
if (!mutabilityChecker.mutable(address)) {
throw JmxLogger.ROOT_LOGGER.attributeNotWritable(attribute);
}
if (!accessControl.isWritableAttribute(attributeName)) {
throw JmxLogger.ROOT_LOGGER.notAuthorizedToWriteAttribute(attributeName);
}
ModelNode op = new ModelNode();
op.get(OP).set(WRITE_ATTRIBUTE_OPERATION);
op.get(OP_ADDR).set(address.toModelNode());
op.get(NAME).set(attributeName);
try {
op.get(VALUE).set(converters.toModelNode(description.require(ATTRIBUTES).require(attributeName), attribute.getValue()));
} catch (ClassCastException e) {
throw JmxLogger.ROOT_LOGGER.invalidAttributeType(e, attribute.getName());
}
ModelNode result = execute(op);
String error = getFailureDescription(result);
if (error != null) {
//Since read-resource-description does not know the parameters of the operation, i.e. if a vault expression is used or not,
//check the error code
//TODO add a separate authorize step where we check ourselves that the operation will pass authorization?
if (isVaultExpression(attribute.getValue()) && error.contains(AUTHORIZED_ERROR)) {
throw JmxLogger.ROOT_LOGGER.notAuthorizedToWriteAttribute(attributeName);
}
throw new InvalidAttributeValueException(error);
}
}
ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException {
final PathAddress address = resolvePathAddress(name);
if (address == null) {
throw JmxLogger.ROOT_LOGGER.mbeanNotFound(name);
}
accessControlUtil.getResourceAccessWithInstanceNotFoundExceptionIfNotAccessible(name, address, false);
return new ObjectInstance(name, CLASS_NAME);
}
Object invoke(ObjectName name, String operationName, Object[] params, String[] signature) throws InstanceNotFoundException, MBeanException, ReflectionException {
Assert.checkNotNullParam("operationName", operationName);
if (params == null) {
params = new Object[0];
}
if (signature == null) {
signature = new String[0];
}
if (params.length != signature.length) {
throw JmxLogger.ROOT_LOGGER.differentLengths("params", "signature");
}
final ManagementModelIntegration.ResourceAndRegistration reg = getRootResourceAndRegistration();
final PathAddress address = resolvePathAddress(name, reg);
if (address == null) {
throw JmxLogger.ROOT_LOGGER.mbeanNotFound(name);
}
final ImmutableManagementResourceRegistration registration = getMBeanRegistration(address, reg);
String realOperationName = null;
OperationEntry opEntry = registration.getOperationEntry(PathAddress.EMPTY_ADDRESS, operationName);
if (opEntry != null) {
realOperationName = operationName;
} else {
String opName = NameConverter.convertFromCamelCase(operationName);
opEntry = registration.getOperationEntry(PathAddress.EMPTY_ADDRESS, opName);
if (opEntry != null) {
realOperationName = opName;
}
}
if (opEntry == null) {
//Brute force search in case the operation name is not standard format
Map<String, OperationEntry> ops = registration.getOperationDescriptions(PathAddress.EMPTY_ADDRESS, false);
for (Map.Entry<String, OperationEntry> entry : ops.entrySet()) {
if (operationName.equals(NameConverter.convertToCamelCase(entry.getKey()))) {
opEntry = entry.getValue();
realOperationName = entry.getKey();
break;
}
}
}
if (opEntry == null) {
ChildAddOperationEntry entry = ChildAddOperationFinder.findAddChildOperation(address, mutabilityChecker, reg.getRegistration().getSubModel(address), operationName);
if (entry == null) {
throw JmxLogger.ROOT_LOGGER.noOperationCalled(null, operationName, address);
}
PathElement element = entry.getElement();
if (element.isWildcard()) {
if (params.length == 0) {
throw JmxLogger.ROOT_LOGGER.wildcardNameParameterRequired();
}
element = PathElement.pathElement(element.getKey(), (String)params[0]);
Object[] newParams = new Object[params.length - 1];
System.arraycopy(params, 1, newParams, 0, newParams.length);
params = newParams;
}
return invoke(entry.getOperationEntry(), ADD, address.append(element), params);
}
return invoke(opEntry, realOperationName, address, params);
}
private Object invoke(final OperationEntry entry, final String operationName, PathAddress address, Object[] params) throws InstanceNotFoundException, MBeanException, ReflectionException {
if (!mutabilityChecker.mutable(address) && !(entry.getFlags().contains(Flag.READ_ONLY) || entry.getFlags().contains(Flag.RUNTIME_ONLY))) {
throw JmxLogger.ROOT_LOGGER.noOperationCalled(operationName);
}
ResourceAccessControl accessControl;
if (operationName.equals("add")) {
accessControl = accessControlUtil.getResourceAccess(address, true);
} else {
ObjectName objectName = ObjectNameAddressUtil.createObjectName(operationName, address);
accessControl = accessControlUtil.getResourceAccessWithInstanceNotFoundExceptionIfNotAccessible(
objectName, address, true);
}
if (!accessControl.isExecutableOperation(operationName)) {
throw JmxLogger.ROOT_LOGGER.notAuthorizedToExecuteOperation(operationName);
}
final ModelNode description = entry.getDescriptionProvider().getModelDescription(null);
ModelNode op = new ModelNode();
op.get(OP).set(operationName);
op.get(OP_ADDR).set(address.toModelNode());
if (params.length > 0) {
ModelNode requestProperties = description.require(REQUEST_PROPERTIES);
Set<String> keys = requestProperties.keys();
if (keys.size() != params.length) {
throw JmxLogger.ROOT_LOGGER.differentLengths("params", "description");
}
Iterator<String> it = requestProperties.keys().iterator();
for (int i = 0 ; i < params.length ; i++) {
String attributeName = it.next();
ModelNode paramDescription = requestProperties.get(attributeName);
op.get(attributeName).set(converters.toModelNode(paramDescription, params[i]));
}
}
ModelNode result = execute(op);
String error = getFailureDescription(result);
if (error != null) {
if (error.contains(AUTHORIZED_ERROR)) {
for (Object param : params) {
//Since read-resource-description does not know the parameters of the operation, i.e. if a vault expression is used or not,
//check the error code
//TODO add a separate authorize step where we check ourselves that the operation will pass authorization?
if (isVaultExpression(param)) {
throw JmxLogger.ROOT_LOGGER.notAuthorizedToExecuteOperation(operationName);
}
}
}
throw new ReflectionException(null, error);
}
if (!description.hasDefined(REPLY_PROPERTIES)) {
return null;
}
//TODO we could have more than one reply property
return converters.fromModelNode(description.get(REPLY_PROPERTIES), result.get(RESULT));
}
private ManagementModelIntegration.ResourceAndRegistration getRootResourceAndRegistration() {
return managementModelProvider.getResourceAndRegistration();
}
private ModelNode execute(ModelNode op) {
op.get(OPERATION_HEADERS, ACCESS_MECHANISM).set(AccessMechanism.JMX.toString());
return controller.execute(op, null, OperationTransactionControl.COMMIT, null);
}
private ImmutableManagementResourceRegistration getMBeanRegistration(PathAddress address, ManagementModelIntegration.ResourceAndRegistration reg) throws InstanceNotFoundException {
//TODO Populate MBeanInfo
ImmutableManagementResourceRegistration resourceRegistration = reg.getRegistration().getSubModel(address);
if (resourceRegistration == null) {
throw JmxLogger.ROOT_LOGGER.registrationNotFound(address);
}
return resourceRegistration;
}
private String getFailureDescription(ModelNode result) {
if (result.hasDefined(FAILURE_DESCRIPTION)) {
return result.get(FAILURE_DESCRIPTION).toString();
}
return null;
}
private String findAttributeName(ModelNode attributes, String attributeName) throws AttributeNotFoundException{
if (attributes.hasDefined(attributeName)) {
return attributeName;
}
for (String key : attributes.keys()) {
if (NameConverter.convertToCamelCase(key).equals(attributeName)) {
return key;
}
}
throw JmxLogger.ROOT_LOGGER.attributeNotFound(attributeName);
}
private boolean isExcludeAddress(PathAddress pathAddress) {
return pathAddress.equals(CORE_SERVICE_PLATFORM_MBEAN);
}
private boolean isVaultExpression(Object value) {
if (value != null && value.getClass() == String.class){
String valueString = (String)value;
if (ExpressionResolver.EXPRESSION_PATTERN.matcher(valueString).matches()) {
return TypeConverters.VAULT_PATTERN.matcher(valueString).matches();
}
}
return false;
}
public static ObjectName createRootObjectName(String domain) {
try {
return ObjectName.getInstance(domain, "management-root", "server");
} catch (MalformedObjectNameException e) {
throw new RuntimeException(e);
}
}
private static ObjectInstance createRootObjectInstance(String domain) {
return new ObjectInstance(createRootObjectName(domain), CLASS_NAME);
}
String getDomain() {
return domain;
}
ImmutableManagementResourceRegistration getMBeanRegistration(ObjectName name) throws InstanceNotFoundException {
final ManagementModelIntegration.ResourceAndRegistration reg = getRootResourceAndRegistration();
final PathAddress address = resolvePathAddress(name, reg);
return getMBeanRegistration(address, reg);
}
TypeConverters getConverters() {
return converters;
}
private abstract class ObjectNameMatchResourceAction<T> implements ResourceAction<T> {
private final ObjectName baseName;
private final Map<String, String> properties;
private final ObjectName domainOnlyName;
private final boolean propertyListPattern;
protected ObjectNameMatchResourceAction(ObjectName baseName) {
this.baseName = baseName;
this.properties = baseName == null ? Collections.<String, String>emptyMap() : baseName.getKeyPropertyList();
try {
this.domainOnlyName = baseName == null ? null : ObjectName.getInstance(baseName.getDomain() + ":*");
} catch (MalformedObjectNameException e) {
throw new IllegalStateException(e);
}
this.propertyListPattern = baseName != null && baseName.isPropertyListPattern();
}
@Override
public ObjectName onAddress(PathAddress address) {
if (isExcludeAddress(address)) {
return null;
}
ObjectName result = null;
ObjectName toMatch = ObjectNameAddressUtil.createObjectName(domain, address);
if (baseName == null) {
result = toMatch;
} else if (address.size() == 0) {
// We can't compare the ObjectName properties a la the final 'else' block,
// because the special management=server property will not match
// Just confirm correct domain
if (domainOnlyName.apply(toMatch)) {
result = toMatch;
}
} else if (!propertyListPattern && address.size() >= properties.size()) {
// We have same or more elements than our target has properties; let it do the match
if (baseName.apply(toMatch)) {
result = toMatch;
}
} else {
// Address may be a parent of an interesting address, so see if it matches all elements it has
boolean matches = domainOnlyName.apply(toMatch);
if (matches) {
for (Map.Entry<String, String> entry : toMatch.getKeyPropertyList().entrySet()) {
String propertyValue = properties.get(entry.getKey());
if ((propertyValue == null && !propertyListPattern)
|| (propertyValue != null
&& !entry.getValue().equals(propertyValue))
&& !baseName.isPropertyValuePattern(entry.getKey())) {
matches = false;
break;
}
}
}
if (matches) {
result = toMatch;
}
}
return result;
}
}
}