提交 4a3cc1c7 编写于 作者: E emcmanus

6336968: Methods to convert AttributeList to/from Map

6750008: Add JMX.getSpecificationVersion(MBeanServerConnection) and document interop
6750472: Add a way to convert a CompositeData into a Map
6752563: Allow CompositeDataSupport to have zero items
Summary: Small JMX RFEs
Reviewed-by: dfuchs
上级 9d04c888
/*
* Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -27,17 +27,23 @@ package javax.management;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Represents a list of values for attributes of an MBean. The methods
* used for the insertion of {@link javax.management.Attribute
* Attribute} objects in the <CODE>AttributeList</CODE> overrides the
* corresponding methods in the superclass
* <CODE>ArrayList</CODE>. This is needed in order to insure that the
* objects contained in the <CODE>AttributeList</CODE> are only
* <CODE>Attribute</CODE> objects. This avoids getting an exception
* when retrieving elements from the <CODE>AttributeList</CODE>.
* <p>Represents a list of values for attributes of an MBean. See the
* {@link MBeanServerConnection#getAttributes getAttributes} and
* {@link MBeanServerConnection#setAttributes setAttributes} methods of
* {@link MBeanServer} and {@link MBeanServerConnection}.</p>
*
* <p id="type-safe">For compatibility reasons, it is possible, though
* highly discouraged, to add objects to an {@code AttributeList} that are
* not instances of {@code Attribute}. However, an {@code AttributeList}
* can be made <em>type-safe</em>, which means that an attempt to add
* an object that is not an {@code Attribute} will produce an {@code
* IllegalArgumentException}. An {@code AttributeList} becomes type-safe
* when the method {@link #asList()} is called on it.</p>
*
* @since 1.5
*/
......@@ -58,8 +64,8 @@ import java.util.List;
*/
public class AttributeList extends ArrayList<Object> {
private transient boolean typeSafe;
private transient boolean tainted;
private transient volatile boolean typeSafe;
private transient volatile boolean tainted;
/* Serial version */
private static final long serialVersionUID = -4077085769279709076L;
......@@ -124,13 +130,63 @@ public class AttributeList extends ArrayList<Object> {
// Check for non-Attribute objects
//
checkTypeSafe(list);
adding(list);
// Build the List<Attribute>
//
super.addAll(list);
}
/**
* <p>Constructs an {@code AttributeList} containing the elements of
* the {@code Map} specified, in the order in which they appear in the
* {@code Map}'s {@link Map#entrySet entrySet}. For each <em>{@code
* key}</em> and <em>{@code value}</em> in the {@code Map}, the constructed
* {@code AttributeList} will contain {@link Attribute#Attribute
* Attribute(<em>key</em>, <em>value</em>)}.</p>
*
* @param map the {@code Map} defining the elements of the new
* {@code AttributeList}.
*/
public AttributeList(Map<String, ?> map) {
for (Map.Entry<String, ?> entry : map.entrySet())
add(new Attribute(entry.getKey(), entry.getValue()));
typeSafe = true;
}
/**
* <p>Return a {@code Map} that is a snapshot of the values in this
* {@code AttributeList}. Each key in the {@code Map} is the {@linkplain
* Attribute#getName() name} of an {@code Attribute} in the list, and each
* value is the corresponding {@linkplain Attribute#getValue() value} of
* that {@code Attribute}. The {@code AttributeList} and the {@code Map}
* are unrelated after the call, that is, changes to one do not affect the
* other.</p>
*
* <p>If the {@code AttributeList} contains more than one {@code Attribute}
* with the same name, then the {@code Map} will contain an entry
* for that name where the value is that of the last of those {@code
* Attribute}s.</p>
*
* @return the new {@code Map}.
*
* @throws IllegalArgumentException if this {@code AttributeList} contains
* an element that is not an {@code Attribute}.
*/
public Map<String, Object> toMap() {
Map<String, Object> map = new LinkedHashMap<String, Object>();
// We can't call adding(this) because we're not necessarily typeSafe
if (tainted)
throw new IllegalArgumentException("AttributeList contains non-Attribute");
for (Object x : this) {
Attribute a = (Attribute) x;
map.put(a.getName(), a.getValue());
}
return map;
}
/**
* Return a view of this list as a {@code List<Attribute>}.
* Changes to the returned value are reflected by changes
......@@ -154,11 +210,9 @@ public class AttributeList extends ArrayList<Object> {
*/
@SuppressWarnings("unchecked")
public List<Attribute> asList() {
if (!typeSafe) {
if (tainted)
checkTypeSafe(this);
typeSafe = true;
}
typeSafe = true;
if (tainted)
adding((Collection<?>) this); // will throw IllegalArgumentException
return (List<Attribute>) (List<?>) this;
}
......@@ -175,7 +229,7 @@ public class AttributeList extends ArrayList<Object> {
* Inserts the attribute specified as an element at the position specified.
* Elements with an index greater than or equal to the current position are
* shifted up. If the index is out of range (index < 0 || index >
* size() a RuntimeOperationsException should be raised, wrapping the
* size()) a RuntimeOperationsException should be raised, wrapping the
* java.lang.IndexOutOfBoundsException thrown.
*
* @param object The <CODE>Attribute</CODE> object to be inserted.
......@@ -245,8 +299,7 @@ public class AttributeList extends ArrayList<Object> {
public boolean addAll(int index, AttributeList list) {
try {
return super.addAll(index, list);
}
catch (IndexOutOfBoundsException e) {
} catch (IndexOutOfBoundsException e) {
throw new RuntimeOperationsException(e,
"The specified index is out of range");
}
......@@ -258,96 +311,77 @@ public class AttributeList extends ArrayList<Object> {
* been called on this instance.
*/
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code element} is not an
* {@code Attribute}.
*/
@Override
public boolean add(Object o) {
if (!tainted)
tainted = isTainted(o);
if (typeSafe)
checkTypeSafe(o);
return super.add(o);
public boolean add(Object element) {
adding(element);
return super.add(element);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code element} is not an
* {@code Attribute}.
*/
@Override
public void add(int index, Object element) {
if (!tainted)
tainted = isTainted(element);
if (typeSafe)
checkTypeSafe(element);
adding(element);
super.add(index, element);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code c} contains an
* element that is not an {@code Attribute}.
*/
@Override
public boolean addAll(Collection<?> c) {
if (!tainted)
tainted = isTainted(c);
if (typeSafe)
checkTypeSafe(c);
adding(c);
return super.addAll(c);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code c} contains an
* element that is not an {@code Attribute}.
*/
@Override
public boolean addAll(int index, Collection<?> c) {
if (!tainted)
tainted = isTainted(c);
if (typeSafe)
checkTypeSafe(c);
adding(c);
return super.addAll(index, c);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException if this {@code AttributeList} is
* <a href="#type-safe">type-safe</a> and {@code element} is not an
* {@code Attribute}.
*/
@Override
public Object set(int index, Object element) {
if (!tainted)
tainted = isTainted(element);
if (typeSafe)
checkTypeSafe(element);
adding(element);
return super.set(index, element);
}
/**
* IllegalArgumentException if o is a non-Attribute object.
*/
private static void checkTypeSafe(Object o) {
try {
o = (Attribute) o;
} catch (ClassCastException e) {
throw new IllegalArgumentException(e);
}
}
/**
* IllegalArgumentException if c contains any non-Attribute objects.
*/
private static void checkTypeSafe(Collection<?> c) {
try {
Attribute a;
for (Object o : c)
a = (Attribute) o;
} catch (ClassCastException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Returns true if o is a non-Attribute object.
*/
private static boolean isTainted(Object o) {
try {
checkTypeSafe(o);
} catch (IllegalArgumentException e) {
return true;
}
return false;
private void adding(Object x) {
if (x == null || x instanceof Attribute)
return;
if (typeSafe)
throw new IllegalArgumentException("Not an Attribute: " + x);
else
tainted = true;
}
/**
* Returns true if c contains any non-Attribute objects.
*/
private static boolean isTainted(Collection<?> c) {
try {
checkTypeSafe(c);
} catch (IllegalArgumentException e) {
return true;
}
return false;
private void adding(Collection<?> c) {
for (Object x : c)
adding(x);
}
}
......@@ -830,4 +830,80 @@ public class JMX {
((DynamicWrapperMBean) mbean).getWrappedObject() : mbean;
return (MBeanInjector.injectsSendNotification(resource));
}
/**
* <p>Return the version of the JMX specification that a (possibly remote)
* MBean Server is using. The JMX specification described in this
* documentation is version 2.0. The earlier versions that might be
* reported by this method are 1.0, 1.1, 1.2, and 1.4. (There is no 1.3.)
* All of these versions and all future versions can be compared using
* {@link String#compareTo(String)}. So, for example, to tell if
* {@code mbsc} is running at least version 2.0 you can write:</p>
*
* <pre>
* String version = JMX.getSpecificationVersion(mbsc, null);
* boolean atLeast2dot0 = (version.compareTo("2.0") >= 0);
* </pre>
*
* <p>A remote MBean Server might be running an earlier version of the
* JMX API, and in that case <a href="package-summary.html#interop">certain
* features</a> might not be available in it.</p>
*
* <p>The version of the MBean Server {@code mbsc} is not necessarily
* the version of all namespaces within that MBean Server, for example
* if some of them use {@link javax.management.namespace.JMXRemoteNamespace
* JMXRemoteNamespace}. To determine the version of the namespace
* that a particular MBean is in, give its name as the {@code mbeanName}
* parameter.</p>
*
* @param mbsc a connection to an MBean Server.
*
* @param mbeanName the name of an MBean within that MBean Server, or null.
* If non-null, the namespace of this name, as determined by
* {@link JMXNamespaces#getContainingNamespace
* JMXNamespaces.getContainingNamespace}, is the one whose specification
* version will be returned.
*
* @return the JMX specification version reported by that MBean Server.
*
* @throws IllegalArgumentException if {@code mbsc} is null, or if
* {@code mbeanName} includes a wildcard character ({@code *} or {@code ?})
* in its namespace.
*
* @throws IOException if the version cannot be obtained, either because
* there is a communication problem or because the remote MBean Server
* does not have the appropriate {@linkplain
* MBeanServerDelegateMBean#getSpecificationVersion() attribute}.
*
* @see <a href="package-summary.html#interop">Interoperability between
* versions of the JMX specification</a>
* @see MBeanServerDelegateMBean#getSpecificationVersion
*/
public static String getSpecificationVersion(
MBeanServerConnection mbsc, ObjectName mbeanName)
throws IOException {
if (mbsc == null)
throw new IllegalArgumentException("Null MBeanServerConnection");
String namespace;
if (mbeanName == null)
namespace = "";
else
namespace = JMXNamespaces.getContainingNamespace(mbeanName);
if (namespace.contains("*") || namespace.contains("?")) {
throw new IllegalArgumentException(
"ObjectName contains namespace wildcard: " + mbeanName);
}
try {
if (namespace.length() > 0)
mbsc = JMXNamespaces.narrowToNamespace(mbsc, namespace);
return (String) mbsc.getAttribute(
MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion");
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}
}
}
......@@ -532,8 +532,30 @@ public interface MBeanServerConnection extends NotificationManager {
/**
* Enables the values of several attributes of a named MBean. The MBean
* is identified by its object name.
* <p>Retrieves the values of several attributes of a named MBean. The MBean
* is identified by its object name.</p>
*
* <p>If one or more attributes cannot be retrieved for some reason, they
* will be omitted from the returned {@code AttributeList}. The caller
* should check that the list is the same size as the {@code attributes}
* array. To discover what problem prevented a given attribute from being
* retrieved, call {@link #getAttribute getAttribute} for that attribute.</p>
*
* <p>Here is an example of calling this method and checking that it
* succeeded in retrieving all the requested attributes:</p>
*
* <pre>
* String[] attrNames = ...;
* AttributeList list = mbeanServerConnection.getAttributes(objectName, attrNames);
* if (list.size() == attrNames.length)
* System.out.println("All attributes were retrieved successfully");
* else {
* {@code List<String>} missing = new {@code ArrayList<String>}(<!--
* -->{@link java.util.Arrays#asList Arrays.asList}(attrNames));
* missing.removeAll(list.toMap().keySet());
* System.out.println("Did not retrieve: " + missing);
* }
* </pre>
*
* @param name The object name of the MBean from which the
* attributes are retrieved.
......@@ -557,6 +579,7 @@ public interface MBeanServerConnection extends NotificationManager {
throws InstanceNotFoundException, ReflectionException,
IOException;
/**
* Sets the value of a specific attribute of a named MBean. The MBean
* is identified by its object name.
......@@ -592,10 +615,36 @@ public interface MBeanServerConnection extends NotificationManager {
ReflectionException, IOException;
/**
* Sets the values of several attributes of a named MBean. The MBean is
* identified by its object name.
* <p>Sets the values of several attributes of a named MBean. The MBean is
* identified by its object name.</p>
*
* <p>If one or more attributes cannot be set for some reason, they will be
* omitted from the returned {@code AttributeList}. The caller should check
* that the input {@code AttributeList} is the same size as the output one.
* To discover what problem prevented a given attribute from being retrieved,
* it will usually be possible to call {@link #setAttribute setAttribute}
* for that attribute, although this is not guaranteed to work. (For
* example, the values of two attributes may have been rejected because
* they were inconsistent with each other. Setting one of them alone might
* be allowed.)<p>
*
* <p>Here is an example of calling this method and checking that it
* succeeded in setting all the requested attributes:</p>
*
* <pre>
* AttributeList inputAttrs = ...;
* AttributeList outputAttrs = mbeanServerConnection.setAttributes(<!--
* -->objectName, inputAttrs);
* if (inputAttrs.size() == outputAttrs.size())
* System.out.println("All attributes were set successfully");
* else {
* {@code List<String>} missing = new {@code ArrayList<String>}(<!--
* -->inputAttrs.toMap().keySet());
* missing.removeAll(outputAttrs.toMap().keySet());
* System.out.println("Did not set: " + missing);
* }
* </pre>
*
* @param name The object name of the MBean within which the
* attributes are to be set.
......@@ -622,7 +671,39 @@ public interface MBeanServerConnection extends NotificationManager {
throws InstanceNotFoundException, ReflectionException, IOException;
/**
* Invokes an operation on an MBean.
* <p>Invokes an operation on an MBean.</p>
*
* <p>Because of the need for a {@code signature} to differentiate
* possibly-overloaded operations, it is much simpler to invoke operations
* through an {@linkplain JMX#newMBeanProxy(MBeanServerConnection, ObjectName,
* Class) MBean proxy} where possible. For example, suppose you have a
* Standard MBean interface like this:</p>
*
* <pre>
* public interface FooMBean {
* public int countMatches(String[] patterns, boolean ignoreCase);
* }
* </pre>
*
* <p>The {@code countMatches} operation can be invoked as follows:</p>
*
* <pre>
* String[] myPatterns = ...;
* int count = (Integer) mbeanServerConnection.invoke(
* objectName,
* "countMatches",
* new Object[] {myPatterns, true},
* new String[] {String[].class.getName(), boolean.class.getName()});
* </pre>
*
* <p>Alternatively, it can be invoked through a proxy as follows:</p>
*
* <pre>
* String[] myPatterns = ...;
* FooMBean fooProxy = JMX.newMBeanProxy(
* mbeanServerConnection, objectName, FooMBean.class);
* int count = fooProxy.countMatches(myPatterns, true);
* </pre>
*
* @param name The object name of the MBean on which the method is
* to be invoked.
......@@ -630,7 +711,8 @@ public interface MBeanServerConnection extends NotificationManager {
* @param params An array containing the parameters to be set when
* the operation is invoked
* @param signature An array containing the signature of the
* operation. The class objects will be loaded using the same
* operation, an array of class names in the format returned by
* {@link Class#getName()}. The class objects will be loaded using the same
* class loader as the one used for loading the MBean on which the
* operation was invoked.
*
......
......@@ -64,6 +64,33 @@ package javax.management;
* MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
* </pre>
*
* <p>The following code prints a message every time an MBean is registered
* or unregistered in the MBean Server {@code mbeanServer}:</p>
*
* <pre>
* private static final NotificationListener printListener = new NotificationListener() {
* public void handleNotification(Notification n, Object handback) {
* if (!(n instanceof MBeanServerNotification)) {
* System.out.println("Ignored notification of class " + n.getClass().getName());
* return;
* }
* MBeanServerNotification mbsn = (MBeanServerNotification) n;
* String what;
* if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
* what = "MBean registered";
* else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
* what = "MBean unregistered";
* else
* what = "Unknown type " + n.getType();
* System.out.println("Received MBean Server notification: " + what + ": " +
* mbsn.getMBeanName());
* };
*
* ...
* mbeanServer.addNotificationListener(
* MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
* </pre>
*
* @since 1.5
*/
public class MBeanServerNotification extends Notification {
......
......@@ -26,7 +26,6 @@
package javax.management;
import com.sun.jmx.mbeanserver.NotificationMBeanSupport;
import com.sun.jmx.mbeanserver.Util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
......@@ -43,6 +42,11 @@ import java.util.Set;
* on both the client and the server in the remote case, so using this class
* instead is recommended where possible.</p>
*
* <p>Because this class was introduced in version 2.0 of the JMX API,
* it may not be present on a remote JMX agent that is running an earlier
* version. The method {@link JMX#getSpecificationVersion
* JMX.getSpecificationVersion} can be used to determine the remote version.</p>
*
* <p>This class uses the {@linkplain Query Query API} to specify the
* filtering logic. For example, to select only notifications where the
* {@linkplain Notification#getType() type} is {@code "com.example.mytype"},
......
......@@ -33,12 +33,14 @@ import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
// jmx import
import java.util.TreeSet;
//
......@@ -60,16 +62,15 @@ public class CompositeDataSupport
* respective values.
* A {@link SortedMap} is used for faster retrieval of elements.
*/
private SortedMap<String, Object> contents = new TreeMap<String, Object>();
private final SortedMap<String, Object> contents;
/**
* @serial The <i>composite type </i> of this <i>composite data</i> instance.
*/
private CompositeType compositeType;
private final CompositeType compositeType;
/**
* <p>
* Constructs a <tt>CompositeDataSupport</tt> instance with the specified
* <p>Constructs a <tt>CompositeDataSupport</tt> instance with the specified
* <tt>compositeType</tt>, whose item values
* are specified by <tt>itemValues[]</tt>, in the same order as in
* <tt>itemNames[]</tt>.
......@@ -79,103 +80,67 @@ public class CompositeDataSupport
* The items contained in this <tt>CompositeDataSupport</tt> instance are
* internally stored in a <tt>TreeMap</tt>,
* thus sorted in ascending lexicographic order of their names, for faster
* retrieval of individual item values.
* <p>
* The constructor checks that all the constraints listed below for each
* retrieval of individual item values.</p>
*
* <p>The constructor checks that all the constraints listed below for each
* parameter are satisfied,
* and throws the appropriate exception if they are not.
* <p>
* @param compositeType the <i>composite type </i> of this <i>composite
* data</i> instance;
* must not be null.
* <p>
* @param itemNames <tt>itemNames</tt> must list, in any order, all the
* item names defined in <tt>compositeType</tt>;
* the order in which the names are listed, is used to
* match values in <tt>itemValues[]</tt>;
* must not be null or empty.
* <p>
* @param itemValues the values of the items, listed in the same order as
* their respective names in <tt>itemNames</tt>;
* each item value can be null, but if it is non-null it must be
* a valid value for the open type defined in <tt>compositeType</tt> for the corresponding item;
* must be of the same size as <tt>itemNames</tt>; must not be null or empty.
* <p>
* @throws IllegalArgumentException <tt>compositeType</tt> is null, or <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null or empty,
* or one of the elements in <tt>itemNames[]</tt> is a null or empty string,
* or <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size.
* <p>
* @throws OpenDataException <tt>itemNames[]</tt> or <tt>itemValues[]</tt>'s size differs from
* the number of items defined in <tt>compositeType</tt>,
* or one of the elements in <tt>itemNames[]</tt> does not exist as an item name defined in <tt>compositeType</tt>,
* or one of the elements in <tt>itemValues[]</tt> is not a valid value for the corresponding item
* as defined in <tt>compositeType</tt>.
* <p>
* and throws the appropriate exception if they are not.</p>
*
* @param compositeType the <i>composite type </i> of this <i>composite
* data</i> instance; must not be null.
*
* @param itemNames <tt>itemNames</tt> must list, in any order, all the
* item names defined in <tt>compositeType</tt>; the order in which the
* names are listed, is used to match values in <tt>itemValues[]</tt>; must
* not be null.
*
* @param itemValues the values of the items, listed in the same order as
* their respective names in <tt>itemNames</tt>; each item value can be
* null, but if it is non-null it must be a valid value for the open type
* defined in <tt>compositeType</tt> for the corresponding item; must be of
* the same size as <tt>itemNames</tt>; must not be null.
*
* @throws IllegalArgumentException <tt>compositeType</tt> is null, or
* <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null or empty, or one
* of the elements in <tt>itemNames[]</tt> is a null or empty string, or
* <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size.
*
* @throws OpenDataException <tt>itemNames[]</tt> or
* <tt>itemValues[]</tt>'s size differs from the number of items defined in
* <tt>compositeType</tt>, or one of the elements in <tt>itemNames[]</tt>
* does not exist as an item name defined in <tt>compositeType</tt>, or one
* of the elements in <tt>itemValues[]</tt> is not a valid value for the
* corresponding item as defined in <tt>compositeType</tt>.
*/
public CompositeDataSupport(CompositeType compositeType, String[] itemNames, Object[] itemValues)
throws OpenDataException {
// Check compositeType is not null
//
if (compositeType == null) {
throw new IllegalArgumentException("Argument compositeType cannot be null.");
}
// item names defined in compositeType:
Set<String> namesSet = compositeType.keySet();
// Check the array itemNames is not null or empty (length!=0) and
// that there is no null element or empty string in it
//
checkForNullElement(itemNames, "itemNames");
checkForEmptyString(itemNames, "itemNames");
public CompositeDataSupport(
CompositeType compositeType, String[] itemNames, Object[] itemValues)
throws OpenDataException {
this(makeMap(itemNames, itemValues), compositeType);
}
// Check the array itemValues is not null or empty (length!=0)
// (NOTE: we allow null values as array elements)
//
if ( (itemValues == null) || (itemValues.length == 0) ) {
throw new IllegalArgumentException("Argument itemValues[] cannot be null or empty.");
}
private static SortedMap<String, Object> makeMap(
String[] itemNames, Object[] itemValues)
throws OpenDataException {
// Check that the sizes of the 2 arrays itemNames and itemValues are the same
//
if (itemNames == null || itemValues == null)
throw new IllegalArgumentException("Null itemNames or itemValues");
if (itemNames.length != itemValues.length) {
throw new IllegalArgumentException("Array arguments itemNames[] and itemValues[] "+
"should be of same length (got "+ itemNames.length +
" and "+ itemValues.length +").");
}
// Check the size of the 2 arrays is equal to the number of items defined in compositeType
//
if (itemNames.length != namesSet.size()) {
throw new OpenDataException("The size of array arguments itemNames[] and itemValues[] should be equal to the number of items defined"+
" in argument compositeType (found "+ itemNames.length +" elements in itemNames[] and itemValues[],"+
" expecting "+ namesSet.size() +" elements according to compositeType.");
}
// Check parameter itemNames[] contains all names defined in the compositeType of this instance
//
if ( ! Arrays.asList(itemNames).containsAll(namesSet) ) {
throw new OpenDataException("Argument itemNames[] does not contain all names defined in the compositeType of this instance.");
throw new IllegalArgumentException(
"Different lengths: itemNames[" + itemNames.length +
"], itemValues[" + itemValues.length + "]");
}
// Check each element of itemValues[], if not null, is of the open type defined for the corresponding item
//
OpenType<?> itemType;
for (int i=0; i<itemValues.length; i++) {
itemType = compositeType.getType(itemNames[i]);
if ( (itemValues[i] != null) && (! itemType.isValue(itemValues[i])) ) {
throw new OpenDataException("Argument's element itemValues["+ i +"]=\""+ itemValues[i] +"\" is not a valid value for"+
" this item (itemName="+ itemNames[i] +",itemType="+ itemType +").");
}
SortedMap<String, Object> map = new TreeMap<String, Object>();
for (int i = 0; i < itemNames.length; i++) {
String name = itemNames[i];
if (name == null || name.equals(""))
throw new IllegalArgumentException("Null or empty item name");
if (map.containsKey(name))
throw new OpenDataException("Duplicate item name " + name);
map.put(itemNames[i], itemValues[i]);
}
// Initialize internal fields: compositeType and contents
//
this.compositeType = compositeType;
for (int i=0; i<itemNames.length; i++) {
this.contents.put(itemNames[i], itemValues[i]);
}
return map;
}
/**
......@@ -184,64 +149,99 @@ public class CompositeDataSupport
* are given by the mappings in the map <tt>items</tt>.
* This constructor converts the keys to a string array and the values to an object array and calls
* <tt>CompositeDataSupport(javax.management.openmbean.CompositeType, java.lang.String[], java.lang.Object[])</tt>.
* <p>
*
* @param compositeType the <i>composite type </i> of this <i>composite data</i> instance;
* must not be null.
* <p>
* @param items the mappings of all the item names to their values;
* <tt>items</tt> must contain all the item names defined in <tt>compositeType</tt>;
* must not be null or empty.
* <p>
* @throws IllegalArgumentException <tt>compositeType</tt> is null, or <tt>items</tt> is null or empty,
* or one of the keys in <tt>items</tt> is a null or empty string,
* or one of the values in <tt>items</tt> is null.
* <p>
* @throws OpenDataException <tt>items</tt>' size differs from the number of items defined in <tt>compositeType</tt>,
* or one of the keys in <tt>items</tt> does not exist as an item name defined in <tt>compositeType</tt>,
* or one of the values in <tt>items</tt> is not a valid value for the corresponding item
* as defined in <tt>compositeType</tt>.
* <p>
* @throws ArrayStoreException one or more keys in <tt>items</tt> is not of the class <tt>java.lang.String</tt>.
* <p>
* must not be null.
*
* @throws IllegalArgumentException <tt>compositeType</tt> is null, or
* <tt>items</tt> is null, or one of the keys in <tt>items</tt> is a null
* or empty string.
* @throws OpenDataException <tt>items</tt>' size differs from the
* number of items defined in <tt>compositeType</tt>, or one of the
* keys in <tt>items</tt> does not exist as an item name defined in
* <tt>compositeType</tt>, or one of the values in <tt>items</tt>
* is not a valid value for the corresponding item as defined in
* <tt>compositeType</tt>.
* @throws ArrayStoreException one or more keys in <tt>items</tt> is not of
* the class <tt>java.lang.String</tt>.
*
* @see #toMap
*/
public CompositeDataSupport(CompositeType compositeType,
Map<String,?> items)
throws OpenDataException {
this(makeMap(items), compositeType);
}
// Let the other constructor do the job, as the call to another constructor must be the first call
//
this( compositeType,
(items==null ? null : items.keySet().toArray(new String[items.size()])), // may raise an ArrayStoreException
(items==null ? null : items.values().toArray()) );
private static SortedMap<String, Object> makeMap(Map<String, ?> items) {
if (items == null)
throw new IllegalArgumentException("Null items map");
if (items.containsKey(null) || items.containsKey(""))
throw new IllegalArgumentException("Null or empty item name");
SortedMap<String, Object> map = new TreeMap<String, Object>();
for (Object key : items.keySet()) {
if (!(key instanceof String)) {
throw new ArrayStoreException("Item name is not string: " + key);
// This can happen because of erasure. The particular
// exception is a historical artifact - an implementation
// detail that leaked into the API.
}
map.put((String) key, items.get(key));
}
return map;
}
/**
*
*/
private static void checkForNullElement(Object[] arg, String argName) {
if ( (arg == null) || (arg.length == 0) ) {
throw new IllegalArgumentException(
"Argument "+ argName +"[] cannot be null or empty.");
private CompositeDataSupport(
SortedMap<String, Object> items, CompositeType compositeType)
throws OpenDataException {
// Check compositeType is not null
//
if (compositeType == null) {
throw new IllegalArgumentException("Argument compositeType cannot be null.");
}
for (int i=0; i<arg.length; i++) {
if (arg[i] == null) {
throw new IllegalArgumentException(
"Argument's element "+ argName +"["+ i +"] cannot be null.");
// item names defined in compositeType:
Set<String> namesFromType = compositeType.keySet();
Set<String> namesFromItems = items.keySet();
// This is just a comparison, but we do it this way for a better
// exception message.
if (!namesFromType.equals(namesFromItems)) {
Set<String> extraFromType = new TreeSet<String>(namesFromType);
extraFromType.removeAll(namesFromItems);
Set<String> extraFromItems = new TreeSet<String>(namesFromItems);
extraFromItems.removeAll(namesFromType);
if (!extraFromType.isEmpty() || !extraFromItems.isEmpty()) {
throw new OpenDataException(
"Item names do not match CompositeType: " +
"names in items but not in CompositeType: " + extraFromItems +
"; names in CompositeType but not in items: " + extraFromType);
}
}
}
/**
*
*/
private static void checkForEmptyString(String[] arg, String argName) {
for (int i=0; i<arg.length; i++) {
if (arg[i].trim().equals("")) {
throw new IllegalArgumentException(
"Argument's element "+ argName +"["+ i +"] cannot be an empty string.");
// Check each value, if not null, is of the open type defined for the
// corresponding item
for (String name : namesFromType) {
Object value = items.get(name);
if (value != null) {
OpenType<?> itemType = compositeType.getType(name);
if (!itemType.isValue(value)) {
throw new OpenDataException(
"Argument value of wrong type for item " + name +
": value " + value + ", type " + itemType);
}
}
}
// Initialize internal fields: compositeType and contents
//
this.compositeType = compositeType;
this.contents = items;
}
/**
......@@ -328,6 +328,54 @@ public class CompositeDataSupport
return Collections.unmodifiableCollection(contents.values());
}
/**
* <p>Returns a Map representing the contents of the given CompositeData.
* Each item in the CompositeData is represented by an entry in the map,
* where the name and value of the item are the key and value of the entry.
* The returned value is modifiable but modifications to it have no effect
* on the original CompositeData.</p>
*
* <p>For example, if you have a CompositeData {@code cd1} and you want
* to produce another CompositeData {@code cd2} which is the same except
* that the value of its {@code id} item has been changed to 253, you
* could write:</p>
*
* <pre>
* CompositeData cd1 = ...;
* {@code Map<String, Object>} map = CompositeDataSupport.toMap(cd1);
* assert(map.get("id") instanceof Integer);
* map.put("id", 253);
* CompositeData cd2 = {@link #CompositeDataSupport(CompositeType, Map)
* new CompositeDataSupport}(cd1.getCompositeType(), map);
* </pre>
*
* <p>Logically, this method would be a method in the {@link CompositeData}
* interface, but cannot be for compatibility reasons.</p>
*
* @param cd the CompositeData to convert to a Map.
*
* @return a Map that is a copy of the contents of {@code cd}.
*
* @throws IllegalArgumentException if {@code cd} is null.
*
* @see #CompositeDataSupport(CompositeType, Map)
*/
public static Map<String, Object> toMap(CompositeData cd) {
if (cd == null)
throw new IllegalArgumentException("Null argument");
// If we really wanted, we could check whether cd is a
// CompositeDataSupport and return a copy of cd.contents if so,
// but I don't think that would be substantially faster.
Map<String, Object> map = new LinkedHashMap<String, Object>();
CompositeType ct = cd.getCompositeType();
for (String key : ct.keySet()) {
Object value = cd.get(key);
map.put(key, value);
}
return map;
}
/**
* Compares the specified <var>obj</var> parameter with this
* <code>CompositeDataSupport</code> instance for equality.
......
<html>
<head>
<title>javax.management package</title>
<!--
<head>
<title>javax.management package</title>
<!--
Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
......@@ -24,37 +24,37 @@ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
CA 95054 USA or visit www.sun.com if you need additional information or
have any questions.
-->
</head>
<body bgcolor="white">
<p>Provides the core classes for the Java Management Extensions.</p>
-->
</head>
<body bgcolor="white">
<p>Provides the core classes for the Java Management Extensions.</p>
<p>The Java Management Extensions
(JMX<sup><font size="-1">TM</font></sup>) API is a standard
API for management and monitoring. Typical uses include:</p>
<p>The Java Management Extensions
(JMX<sup><font size="-1">TM</font></sup>) API is a standard
API for management and monitoring. Typical uses include:</p>
<ul>
<li>consulting and changing application configuration</li>
<ul>
<li>consulting and changing application configuration</li>
<li>accumulating statistics about application behavior and
making them available</li>
<li>accumulating statistics about application behavior and
making them available</li>
<li>notifying of state changes and erroneous conditions.</li>
</ul>
<li>notifying of state changes and erroneous conditions.</li>
</ul>
<p>The JMX API can also be used as part of a solution for
managing systems, networks, and so on.</p>
<p>The JMX API can also be used as part of a solution for
managing systems, networks, and so on.</p>
<p>The API includes remote access, so a remote management
program can interact with a running application for these
purposes.</p>
<p>The API includes remote access, so a remote management
program can interact with a running application for these
purposes.</p>
<h2>MBeans</h2>
<h2>MBeans</h2>
<p>The fundamental notion of the JMX API is the <em>MBean</em>.
An MBean is a named <em>managed object</em> representing a
resource. It has a <em>management interface</em> consisting
of:</p>
<p>The fundamental notion of the JMX API is the <em>MBean</em>.
An MBean is a named <em>managed object</em> representing a
resource. It has a <em>management interface</em> consisting
of:</p>
<ul>
<li>named and typed attributes that can be read and/or
......@@ -92,40 +92,40 @@ have any questions.
<pre>
public interface ConfigurationMBean {
public int getCacheSize();
public void setCacheSize(int size);
public long getLastChangedTime();
public void save();
public int getCacheSize();
public void setCacheSize(int size);
public long getLastChangedTime();
public void save();
}
</pre>
</pre>
<p>The methods <code>getCacheSize</code> and
<code>setCacheSize</code> define a read-write attribute of
type <code>int</code> called <code>CacheSize</code> (with an
initial capital, unlike the JavaBeans convention).</p>
<p>The methods <code>getCacheSize</code> and
<code>setCacheSize</code> define a read-write attribute of
type <code>int</code> called <code>CacheSize</code> (with an
initial capital, unlike the JavaBeans convention).</p>
<p>The method <code>getLastChangedTime</code> defines an
attribute of type <code>long</code> called
<code>LastChangedTime</code>. This is a read-only attribute,
since there is no method <code>setLastChangedTime</code>.</p>
<p>The method <code>getLastChangedTime</code> defines an
attribute of type <code>long</code> called
<code>LastChangedTime</code>. This is a read-only attribute,
since there is no method <code>setLastChangedTime</code>.</p>
<p>The method <code>save</code> defines an operation called
<code>save</code>. It is not an attribute, since its name
does not begin with <code>get</code>, <code>set</code>, or
<code>is</code>.</p>
<p>The method <code>save</code> defines an operation called
<code>save</code>. It is not an attribute, since its name
does not begin with <code>get</code>, <code>set</code>, or
<code>is</code>.</p>
<p>The exact naming patterns for Standard MBeans are detailed in
the <a href="#spec">JMX Specification</a>.</p>
<p>The exact naming patterns for Standard MBeans are detailed in
the <a href="#spec">JMX Specification</a>.</p>
<p>There are two ways to make a Java object that is an MBean
with this management interface. One is for the object to be
of a class that has exactly the same name as the Java
interface but without the <code>MBean</code> suffix. So in
the example the object would be of the class
<code>Configuration</code>, in the same Java package as
<code>ConfigurationMBean</code>. The second way is to use the
{@link javax.management.StandardMBean StandardMBean}
class.</p>
<p>There are two ways to make a Java object that is an MBean
with this management interface. One is for the object to be
of a class that has exactly the same name as the Java
interface but without the <code>MBean</code> suffix. So in
the example the object would be of the class
<code>Configuration</code>, in the same Java package as
<code>ConfigurationMBean</code>. The second way is to use the
{@link javax.management.StandardMBean StandardMBean}
class.</p>
<h3 id="stdannot">Defining Standard MBeans with annotations</h3>
......@@ -272,37 +272,37 @@ have any questions.
<pre>
int cacheSize = mbs.getAttribute(name, "CacheSize");
{@link javax.management.Attribute Attribute} newCacheSize =
new Attribute("CacheSize", new Integer(2000));
new Attribute("CacheSize", new Integer(2000));
mbs.setAttribute(name, newCacheSize);
mbs.invoke(name, "save", new Object[0], new Class[0]);
</pre>
</pre>
<p id="proxy">Alternatively, if you have a Java interface that
corresponds to the management interface for the MBean, you can use an
<em>MBean proxy</em> like this:</p>
<pre>
<pre>
ConfigurationMBean conf =
{@link javax.management.JMX#newMBeanProxy
JMX.newMBeanProxy}(mbs, name, ConfigurationMBean.class);
int cacheSize = conf.getCacheSize();
conf.setCacheSize(2000);
conf.save();
</pre>
</pre>
<p>Using an MBean proxy is just a convenience. The second
example ends up calling the same <code>MBeanServer</code>
operations as the first one.</p>
<p>Using an MBean proxy is just a convenience. The second
example ends up calling the same <code>MBeanServer</code>
operations as the first one.</p>
<p>An MBean Server can be queried for MBeans whose names match
certain patterns and/or whose attributes meet certain
constraints. Name patterns are constructed using the {@link
javax.management.ObjectName ObjectName} class and constraints
are constructed using the {@link javax.management.Query Query}
class. The methods {@link
javax.management.MBeanServer#queryNames queryNames} and {@link
javax.management.MBeanServer#queryMBeans queryMBeans} then
perform the query.</p>
<p>An MBean Server can be queried for MBeans whose names match
certain patterns and/or whose attributes meet certain
constraints. Name patterns are constructed using the {@link
javax.management.ObjectName ObjectName} class and constraints
are constructed using the {@link javax.management.Query Query}
class. The methods {@link
javax.management.MBeanServer#queryNames queryNames} and {@link
javax.management.MBeanServer#queryMBeans queryMBeans} then
perform the query.</p>
<h3>MBean lifecycle and resource injection</h3>
......@@ -407,6 +407,92 @@ have any questions.
So for example an SNMP GET operation might result in a
<code>getAttribute</code> on the MBean Server.</p>
<h3 id="interop">Interoperability between versions of the JMX
specification</h3>
<p>When a client connects to a server using the JMX Remote
API, it is possible that they do not have the same version
of the JMX specification. The version of the JMX
specification described here is version 2.0. Previous
versions were 1.0, 1.1, 1.2, and 1.4. (There was no 1.3.)
The standard JMX Remote API is defined to work with version
1.2 onwards, so in standards-based deployment the only
interoperability questions that arise concern version 1.2
onwards.</p>
<p>Every version of the JMX specification continues to
implement the features of previous versions. So when the
client is running an earlier version than the server, there
should not be any interoperability concerns. The only
exception is the unlikely one where a pre-2.0 client used
the string {@code //} in the domain part of an {@link
javax.management.ObjectName ObjectName}.</p>
<p>When the client is running a later version than the server,
certain newer features may not be available, as detailed in
the next sections. The method {@link
javax.management.JMX#getSpecificationVersion
JMX.getSpecificationVersion} can be used to determine the
server version to check if required features are
available.</p>
<h4 id="interop-1.4">If the remote MBean Server is 1.4</h4>
<ul>
<li><p>You cannot use {@link
javax.management.QueryNotificationFilter
QueryNotificationFilter} in {@link
javax.management.MBeanServerConnection#addNotificationListener
addNotificationListener} since this class did not exist
in 1.4.</p>
<li><p>In an attribute in a query, you cannot access values
inside complex types using dot syntax, for example
{@link javax.management.Query#attr Query.attr}{@code
("HeapMemoryUsage.used")}.</p>
<li><p>The packages {@link javax.management.event} and
{@link javax.management.namespace} did not exist in 1.4,
so you cannot remotely create instances of the MBeans
they define.</p>
<li><p>Even if the remote MBean Server is 2.0, you cannot in
general suppose that {@link
javax.management.event.EventClient EventClient} or
{@link javax.management.ClientContext ClientContext}
will work there without first checking. If the remote
MBean Server is 1.4 then those checks will return false.
An attempt to use these features without checking will
fail in the same way as for a remote 2.0 that is not
configured to support them.</p>
</ul>
<h4 id="interop-1.2">If the remote MBean Server is 1.2</h4>
<p><b>In addition to the above</b>,</p>
<ul>
<li><p>You cannot use wildcards in a key property of an
{@link javax.management.ObjectName ObjectName}, for
example {@code domain:type=Foo,name=*}. Wildcards that
match whole properties are still allowed, for example
{@code *:*} or {@code *:type=Foo,*}.</p>
<li><p>You cannot use {@link
javax.management.Query#isInstanceOf Query.isInstanceOf}
in a query.</p>
<li><p>You cannot use dot syntax such as {@code
HeapMemoryUsage.used} in the {@linkplain
javax.management.monitor.Monitor#setObservedAttribute
observed attribute} of a monitor, as described in the
documentation for the {@link javax.management.monitor}
package.</p>
</ul>
<p id="spec">
@see <a href="{@docRoot}/../technotes/guides/jmx/index.html">
Java SE 6 Platform documentation on JMX technology</a>
......
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6336968
* @summary Test AttributeList.toMap
* @author Eamonn McManus
*/
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.management.Attribute;
import javax.management.AttributeList;
public class AttributeListMapTest {
private static String failure;
public static void main(String[] args) throws Exception {
AttributeList attrs = new AttributeList(Arrays.asList(
new Attribute("Str", "Five"),
new Attribute("Int", 5),
new Attribute("Flt", 5.0)));
Map<String, Object> map = attrs.toMap();
final Map<String, Object> expectMap = new HashMap<String, Object>();
for (Attribute attr : attrs.asList())
expectMap.put(attr.getName(), attr.getValue());
assertEquals("Initial map", expectMap, map);
assertEquals("Initial map size", 3, map.size());
assertEquals("Name set", expectMap.keySet(), map.keySet());
assertEquals("Values", new HashSet<Object>(expectMap.values()),
new HashSet<Object>(map.values()));
assertEquals("Entry set", expectMap.entrySet(), map.entrySet());
AttributeList attrs2 = new AttributeList(map);
assertEquals("AttributeList from Map", attrs, attrs2);
// This assumes that the Map conserves the order of the attributes,
// which is not specified but true because we use LinkedHashMap.
// Check that toMap fails if the list contains non-Attribute elements.
AttributeList attrs3 = new AttributeList(attrs);
attrs3.add("Hello"); // allowed but curious
try {
map = attrs3.toMap();
fail("toMap succeeded on list with non-Attribute elements");
} catch (Exception e) {
assertEquals("Exception for toMap with non-Atttribute elements",
IllegalArgumentException.class, e.getClass());
}
// Check that the Map does not reflect changes made to the list after
// the Map was obtained.
AttributeList attrs4 = new AttributeList(attrs);
map = attrs4.toMap();
attrs4.add(new Attribute("Big", new BigInteger("5")));
assertEquals("Map after adding element to list", expectMap, map);
// Check that if there is more than one Attribute with the same name
// then toMap() chooses the last of them.
AttributeList attrs5 = new AttributeList(attrs);
attrs5.add(new Attribute("Str", "Cinq"));
map = attrs5.toMap();
assertEquals("Size of Map for list with duplicate attribute name",
3, map.size());
Object value = map.get("Str");
assertEquals("Value of Str in Map for list with two values for it",
"Cinq", value);
if (failure == null)
System.out.println("TEST PASSED");
else
throw new Exception("TEST FAILED: " + failure);
}
private static void assertEquals(String what, Object expect, Object actual) {
if (eq(expect, actual))
System.out.println("OK: " + what);
else
fail(what + ": expected " + expect + ", got " + actual);
}
private static boolean eq(Object x, Object y) {
return (x == null) ? (y == null) : x.equals(y);
}
private static void fail(String why) {
System.out.println("FAIL: " + why);
failure = why;
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6336968
* @summary Test adding non-Attribute values to an AttributeList.
* @author Eamonn McManus
*/
import java.util.Collections;
import java.util.List;
import javax.management.Attribute;
import javax.management.AttributeList;
public class AttributeListTypeSafeTest {
private static String failure;
public static void main(String[] args) throws Exception {
// Test calling asList after adding non-Attribute by various means
for (Op op : Op.values()) {
AttributeList alist = new AttributeList();
alist.add(new Attribute("foo", "bar"));
doOp(alist, op);
String what = "asList() after calling " + op + " with non-Attribute";
try {
List<Attribute> lista = alist.asList();
fail(what + ": succeeded but should not have");
} catch (IllegalArgumentException e) {
System.out.println("OK: " + what + ": got IllegalArgumentException");
}
}
// Test adding non-Attribute by various means after calling asList
for (Op op : Op.values()) {
AttributeList alist = new AttributeList();
List<Attribute> lista = alist.asList();
lista.add(new Attribute("foo", "bar"));
String what = op + " with non-Attribute after calling asList()";
try {
doOp(alist, op);
fail(what + ": succeeded but should not have");
} catch (IllegalArgumentException e) {
System.out.println("OK: " + what + ": got IllegalArgumentException");
}
}
if (failure == null)
System.out.println("TEST PASSED");
else
throw new Exception("TEST FAILED: " + failure);
}
private static enum Op {
ADD("add(Object)"), ADD_AT("add(int, Object)"),
ADD_ALL("add(Collection)"), ADD_ALL_AT("add(int, Collection)"),
SET("set(int, Object)");
private Op(String what) {
this.what = what;
}
@Override
public String toString() {
return what;
}
private final String what;
}
private static void doOp(AttributeList alist, Op op) {
Object x = "oops";
switch (op) {
case ADD: alist.add(x); break;
case ADD_AT: alist.add(0, x); break;
case ADD_ALL: alist.add(Collections.singleton(x)); break;
case ADD_ALL_AT: alist.add(0, Collections.singleton(x)); break;
case SET: alist.set(0, x); break;
default: throw new AssertionError("Case not covered");
}
}
private static void fail(String why) {
System.out.println("FAIL: " + why);
failure = why;
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6750472 6752563
* @summary Test CompositeDataSupport.toMap.
* @author Eamonn McManus
* @run main/othervm -ea CompositeDataToMapTest
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
public class CompositeDataToMapTest {
private static class IdentityInvocationHandler implements InvocationHandler {
private final Object wrapped;
public IdentityInvocationHandler(Object wrapped) {
this.wrapped = wrapped;
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
try {
return m.invoke(wrapped, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
}
private static <T> T wrap(T x, Class<T> intf) {
InvocationHandler ih = new IdentityInvocationHandler(x);
return intf.cast(Proxy.newProxyInstance(
intf.getClassLoader(), new Class<?>[] {intf}, ih));
}
public static void main(String[] args) throws Exception {
if (!CompositeDataToMapTest.class.desiredAssertionStatus())
throw new AssertionError("Must be run with -ea");
CompositeType emptyCT = new CompositeType(
"empty", "empty", new String[0], new String[0], new OpenType<?>[0]);
CompositeData emptyCD = new CompositeDataSupport(
emptyCT, Collections.<String, Object>emptyMap());
assert CompositeDataSupport.toMap(emptyCD).isEmpty() :
"Empty CD produces empty Map";
CompositeData emptyCD2 = new CompositeDataSupport(
emptyCT, new String[0], new Object[0]);
assert emptyCD.equals(emptyCD2) : "Empty CD can be constructed two ways";
CompositeType namedNumberCT = new CompositeType(
"NamedNumber", "NamedNumber",
new String[] {"name", "number"},
new String[] {"name", "number"},
new OpenType<?>[] {SimpleType.STRING, SimpleType.INTEGER});
Map<String, Object> namedNumberMap = new HashMap<String, Object>();
namedNumberMap.put("name", "Deich");
namedNumberMap.put("number", 10);
CompositeData namedNumberCD = new CompositeDataSupport(
namedNumberCT, namedNumberMap);
assert CompositeDataSupport.toMap(namedNumberCD).equals(namedNumberMap) :
"Map survives passage through CompositeData";
namedNumberCD = wrap(namedNumberCD, CompositeData.class);
assert CompositeDataSupport.toMap(namedNumberCD).equals(namedNumberMap) :
"Map survives passage through wrapped CompositeData";
namedNumberMap = CompositeDataSupport.toMap(namedNumberCD);
namedNumberMap.put("name", "Ceathar");
namedNumberMap.put("number", 4);
namedNumberCD = new CompositeDataSupport(namedNumberCT, namedNumberMap);
assert CompositeDataSupport.toMap(namedNumberCD).equals(namedNumberMap) :
"Modified Map survives passage through CompositeData";
try {
namedNumberMap = CompositeDataSupport.toMap(null);
assert false : "Null toMap arg provokes exception";
} catch (Exception e) {
assert e instanceof IllegalArgumentException :
"Exception for null toMap arg is IllegalArgumentException";
}
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6750008
* @summary Test JMX.getSpecificationVersion
* @author Eamonn McManus
*/
import java.io.IOException;
import java.util.Collections;
import java.util.ListIterator;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InstanceNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMX;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerDelegateMBean;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.StandardMBean;
import javax.management.namespace.JMXNamespace;
import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.MBeanServerSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
public class JMXSpecVersionTest {
private static String failure;
private static final Object POISON_PILL = new Object();
private static class FakeDelegate implements DynamicMBean {
private final Object specVersion;
private final DynamicMBean delegate = new StandardMBean(
new MBeanServerDelegate(), MBeanServerDelegateMBean.class, false);
FakeDelegate(Object specVersion) {
this.specVersion = specVersion;
}
public Object getAttribute(String attribute)
throws AttributeNotFoundException, MBeanException,
ReflectionException {
if ("SpecificationVersion".equals(attribute)) {
if (specVersion == POISON_PILL)
throw new AttributeNotFoundException(attribute);
else
return specVersion;
} else
return delegate.getAttribute(attribute);
}
public void setAttribute(Attribute attribute)
throws AttributeNotFoundException, InvalidAttributeValueException,
MBeanException, ReflectionException {
delegate.setAttribute(attribute);
}
public AttributeList getAttributes(String[] attributes) {
AttributeList list = delegate.getAttributes(attributes);
for (ListIterator<Attribute> it = list.asList().listIterator();
it.hasNext(); ) {
Attribute attr = it.next();
if (attr.getName().equals("SpecificationVersion")) {
it.remove();
if (specVersion != POISON_PILL) {
attr = new Attribute(attr.getName(), specVersion);
it.add(attr);
}
}
}
return list;
}
public AttributeList setAttributes(AttributeList attributes) {
return delegate.setAttributes(attributes);
}
public Object invoke(String actionName, Object[] params,
String[] signature) throws MBeanException,
ReflectionException {
return delegate.invoke(actionName, params, signature);
}
public MBeanInfo getMBeanInfo() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
private static class MBeanServerWithVersion extends MBeanServerSupport {
private final DynamicMBean delegate;
public MBeanServerWithVersion(Object specVersion) {
this.delegate = new FakeDelegate(specVersion);
}
@Override
public DynamicMBean getDynamicMBeanFor(ObjectName name)
throws InstanceNotFoundException {
if (MBeanServerDelegate.DELEGATE_NAME.equals(name))
return delegate;
else
throw new InstanceNotFoundException(name);
}
@Override
protected Set<ObjectName> getNames() {
return Collections.singleton(MBeanServerDelegate.DELEGATE_NAME);
}
}
private static class EmptyMBeanServer extends MBeanServerSupport {
@Override
public DynamicMBean getDynamicMBeanFor(ObjectName name) throws InstanceNotFoundException {
throw new InstanceNotFoundException(name);
}
@Override
protected Set<ObjectName> getNames() {
return Collections.emptySet();
}
}
public static void main(String[] args) throws Exception {
MBeanServer mbs = MBeanServerFactory.newMBeanServer();
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///");
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
url, null, mbs);
cs.start();
String realVersion = (String) mbs.getAttribute(
MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion");
assertEquals("Reported local version",
realVersion, JMX.getSpecificationVersion(mbs, null));
assertEquals("Reported local version >= \"2.0\"",
true, (realVersion.compareTo("2.0") >= 0));
JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
MBeanServerConnection mbsc = cc.getMBeanServerConnection();
assertEquals("Reported remote version",
realVersion, JMX.getSpecificationVersion(mbsc, null));
cc.close();
try {
String brokenVersion = JMX.getSpecificationVersion(mbsc, null);
fail("JMX.getSpecificationVersion succeded over closed connection" +
" (returned " + brokenVersion + ")");
} catch (Exception e) {
assertEquals("Exception for closed connection",
IOException.class, e.getClass());
}
try {
String brokenVersion = JMX.getSpecificationVersion(
new EmptyMBeanServer(), null);
fail("JMX.getSpecificationVersion succeded with empty MBean Server" +
" (returned " + brokenVersion + ")");
} catch (Exception e) {
assertEquals("Exception for empty MBean Server",
IOException.class, e.getClass());
}
try {
String brokenVersion = JMX.getSpecificationVersion(null, null);
fail("JMX.getSpecificationVersion succeded with null MBean Server" +
" (returned " + brokenVersion + ")");
} catch (Exception e) {
assertEquals("Exception for null MBean Server",
IllegalArgumentException.class, e.getClass());
}
MBeanServer mbs1_2 = new MBeanServerWithVersion("1.2");
String version1_2 = JMX.getSpecificationVersion(mbs1_2, null);
assertEquals("Version for 1.2 MBean Server", "1.2", version1_2);
// It's completely nutty for an MBean Server to return null as the
// value of its spec version, and we don't actually say what happens
// in that case, but in fact we return the null to the caller.
MBeanServer mbs_null = new MBeanServerWithVersion(null);
String version_null = JMX.getSpecificationVersion(mbs_null, null);
assertEquals("Version for MBean Server that declares null spec version",
null, version_null);
try {
MBeanServer mbs1_2_float = new MBeanServerWithVersion(1.2f);
String version1_2_float =
JMX.getSpecificationVersion(mbs1_2_float, null);
fail("JMX.getSpecificationVersion succeeded with version 1.2f" +
" (returned " + version1_2_float + ")");
} catch (Exception e) {
assertEquals("Exception for non-string version (1.2f)",
IOException.class, e.getClass());
}
try {
MBeanServer mbs_missing = new MBeanServerWithVersion(POISON_PILL);
String version_missing =
JMX.getSpecificationVersion(mbs_missing, null);
fail("JMX.getSpecificationVersion succeeded with null version" +
" (returned " + version_missing + ")");
} catch (Exception e) {
assertEquals("Exception for missing version",
IOException.class, e.getClass());
}
ObjectName wildcardNamespaceName = new ObjectName("foo//*//bar//baz:k=v");
try {
String brokenVersion =
JMX.getSpecificationVersion(mbsc, wildcardNamespaceName);
fail("JMX.getSpecificationVersion succeeded with wildcard namespace" +
" (returned " + brokenVersion + ")");
} catch (Exception e) {
assertEquals("Exception for wildcard namespace",
IllegalArgumentException.class, e.getClass());
}
String sub1_2namespace = "blibby";
JMXNamespace sub1_2 = new JMXNamespace(mbs1_2);
ObjectName sub1_2name =
JMXNamespaces.getNamespaceObjectName(sub1_2namespace);
mbs.registerMBean(sub1_2, sub1_2name);
String sub1_2namespaceHandlerVersion =
JMX.getSpecificationVersion(mbs, sub1_2name);
assertEquals("Spec version of namespace handler",
realVersion, sub1_2namespaceHandlerVersion);
// The namespace handler is in the top-level namespace so its
// version should not be 1.2.
for (String nameInSub : new String[] {"*:*", "d:k=v"}) {
ObjectName subName = new ObjectName(sub1_2namespace + "//" + nameInSub);
String subVersion = JMX.getSpecificationVersion(mbs, subName);
assertEquals("Spec version in 1.2 namespace (" + nameInSub + ")",
"1.2", subVersion);
}
mbs.unregisterMBean(sub1_2name);
for (String noSuchNamespace : new String[] {
sub1_2namespace + "//*:*", sub1_2namespace + "//d:k=v",
}) {
try {
String brokenVersion = JMX.getSpecificationVersion(
mbs, new ObjectName(noSuchNamespace));
fail("JMX.getSpecificationVersion succeeded with missing " +
"namespace (" + noSuchNamespace + " -> " +
brokenVersion);
} catch (Exception e) {
assertEquals("Exception for missing namespace",
IOException.class, e.getClass());
}
}
if (failure != null)
throw new Exception("TEST FAILED: " + failure);
System.out.println("TEST PASSED");
}
private static void assertEquals(String what, Object expect, Object actual) {
if (equal(expect, actual))
System.out.println("OK: " + what + ": " + expect);
else
fail(what + ": expected " + expect + ", got " + actual);
}
private static boolean equal(Object x, Object y) {
if (x == null)
return (y == null);
else
return x.equals(y);
}
private static void fail(String why) {
System.out.println("FAILED: " + why);
failure = why;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册