/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.brooklyn.entity.software.base.test.jmx;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Map;
import java.util.Map.Entry;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.DynamicMBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
/**
* A quick-and-simple general-purpose implementation of DynamicMBean.
*
* This class provides an implementation of {@link DynamicMBean}. Its initial set of attribute names and values are
* provided to the constructor; from this it figures an {@link MBeanInfo}.
* <p>
* It presently assumes that all attributes are read-only; operations and notifications are not currently supported.
* Choosing the descriptions is not supported - they are set to be the same as the name.
* <p>
* Getting a valid dynamic MBean (in Groovy) is as simple as:
* <pre>
* new GeneralisedDynamicMBean(meaning: 42, advice: "Don't panic")
* </pre>
*/
public class GeneralisedDynamicMBean implements DynamicMBean {
private final MBeanInfo mBeanInfo;
private final Map<String,Object> attributes = Maps.newLinkedHashMap();
private final Map<String,Function> operations = Maps.newLinkedHashMap();
public GeneralisedDynamicMBean(Map<String,?> initialAttributes, Map<?,?> initialOperations) {
attributes.putAll(initialAttributes);
for (Entry<?,?> entry : initialOperations.entrySet()) {
checkArgument(entry.getKey() instanceof String || entry.getKey() instanceof MBeanOperationInfo, "entry.key=%s", entry.getKey());
String opName = (entry.getKey() instanceof String) ? (String)entry.getKey() : ((MBeanOperationInfo)entry.getKey()).getName();
operations.put(opName, (Function) entry.getValue());
}
Iterable<MBeanAttributeInfo> attrInfo = Iterables.transform(initialAttributes.entrySet(), new Function<Map.Entry<String,?>, MBeanAttributeInfo>() {
@Override public MBeanAttributeInfo apply(Map.Entry<String,?> entry) {
return new MBeanAttributeInfo(entry.getKey(), entry.getValue().getClass().getName(), entry.getKey(), true, false, false);
}
});
Iterable<MBeanOperationInfo> opInfo = Iterables.transform(initialOperations.keySet(), new Function<Object, MBeanOperationInfo>() {
public MBeanOperationInfo apply(Object it) {
if (it instanceof MBeanOperationInfo) {
return (MBeanOperationInfo) it;
} else if (it instanceof CharSequence) {
return new MBeanOperationInfo(
it.toString(),
"my descr",
new MBeanParameterInfo[0],
"void",
MBeanOperationInfo.ACTION_INFO);
} else {
throw new IllegalArgumentException("Cannot convert "+it+" to MBeanOperationInfo");
}
}});
mBeanInfo = new MBeanInfo(
GeneralisedDynamicMBean.class.getName(),
GeneralisedDynamicMBean.class.getName(),
Iterables.toArray(attrInfo, MBeanAttributeInfo.class),
new MBeanConstructorInfo[0],
Iterables.toArray(opInfo, MBeanOperationInfo.class),
new MBeanNotificationInfo[0]);
}
public void updateAttributeValue(String name, Object value) {
attributes.put(name, value);
}
@Override
public Object getAttribute(String s) {
return attributes.get(s);
}
@Override
public void setAttribute(Attribute attribute) {
attributes.put(attribute.getName(), attribute.getValue());
}
@Override
public AttributeList getAttributes(String[] strings) {
AttributeList result = new AttributeList();
for (Object obj : mBeanInfo.getAttributes()) {
Attribute attrib = (Attribute) obj;
result.add(new Attribute(attrib.getName(), attributes.get(attrib.getName())));
}
return result;
}
@Override
public AttributeList setAttributes(AttributeList attributeList) {
for (Object element : attributeList) {
Attribute attrib = (Attribute) element;
attributes.put(attrib.getName(), attrib.getValue());
}
return attributeList;
}
@Override
public Object invoke(String s, Object[] objects, String[] strings) {
Function op = operations.get(s);
if (op != null) {
return op.apply(objects);
} else {
throw new RuntimeException("Unknown operation "+s);
}
}
@Override
public MBeanInfo getMBeanInfo() {
return mBeanInfo;
}
}