mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-21 19:08:31 +00:00
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 Small JMX RFEs Reviewed-by: dfuchs
This commit is contained in:
parent
ab227cb671
commit
bbac59f218
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
private void adding(Object x) {
|
||||
if (x == null || x instanceof Attribute)
|
||||
return;
|
||||
if (typeSafe)
|
||||
throw new IllegalArgumentException("Not an Attribute: " + x);
|
||||
else
|
||||
tainted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public CompositeDataSupport(
|
||||
CompositeType compositeType, String[] itemNames, Object[] itemValues)
|
||||
throws OpenDataException {
|
||||
this(makeMap(itemNames, itemValues), compositeType);
|
||||
}
|
||||
|
||||
// Check compositeType is not null
|
||||
//
|
||||
if (compositeType == null) {
|
||||
throw new IllegalArgumentException("Argument compositeType cannot be null.");
|
||||
}
|
||||
private static SortedMap<String, Object> makeMap(
|
||||
String[] itemNames, Object[] itemValues)
|
||||
throws OpenDataException {
|
||||
|
||||
// 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");
|
||||
|
||||
// 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.");
|
||||
}
|
||||
|
||||
// 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 +").");
|
||||
throw new IllegalArgumentException(
|
||||
"Different lengths: itemNames[" + itemNames.length +
|
||||
"], itemValues[" + 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.");
|
||||
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]);
|
||||
}
|
||||
|
||||
// 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.");
|
||||
}
|
||||
|
||||
// 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 +").");
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
// Let the other constructor do the job, as the call to another constructor must be the first call
|
||||
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 CompositeDataSupport(
|
||||
SortedMap<String, Object> items, CompositeType compositeType)
|
||||
throws OpenDataException {
|
||||
|
||||
// Check compositeType is not null
|
||||
//
|
||||
this( compositeType,
|
||||
(items==null ? null : items.keySet().toArray(new String[items.size()])), // may raise an ArrayStoreException
|
||||
(items==null ? null : items.values().toArray()) );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static void checkForNullElement(Object[] arg, String argName) {
|
||||
if ( (arg == null) || (arg.length == 0) ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Argument "+ argName +"[] cannot be null or empty.");
|
||||
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.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<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>
|
||||
|
||||
115
jdk/test/javax/management/MBeanServer/AttributeListMapTest.java
Normal file
115
jdk/test/javax/management/MBeanServer/AttributeListMapTest.java
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
116
jdk/test/javax/management/openmbean/CompositeDataToMapTest.java
Normal file
116
jdk/test/javax/management/openmbean/CompositeDataToMapTest.java
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,308 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user