|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
/* |
|
* @author IBM Corp. |
|
* |
|
* Copyright IBM Corp. 1999-2000. All rights reserved. |
|
*/ |
|
|
|
package javax.management.modelmbean; |
|
|
|
import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER; |
|
import static com.sun.jmx.mbeanserver.Util.cast; |
|
import com.sun.jmx.mbeanserver.GetPropertyAction; |
|
import com.sun.jmx.mbeanserver.Util; |
|
|
|
import java.io.IOException; |
|
import java.io.ObjectInputStream; |
|
import java.io.ObjectOutputStream; |
|
import java.io.ObjectStreamField; |
|
|
|
import java.lang.reflect.Constructor; |
|
|
|
import java.security.AccessController; |
|
import java.util.HashMap; |
|
import java.util.Iterator; |
|
import java.util.Map; |
|
import java.util.Set; |
|
import java.util.SortedMap; |
|
import java.util.StringTokenizer; |
|
import java.util.TreeMap; |
|
import java.util.logging.Level; |
|
|
|
import javax.management.Descriptor; |
|
import javax.management.ImmutableDescriptor; |
|
import javax.management.MBeanException; |
|
import javax.management.RuntimeOperationsException; |
|
|
|
import sun.reflect.misc.ReflectUtil; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("serial") |
|
public class DescriptorSupport |
|
implements javax.management.Descriptor |
|
{ |
|
|
|
// Serialization compatibility stuff: |
|
// Two serial forms are supported in this class. The selected form depends |
|
// on system property "jmx.serial.form": |
|
// - "1.0" for JMX 1.0 |
|
// - any other value for JMX 1.1 and higher |
|
// |
|
|
|
private static final long oldSerialVersionUID = 8071560848919417985L; |
|
// |
|
|
|
private static final long newSerialVersionUID = -6292969195866300415L; |
|
// |
|
|
|
private static final ObjectStreamField[] oldSerialPersistentFields = |
|
{ |
|
new ObjectStreamField("descriptor", HashMap.class), |
|
new ObjectStreamField("currClass", String.class) |
|
}; |
|
// |
|
|
|
private static final ObjectStreamField[] newSerialPersistentFields = |
|
{ |
|
new ObjectStreamField("descriptor", HashMap.class) |
|
}; |
|
// |
|
|
|
private static final long serialVersionUID; |
|
|
|
|
|
*/ |
|
private static final ObjectStreamField[] serialPersistentFields; |
|
private static final String serialForm; |
|
static { |
|
String form = null; |
|
boolean compat = false; |
|
try { |
|
GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); |
|
form = AccessController.doPrivileged(act); |
|
compat = "1.0".equals(form); |
|
} catch (Exception e) { |
|
// OK: No compat with 1.0 |
|
} |
|
serialForm = form; |
|
if (compat) { |
|
serialPersistentFields = oldSerialPersistentFields; |
|
serialVersionUID = oldSerialVersionUID; |
|
} else { |
|
serialPersistentFields = newSerialPersistentFields; |
|
serialVersionUID = newSerialVersionUID; |
|
} |
|
} |
|
// |
|
// END Serialization compatibility stuff |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private transient SortedMap<String, Object> descriptorMap; |
|
|
|
private static final String currClass = "DescriptorSupport"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public DescriptorSupport() { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"DescriptorSupport()" , "Constructor"); |
|
} |
|
init(null); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public DescriptorSupport(int initNumFields) |
|
throws MBeanException, RuntimeOperationsException { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(initNumFields = " + initNumFields + ")", |
|
"Constructor"); |
|
} |
|
if (initNumFields <= 0) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(initNumFields)", |
|
"Illegal arguments: initNumFields <= 0"); |
|
} |
|
final String msg = |
|
"Descriptor field limit invalid: " + initNumFields; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
init(null); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public DescriptorSupport(DescriptorSupport inDescr) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(Descriptor)", "Constructor"); |
|
} |
|
if (inDescr == null) |
|
init(null); |
|
else |
|
init(inDescr.descriptorMap); |
|
} |
|
|
|
|
|
/** |
|
* <p>Descriptor constructor taking an XML String.</p> |
|
* |
|
* <p>The format of the XML string is not defined, but an |
|
* implementation must ensure that the string returned by |
|
* {@link #toXMLString() toXMLString()} on an existing |
|
* descriptor can be used to instantiate an equivalent |
|
* descriptor using this constructor.</p> |
|
* |
|
* <p>In this implementation, all field values will be created |
|
* as Strings. If the field values are not Strings, the |
|
* programmer will have to reset or convert these fields |
|
* correctly.</p> |
|
* |
|
* @param inStr An XML-formatted string used to populate this |
|
* Descriptor. The format is not defined, but any |
|
* implementation must ensure that the string returned by |
|
* method {@link #toXMLString toXMLString} on an existing |
|
* descriptor can be used to instantiate an equivalent |
|
* descriptor when instantiated using this constructor. |
|
* |
|
* @exception RuntimeOperationsException If the String inStr |
|
* passed in parameter is null |
|
* @exception XMLParseException XML parsing problem while parsing |
|
* the input String |
|
* @exception MBeanException Wraps a distributed communication Exception. |
|
*/ |
|
|
|
|
|
|
|
|
|
occur in the middle of a field value. */ |
|
public DescriptorSupport(String inStr) |
|
throws MBeanException, RuntimeOperationsException, |
|
XMLParseException { |
|
|
|
* structure with it */ |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(String = '" + inStr + "')", "Constructor"); |
|
} |
|
if (inStr == null) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(String = null)", "Illegal arguments"); |
|
} |
|
final String msg = "String in parameter is null"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
|
|
final String lowerInStr = inStr.toLowerCase(); |
|
if (!lowerInStr.startsWith("<descriptor>") |
|
|| !lowerInStr.endsWith("</descriptor>")) { |
|
throw new XMLParseException("No <descriptor>, </descriptor> pair"); |
|
} |
|
|
|
|
|
init(null); |
|
// create dummy descriptor: should have same size |
|
// as number of fields in xmlstring |
|
// loop through structures and put them in descriptor |
|
|
|
StringTokenizer st = new StringTokenizer(inStr, "<> \t\n\r\f"); |
|
|
|
boolean inFld = false; |
|
boolean inDesc = false; |
|
String fieldName = null; |
|
String fieldValue = null; |
|
|
|
|
|
while (st.hasMoreTokens()) { |
|
String tok = st.nextToken(); |
|
|
|
if (tok.equalsIgnoreCase("FIELD")) { |
|
inFld = true; |
|
} else if (tok.equalsIgnoreCase("/FIELD")) { |
|
if ((fieldName != null) && (fieldValue != null)) { |
|
fieldName = |
|
fieldName.substring(fieldName.indexOf('"') + 1, |
|
fieldName.lastIndexOf('"')); |
|
final Object fieldValueObject = |
|
parseQuotedFieldValue(fieldValue); |
|
setField(fieldName, fieldValueObject); |
|
} |
|
fieldName = null; |
|
fieldValue = null; |
|
inFld = false; |
|
} else if (tok.equalsIgnoreCase("DESCRIPTOR")) { |
|
inDesc = true; |
|
} else if (tok.equalsIgnoreCase("/DESCRIPTOR")) { |
|
inDesc = false; |
|
fieldName = null; |
|
fieldValue = null; |
|
inFld = false; |
|
} else if (inFld && inDesc) { |
|
|
|
int eq_separator = tok.indexOf("="); |
|
if (eq_separator > 0) { |
|
String kwPart = tok.substring(0,eq_separator); |
|
String valPart = tok.substring(eq_separator+1); |
|
if (kwPart.equalsIgnoreCase("NAME")) |
|
fieldName = valPart; |
|
else if (kwPart.equalsIgnoreCase("VALUE")) |
|
fieldValue = valPart; |
|
else { |
|
final String msg = |
|
"Expected `name' or `value', got `" + tok + "'"; |
|
throw new XMLParseException(msg); |
|
} |
|
} else { |
|
final String msg = |
|
"Expected `keyword=value', got `" + tok + "'"; |
|
throw new XMLParseException(msg); |
|
} |
|
} |
|
} |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(XMLString)", "Exit"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public DescriptorSupport(String[] fieldNames, Object[] fieldValues) |
|
throws RuntimeOperationsException { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(fieldNames,fieldObjects)", "Constructor"); |
|
} |
|
|
|
if ((fieldNames == null) || (fieldValues == null) || |
|
(fieldNames.length != fieldValues.length)) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(fieldNames,fieldObjects)", |
|
"Illegal arguments"); |
|
} |
|
|
|
final String msg = |
|
"Null or invalid fieldNames or fieldValues"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
|
|
|
|
init(null); |
|
for (int i=0; i < fieldNames.length; i++) { |
|
// setField will throw an exception if a fieldName is be null. |
|
|
|
setField(fieldNames[i], fieldValues[i]); |
|
} |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(fieldNames,fieldObjects)", "Exit"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public DescriptorSupport(String... fields) |
|
{ |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(String... fields)", "Constructor"); |
|
} |
|
init(null); |
|
if (( fields == null ) || ( fields.length == 0)) |
|
return; |
|
|
|
init(null); |
|
|
|
for (int i=0; i < fields.length; i++) { |
|
if ((fields[i] == null) || (fields[i].equals(""))) { |
|
continue; |
|
} |
|
int eq_separator = fields[i].indexOf("="); |
|
if (eq_separator < 0) { |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(String... fields)", |
|
"Illegal arguments: field does not have " + |
|
"'=' as a name and value separator"); |
|
} |
|
final String msg = "Field in invalid format: no equals sign"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
|
|
String fieldName = fields[i].substring(0,eq_separator); |
|
String fieldValue = null; |
|
if (eq_separator < fields[i].length()) { |
|
|
|
fieldValue = fields[i].substring(eq_separator+1); |
|
} |
|
|
|
if (fieldName.equals("")) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(String... fields)", |
|
"Illegal arguments: fieldName is empty"); |
|
} |
|
|
|
final String msg = "Field in invalid format: no fieldName"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
|
|
setField(fieldName,fieldValue); |
|
} |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"Descriptor(String... fields)", "Exit"); |
|
} |
|
} |
|
|
|
private void init(Map<String, ?> initMap) { |
|
descriptorMap = |
|
new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER); |
|
if (initMap != null) |
|
descriptorMap.putAll(initMap); |
|
} |
|
|
|
// Implementation of the Descriptor interface |
|
|
|
|
|
public synchronized Object getFieldValue(String fieldName) |
|
throws RuntimeOperationsException { |
|
|
|
if ((fieldName == null) || (fieldName.equals(""))) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldValue(String fieldName)", |
|
"Illegal arguments: null field name"); |
|
} |
|
final String msg = "Fieldname requested is null"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
Object retValue = descriptorMap.get(fieldName); |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldValue(String fieldName = " + fieldName + ")", |
|
"Returns '" + retValue + "'"); |
|
} |
|
return(retValue); |
|
} |
|
|
|
public synchronized void setField(String fieldName, Object fieldValue) |
|
throws RuntimeOperationsException { |
|
|
|
|
|
if ((fieldName == null) || (fieldName.equals(""))) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"setField(fieldName,fieldValue)", |
|
"Illegal arguments: null or empty field name"); |
|
} |
|
|
|
final String msg = "Field name to be set is null or empty"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
|
|
if (!validateField(fieldName, fieldValue)) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"setField(fieldName,fieldValue)", |
|
"Illegal arguments"); |
|
} |
|
|
|
final String msg = |
|
"Field value invalid: " + fieldName + "=" + fieldValue; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"setField(fieldName,fieldValue)", "Entry: setting '" |
|
+ fieldName + "' to '" + fieldValue + "'"); |
|
} |
|
|
|
// Since we do not remove any existing entry with this name, |
|
// the field will preserve whatever case it had, ignoring |
|
|
|
descriptorMap.put(fieldName, fieldValue); |
|
} |
|
|
|
public synchronized String[] getFields() { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFields()", "Entry"); |
|
} |
|
int numberOfEntries = descriptorMap.size(); |
|
|
|
String[] responseFields = new String[numberOfEntries]; |
|
Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet(); |
|
|
|
int i = 0; |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFields()", "Returning " + numberOfEntries + " fields"); |
|
} |
|
for (Iterator<Map.Entry<String, Object>> iter = returnedSet.iterator(); |
|
iter.hasNext(); i++) { |
|
Map.Entry<String, Object> currElement = iter.next(); |
|
|
|
if (currElement == null) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFields()", "Element is null"); |
|
} |
|
} else { |
|
Object currValue = currElement.getValue(); |
|
if (currValue == null) { |
|
responseFields[i] = currElement.getKey() + "="; |
|
} else { |
|
if (currValue instanceof java.lang.String) { |
|
responseFields[i] = |
|
currElement.getKey() + "=" + currValue.toString(); |
|
} else { |
|
responseFields[i] = |
|
currElement.getKey() + "=(" + |
|
currValue.toString() + ")"; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFields()", "Exit"); |
|
} |
|
|
|
return responseFields; |
|
} |
|
|
|
public synchronized String[] getFieldNames() { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldNames()", "Entry"); |
|
} |
|
int numberOfEntries = descriptorMap.size(); |
|
|
|
String[] responseFields = new String[numberOfEntries]; |
|
Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet(); |
|
|
|
int i = 0; |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldNames()", |
|
"Returning " + numberOfEntries + " fields"); |
|
} |
|
|
|
for (Iterator<Map.Entry<String, Object>> iter = returnedSet.iterator(); |
|
iter.hasNext(); i++) { |
|
Map.Entry<String, Object> currElement = iter.next(); |
|
|
|
if (( currElement == null ) || (currElement.getKey() == null)) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldNames()", "Field is null"); |
|
} |
|
} else { |
|
responseFields[i] = currElement.getKey().toString(); |
|
} |
|
} |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldNames()", "Exit"); |
|
} |
|
|
|
return responseFields; |
|
} |
|
|
|
|
|
public synchronized Object[] getFieldValues(String... fieldNames) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldValues(String... fieldNames)", "Entry"); |
|
} |
|
// if fieldNames == null return all values |
|
// if fieldNames is String[0] return no values |
|
|
|
final int numberOfEntries = |
|
(fieldNames == null) ? descriptorMap.size() : fieldNames.length; |
|
final Object[] responseFields = new Object[numberOfEntries]; |
|
|
|
int i = 0; |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldValues(String... fieldNames)", |
|
"Returning " + numberOfEntries + " fields"); |
|
} |
|
|
|
if (fieldNames == null) { |
|
for (Object value : descriptorMap.values()) |
|
responseFields[i++] = value; |
|
} else { |
|
for (i=0; i < fieldNames.length; i++) { |
|
if ((fieldNames[i] == null) || (fieldNames[i].equals(""))) { |
|
responseFields[i] = null; |
|
} else { |
|
responseFields[i] = getFieldValue(fieldNames[i]); |
|
} |
|
} |
|
} |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"getFieldValues(String... fieldNames)", "Exit"); |
|
} |
|
|
|
return responseFields; |
|
} |
|
|
|
public synchronized void setFields(String[] fieldNames, |
|
Object[] fieldValues) |
|
throws RuntimeOperationsException { |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"setFields(fieldNames,fieldValues)", "Entry"); |
|
} |
|
|
|
if ((fieldNames == null) || (fieldValues == null) || |
|
(fieldNames.length != fieldValues.length)) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"setFields(fieldNames,fieldValues)", |
|
"Illegal arguments"); |
|
} |
|
|
|
final String msg = "fieldNames and fieldValues are null or invalid"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
|
|
for (int i=0; i < fieldNames.length; i++) { |
|
if (( fieldNames[i] == null) || (fieldNames[i].equals(""))) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"setFields(fieldNames,fieldValues)", |
|
"Null field name encountered at element " + i); |
|
} |
|
final String msg = "fieldNames is null or invalid"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, msg); |
|
} |
|
setField(fieldNames[i], fieldValues[i]); |
|
} |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"setFields(fieldNames,fieldValues)", "Exit"); |
|
} |
|
} |
|
|
|
/** |
|
* Returns a new Descriptor which is a duplicate of the Descriptor. |
|
* |
|
* @exception RuntimeOperationsException for illegal value for |
|
* field Names or field Values. If the descriptor construction |
|
* fails for any reason, this exception will be thrown. |
|
*/ |
|
|
|
@Override |
|
public synchronized Object clone() throws RuntimeOperationsException { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"clone()", "Entry"); |
|
} |
|
return(new DescriptorSupport(this)); |
|
} |
|
|
|
public synchronized void removeField(String fieldName) { |
|
if ((fieldName == null) || (fieldName.equals(""))) { |
|
return; |
|
} |
|
|
|
descriptorMap.remove(fieldName); |
|
} |
|
|
|
/** |
|
* Compares this descriptor to the given object. The objects are equal if |
|
* the given object is also a Descriptor, and if the two Descriptors have |
|
* the same field names (possibly differing in case) and the same |
|
* associated values. The respective values for a field in the two |
|
* Descriptors are equal if the following conditions hold: |
|
* |
|
* <ul> |
|
* <li>If one value is null then the other must be too.</li> |
|
* <li>If one value is a primitive array then the other must be a primitive |
|
* array of the same type with the same elements.</li> |
|
* <li>If one value is an object array then the other must be too and |
|
* {@link java.util.Arrays#deepEquals(Object[],Object[]) Arrays.deepEquals} |
|
* must return true.</li> |
|
* <li>Otherwise {@link Object#equals(Object)} must return true.</li> |
|
* </ul> |
|
* |
|
* @param o the object to compare with. |
|
* |
|
* @return {@code true} if the objects are the same; {@code false} |
|
* otherwise. |
|
* |
|
*/ |
|
// Note: this Javadoc is copied from javax.management.Descriptor |
|
|
|
@Override |
|
public synchronized boolean equals(Object o) { |
|
if (o == this) |
|
return true; |
|
if (! (o instanceof Descriptor)) |
|
return false; |
|
if (o instanceof ImmutableDescriptor) |
|
return o.equals(this); |
|
return new ImmutableDescriptor(descriptorMap).equals(o); |
|
} |
|
|
|
/** |
|
* <p>Returns the hash code value for this descriptor. The hash |
|
* code is computed as the sum of the hash codes for each field in |
|
* the descriptor. The hash code of a field with name {@code n} |
|
* and value {@code v} is {@code n.toLowerCase().hashCode() ^ h}. |
|
* Here {@code h} is the hash code of {@code v}, computed as |
|
* follows:</p> |
|
* |
|
* <ul> |
|
* <li>If {@code v} is null then {@code h} is 0.</li> |
|
* <li>If {@code v} is a primitive array then {@code h} is computed using |
|
* the appropriate overloading of {@code java.util.Arrays.hashCode}.</li> |
|
* <li>If {@code v} is an object array then {@code h} is computed using |
|
* {@link java.util.Arrays#deepHashCode(Object[]) Arrays.deepHashCode}.</li> |
|
* <li>Otherwise {@code h} is {@code v.hashCode()}.</li> |
|
* </ul> |
|
* |
|
* @return A hash code value for this object. |
|
* |
|
*/ |
|
// Note: this Javadoc is copied from javax.management.Descriptor |
|
|
|
@Override |
|
public synchronized int hashCode() { |
|
final int size = descriptorMap.size(); |
|
// descriptorMap is sorted with a comparator that ignores cases. |
|
|
|
return Util.hashCode( |
|
descriptorMap.keySet().toArray(new String[size]), |
|
descriptorMap.values().toArray(new Object[size])); |
|
} |
|
|
|
/** |
|
* Returns true if all of the fields have legal values given their |
|
* names. |
|
* <P> |
|
* This implementation does not support interoperating with a directory |
|
* or lookup service. Thus, conforming to the specification, no checking is |
|
* done on the <i>"export"</i> field. |
|
* <P> |
|
* Otherwise this implementation returns false if: |
|
* <UL> |
|
* <LI> name and descriptorType fieldNames are not defined, or |
|
* null, or empty, or not String |
|
* <LI> class, role, getMethod, setMethod fieldNames, if defined, |
|
* are null or not String |
|
* <LI> persistPeriod, currencyTimeLimit, lastUpdatedTimeStamp, |
|
* lastReturnedTimeStamp if defined, are null, or not a Numeric |
|
* String or not a Numeric Value {@literal >= -1} |
|
* <LI> log fieldName, if defined, is null, or not a Boolean or |
|
* not a String with value "t", "f", "true", "false". These String |
|
* values must not be case sensitive. |
|
* <LI> visibility fieldName, if defined, is null, or not a |
|
* Numeric String or a not Numeric Value {@literal >= 1 and <= 4} |
|
* <LI> severity fieldName, if defined, is null, or not a Numeric |
|
* String or not a Numeric Value {@literal >= 0 and <= 6}<br> |
|
* <LI> persistPolicy fieldName, if defined, is null, or not one of |
|
* the following strings:<br> |
|
* "OnUpdate", "OnTimer", "NoMoreOftenThan", "OnUnregister", "Always", |
|
* "Never". These String values must not be case sensitive.<br> |
|
* </UL> |
|
* |
|
* @exception RuntimeOperationsException If the validity checking |
|
* fails for any reason, this exception will be thrown. |
|
*/ |
|
|
|
public synchronized boolean isValid() throws RuntimeOperationsException { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"isValid()", "Entry"); |
|
} |
|
// verify that the descriptor is valid, by iterating over each field... |
|
|
|
Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet(); |
|
|
|
if (returnedSet == null) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"isValid()", "Returns false (null set)"); |
|
} |
|
return false; |
|
} |
|
|
|
String thisName = (String)(this.getFieldValue("name")); |
|
String thisDescType = (String)(getFieldValue("descriptorType")); |
|
|
|
if ((thisName == null) || (thisDescType == null) || |
|
(thisName.equals("")) || (thisDescType.equals(""))) { |
|
return false; |
|
} |
|
|
|
// According to the descriptor type we validate the fields contained |
|
|
|
for (Map.Entry<String, Object> currElement : returnedSet) { |
|
if (currElement != null) { |
|
if (currElement.getValue() != null) { |
|
|
|
if (validateField((currElement.getKey()).toString(), |
|
(currElement.getValue()).toString())) { |
|
continue; |
|
} else { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"isValid()", |
|
"Field " + currElement.getKey() + "=" + |
|
currElement.getValue() + " is not valid"); |
|
} |
|
return false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"isValid()", "Returns true"); |
|
} |
|
return true; |
|
} |
|
|
|
|
|
// worker routine for isValid() |
|
// name is not null |
|
// descriptorType is not null |
|
// getMethod and setMethod are not null |
|
// persistPeriod is numeric |
|
// currencyTimeLimit is numeric |
|
// lastUpdatedTimeStamp is numeric |
|
// visibility is 1-4 |
|
// severity is 0-6 |
|
// log is T or F |
|
// role is not null |
|
// class is not null |
|
// lastReturnedTimeStamp is numeric |
|
|
|
|
|
private boolean validateField(String fldName, Object fldValue) { |
|
if ((fldName == null) || (fldName.equals(""))) |
|
return false; |
|
String SfldValue = ""; |
|
boolean isAString = false; |
|
if ((fldValue != null) && (fldValue instanceof java.lang.String)) { |
|
SfldValue = (String) fldValue; |
|
isAString = true; |
|
} |
|
|
|
boolean nameOrDescriptorType = |
|
(fldName.equalsIgnoreCase("Name") || |
|
fldName.equalsIgnoreCase("DescriptorType")); |
|
if (nameOrDescriptorType || |
|
fldName.equalsIgnoreCase("SetMethod") || |
|
fldName.equalsIgnoreCase("GetMethod") || |
|
fldName.equalsIgnoreCase("Role") || |
|
fldName.equalsIgnoreCase("Class")) { |
|
if (fldValue == null || !isAString) |
|
return false; |
|
if (nameOrDescriptorType && SfldValue.equals("")) |
|
return false; |
|
return true; |
|
} else if (fldName.equalsIgnoreCase("visibility")) { |
|
long v; |
|
if ((fldValue != null) && (isAString)) { |
|
v = toNumeric(SfldValue); |
|
} else if (fldValue instanceof java.lang.Integer) { |
|
v = ((Integer)fldValue).intValue(); |
|
} else return false; |
|
|
|
if (v >= 1 && v <= 4) |
|
return true; |
|
else |
|
return false; |
|
} else if (fldName.equalsIgnoreCase("severity")) { |
|
|
|
long v; |
|
if ((fldValue != null) && (isAString)) { |
|
v = toNumeric(SfldValue); |
|
} else if (fldValue instanceof java.lang.Integer) { |
|
v = ((Integer)fldValue).intValue(); |
|
} else return false; |
|
|
|
return (v >= 0 && v <= 6); |
|
} else if (fldName.equalsIgnoreCase("PersistPolicy")) { |
|
return (((fldValue != null) && (isAString)) && |
|
( SfldValue.equalsIgnoreCase("OnUpdate") || |
|
SfldValue.equalsIgnoreCase("OnTimer") || |
|
SfldValue.equalsIgnoreCase("NoMoreOftenThan") || |
|
SfldValue.equalsIgnoreCase("Always") || |
|
SfldValue.equalsIgnoreCase("Never") || |
|
SfldValue.equalsIgnoreCase("OnUnregister"))); |
|
} else if (fldName.equalsIgnoreCase("PersistPeriod") || |
|
fldName.equalsIgnoreCase("CurrencyTimeLimit") || |
|
fldName.equalsIgnoreCase("LastUpdatedTimeStamp") || |
|
fldName.equalsIgnoreCase("LastReturnedTimeStamp")) { |
|
|
|
long v; |
|
if ((fldValue != null) && (isAString)) { |
|
v = toNumeric(SfldValue); |
|
} else if (fldValue instanceof java.lang.Number) { |
|
v = ((Number)fldValue).longValue(); |
|
} else return false; |
|
|
|
return (v >= -1); |
|
} else if (fldName.equalsIgnoreCase("log")) { |
|
return ((fldValue instanceof java.lang.Boolean) || |
|
(isAString && |
|
(SfldValue.equalsIgnoreCase("T") || |
|
SfldValue.equalsIgnoreCase("true") || |
|
SfldValue.equalsIgnoreCase("F") || |
|
SfldValue.equalsIgnoreCase("false") ))); |
|
} |
|
|
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized String toXMLString() { |
|
final StringBuilder buf = new StringBuilder("<Descriptor>"); |
|
Set<Map.Entry<String, Object>> returnedSet = descriptorMap.entrySet(); |
|
for (Map.Entry<String, Object> currElement : returnedSet) { |
|
final String name = currElement.getKey(); |
|
Object value = currElement.getValue(); |
|
String valueString = null; |
|
|
|
|
|
|
|
|
|
up with an encoding like "(java.lang.String/(thing))". */ |
|
if (value instanceof String) { |
|
final String svalue = (String) value; |
|
if (!svalue.startsWith("(") || !svalue.endsWith(")")) |
|
valueString = quote(svalue); |
|
} |
|
if (valueString == null) |
|
valueString = makeFieldValue(value); |
|
buf.append("<field name=\"").append(name).append("\" value=\"") |
|
.append(valueString).append("\"></field>"); |
|
} |
|
buf.append("</Descriptor>"); |
|
return buf.toString(); |
|
} |
|
|
|
private static final String[] entities = { |
|
"  ", |
|
"\""", |
|
"<<", |
|
">>", |
|
"&&", |
|
"\r ", |
|
"\t	", |
|
"\n ", |
|
"\f", |
|
}; |
|
private static final Map<String,Character> entityToCharMap = |
|
new HashMap<String,Character>(); |
|
private static final String[] charToEntityMap; |
|
|
|
static { |
|
char maxChar = 0; |
|
for (int i = 0; i < entities.length; i++) { |
|
final char c = entities[i].charAt(0); |
|
if (c > maxChar) |
|
maxChar = c; |
|
} |
|
charToEntityMap = new String[maxChar + 1]; |
|
for (int i = 0; i < entities.length; i++) { |
|
final char c = entities[i].charAt(0); |
|
final String entity = entities[i].substring(1); |
|
charToEntityMap[c] = entity; |
|
entityToCharMap.put(entity, c); |
|
} |
|
} |
|
|
|
private static boolean isMagic(char c) { |
|
return (c < charToEntityMap.length && charToEntityMap[c] != null); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static String quote(String s) { |
|
boolean found = false; |
|
for (int i = 0; i < s.length(); i++) { |
|
if (isMagic(s.charAt(i))) { |
|
found = true; |
|
break; |
|
} |
|
} |
|
if (!found) |
|
return s; |
|
final StringBuilder buf = new StringBuilder(); |
|
for (int i = 0; i < s.length(); i++) { |
|
char c = s.charAt(i); |
|
if (isMagic(c)) |
|
buf.append(charToEntityMap[c]); |
|
else |
|
buf.append(c); |
|
} |
|
return buf.toString(); |
|
} |
|
|
|
private static String unquote(String s) throws XMLParseException { |
|
if (!s.startsWith("\"") || !s.endsWith("\"")) |
|
throw new XMLParseException("Value must be quoted: <" + s + ">"); |
|
final StringBuilder buf = new StringBuilder(); |
|
final int len = s.length() - 1; |
|
for (int i = 1; i < len; i++) { |
|
final char c = s.charAt(i); |
|
final int semi; |
|
final Character quoted; |
|
if (c == '&' |
|
&& (semi = s.indexOf(';', i + 1)) >= 0 |
|
&& ((quoted = entityToCharMap.get(s.substring(i, semi+1))) |
|
!= null)) { |
|
buf.append(quoted); |
|
i = semi; |
|
} else |
|
buf.append(c); |
|
} |
|
return buf.toString(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static String makeFieldValue(Object value) { |
|
if (value == null) |
|
return "(null)"; |
|
|
|
Class<?> valueClass = value.getClass(); |
|
try { |
|
valueClass.getConstructor(String.class); |
|
} catch (NoSuchMethodException e) { |
|
final String msg = |
|
"Class " + valueClass + " does not have a public " + |
|
"constructor with a single string arg"; |
|
final RuntimeException iae = new IllegalArgumentException(msg); |
|
throw new RuntimeOperationsException(iae, |
|
"Cannot make XML descriptor"); |
|
} catch (SecurityException e) { |
|
// OK: we'll pretend the constructor is there |
|
// too bad if it's not: we'll find out when we try to |
|
// reconstruct the DescriptorSupport |
|
} |
|
|
|
final String quotedValueString = quote(value.toString()); |
|
|
|
return "(" + valueClass.getName() + "/" + quotedValueString + ")"; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static Object parseQuotedFieldValue(String s) |
|
throws XMLParseException { |
|
s = unquote(s); |
|
if (s.equalsIgnoreCase("(null)")) |
|
return null; |
|
if (!s.startsWith("(") || !s.endsWith(")")) |
|
return s; |
|
final int slash = s.indexOf('/'); |
|
if (slash < 0) { |
|
|
|
return s.substring(1, s.length() - 1); |
|
} |
|
final String className = s.substring(1, slash); |
|
|
|
final Constructor<?> constr; |
|
try { |
|
ReflectUtil.checkPackageAccess(className); |
|
final ClassLoader contextClassLoader = |
|
Thread.currentThread().getContextClassLoader(); |
|
final Class<?> c = |
|
Class.forName(className, false, contextClassLoader); |
|
constr = c.getConstructor(new Class<?>[] {String.class}); |
|
} catch (Exception e) { |
|
throw new XMLParseException(e, |
|
"Cannot parse value: <" + s + ">"); |
|
} |
|
final String arg = s.substring(slash + 1, s.length() - 1); |
|
try { |
|
return constr.newInstance(new Object[] {arg}); |
|
} catch (Exception e) { |
|
final String msg = |
|
"Cannot construct instance of " + className + |
|
" with arg: <" + s + ">"; |
|
throw new XMLParseException(e, msg); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public synchronized String toString() { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"toString()", "Entry"); |
|
} |
|
|
|
String respStr = ""; |
|
String[] fields = getFields(); |
|
|
|
if ((fields == null) || (fields.length == 0)) { |
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"toString()", "Empty Descriptor"); |
|
} |
|
return respStr; |
|
} |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"toString()", "Printing " + fields.length + " fields"); |
|
} |
|
|
|
for (int i=0; i < fields.length; i++) { |
|
if (i == (fields.length - 1)) { |
|
respStr = respStr.concat(fields[i]); |
|
} else { |
|
respStr = respStr.concat(fields[i] + ", "); |
|
} |
|
} |
|
|
|
if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) { |
|
MODELMBEAN_LOGGER.logp(Level.FINEST, |
|
DescriptorSupport.class.getName(), |
|
"toString()", "Exit returning " + respStr); |
|
} |
|
|
|
return respStr; |
|
} |
|
|
|
// utility to convert to int, returns -2 if bogus. |
|
|
|
private long toNumeric(String inStr) { |
|
try { |
|
return java.lang.Long.parseLong(inStr); |
|
} catch (Exception e) { |
|
return -2; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void readObject(ObjectInputStream in) |
|
throws IOException, ClassNotFoundException { |
|
ObjectInputStream.GetField fields = in.readFields(); |
|
Map<String, Object> descriptor = cast(fields.get("descriptor", null)); |
|
init(null); |
|
if (descriptor != null) { |
|
descriptorMap.putAll(descriptor); |
|
} |
|
} |
|
|
|
|
|
/** |
|
* Serializes a {@link DescriptorSupport} to an {@link ObjectOutputStream}. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void writeObject(ObjectOutputStream out) throws IOException { |
|
ObjectOutputStream.PutField fields = out.putFields(); |
|
boolean compat = "1.0".equals(serialForm); |
|
if (compat) |
|
fields.put("currClass", currClass); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
SortedMap<String, Object> startMap = descriptorMap; |
|
if (startMap.containsKey("targetObject")) { |
|
startMap = new TreeMap<String, Object>(descriptorMap); |
|
startMap.remove("targetObject"); |
|
} |
|
|
|
final HashMap<String, Object> descriptor; |
|
if (compat || "1.2.0".equals(serialForm) || |
|
"1.2.1".equals(serialForm)) { |
|
descriptor = new HashMap<String, Object>(); |
|
for (Map.Entry<String, Object> entry : startMap.entrySet()) |
|
descriptor.put(entry.getKey().toLowerCase(), entry.getValue()); |
|
} else |
|
descriptor = new HashMap<String, Object>(startMap); |
|
|
|
fields.put("descriptor", descriptor); |
|
out.writeFields(); |
|
} |
|
|
|
} |