org.jboss.mx.modelmbean.XMBean Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, 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.mx.modelmbean;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.management.Descriptor;
import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.RuntimeOperationsException;
import javax.management.StandardMBean;
import javax.management.modelmbean.InvalidTargetObjectTypeException;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanConstructorInfo;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanNotificationInfo;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.jboss.mx.interceptor.StandardMBeanInfoInterceptor;
import org.jboss.mx.metadata.MBeanInfoConversion;
import org.jboss.mx.metadata.MetaDataBuilder;
import org.jboss.mx.metadata.StandardMetaData;
import org.jboss.mx.metadata.XMLMetaData;
/**
* XMBean implementation.
*
* @author Juha Lindfors.
* @author Matt Munz
* @author Dimitris Andreadis
* @version $Revision: 81026 $
*/
public class XMBean
extends ModelMBeanInvoker
implements XMBeanConstants, NotificationListener
{
// Constructors --------------------------------------------------
/**
* Default constructor for the XMBean Model MBean implementation. This
* creates an uninitialized Model MBean template.
*/
public XMBean() throws MBeanException
{
try
{
setManagedResource(new Object(), OBJECT_REF);
setModelMBeanInfo(new ModelMBeanInfoSupport("XMBean", "Uninitialized XMBean", new ModelMBeanAttributeInfo[0],
new ModelMBeanConstructorInfo[0], new ModelMBeanOperationInfo[0], new ModelMBeanNotificationInfo[0]));
}
catch (RuntimeException e)
{
throw new RuntimeOperationsException(e);
}
catch (Exception e)
{
throw new MBeanException(e);
}
}
/**
* Creates an XMBean Model MBean implementation with a predefined JMX
* metadata.
*
* @param info Model MBean metadata describing this MBean template
*/
public XMBean(ModelMBeanInfo info) throws MBeanException
{
super(info);
}
/**
* Creates a XMBean instance with a given resource object and resource type.
*
* This Model MBean implementation supports the following resource types:
*
* - {@link ModelMBeanConstants#OBJECT_REF OBJECT_REF}
* - {@link XMBeanConstants#STANDARD_INTERFACE STANDARD_INTERFACE}
* - {@link XMBeanConstants#DESCRIPTOR DESCRIPTOR}
* - Any valid URL string to a *.xml file.
*
*
*
* OBJECT_REF: resource object can be any Java object. The
* management interface must be set separately via
* {@link javax.management.modelmbean.ModelMBean#setModelMBeanInfo setModelMBeanInfo}
* method.
*
* STANDARD_INTERFACE: the resource object is assumed to
* follow the Standard MBean naming conventions to expose its management
* interface, including implementing a xxxMBean interface. A
* corresponding Model MBean metadata is generated for the Model MBean
* representing this resource type.
*
* DESCRIPTOR: the resource object is wrapped as a part of
* the {@link javax.management.Descriptor Descriptor} object passed to this
* Model MBean instance. The descriptor object must contain the mandatory
* fields {@link XMBeanConstants#RESOURCE_REFERENCE RESOURCE_REFERENCE} and
* {@link XMBeanConstants#RESOURCE_TYPE RESOURCE_TYPE} that identify the
* correct resource reference and type used for this Model MBean instance.
* The descriptor object may also contain additional fields, such as
* {@link XMBeanConstants#SAX_PARSER SAX_PARSER} and
* {@link XMBeanConstants#XML_VALIDATION XML_VALIDATION} that are passed as
* configuration properties for the metadata builder instances. Any
* additional descriptor fields that match the
* {@link XMBeanConstants#METADATA_DESCRIPTOR_PREFIX METADATA_DESCRIPTOR_PREFIX}
* naming pattern will be passed to the builder implementation via its
* {@link org.jboss.mx.metadata.MetaDataBuilder#setProperty setProperty}
* method.
*
* URL String: if a resource type string contains an URL
* that ends with a *.xml file name the resource object is exposed via the
* XML management interface definition read from this URL. The XML parser
* implementation is picked based on the schema definition in the XML
* document.
*
* @param resource resource object or descriptor
* @param resourceType resource type string or URL to *.xml file
*/
public XMBean(Object resource, String resourceType) throws MBeanException, NotCompliantMBeanException
{
// TODO: document STANDARD_MBEAN
ModelMBeanInfo minfo = null;
try
{
HashMap properties = new HashMap();
if (resourceType.equals(DESCRIPTOR))
{
Descriptor d = (Descriptor)resource;
// get the actual resource type from the descriptor
resourceType = (String)d.getFieldValue(RESOURCE_TYPE);
// and the resource reference
resource = d.getFieldValue(RESOURCE_REFERENCE);
// extract builder configuration fields
String[] fields = d.getFieldNames();
for (int i = 0; i < fields.length; ++i)
{
// extract all the fields starting with the METADATA_DESCRIPTOR_PREFIX
// prefix to a property map that is passed to the builder implementations
if (fields[i].startsWith(METADATA_DESCRIPTOR_PREFIX))
properties.put(fields[i], d.getFieldValue(fields[i]));
}
}
if (resourceType.equals(STANDARD_MBEAN) && resource instanceof StandardMBean)
setManagedResource(((StandardMBean)resource).getImplementation(), resourceType);
else
setManagedResource(resource, resourceType);
// automatically create management operations that the attributes
// can map to.
final boolean CREATE_ATTRIBUTE_OPERATION_MAPPING = true;
// the resource extends StandardMBean
if (resourceType.equals(STANDARD_MBEAN) &&
resource instanceof StandardMBean)
{
StandardMBean standardMBean = (StandardMBean) resource;
minfo = MBeanInfoConversion.toModelMBeanInfo(standardMBean.getMBeanInfo(),
CREATE_ATTRIBUTE_OPERATION_MAPPING);
}
// the resource implements a Standard MBean interface
else if ((resourceType.equals(STANDARD_INTERFACE)) ||
(resourceType.equals(STANDARD_MBEAN)))
{
dynamicResource = false;
// create and configure the builder
MetaDataBuilder builder = new StandardMetaData(resource);
// pass the config keys to the builder instance
for (Iterator it = properties.keySet().iterator(); it.hasNext();)
{
String key = (String)it.next();
builder.setProperty(key, properties.get(key));
}
// build the metadata
MBeanInfo standardInfo = builder.build();
// StandardMetaData is used by the MBean server to introspect
// standard MBeans. We need to now turn that Standard metadata into
// ModelMBean metadata (including operation mapping for attributes)
minfo = MBeanInfoConversion.toModelMBeanInfo(standardInfo, CREATE_ATTRIBUTE_OPERATION_MAPPING);
}
// If the resource type string ends with an '.xml' extension attempt
// to create the metadata with the aggregated XML builder.
else if (resourceType.endsWith(".xml"))
{
// Create and configure the builder. XMLMetaData builder is an
// aggregate builder that picks the correct schema specific builder
// based on schema declaration at the beginning of the XML file.
MetaDataBuilder builder = new XMLMetaData(
this.getClass().getName(), // MMBean implementation name
resource.getClass().getName(), // resource class name
resourceType
);
// pass the config keys to the builder instance
for (Iterator it = properties.keySet().iterator(); it.hasNext();)
{
String key = (String)it.next();
builder.setProperty(key, properties.get(key));
}
minfo = (ModelMBeanInfo) builder.build();
}
// Sotre the ModelMBeanInfo
this.setModelMBeanInfo(minfo);
// we must try to load this MBean (as the superclass does), even if only NullPersistence
// is used - MMM
load();
}
catch (InstanceNotFoundException e)
{
throw new MBeanException(e);
}
catch (InvalidTargetObjectTypeException e)
{
if (resourceType.endsWith(".xml"))
throw new MBeanException(e, "Malformed URL: " + resourceType);
throw new MBeanException(e, "Unsupported resource type: " + resourceType);
}
catch (MalformedURLException e)
{
throw new MBeanException(e, "Malformed URL: " + resourceType);
}
}
public XMBean(Object resource, URL interfaceURL) throws MBeanException, NotCompliantMBeanException
{
this(resource, interfaceURL.toString());
}
public XMBean(Descriptor descriptor) throws MBeanException, NotCompliantMBeanException
{
this(descriptor, DESCRIPTOR);
}
public XMBean(Object resource, org.w3c.dom.Element element, String version) throws MBeanException, NotCompliantMBeanException
{
try
{
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
org.w3c.dom.Document doc = builder.newDocument();
doc.appendChild(doc.importNode(element, true));
org.dom4j.io.DOMReader domReader = new org.dom4j.io.DOMReader();
org.dom4j.Document dom4jDoc = domReader.read(doc);
org.dom4j.Element dom4jElem = dom4jDoc.getRootElement();
dom4jElem.detach();
createXMBean(resource, dom4jElem, version);
}
catch (ParserConfigurationException e)
{
throw new MBeanException(e, "Could not convert w3c Element to dom4j Element.");
}
}
public XMBean(Object resource, org.dom4j.Element element, String version) throws MBeanException, NotCompliantMBeanException
{
// this(resource, OBJECT_REF);
createXMBean(resource, element, version);
}
private void createXMBean(Object resource, org.dom4j.Element element, String version)
throws MBeanException, NotCompliantMBeanException
{
try
{
setManagedResource(resource, OBJECT_REF);
MetaDataBuilder builder = new XMLMetaData(
this.getClass().getName(), // MMBean implementation name
resource.getClass().getName(), // resource class name
element,
version
);
ModelMBeanInfo minfo = (ModelMBeanInfo) builder.build();
this.setModelMBeanInfo(minfo);
}
catch (InstanceNotFoundException e)
{
throw new MBeanException(e);
}
catch (InvalidTargetObjectTypeException e)
{
throw new MBeanException(e, "Unsupported resource type: " + resourceType);
}
}
// Public --------------------------------------------------------
public boolean isSupportedResourceType(Object resource, String resourceType)
{
if (resourceType == null)
return false;
if (resourceType.equalsIgnoreCase(OBJECT_REF))
return true;
if (resourceType.equalsIgnoreCase(STANDARD_INTERFACE))
return true;
if (resourceType.equalsIgnoreCase(STANDARD_MBEAN))
return true;
if (resourceType.equalsIgnoreCase(DESCRIPTOR))
{
if (resource == null || !(resource instanceof Descriptor))
return false;
Descriptor d = (Descriptor)resource;
if (d.getFieldValue(RESOURCE_REFERENCE) == null)
return false;
if (d.getFieldValue(RESOURCE_TYPE) == null)
return false;
return true;
}
if (resourceType.endsWith(".xml"))
{
try
{
new URL(resourceType);
return true;
}
catch (MalformedURLException e)
{
return false;
}
}
return false;
}
// ModelMBeanInvoker overrides -----------------------------------
protected void configureInterceptorStack(ModelMBeanInfo info,
MBeanServer server, ObjectName name)
throws Exception
{
// FIXME: do not require super calls
super.configureInterceptorStack(info, server, name);
if (resourceType.equals(STANDARD_MBEAN))
{
List interceptors = getMBeanInfoCtx.getInterceptors();
interceptors.add(0, new StandardMBeanInfoInterceptor());
getMBeanInfoCtx.setInterceptors(interceptors);
}
}
// NotificationBroadcaster overrides -----------------------------
// TODO: intercept these... (?) rather than do this overriding
public void addNotificationListener(NotificationListener listener,
NotificationFilter filter, Object handback)
{
// a standard mbean handles broadcasting itself (if a broadcaster)
if (resourceType.equals(STANDARD_MBEAN))
{
addNotificationListenerToResource(listener, filter, handback);
}
else
{
// for all other types register a listener for AVCs
// (including XMBeans wrapping POJOs or standard mbean impls)
super.addNotificationListener(listener, filter, handback);
// in addition if the resource is a broadcaster update its subscription list
if (getResource() instanceof NotificationBroadcaster)
addNotificationListenerToResource(listener, filter, handback);
}
}
public void removeNotificationListener(NotificationListener listener)
throws ListenerNotFoundException
{
// a standard mbean handles broadcasting itself (if a broadcaster)
if (resourceType.equals(STANDARD_MBEAN))
{
removeNotificationListenerFromResource(listener);
}
else
{
// for all other types remove the listener for AVCs
// (including XMBeans wrapping POJOs or standard mbean impls)
super.removeNotificationListener(listener);
// in addition if the resource is a broadcaster update its subscription list
if (getResource() instanceof NotificationBroadcaster)
removeNotificationListenerFromResource(listener);
}
}
public void removeNotificationListener(NotificationListener listener,
NotificationFilter filter,
Object handback)
throws ListenerNotFoundException
{
// a standard mbean handles broadcasting itself (if a broadcaster)
if (resourceType.equals(STANDARD_MBEAN))
{
removeNotificationListenerFromResource(listener, filter, handback);
}
else
{
// for all other types remove the listener for AVCs
// (including XMBeans wrapping POJOs or standard mbean impls)
super.removeNotificationListener(listener, filter, handback);
// in addition if the resource is a broadcaster update its subscription list
if (getResource() instanceof NotificationBroadcaster)
removeNotificationListenerFromResource(listener, filter, handback);
}
}
public MBeanNotificationInfo[] getNotificationInfo()
{
if (resourceType.equals(STANDARD_MBEAN))
return getNotificationInfoFromResource();
else
return super.getNotificationInfo();
}
// NotificationListener overrides --------------------------------
/**
* Implements NotificationListener interface by simply forwarding
* any received Notification to the wrapped resource, if it
* implements the NotificationListener interface, too.
*
* This is needed to allow the wrapped resource to register for
* Notifications using the XMBean ObjectName, rather than its own
* "this" reference - dimitris
*/
public void handleNotification(Notification notification, Object handback)
{
Object resource = getResource();
if (resource instanceof NotificationListener)
((NotificationListener)resource).handleNotification(notification, handback);
}
}