/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.mx.metadata;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.DOMBuilder;
import org.jdom.input.SAXBuilder;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.InputStream;
import java.io.IOException;
import javax.management.Descriptor;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.modelmbean.DescriptorSupport;
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 java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import org.jboss.mx.modelmbean.XMBeanConstants;
/**
* @author Matt Munz
* @deprecated This XML schema builder has been deprecated in 1.2 release and
* is no longer maintained. Please update to 1.2 specific schemas.
*/
public class JBossXMBean10
extends AbstractBuilder
implements XMBeanConstants
{
// Attributes ----------------------------------------------------
/**
* URL for the XML definition of the management interface
*/
private URL url = null;
private org.w3c.dom.Element element;
/**
* The class name of the Model MBean implementation class.
*/
private String mmbClassName = null;
/**
* The class name of the resource object represented by this Model MBean.
*/
private String resourceClassName = null;
// Constructors --------------------------------------------------
/**
* Initialized a parser for the JBossMX 1.0 XMBean schema.
*
* @param mmbClassName the name of the Model MBean implementation class
* @param resourceClassName the name of the resource class this Model
* MBean represents
* @param url URL to the XMBean management interface definition
*/
public JBossXMBean10(String mmbClassName, String resourceClassName, URL url)
{
super();
this.url = url;
this.mmbClassName = mmbClassName;
this.resourceClassName = resourceClassName;
}
/**
* Initialized a parser for the JBossMX 1.0 XMBean schema.
*
* @param mmbClassName the name of the Model MBean implementation class
* @param resourceClassName the name of the resource class this Model
* MBean represents
* @param url URL to the XMBean management interface definition
*
* @throws MalformedURLException if the given management interface URL cannot
* be resolved
*/
public JBossXMBean10(String mmbClassName, String resourceClassName, String url) throws MalformedURLException
{
this(mmbClassName, resourceClassName, new URL(url));
}
/**
* Initialized a parser for the JBossMX 1.0 XMBean schema.
*
* @param mmbClassName the name of the Model MBean implementation class
* @param resourceClassName the name of the resource class this Model
* MBean represents
* @param url URL to the XMBean management interface definition
*/
public JBossXMBean10(String mmbClassName, String resourceClassName, URL url, Map properties)
{
this(mmbClassName, resourceClassName, url);
setProperties(properties);
}
/**
* Initialized a parser for the JBossMX 1.0 XMBean schema.
*
* @param mmbClassName the name of the Model MBean implementation class
* @param resourceClassName the name of the resource class this Model
* MBean represents
* @param url URL to the XMBean management interface definition
*
* @throws MalformedURLException if the given management interface URL cannot
* be resolved
*/
public JBossXMBean10(String mmbClassName, String resourceClassName,
String url, Map properties) throws MalformedURLException
{
this(mmbClassName, resourceClassName, new URL(url), properties);
}
public JBossXMBean10(String mmbClassName, String resourceClassName, org.w3c.dom.Element element)
{
this.mmbClassName = mmbClassName;
this.resourceClassName = resourceClassName;
this.element = element;
}
// MetaDataBuilder implementation --------------------------------
public MBeanInfo build() throws NotCompliantMBeanException
{
try
{
Element root = null;
if (element == null)
{
// by default, let JAXP pick the SAX parser
SAXBuilder builder = null;
// check if user wants to override the SAX parser property
if (properties.get(SAX_PARSER) != null)
{
builder = new SAXBuilder(getStringProperty(SAX_PARSER));
}
else
{
builder = new SAXBuilder();
}
// by default we validate
builder.setValidation(true);
// the user can override the validation by setting the VALIDATE property
try
{
boolean validate = getBooleanProperty(XML_VALIDATION);
builder.setValidation(validate);
}
catch (IllegalPropertyException e)
{
// FIXME: log the exception (warning)
// fall through, use the default value
}
//supply it with our dtd locally.
builder.setEntityResolver(new XMBeanEntityResolver());
// get the root and start parsing...
InputStream docStream = url.openStream();
root = builder.build(docStream).getRootElement();
docStream.close();
}
else
{
DOMBuilder builder = new DOMBuilder();
root = builder.build(element);
}
String description = root.getChildText("description");
if (resourceClassName == null)
{
resourceClassName = root.getChildText("class");
}
List constructors = root.getChildren("constructor");
List operations = root.getChildren("operation");
List attributes = root.getChildren("attribute");
List notifications = root.getChildren("notifications");
Descriptor descr = getDescriptor(root, resourceClassName, "mbean");
ModelMBeanInfo info = buildMBeanMetaData(
description, constructors, operations,
attributes, notifications, descr
);
return (MBeanInfo) info;
}
catch (JDOMException e)
{
e.printStackTrace();
throw new NotCompliantMBeanException("Error parsing the XML file: " + ((e.getCause() == null) ? e.toString() : e.getCause().toString()));
}
catch (IOException e)
{
//e.printStackTrace();
//jdk 1.4 throw new NotCompliantMBeanException("Error parsing the XML file: " + ((e.getCause() == null) ? e.toString() : e.getCause().toString()));
throw new NotCompliantMBeanException("Error parsing the XML file: " + e.toString());
}
}
// Protected -----------------------------------------------------
protected Descriptor getDescriptor(final Element parent, final String infoName, final String type) throws NotCompliantMBeanException
{
Descriptor descr = new DescriptorSupport();
descr.setField(NAME, infoName);
descr.setField(DESCRIPTOR_TYPE, type);
Element descriptors = parent.getChild("descriptors");
if (descriptors == null)
{
return descr;
} // end of if ()
for (Iterator i = descriptors.getChildren().iterator(); i.hasNext();)
{
Element descriptor = (Element)i.next();
String name = descriptor.getName();
if (name.equals("persistence"))
{
Attribute persistPolicy = descriptor.getAttribute(PERSIST_POLICY);
Attribute persistPeriod = descriptor.getAttribute(PERSIST_PERIOD);
Attribute persistLocation = descriptor.getAttribute(PERSIST_LOCATION);
Attribute persistName = descriptor.getAttribute(PERSIST_NAME);
if (persistPolicy != null)
{
String value = persistPolicy.getValue();
validate(value, PERSIST_POLICY_LIST);
descr.setField(PERSIST_POLICY, value);
}
if (persistPeriod != null)
{
descr.setField(PERSIST_PERIOD, persistPeriod.getValue());
}
if (persistLocation != null)
{
descr.setField(PERSIST_LOCATION, persistLocation.getValue());
}
if (persistName != null)
{
descr.setField(PERSIST_NAME, persistName.getValue());
}
}
else if (name.equals(CURRENCY_TIME_LIMIT))
{
descr.setField(CURRENCY_TIME_LIMIT, descriptor.getAttributeValue("value"));
} // end of else
else if (name.equals(STATE_ACTION_ON_UPDATE))
{
String value = descriptor.getAttributeValue("value");
validate(value, STATE_ACTION_ON_UPDATE_LIST);
descr.setField(STATE_ACTION_ON_UPDATE, value);
} // end of else
else if (name.equals(DEFAULT))
{
String value = descriptor.getAttributeValue("value");
descr.setField(DEFAULT, value);
}
else if (name.equals("display-name"))
{
String value = descriptor.getAttributeValue("value");
descr.setField(DISPLAY_NAME, value);
}
else if (name.equals(VALUE))
{
String value = descriptor.getAttributeValue("value");
descr.setField(VALUE, value);
}
else if (name.equals(PERSISTENCE_MANAGER))
{
descr.setField(PERSISTENCE_MANAGER, descriptor.getAttributeValue("value"));
} // end of else
else if (name.equals(DESCRIPTOR))
{
descr.setField(descriptor.getAttributeValue("name"), descriptor.getAttributeValue("value"));
} // end of else
} // end of for ()
return descr;
}
private void validate(String value, String[] valid) throws NotCompliantMBeanException
{
for (int i = 0; i< valid.length; i++)
{
if (valid[i].equalsIgnoreCase(value))
{
return;
} // end of if ()
} // end of for ()
throw new NotCompliantMBeanException("Unknown descriptor value: " + value);
}
// builder methods
protected ModelMBeanInfo buildMBeanMetaData(String description,
List constructors, List operations, List attributes,
List notifications, Descriptor descr)
throws NotCompliantMBeanException
{
ModelMBeanOperationInfo[] operInfo =
buildOperationInfo(operations, attributes);
ModelMBeanAttributeInfo[] attrInfo =
buildAttributeInfo(attributes);
ModelMBeanConstructorInfo[] constrInfo =
buildConstructorInfo(constructors);
ModelMBeanNotificationInfo[] notifInfo =
buildNotificationInfo(notifications);
ModelMBeanInfo info = new ModelMBeanInfoSupport(
mmbClassName, description, attrInfo, constrInfo,
operInfo, notifInfo, descr
);
return info;
}
protected ModelMBeanConstructorInfo[] buildConstructorInfo(List constructors)
throws NotCompliantMBeanException
{
List infos = new ArrayList();
for (Iterator it = constructors.iterator(); it.hasNext();)
{
Element constr = (Element) it.next();
String name = constr.getChildTextTrim("name");
String description = constr.getChildTextTrim("description");
List params = constr.getChildren("parameter");
MBeanParameterInfo[] paramInfo =
buildParameterInfo(params);
Descriptor descr = getDescriptor(constr, name, CONSTRUCTOR_DESCRIPTOR);
ModelMBeanConstructorInfo info =
new ModelMBeanConstructorInfo(name, description, paramInfo, descr);
infos.add(info);
}
return (ModelMBeanConstructorInfo[]) infos.toArray(
new ModelMBeanConstructorInfo[0]);
}
protected ModelMBeanOperationInfo[] buildOperationInfo(List operations, List attributes)
throws NotCompliantMBeanException
{
List infos = new ArrayList();
// Map of method names to types for possible getters
HashMap getters = new HashMap();
// Map of method names to a set of types for possible setters
HashMap setters = new HashMap();
for (Iterator it = operations.iterator(); it.hasNext(); )
{
Element oper = (Element) it.next();
String name = oper.getChildTextTrim("name");
String description = oper.getChildTextTrim("description");
String type = oper.getChildTextTrim("return-type");
String impact = oper.getAttributeValue("impact");
List params = oper.getChildren("parameter");
MBeanParameterInfo[] paramInfo =
buildParameterInfo(params);
Descriptor descr = getDescriptor(oper, name, OPERATION_DESCRIPTOR);
// defaults to ACTION_INFO
int operImpact = MBeanOperationInfo.ACTION_INFO;
if (impact != null)
{
if (impact.equals(INFO))
operImpact = MBeanOperationInfo.INFO;
else if (impact.equals(ACTION))
operImpact = MBeanOperationInfo.ACTION;
else if (impact.equals(ACTION_INFO))
operImpact = MBeanOperationInfo.ACTION_INFO;
}
// default return-type is void
if (type == null)
type = "void";
// Possible getter?
if (paramInfo.length == 0 && type.equals("void") == false)
getters.put(name, type);
// Possible setter?
if (paramInfo.length == 1)
{
HashSet types = (HashSet) setters.get(name);
if (types == null)
{
types = new HashSet();
setters.put(name, types);
}
types.add(paramInfo[0].getType());
}
ModelMBeanOperationInfo info = new ModelMBeanOperationInfo(
name, description, paramInfo, type, operImpact, descr);
infos.add(info);
}
// Add operations for get/setMethod that aren't already present
for (Iterator it = attributes.iterator(); it.hasNext();)
{
Element attr = (Element) it.next();
String name = attr.getChildTextTrim("name");
String type = attr.getChildTextTrim("type");
String getMethod = attr.getAttributeValue(GET_METHOD);
String setMethod = attr.getAttributeValue(SET_METHOD);
// Fabricate a getter operation
if (getMethod != null)
{
Object getterOpType = getters.get(getMethod);
if (getterOpType == null || getterOpType.equals(type) == false)
{
Descriptor getterDescriptor = new DescriptorSupport();
getterDescriptor.setField(NAME, getMethod);
getterDescriptor.setField(DESCRIPTOR_TYPE, OPERATION_DESCRIPTOR);
getterDescriptor.setField(ROLE, GETTER);
ModelMBeanOperationInfo info = new ModelMBeanOperationInfo
(
getMethod,
"getMethod operation for '" + name + "' attribute.",
new MBeanParameterInfo[0],
type,
MBeanOperationInfo.INFO,
getterDescriptor
);
infos.add(info);
}
}
// Fabricate a setter operation
if (setMethod != null)
{
HashSet setterOpTypes = (HashSet) setters.get(setMethod);
if (setterOpTypes == null || setterOpTypes.contains(type) == false)
{
Descriptor setterDescriptor = new DescriptorSupport();
setterDescriptor.setField(NAME, setMethod);
setterDescriptor.setField(DESCRIPTOR_TYPE, OPERATION_DESCRIPTOR);
setterDescriptor.setField(ROLE, SETTER);
ModelMBeanOperationInfo info = new ModelMBeanOperationInfo
(
setMethod,
"setMethod operation for '" + name + "' attribute.",
new MBeanParameterInfo[]
{
new MBeanParameterInfo("value", type, "The new value")
},
Void.TYPE.getName(),
MBeanOperationInfo.ACTION,
setterDescriptor
);
infos.add(info);
}
}
}
return (ModelMBeanOperationInfo[]) infos.toArray(
new ModelMBeanOperationInfo[0]);
}
protected ModelMBeanNotificationInfo[] buildNotificationInfo(List notifications)
throws NotCompliantMBeanException
{
List infos = new ArrayList();
for (Iterator it = notifications.iterator(); it.hasNext();)
{
Element notif = (Element) it.next();
String name = notif.getChildTextTrim("name");
String description = notif.getChildTextTrim("description");
List notifTypes = notif.getChildren("notification-type");
Descriptor descr = getDescriptor(notif, name, NOTIFICATION_DESCRIPTOR);
List types = new ArrayList();
for (Iterator iterator = notifTypes.iterator(); iterator.hasNext();)
{
Element type = (Element) iterator.next();
types.add(type.getTextTrim());
}
ModelMBeanNotificationInfo info = new ModelMBeanNotificationInfo(
(String[]) types.toArray(), name, description, descr);
infos.add(info);
}
return (ModelMBeanNotificationInfo[]) infos.toArray(
new ModelMBeanNotificationInfo[0]
);
}
protected ModelMBeanAttributeInfo[] buildAttributeInfo(List attributes)
throws NotCompliantMBeanException
{
List infos = new ArrayList();
for (Iterator it = attributes.iterator(); it.hasNext();)
{
Element attr = (Element) it.next();
String name = attr.getChildTextTrim("name");
String description = attr.getChildTextTrim("description");
String type = attr.getChildTextTrim("type");
String access = attr.getAttributeValue("access");
String getMethod = attr.getAttributeValue("getMethod");
String setMethod = attr.getAttributeValue("setMethod");
Descriptor descr = getDescriptor(attr, name, ATTRIBUTE_DESCRIPTOR);
//Convert types here from string to specified type
String unconvertedValue = (String)descr.getFieldValue(VALUE);
if (unconvertedValue != null && !"java.lang.String".equals(type))
{
descr.setField(VALUE, convertValue(unconvertedValue, type));
}
String unconvertedDefault = (String)descr.getFieldValue(DEFAULT);
if (unconvertedDefault != null && !"java.lang.String".equals(type))
{
descr.setField(DEFAULT, convertValue(unconvertedDefault, type));
}
if (getMethod != null)
{
descr.setField(GET_METHOD, getMethod);
} // end of if ()
if (setMethod != null)
{
descr.setField(SET_METHOD, setMethod);
} // end of if ()
// defaults read-write
boolean isReadable = true;
boolean isWritable = true;
if (access.equalsIgnoreCase("read-only"))
isWritable = false;
else if (access.equalsIgnoreCase("write-only"))
isReadable = false;
ModelMBeanAttributeInfo info = new ModelMBeanAttributeInfo(
name, type, description, isReadable, isWritable, false, descr
);
infos.add(info);
}
return (ModelMBeanAttributeInfo[]) infos.toArray(
new ModelMBeanAttributeInfo[0]
);
}
/**
* Describe <code>convertType</code> method here.
* Copied from ServiceConfigurator, without Element support.
*
* @param unconverted a <code>String</code> value
* @param typeName a <code>String</code> value
* @return an <code>Object</code> value
* @exception NotCompliantMBeanException if an error occurs
*/
protected Object convertValue(String unconverted, String typeName)
throws NotCompliantMBeanException
{
// see if it is a primitive type first
Class typeClass = getPrimitiveTypeForName(typeName);
if (typeClass == null)
{
// nope try look up
try
{
typeClass = Class.forName(typeName);
}
catch (ClassNotFoundException e)
{
throw new NotCompliantMBeanException
("Class not found for type: " + typeName);
}
}
PropertyEditor editor = PropertyEditorManager.findEditor(typeClass);
if (editor == null)
{
//throw new NotCompliantMBeanException
//("No property editor for type=" + typeClass);
System.out.println("No property editor for type: " + typeClass + ", setting value to null rather than " + unconverted);
return null;
}
editor.setAsText(unconverted);
return editor.getValue();
}
protected MBeanParameterInfo[] buildParameterInfo(List parameters)
{
Iterator it = parameters.iterator();
List infos = new ArrayList();
while (it.hasNext())
{
Element param = (Element) it.next();
String name = param.getChildTextTrim("name");
String type = param.getChildTextTrim("type");
String descr = param.getChildTextTrim("description");
MBeanParameterInfo info = new MBeanParameterInfo(name, type, descr);
infos.add(info);
}
return (MBeanParameterInfo[]) infos.toArray(new MBeanParameterInfo[0]);
}
//helper stuff
//from util.Classes
/** Primitive type name -> class map. */
private static final Map PRIMITIVE_NAME_TYPE_MAP = new HashMap();
/** Setup the primitives map. */
static
{
PRIMITIVE_NAME_TYPE_MAP.put("boolean", Boolean.TYPE);
PRIMITIVE_NAME_TYPE_MAP.put("byte", Byte.TYPE);
PRIMITIVE_NAME_TYPE_MAP.put("char", Character.TYPE);
PRIMITIVE_NAME_TYPE_MAP.put("short", Short.TYPE);
PRIMITIVE_NAME_TYPE_MAP.put("int", Integer.TYPE);
PRIMITIVE_NAME_TYPE_MAP.put("long", Long.TYPE);
PRIMITIVE_NAME_TYPE_MAP.put("float", Float.TYPE);
PRIMITIVE_NAME_TYPE_MAP.put("double", Double.TYPE);
}
/**
* Get the primitive type for the given primitive name.
*
* <p>
* For example, "boolean" returns Boolean.TYPE and so on...
*
* @param name Primitive type name (boolean, int, byte, ...)
* @return Primitive type or null.
*
* @exception IllegalArgumentException Type is not a primitive class
*/
public static Class getPrimitiveTypeForName(final String name) {
return (Class)PRIMITIVE_NAME_TYPE_MAP.get(name);
}
}