Date: Tue, 9 Sep 2008 15:20:07 -0700
Subject: 6728229: (str) StringBuilder.append(CharSequence) does not throw
IndexOutOfBoundsException Summary: Major spec rework Reviewed-by: alanb
---
.../classes/java/lang/AbstractStringBuilder.java | 444 +++++++++++----------
src/share/classes/java/lang/StringBuffer.java | 57 +--
src/share/classes/java/lang/StringBuilder.java | 56 +--
3 files changed, 244 insertions(+), 313 deletions(-)
diff --git a/src/share/classes/java/lang/AbstractStringBuilder.java b/src/share/classes/java/lang/AbstractStringBuilder.java
index 4ba130b49..3ee4c21d0 100644
--- a/src/share/classes/java/lang/AbstractStringBuilder.java
+++ b/src/share/classes/java/lang/AbstractStringBuilder.java
@@ -42,7 +42,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
- char value[];
+ char[] value;
/**
* The count is the number of characters used.
@@ -333,8 +333,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* dst.length
*
*/
- public void getChars(int srcBegin, int srcEnd, char dst[],
- int dstBegin)
+ public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin);
@@ -366,14 +365,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the Object
- * argument.
+ * Appends the string representation of the {@code Object} argument.
*
- * The argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then appended to this sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(Object)},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
- * @param obj an Object
.
+ * @param obj an {@code Object}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(Object obj) {
@@ -383,17 +382,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* Appends the specified string to this character sequence.
*
- * The characters of the String
argument are appended, in
+ * The characters of the {@code String} argument are appended, in
* order, increasing the length of this sequence by the length of the
- * argument. If str
is null
, then the four
- * characters "null"
are appended.
+ * argument. If {@code str} is {@code null}, then the four
+ * characters {@code "null"} are appended.
*
* Let n be the length of this character sequence just prior to
- * execution of the append
method. Then the character at
+ * execution of the {@code append} method. Then the character at
* index k in the new character sequence is equal to the character
* at index k in the old character sequence, if k is less
* than n; otherwise, it is equal to the character at index
- * k-n in the argument str
.
+ * k-n in the argument {@code str}.
*
* @param str a string.
* @return a reference to this object.
@@ -435,33 +434,33 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends a subsequence of the specified CharSequence
to this
+ * Appends a subsequence of the specified {@code CharSequence} to this
* sequence.
*
- * Characters of the argument s
, starting at
- * index start
, are appended, in order, to the contents of
- * this sequence up to the (exclusive) index end
. The length
- * of this sequence is increased by the value of end - start
.
+ * Characters of the argument {@code s}, starting at
+ * index {@code start}, are appended, in order, to the contents of
+ * this sequence up to the (exclusive) index {@code end}. The length
+ * of this sequence is increased by the value of {@code end - start}.
*
* Let n be the length of this character sequence just prior to
- * execution of the append
method. Then the character at
+ * execution of the {@code append} method. Then the character at
* index k in this character sequence becomes equal to the
* character at index k in this sequence, if k is less than
* n; otherwise, it is equal to the character at index
- * k+start-n in the argument s
.
+ * k+start-n in the argument {@code s}.
*
- * If s
is null
, then this method appends
+ * If {@code s} is {@code null}, then this method appends
* characters as if the s parameter was a sequence containing the four
- * characters "null"
.
+ * characters {@code "null"}.
*
* @param s the sequence to append.
* @param start the starting index of the subsequence to be appended.
* @param end the end index of the subsequence to be appended.
* @return a reference to this object.
* @throws IndexOutOfBoundsException if
- * start
or end
are negative, or
- * start
is greater than end
or
- * end
is greater than s.length()
+ * {@code start} is negative, or
+ * {@code start} is greater than {@code end} or
+ * {@code end} is greater than {@code s.length()}
*/
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
@@ -483,22 +482,22 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the char
array
+ * Appends the string representation of the {@code char} array
* argument to this sequence.
*
* The characters of the array argument are appended, in order, to
* the contents of this sequence. The length of this sequence
* increases by the length of the argument.
*
- * The overall effect is exactly as if the argument were converted to
- * a string by the method {@link String#valueOf(char[])} and the
- * characters of that string were then {@link #append(String) appended}
- * to this character sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(char[])},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
* @param str the characters to be appended.
* @return a reference to this object.
*/
- public AbstractStringBuilder append(char str[]) {
+ public AbstractStringBuilder append(char[] str) {
int newCount = count + str.length;
if (newCount > value.length)
expandCapacity(newCount);
@@ -509,22 +508,25 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* Appends the string representation of a subarray of the
- * char
array argument to this sequence.
+ * {@code char} array argument to this sequence.
*
- * Characters of the char
array str
, starting at
- * index offset
, are appended, in order, to the contents
+ * Characters of the {@code char} array {@code str}, starting at
+ * index {@code offset}, are appended, in order, to the contents
* of this sequence. The length of this sequence increases
- * by the value of len
.
+ * by the value of {@code len}.
*
- * The overall effect is exactly as if the arguments were converted to
- * a string by the method {@link String#valueOf(char[],int,int)} and the
- * characters of that string were then {@link #append(String) appended}
- * to this character sequence.
+ * The overall effect is exactly as if the arguments were converted
+ * to a string by the method {@link String#valueOf(char[],int,int)},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
* @param str the characters to be appended.
- * @param offset the index of the first char
to append.
- * @param len the number of char
s to append.
+ * @param offset the index of the first {@code char} to append.
+ * @param len the number of {@code char}s to append.
* @return a reference to this object.
+ * @throws IndexOutOfBoundsException
+ * if {@code offset < 0} or {@code len < 0}
+ * or {@code offset+len > str.length}
*/
public AbstractStringBuilder append(char str[], int offset, int len) {
int newCount = count + len;
@@ -536,14 +538,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the boolean
+ * Appends the string representation of the {@code boolean}
* argument to the sequence.
*
- * The argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then appended to this sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(boolean)},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
- * @param b a boolean
.
+ * @param b a {@code boolean}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(boolean b) {
@@ -569,18 +572,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the char
+ * Appends the string representation of the {@code char}
* argument to this sequence.
*
* The argument is appended to the contents of this sequence.
- * The length of this sequence increases by 1
.
+ * The length of this sequence increases by {@code 1}.
*
- * The overall effect is exactly as if the argument were converted to
- * a string by the method {@link String#valueOf(char)} and the character
- * in that string were then {@link #append(String) appended} to this
- * character sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(char)},
+ * and the character in that string were then
+ * {@link #append(String) appended} to this character sequence.
*
- * @param c a char
.
+ * @param c a {@code char}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(char c) {
@@ -592,14 +595,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the int
+ * Appends the string representation of the {@code int}
* argument to this sequence.
*
- * The argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then appended to this sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(int)},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
- * @param i an int
.
+ * @param i an {@code int}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(int i) {
@@ -618,14 +622,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the long
+ * Appends the string representation of the {@code long}
* argument to this sequence.
*
- * The argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then appended to this sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(long)},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
- * @param l a long
.
+ * @param l a {@code long}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(long l) {
@@ -644,14 +649,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the float
+ * Appends the string representation of the {@code float}
* argument to this sequence.
*
- * The argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then appended to this string sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(float)},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
- * @param f a float
.
+ * @param f a {@code float}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(float f) {
@@ -660,14 +666,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the double
+ * Appends the string representation of the {@code double}
* argument to this sequence.
*
- * The argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then appended to this sequence.
+ * The overall effect is exactly as if the argument were converted
+ * to a string by the method {@link String#valueOf(double)},
+ * and the characters of that string were then
+ * {@link #append(String) appended} to this character sequence.
*
- * @param d a double
.
+ * @param d a {@code double}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(double d) {
@@ -677,17 +684,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* Removes the characters in a substring of this sequence.
- * The substring begins at the specified start
and extends to
- * the character at index end - 1
or to the end of the
+ * The substring begins at the specified {@code start} and extends to
+ * the character at index {@code end - 1} or to the end of the
* sequence if no such character exists. If
- * start
is equal to end
, no changes are made.
+ * {@code start} is equal to {@code end}, no changes are made.
*
* @param start The beginning index, inclusive.
* @param end The ending index, exclusive.
* @return This object.
- * @throws StringIndexOutOfBoundsException if start
- * is negative, greater than length()
, or
- * greater than end
.
+ * @throws StringIndexOutOfBoundsException if {@code start}
+ * is negative, greater than {@code length()}, or
+ * greater than {@code end}.
*/
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
@@ -705,7 +712,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Appends the string representation of the codePoint
+ * Appends the string representation of the {@code codePoint}
* argument to this sequence.
*
*
The argument is appended to the contents of this sequence.
@@ -713,15 +720,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@link Character#charCount(int) Character.charCount(codePoint)}.
*
*
The overall effect is exactly as if the argument were
- * converted to a char
array by the method {@link
- * Character#toChars(int)} and the character in that array were
- * then {@link #append(char[]) appended} to this character
+ * converted to a {@code char} array by the method
+ * {@link Character#toChars(int)} and the character in that array
+ * were then {@link #append(char[]) appended} to this character
* sequence.
*
* @param codePoint a Unicode code point
* @return a reference to this object.
* @exception IllegalArgumentException if the specified
- * codePoint
isn't a valid Unicode code point
+ * {@code codePoint} isn't a valid Unicode code point
*/
public AbstractStringBuilder appendCodePoint(int codePoint) {
if (!Character.isValidCodePoint(codePoint)) {
@@ -879,27 +886,27 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of a subarray of the str
+ * Inserts the string representation of a subarray of the {@code str}
* array argument into this sequence. The subarray begins at the
- * specified offset
and extends len
char
s.
+ * specified {@code offset} and extends {@code len} {@code char}s.
* The characters of the subarray are inserted into this sequence at
- * the position indicated by index
. The length of this
- * sequence increases by len
char
s.
+ * the position indicated by {@code index}. The length of this
+ * sequence increases by {@code len} {@code char}s.
*
* @param index position at which to insert subarray.
- * @param str A char
array.
- * @param offset the index of the first char
in subarray to
+ * @param str A {@code char} array.
+ * @param offset the index of the first {@code char} in subarray to
* be inserted.
- * @param len the number of char
s in the subarray to
+ * @param len the number of {@code char}s in the subarray to
* be inserted.
* @return This object
- * @throws StringIndexOutOfBoundsException if index
- * is negative or greater than length()
, or
- * offset
or len
are negative, or
- * (offset+len)
is greater than
- * str.length
.
+ * @throws StringIndexOutOfBoundsException if {@code index}
+ * is negative or greater than {@code length()}, or
+ * {@code offset} or {@code len} are negative, or
+ * {@code (offset+len)} is greater than
+ * {@code str.length}.
*/
- public AbstractStringBuilder insert(int index, char str[], int offset,
+ public AbstractStringBuilder insert(int index, char[] str, int offset,
int len)
{
if ((index < 0) || (index > length()))
@@ -918,20 +925,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the Object
+ * Inserts the string representation of the {@code Object}
* argument into this character sequence.
*
- * The second argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then inserted into this sequence at the indicated
- * offset.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(Object)},
+ * and the characters of that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
- * @param obj an Object
.
+ * @param obj an {@code Object}.
* @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
@@ -942,28 +950,28 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* Inserts the string into this character sequence.
*
- * The characters of the String
argument are inserted, in
+ * The characters of the {@code String} argument are inserted, in
* order, into this sequence at the indicated offset, moving up any
* characters originally above that position and increasing the length
* of this sequence by the length of the argument. If
- * str
is null
, then the four characters
- * "null"
are inserted into this sequence.
+ * {@code str} is {@code null}, then the four characters
+ * {@code "null"} are inserted into this sequence.
*
* The character at index k in the new character sequence is
* equal to:
*
* - the character at index k in the old character sequence, if
- * k is less than
offset
- * - the character at index k
-offset
in the
- * argument str
, if k is not less than
- * offset
but is less than offset+str.length()
- * - the character at index k
-str.length()
in the
+ * k is less than {@code offset}
+ * - the character at index k{@code -offset} in the
+ * argument {@code str}, if k is not less than
+ * {@code offset} but is less than {@code offset+str.length()}
+ *
- the character at index k{@code -str.length()} in the
* old character sequence, if k is not less than
- *
offset+str.length()
+ * {@code offset+str.length()}
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
* @param str a string.
@@ -986,27 +994,30 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the char
array
+ * Inserts the string representation of the {@code char} array
* argument into this sequence.
*
* The characters of the array argument are inserted into the
* contents of this sequence at the position indicated by
- * offset
. The length of this sequence increases by
+ * {@code offset}. The length of this sequence increases by
* the length of the argument.
*
- * The overall effect is exactly as if the argument were converted to
- * a string by the method {@link String#valueOf(char[])} and the
- * characters of that string were then
- * {@link #insert(int,String) inserted} into this
- * character sequence at the position indicated by
- * offset
.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(char[])},
+ * and the characters of that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
+ *
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
* @param str a character array.
* @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
- public AbstractStringBuilder insert(int offset, char str[]) {
+ public AbstractStringBuilder insert(int offset, char[] str) {
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
int len = str.length;
@@ -1020,18 +1031,20 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the specified CharSequence
into this sequence.
+ * Inserts the specified {@code CharSequence} into this sequence.
*
- * The characters of the CharSequence
argument are inserted,
+ * The characters of the {@code CharSequence} argument are inserted,
* in order, into this sequence at the indicated offset, moving up
* any characters originally above that position and increasing the length
* of this sequence by the length of the argument s.
*
* The result of this method is exactly the same as if it were an
- * invocation of this object's insert(dstOffset, s, 0, s.length()) method.
+ * invocation of this object's
+ * {@link #insert(int,CharSequence,int,int) insert}(dstOffset, s, 0, s.length())
+ * method.
*
- *
If s
is null
, then the four characters
- * "null"
are inserted into this sequence.
+ *
If {@code s} is {@code null}, then the four characters
+ * {@code "null"} are inserted into this sequence.
*
* @param dstOffset the offset.
* @param s the sequence to be inserted
@@ -1047,51 +1060,51 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts a subsequence of the specified CharSequence
into
+ * Inserts a subsequence of the specified {@code CharSequence} into
* this sequence.
*
- * The subsequence of the argument s
specified by
- * start
and end
are inserted,
+ * The subsequence of the argument {@code s} specified by
+ * {@code start} and {@code end} are inserted,
* in order, into this sequence at the specified destination offset, moving
* up any characters originally above that position. The length of this
- * sequence is increased by end - start
.
+ * sequence is increased by {@code end - start}.
*
* The character at index k in this sequence becomes equal to:
*
* - the character at index k in this sequence, if
- * k is less than
dstOffset
- * - the character at index k
+start-dstOffset
in
- * the argument s
, if k is greater than or equal to
- * dstOffset
but is less than dstOffset+end-start
- * - the character at index k
-(end-start)
in this
+ * k is less than {@code dstOffset}
+ * - the character at index k{@code +start-dstOffset} in
+ * the argument {@code s}, if k is greater than or equal to
+ * {@code dstOffset} but is less than {@code dstOffset+end-start}
+ *
- the character at index k{@code -(end-start)} in this
* sequence, if k is greater than or equal to
- *
dstOffset+end-start
+ * {@code dstOffset+end-start}
*
- * The dstOffset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code dstOffset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
The start argument must be nonnegative, and not greater than
- * end
.
+ * {@code end}.
*
The end argument must be greater than or equal to
- * start
, and less than or equal to the length of s.
+ * {@code start}, and less than or equal to the length of s.
*
- *
If s
is null
, then this method inserts
+ *
If {@code s} is {@code null}, then this method inserts
* characters as if the s parameter was a sequence containing the four
- * characters "null"
.
+ * characters {@code "null"}.
*
* @param dstOffset the offset in this sequence.
* @param s the sequence to be inserted.
* @param start the starting index of the subsequence to be inserted.
* @param end the end index of the subsequence to be inserted.
* @return a reference to this object.
- * @throws IndexOutOfBoundsException if dstOffset
- * is negative or greater than this.length()
, or
- * start
or end
are negative, or
- * start
is greater than end
or
- * end
is greater than s.length()
+ * @throws IndexOutOfBoundsException if {@code dstOffset}
+ * is negative or greater than {@code this.length()}, or
+ * {@code start} or {@code end} are negative, or
+ * {@code start} is greater than {@code end} or
+ * {@code end} is greater than {@code s.length()}
*/
public AbstractStringBuilder insert(int dstOffset, CharSequence s,
- int start, int end) {
+ int start, int end) {
if (s == null)
s = "null";
if ((dstOffset < 0) || (dstOffset > this.length()))
@@ -1115,20 +1128,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the boolean
+ * Inserts the string representation of the {@code boolean}
* argument into this sequence.
*
- * The second argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then inserted into this sequence at the indicated
- * offset.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(boolean)},
+ * and the characters of that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
- * @param b a boolean
.
+ * @param b a {@code boolean}.
* @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
@@ -1137,25 +1151,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the char
+ * Inserts the string representation of the {@code char}
* argument into this sequence.
*
- * The second argument is inserted into the contents of this sequence
- * at the position indicated by offset
. The length
- * of this sequence increases by one.
- *
- * The overall effect is exactly as if the argument were converted to
- * a string by the method {@link String#valueOf(char)} and the character
- * in that string were then {@link #insert(int, String) inserted} into
- * this character sequence at the position indicated by
- * offset
.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(char)},
+ * and the character in that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
- * @param c a char
.
+ * @param c a {@code char}.
* @return a reference to this object.
* @throws IndexOutOfBoundsException if the offset is invalid.
*/
@@ -1170,20 +1180,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the second int
+ * Inserts the string representation of the second {@code int}
* argument into this sequence.
*
- * The second argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then inserted into this sequence at the indicated
- * offset.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(int)},
+ * and the characters of that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
- * @param i an int
.
+ * @param i an {@code int}.
* @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
@@ -1192,20 +1203,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the long
+ * Inserts the string representation of the {@code long}
* argument into this sequence.
*
- * The second argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then inserted into this sequence at the position
- * indicated by offset
.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(long)},
+ * and the characters of that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
- * @param l a long
.
+ * @param l a {@code long}.
* @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
@@ -1214,20 +1226,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the float
+ * Inserts the string representation of the {@code float}
* argument into this sequence.
*
- * The second argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then inserted into this sequence at the indicated
- * offset.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(float)},
+ * and the characters of that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
- * @param f a float
.
+ * @param f a {@code float}.
* @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
@@ -1236,20 +1249,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
/**
- * Inserts the string representation of the double
+ * Inserts the string representation of the {@code double}
* argument into this sequence.
*
- * The second argument is converted to a string as if by the method
- * String.valueOf
, and the characters of that
- * string are then inserted into this sequence at the indicated
- * offset.
+ * The overall effect is exactly as if the second argument were
+ * converted to a string by the method {@link String#valueOf(double)},
+ * and the characters of that string were then
+ * {@link #insert(int,String) inserted} into this character
+ * sequence at the indicated offset.
*
- * The offset argument must be greater than or equal to
- * 0
, and less than or equal to the length of this
- * sequence.
+ * The {@code offset} argument must be greater than or equal to
+ * {@code 0}, and less than or equal to the {@linkplain #length() length}
+ * of this sequence.
*
* @param offset the offset.
- * @param d a double
.
+ * @param d a {@code double}.
* @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
diff --git a/src/share/classes/java/lang/StringBuffer.java b/src/share/classes/java/lang/StringBuffer.java
index e0ecbef0e..f44bb2bae 100644
--- a/src/share/classes/java/lang/StringBuffer.java
+++ b/src/share/classes/java/lang/StringBuffer.java
@@ -212,7 +212,7 @@ package java.lang;
* @throws NullPointerException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
- public synchronized void getChars(int srcBegin, int srcEnd, char dst[],
+ public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
int dstBegin)
{
super.getChars(srcBegin, srcEnd, dst, dstBegin);
@@ -228,10 +228,6 @@ package java.lang;
value[index] = ch;
}
- /**
- * @see java.lang.String#valueOf(java.lang.Object)
- * @see #append(java.lang.String)
- */
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
@@ -314,20 +310,19 @@ package java.lang;
return this;
}
- public synchronized StringBuffer append(char str[]) {
+ public synchronized StringBuffer append(char[] str) {
super.append(str);
return this;
}
- public synchronized StringBuffer append(char str[], int offset, int len) {
+ /**
+ * @throws IndexOutOfBoundsException {@inheritDoc}
+ */
+ public synchronized StringBuffer append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
- /**
- * @see java.lang.String#valueOf(boolean)
- * @see #append(java.lang.String)
- */
public synchronized StringBuffer append(boolean b) {
super.append(b);
return this;
@@ -338,10 +333,6 @@ package java.lang;
return this;
}
- /**
- * @see java.lang.String#valueOf(int)
- * @see #append(java.lang.String)
- */
public synchronized StringBuffer append(int i) {
super.append(i);
return this;
@@ -355,28 +346,16 @@ package java.lang;
return this;
}
- /**
- * @see java.lang.String#valueOf(long)
- * @see #append(java.lang.String)
- */
public synchronized StringBuffer append(long lng) {
super.append(lng);
return this;
}
- /**
- * @see java.lang.String#valueOf(float)
- * @see #append(java.lang.String)
- */
public synchronized StringBuffer append(float f) {
super.append(f);
return this;
}
- /**
- * @see java.lang.String#valueOf(double)
- * @see #append(java.lang.String)
- */
public synchronized StringBuffer append(double d) {
super.append(d);
return this;
@@ -437,7 +416,7 @@ package java.lang;
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
- public synchronized StringBuffer insert(int index, char str[], int offset,
+ public synchronized StringBuffer insert(int index, char[] str, int offset,
int len)
{
super.insert(index, str, offset, len);
@@ -446,9 +425,6 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(java.lang.Object)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public synchronized StringBuffer insert(int offset, Object obj) {
super.insert(offset, String.valueOf(obj));
@@ -457,7 +433,6 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see #length()
*/
public synchronized StringBuffer insert(int offset, String str) {
super.insert(offset, str);
@@ -467,7 +442,7 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
- public synchronized StringBuffer insert(int offset, char str[]) {
+ public synchronized StringBuffer insert(int offset, char[] str) {
super.insert(offset, str);
return this;
}
@@ -498,9 +473,6 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(boolean)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuffer insert(int offset, boolean b) {
return insert(offset, String.valueOf(b));
@@ -508,7 +480,6 @@ package java.lang;
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
- * @see #length()
*/
public synchronized StringBuffer insert(int offset, char c) {
super.insert(offset, c);
@@ -517,9 +488,6 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(int)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuffer insert(int offset, int i) {
return insert(offset, String.valueOf(i));
@@ -527,9 +495,6 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(long)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuffer insert(int offset, long l) {
return insert(offset, String.valueOf(l));
@@ -537,9 +502,6 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(float)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuffer insert(int offset, float f) {
return insert(offset, String.valueOf(f));
@@ -547,9 +509,6 @@ package java.lang;
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(double)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuffer insert(int offset, double d) {
return insert(offset, String.valueOf(d));
diff --git a/src/share/classes/java/lang/StringBuilder.java b/src/share/classes/java/lang/StringBuilder.java
index 99f19768d..e7eea47be 100644
--- a/src/share/classes/java/lang/StringBuilder.java
+++ b/src/share/classes/java/lang/StringBuilder.java
@@ -124,10 +124,6 @@ public final class StringBuilder
append(seq);
}
- /**
- * @see java.lang.String#valueOf(java.lang.Object)
- * @see #append(java.lang.String)
- */
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@@ -175,7 +171,6 @@ public final class StringBuilder
}
/**
- * @throws IndexOutOfBoundsException {@inheritDoc}
*/
public StringBuilder append(CharSequence s) {
if (s == null)
@@ -197,20 +192,19 @@ public final class StringBuilder
return this;
}
- public StringBuilder append(char str[]) {
+ public StringBuilder append(char[] str) {
super.append(str);
return this;
}
- public StringBuilder append(char str[], int offset, int len) {
+ /**
+ * @throws IndexOutOfBoundsException {@inheritDoc}
+ */
+ public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
- /**
- * @see java.lang.String#valueOf(boolean)
- * @see #append(java.lang.String)
- */
public StringBuilder append(boolean b) {
super.append(b);
return this;
@@ -221,37 +215,21 @@ public final class StringBuilder
return this;
}
- /**
- * @see java.lang.String#valueOf(int)
- * @see #append(java.lang.String)
- */
public StringBuilder append(int i) {
super.append(i);
return this;
}
- /**
- * @see java.lang.String#valueOf(long)
- * @see #append(java.lang.String)
- */
public StringBuilder append(long lng) {
super.append(lng);
return this;
}
- /**
- * @see java.lang.String#valueOf(float)
- * @see #append(java.lang.String)
- */
public StringBuilder append(float f) {
super.append(f);
return this;
}
- /**
- * @see java.lang.String#valueOf(double)
- * @see #append(java.lang.String)
- */
public StringBuilder append(double d) {
super.append(d);
return this;
@@ -292,7 +270,7 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
- public StringBuilder insert(int index, char str[], int offset,
+ public StringBuilder insert(int index, char[] str, int offset,
int len)
{
super.insert(index, str, offset, len);
@@ -301,9 +279,6 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(java.lang.Object)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuilder insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj));
@@ -311,7 +286,6 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see #length()
*/
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);
@@ -321,7 +295,7 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
- public StringBuilder insert(int offset, char str[]) {
+ public StringBuilder insert(int offset, char[] str) {
super.insert(offset, str);
return this;
}
@@ -349,9 +323,6 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(boolean)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuilder insert(int offset, boolean b) {
super.insert(offset, b);
@@ -360,7 +331,6 @@ public final class StringBuilder
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
- * @see #length()
*/
public StringBuilder insert(int offset, char c) {
super.insert(offset, c);
@@ -369,9 +339,6 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(int)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuilder insert(int offset, int i) {
return insert(offset, String.valueOf(i));
@@ -379,9 +346,6 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(long)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuilder insert(int offset, long l) {
return insert(offset, String.valueOf(l));
@@ -389,9 +353,6 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(float)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuilder insert(int offset, float f) {
return insert(offset, String.valueOf(f));
@@ -399,9 +360,6 @@ public final class StringBuilder
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
- * @see java.lang.String#valueOf(double)
- * @see #insert(int, java.lang.String)
- * @see #length()
*/
public StringBuilder insert(int offset, double d) {
return insert(offset, String.valueOf(d));
--
cgit v1.2.3
From 2244265d33ba3a74a5958fbd3d44b1636bf0651e Mon Sep 17 00:00:00 2001
From: martin
Date: Tue, 9 Sep 2008 15:20:07 -0700
Subject: 6733145: (bf) CharBuffer.subSequence can be updated to take advantage
of covariant returns Summary: Change return type to CharBuffer Reviewed-by:
alanb
---
src/share/classes/java/nio/ByteBufferAs-X-Buffer.java | 2 +-
src/share/classes/java/nio/Direct-X-Buffer.java | 2 +-
src/share/classes/java/nio/Heap-X-Buffer.java | 2 +-
src/share/classes/java/nio/StringCharBuffer.java | 2 +-
src/share/classes/java/nio/X-Buffer.java | 4 ++--
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java
index 5761fd867..1b959ab6e 100644
--- a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java
+++ b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java
@@ -186,7 +186,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
// --- Methods to support CharSequence ---
- public CharSequence subSequence(int start, int end) {
+ public CharBuffer subSequence(int start, int end) {
int pos = position();
int lim = limit();
assert (pos <= lim);
diff --git a/src/share/classes/java/nio/Direct-X-Buffer.java b/src/share/classes/java/nio/Direct-X-Buffer.java
index d1cfb6b5c..44915f207 100644
--- a/src/share/classes/java/nio/Direct-X-Buffer.java
+++ b/src/share/classes/java/nio/Direct-X-Buffer.java
@@ -402,7 +402,7 @@ class Direct$Type$Buffer$RW$$BO$
// --- Methods to support CharSequence ---
- public CharSequence subSequence(int start, int end) {
+ public CharBuffer subSequence(int start, int end) {
int pos = position();
int lim = limit();
assert (pos <= lim);
diff --git a/src/share/classes/java/nio/Heap-X-Buffer.java b/src/share/classes/java/nio/Heap-X-Buffer.java
index 0c19ca554..ed59c73a8 100644
--- a/src/share/classes/java/nio/Heap-X-Buffer.java
+++ b/src/share/classes/java/nio/Heap-X-Buffer.java
@@ -566,7 +566,7 @@ class Heap$Type$Buffer$RW$
// --- Methods to support CharSequence ---
- public CharSequence subSequence(int start, int end) {
+ public CharBuffer subSequence(int start, int end) {
if ((start < 0)
|| (end > length())
|| (start > end))
diff --git a/src/share/classes/java/nio/StringCharBuffer.java b/src/share/classes/java/nio/StringCharBuffer.java
index 3f49ae1eb..648b1986f 100644
--- a/src/share/classes/java/nio/StringCharBuffer.java
+++ b/src/share/classes/java/nio/StringCharBuffer.java
@@ -99,7 +99,7 @@ class StringCharBuffer // package-private
return str.toString().substring(start + offset, end + offset);
}
- public final CharSequence subSequence(int start, int end) {
+ public final CharBuffer subSequence(int start, int end) {
try {
int pos = position();
return new StringCharBuffer(str, -1,
diff --git a/src/share/classes/java/nio/X-Buffer.java b/src/share/classes/java/nio/X-Buffer.java
index 99a7468ff..67cf6db3d 100644
--- a/src/share/classes/java/nio/X-Buffer.java
+++ b/src/share/classes/java/nio/X-Buffer.java
@@ -1239,13 +1239,13 @@ public abstract class $Type$Buffer
* smaller than start and no larger than
* remaining()
*
- * @return The new character sequence
+ * @return The new character buffer
*
* @throws IndexOutOfBoundsException
* If the preconditions on start and end
* do not hold
*/
- public abstract CharSequence subSequence(int start, int end);
+ public abstract CharBuffer subSequence(int start, int end);
// --- Methods to support Appendable ---
--
cgit v1.2.3
From 44714f079ee897c2c80ca0a6248b608f650afb66 Mon Sep 17 00:00:00 2001
From: emcmanus
Date: Wed, 10 Sep 2008 13:36:47 +0200
Subject: 6734813: Provide a way to construct an ObjectName without checked
exceptions 6746649: ObjectName constructors and methods declare unchecked
exceptions in throws clauses Reviewed-by: dfuchs
---
.../interceptor/DefaultMBeanServerInterceptor.java | 5 +-
.../com/sun/jmx/mbeanserver/Repository.java | 2 +-
.../classes/com/sun/jmx/mbeanserver/Util.java | 8 -
.../com/sun/jmx/namespace/DomainInterceptor.java | 4 +-
.../java/lang/management/PlatformComponent.java | 2 +-
src/share/classes/java/util/logging/Logging.java | 2 +-
.../javax/management/MBeanServerDelegate.java | 2 +-
src/share/classes/javax/management/ObjectName.java | 161 ++++++++++++++++---
.../javax/management/QueryNotificationFilter.java | 2 +-
.../management/event/EventClientDelegateMBean.java | 2 +-
.../management/namespace/MBeanServerSupport.java | 14 +-
src/share/classes/sun/management/Util.java | 6 +-
test/javax/management/ObjectName/ValueOfTest.java | 175 +++++++++++++++++++++
13 files changed, 327 insertions(+), 58 deletions(-)
create mode 100644 test/javax/management/ObjectName/ValueOfTest.java
diff --git a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
index 7faeb8727..7da3406b9 100644
--- a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
+++ b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
@@ -613,8 +613,7 @@ public class DefaultMBeanServerInterceptor
List result = new ArrayList(domains.length);
for (int i = 0; i < domains.length; i++) {
try {
- ObjectName dom =
- Util.newObjectName(domains[i] + ":x=x");
+ ObjectName dom = ObjectName.valueOf(domains[i] + ":x=x");
checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains");
result.add(domains[i]);
} catch (SecurityException e) {
@@ -1170,7 +1169,7 @@ public class DefaultMBeanServerInterceptor
if one is supplied where it shouldn't be). */
final String completeName = domain + name;
- return Util.newObjectName(completeName);
+ return ObjectName.valueOf(completeName);
}
public String getDefaultDomain() {
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/Repository.java b/src/share/classes/com/sun/jmx/mbeanserver/Repository.java
index 5c3339833..03f3e5277 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/Repository.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Repository.java
@@ -396,7 +396,7 @@ public class Repository {
// Set domain to default if domain is empty and not already set
if (dom.length() == 0)
- name = Util.newObjectName(domain + name.toString());
+ name = ObjectName.valueOf(domain + name.toString());
// Do we have default domain ?
if (dom == domain) { // ES: OK (dom & domain are interned)
diff --git a/src/share/classes/com/sun/jmx/mbeanserver/Util.java b/src/share/classes/com/sun/jmx/mbeanserver/Util.java
index 93c5c97f6..6307adbf8 100644
--- a/src/share/classes/com/sun/jmx/mbeanserver/Util.java
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Util.java
@@ -110,14 +110,6 @@ public class Util {
return new ArrayList(c);
}
- public static ObjectName newObjectName(String s) {
- try {
- return new ObjectName(s);
- } catch (MalformedObjectNameException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
/* This method can be used by code that is deliberately violating the
* allowed checked casts. Rather than marking the whole method containing
* the code with @SuppressWarnings, you can use a call to this method for
diff --git a/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java b/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java
index 84644d831..7b88087a8 100644
--- a/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java
+++ b/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java
@@ -110,7 +110,7 @@ public class DomainInterceptor extends HandlerInterceptor {
super(handler);
this.domainName = domainName;
this.serverName = serverName;
- ALL = Util.newObjectName(domainName+":*");
+ ALL = ObjectName.valueOf(domainName+":*");
}
@Override
@@ -437,7 +437,7 @@ public class DomainInterceptor extends HandlerInterceptor {
int count=0;
for (int i=0;i set = mbs.queryNames(on, null);
for (PlatformComponent pc : subComponents) {
set.addAll(pc.getObjectNames(mbs));
diff --git a/src/share/classes/java/util/logging/Logging.java b/src/share/classes/java/util/logging/Logging.java
index 72468699e..d99782407 100644
--- a/src/share/classes/java/util/logging/Logging.java
+++ b/src/share/classes/java/util/logging/Logging.java
@@ -118,6 +118,6 @@ class Logging implements LoggingMXBean {
}
public ObjectName getObjectName() {
- return com.sun.jmx.mbeanserver.Util.newObjectName(LogManager.LOGGING_MXBEAN_NAME);
+ return ObjectName.valueOf(LogManager.LOGGING_MXBEAN_NAME);
}
}
diff --git a/src/share/classes/javax/management/MBeanServerDelegate.java b/src/share/classes/javax/management/MBeanServerDelegate.java
index ea4799d3f..00b82a92f 100644
--- a/src/share/classes/javax/management/MBeanServerDelegate.java
+++ b/src/share/classes/javax/management/MBeanServerDelegate.java
@@ -304,7 +304,7 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean,
* @since 1.6
*/
public static final ObjectName DELEGATE_NAME =
- Util.newObjectName("JMImplementation:type=MBeanServerDelegate");
+ ObjectName.valueOf("JMImplementation:type=MBeanServerDelegate");
/* Return a timestamp that is monotonically increasing even if
System.currentTimeMillis() isn't (for example, if you call this
diff --git a/src/share/classes/javax/management/ObjectName.java b/src/share/classes/javax/management/ObjectName.java
index 20bcfce72..8185edc27 100644
--- a/src/share/classes/javax/management/ObjectName.java
+++ b/src/share/classes/javax/management/ObjectName.java
@@ -413,7 +413,7 @@ public class ObjectName implements Comparable, QueryExp {
}
private void copyToOtherDomain(String domain, ObjectName aname)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
// The domain cannot be null
if (domain == null)
@@ -467,7 +467,7 @@ public class ObjectName implements Comparable, QueryExp {
* is null.
*/
private void construct(String name)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
// The name cannot be null
if (name == null)
@@ -729,7 +729,7 @@ public class ObjectName implements Comparable, QueryExp {
* @exception NullPointerException One of the parameters is null.
*/
private void construct(String domain, Map props)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
// The domain cannot be null
if (domain == null)
@@ -1071,7 +1071,7 @@ public class ObjectName implements Comparable, QueryExp {
* Check if the supplied key is a valid key.
*/
private static void checkKey(String key)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
if (key == null) throw new
NullPointerException("Invalid key (null)");
@@ -1359,9 +1359,10 @@ public class ObjectName implements Comparable, QueryExp {
* @exception NullPointerException The name
parameter
* is null.
*
+ * @see #valueOf(String)
*/
public static ObjectName getInstance(String name)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
return new ObjectName(name);
}
@@ -1386,10 +1387,11 @@ public class ObjectName implements Comparable, QueryExp {
* follow the rules for quoting.
* @exception NullPointerException One of the parameters is null.
*
+ * @see #valueOf(String, String, String)
*/
public static ObjectName getInstance(String domain, String key,
String value)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
return new ObjectName(domain, key, value);
}
@@ -1417,10 +1419,11 @@ public class ObjectName implements Comparable, QueryExp {
* quoting.
* @exception NullPointerException One of the parameters is null.
*
+ * @see #valueOf(String, Hashtable)
*/
public static ObjectName getInstance(String domain,
Hashtable table)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
return new ObjectName(domain, table);
}
@@ -1453,11 +1456,120 @@ public class ObjectName implements Comparable, QueryExp {
* @exception NullPointerException The name
is null.
*
*/
- public static ObjectName getInstance(ObjectName name)
- throws NullPointerException {
+ public static ObjectName getInstance(ObjectName name) {
if (name.getClass().equals(ObjectName.class))
return name;
- return Util.newObjectName(name.getSerializedNameString());
+ return valueOf(name.getSerializedNameString());
+ }
+
+ /**
+ * Return an instance of ObjectName that can be used anywhere
+ * an object obtained with {@link #ObjectName(String) new
+ * ObjectName(name)} can be used. The returned object may be of
+ * a subclass of ObjectName. Calling this method twice with the
+ * same parameters may return the same object or two equal but
+ * not identical objects.
+ *
+ * This method is equivalent to {@link #getInstance(String)} except that
+ * it does not throw any checked exceptions.
+ *
+ * @param name A string representation of the object name.
+ *
+ * @return an ObjectName corresponding to the given String.
+ *
+ * @exception IllegalArgumentException The string passed as a
+ * parameter does not have the right format. The {@linkplain
+ * Throwable#getCause() cause} of this exception will be a
+ * {@link MalformedObjectNameException}.
+ * @exception NullPointerException The name
parameter
+ * is null.
+ *
+ * @since 1.7
+ */
+ public static ObjectName valueOf(String name) {
+ try {
+ return getInstance(name);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ // Just plain IllegalArgumentException(e) produces an exception
+ // message "javax.management.MalformedObjectNameException: ..."
+ // which is distracting.
+ }
+ }
+
+ /**
+ * Return an instance of ObjectName that can be used anywhere
+ * an object obtained with {@link #ObjectName(String, String,
+ * String) new ObjectName(domain, key, value)} can be used. The
+ * returned object may be of a subclass of ObjectName. Calling
+ * this method twice with the same parameters may return the same
+ * object or two equal but not identical objects.
+ *
+ * This method is equivalent to {@link #getInstance(String, String,
+ * String)} except that it does not throw any checked exceptions.
+ *
+ * @param domain The domain part of the object name.
+ * @param key The attribute in the key property of the object name.
+ * @param value The value in the key property of the object name.
+ *
+ * @return an ObjectName corresponding to the given domain,
+ * key, and value.
+ *
+ * @exception IllegalArgumentException The
+ * domain
, key
, or value
+ * contains an illegal character, or value
does not
+ * follow the rules for quoting. The {@linkplain
+ * Throwable#getCause() cause} of this exception will be a
+ * {@link MalformedObjectNameException}.
+ * @exception NullPointerException One of the parameters is null.
+ *
+ * @since 1.7
+ */
+ public static ObjectName valueOf(String domain, String key, String value) {
+ try {
+ return getInstance(domain, key, value);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Return an instance of ObjectName that can be used anywhere
+ * an object obtained with {@link #ObjectName(String, Hashtable)
+ * new ObjectName(domain, table)} can be used. The returned
+ * object may be of a subclass of ObjectName. Calling this method
+ * twice with the same parameters may return the same object or
+ * two equal but not identical objects.
+ *
+ * This method is equivalent to {@link #getInstance(String, Hashtable)}
+ * except that it does not throw any checked exceptions.
+ *
+ * @param domain The domain part of the object name.
+ * @param table A hash table containing one or more key
+ * properties. The key of each entry in the table is the key of a
+ * key property in the object name. The associated value in the
+ * table is the associated value in the object name.
+ *
+ * @return an ObjectName corresponding to the given domain and
+ * key mappings.
+ *
+ * @exception IllegalArgumentException The domain
+ * contains an illegal character, or one of the keys or values in
+ * table
contains an illegal character, or one of the
+ * values in table
does not follow the rules for
+ * quoting. The {@linkplain Throwable#getCause() cause} of this exception
+ * will be a {@link MalformedObjectNameException}.
+ * @exception NullPointerException One of the parameters is null.
+ *
+ * @since 1.7
+ */
+ public static ObjectName valueOf(String domain,
+ Hashtable table) {
+ try {
+ return new ObjectName(domain, table);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ }
}
/**
@@ -1477,7 +1589,7 @@ public class ObjectName implements Comparable, QueryExp {
* @since 1.7
**/
public final ObjectName withDomain(String newDomain)
- throws NullPointerException, MalformedObjectNameException {
+ throws MalformedObjectNameException {
return new ObjectName(newDomain, this);
}
@@ -1490,9 +1602,11 @@ public class ObjectName implements Comparable, QueryExp {
* parameter does not have the right format.
* @exception NullPointerException The name
parameter
* is null.
+ *
+ * @see #valueOf(String)
*/
public ObjectName(String name)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
construct(name);
}
@@ -1508,9 +1622,11 @@ public class ObjectName implements Comparable, QueryExp {
* contains an illegal character, or value
does not
* follow the rules for quoting.
* @exception NullPointerException One of the parameters is null.
+ *
+ * @see #valueOf(String, String, String)
*/
public ObjectName(String domain, String key, String value)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
// If key or value are null a NullPointerException
// will be thrown by the put method in Hashtable.
//
@@ -1533,9 +1649,11 @@ public class ObjectName implements Comparable, QueryExp {
* values in table
does not follow the rules for
* quoting.
* @exception NullPointerException One of the parameters is null.
+ *
+ * @see #valueOf(String, Hashtable)
*/
public ObjectName(String domain, Hashtable table)
- throws MalformedObjectNameException, NullPointerException {
+ throws MalformedObjectNameException {
construct(domain, table);
/* The exception for when a key or value in the table is not a
String is now ClassCastException rather than
@@ -1629,8 +1747,7 @@ public class ObjectName implements Comparable, QueryExp {
*
* @since 1.6
*/
- public boolean isPropertyValuePattern(String property)
- throws NullPointerException, IllegalArgumentException {
+ public boolean isPropertyValuePattern(String property) {
if (property == null)
throw new NullPointerException("key property can't be null");
for (int i = 0; i < _ca_array.length; i++) {
@@ -1691,7 +1808,7 @@ public class ObjectName implements Comparable, QueryExp {
*
* @exception NullPointerException If property
is null.
*/
- public String getKeyProperty(String property) throws NullPointerException {
+ public String getKeyProperty(String property) {
return _getKeyPropertyList().get(property);
}
@@ -1950,8 +2067,7 @@ public class ObjectName implements Comparable, QueryExp {
* @exception NullPointerException if s
is null.
*
*/
- public static String quote(String s)
- throws NullPointerException {
+ public static String quote(String s) {
final StringBuilder buf = new StringBuilder("\"");
final int len = s.length();
for (int i = 0; i < len; i++) {
@@ -1995,8 +2111,7 @@ public class ObjectName implements Comparable, QueryExp {
* @exception NullPointerException if q
is null.
*
*/
- public static String unquote(String q)
- throws IllegalArgumentException, NullPointerException {
+ public static String unquote(String q) {
final StringBuilder buf = new StringBuilder();
final int len = q.length();
if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"')
@@ -2041,7 +2156,7 @@ public class ObjectName implements Comparable, QueryExp {
*
* @since 1.6
*/
- public static final ObjectName WILDCARD = Util.newObjectName("*:*");
+ public static final ObjectName WILDCARD = valueOf("*:*");
// Category : Utilities <===================================
@@ -2064,7 +2179,7 @@ public class ObjectName implements Comparable, QueryExp {
* @exception NullPointerException if name
is null.
*
*/
- public boolean apply(ObjectName name) throws NullPointerException {
+ public boolean apply(ObjectName name) {
if (name == null) throw new NullPointerException();
diff --git a/src/share/classes/javax/management/QueryNotificationFilter.java b/src/share/classes/javax/management/QueryNotificationFilter.java
index 42451088f..7d1990fa2 100644
--- a/src/share/classes/javax/management/QueryNotificationFilter.java
+++ b/src/share/classes/javax/management/QueryNotificationFilter.java
@@ -170,7 +170,7 @@ public class QueryNotificationFilter implements NotificationFilter {
private static final long serialVersionUID = -8408613922660635231L;
private static final ObjectName DEFAULT_NAME =
- Util.newObjectName(":type=Notification");
+ ObjectName.valueOf(":type=Notification");
private static final QueryExp trueQuery;
static {
ValueExp zero = Query.value(0);
diff --git a/src/share/classes/javax/management/event/EventClientDelegateMBean.java b/src/share/classes/javax/management/event/EventClientDelegateMBean.java
index ba57cce9c..7c0b3107c 100644
--- a/src/share/classes/javax/management/event/EventClientDelegateMBean.java
+++ b/src/share/classes/javax/management/event/EventClientDelegateMBean.java
@@ -96,7 +96,7 @@ public interface EventClientDelegateMBean {
* {@value #OBJECT_NAME_STRING}
.
*/
public final static ObjectName OBJECT_NAME =
- Util.newObjectName(OBJECT_NAME_STRING);
+ ObjectName.valueOf(OBJECT_NAME_STRING);
/**
* A unique listener identifier specified for an EventClient.
diff --git a/src/share/classes/javax/management/namespace/MBeanServerSupport.java b/src/share/classes/javax/management/namespace/MBeanServerSupport.java
index 2f0e19838..903be3c30 100644
--- a/src/share/classes/javax/management/namespace/MBeanServerSupport.java
+++ b/src/share/classes/javax/management/namespace/MBeanServerSupport.java
@@ -193,14 +193,6 @@ import javax.management.loading.ClassLoaderRepository;
* }
*
* public class PropsMBS extends MBeanServerSupport {
- * private static ObjectName newObjectName(String name) {
- * try {
- * return new ObjectName(name);
- * } catch (MalformedObjectNameException e) {
- * throw new AssertionError(e);
- * }
- * }
- *
* public static class PropertyImpl implements PropertyMBean {
* private final String name;
*
@@ -219,7 +211,7 @@ import javax.management.loading.ClassLoaderRepository;
* throws InstanceNotFoundException {
*
* // Check that the name is a legal one for a Property MBean
- * ObjectName namePattern = newObjectName(
+ * ObjectName namePattern = ObjectName.valueOf(
* "com.example:type=Property,name=\"*\"");
* if (!namePattern.apply(name))
* throw new InstanceNotFoundException(name);
@@ -239,7 +231,7 @@ import javax.management.loading.ClassLoaderRepository;
* {@code Set names = new TreeSet();}
* Properties props = System.getProperties();
* for (String propName : props.stringPropertyNames()) {
- * ObjectName objectName = newObjectName(
+ * ObjectName objectName = ObjectName.valueOf(
* "com.example:type=Property,name=" +
* ObjectName.quote(propName));
* names.add(objectName);
@@ -278,7 +270,7 @@ import javax.management.loading.ClassLoaderRepository;
* }
*
* public void propertyChanged(String name, String newValue) {
- * ObjectName objectName = newObjectName(
+ * ObjectName objectName = ObjectName.valueOf(
* "com.example:type=Property,name=" + ObjectName.quote(name));
* Notification n = new Notification(
* "com.example.property.changed", objectName, 0L,
diff --git a/src/share/classes/sun/management/Util.java b/src/share/classes/sun/management/Util.java
index 3c0997531..1da808300 100644
--- a/src/share/classes/sun/management/Util.java
+++ b/src/share/classes/sun/management/Util.java
@@ -43,12 +43,8 @@ class Util {
return (String[]) list.toArray(EMPTY_STRING_ARRAY);
}
- static ObjectName newObjectName(String name) {
- return com.sun.jmx.mbeanserver.Util.newObjectName(name);
- }
-
public static ObjectName newObjectName(String domainAndType, String name) {
- return newObjectName(domainAndType + ",name=" + name);
+ return ObjectName.valueOf(domainAndType + ",name=" + name);
}
private static ManagementPermission monitorPermission =
diff --git a/test/javax/management/ObjectName/ValueOfTest.java b/test/javax/management/ObjectName/ValueOfTest.java
new file mode 100644
index 000000000..4a68a3d4c
--- /dev/null
+++ b/test/javax/management/ObjectName/ValueOfTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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 6734813
+ * @summary Test the ObjectName.valueOf methods
+ * @author Eamonn McManus
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Hashtable;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+public class ValueOfTest {
+ public static void main(String[] args) throws Exception {
+ // Calls that should work
+ testPositive("d:foo=bar,baz=buh");
+ testPositive("foo", "bar", "baz");
+ Hashtable h = new Hashtable();
+ h.put("foo", "bar");
+ h.put("baz", "buh");
+ testPositive("domain", h);
+
+ // Calls that should not work
+ testNegative("d");
+ testNegative("d:");
+ testNegative("d::foo=bar");
+ testNegative("d:", "foo", "bar");
+ testNegative("d", "foo=", "bar");
+ testNegative("d:", h);
+ testNegative("d", new Hashtable());
+ }
+
+ private static void testPositive(Object... args) throws Exception {
+ Method valueOf = valueOfMethod(args);
+ Method getInstance = getInstanceMethod(args);
+ Constructor> constructor = constructor(args);
+
+ Object valueOfValue = valueOf.invoke(null, args);
+ Object getInstanceValue = getInstance.invoke(null, args);
+ Object constructorValue = constructor.newInstance(args);
+
+ String argString =
+ Arrays.toString(args).replace('[', '(').replace(']', ')');
+
+ if (!valueOfValue.equals(getInstanceValue)) {
+ throw new Exception(
+ "valueOf" + argString + " differs from getInstance" +
+ argString);
+ }
+
+ if (!valueOfValue.equals(constructorValue)) {
+ throw new Exception(
+ "valueOf" + argString + " differs from new ObjectName " +
+ argString);
+ }
+
+ System.out.println("OK: valueOf" + argString);
+ }
+
+ private static void testNegative(Object... args) throws Exception {
+ Method valueOf = valueOfMethod(args);
+ Method getInstance = getInstanceMethod(args);
+
+ String argString =
+ Arrays.toString(args).replace('[', '(').replace(']', ')');
+
+ final Throwable valueOfException;
+ try {
+ valueOf.invoke(null, args);
+ throw new Exception("valueOf" + argString + " did not fail but should");
+ } catch (InvocationTargetException e) {
+ valueOfException = e.getCause();
+ }
+ if (!(valueOfException instanceof IllegalArgumentException)) {
+ throw new Exception(
+ "valueOf" + argString + " threw " +
+ valueOfException.getClass().getName() + " instead of " +
+ "IllegalArgumentException", valueOfException);
+ }
+
+ final Throwable valueOfCause = valueOfException.getCause();
+ if (!(valueOfCause instanceof MalformedObjectNameException)) {
+ throw new Exception(
+ "valueOf" + argString + " threw exception with wrong " +
+ "type of cause", valueOfCause);
+ }
+
+ if (!valueOfException.getMessage().equals(valueOfCause.getMessage())) {
+ // The IllegalArgumentException should have the same message as
+ // the MalformedObjectNameException it wraps.
+ // This isn't specified but is desirable.
+ throw new Exception(
+ "valueOf" + argString + ": message in wrapping " +
+ "IllegalArgumentException (" + valueOfException.getMessage() +
+ ") differs from message in wrapped " +
+ "MalformedObjectNameException (" + valueOfCause.getMessage() +
+ ")");
+ }
+
+ final Throwable getInstanceException;
+ try {
+ getInstance.invoke(null, args);
+ throw new Exception("getInstance" + argString + " did not fail but should");
+ } catch (InvocationTargetException e) {
+ getInstanceException = e.getCause();
+ }
+ if (!(getInstanceException instanceof MalformedObjectNameException)) {
+ throw new Exception(
+ "getInstance" + argString + " threw wrong exception",
+ getInstanceException);
+ }
+
+ if (!valueOfException.getMessage().equals(getInstanceException.getMessage())) {
+ // Again this is not specified.
+ throw new Exception(
+ "Exception message from valueOf" + argString + " (" +
+ valueOfException.getMessage() + ") differs from message " +
+ "from getInstance" + argString + " (" +
+ getInstanceException.getMessage() + ")");
+ }
+
+ System.out.println("OK (correct exception): valueOf" + argString);
+ }
+
+ private static Method valueOfMethod(Object[] args) throws Exception {
+ return method("valueOf", args);
+ }
+
+ private static Method getInstanceMethod(Object[] args) throws Exception {
+ return method("getInstance", args);
+ }
+
+ private static Method method(String name, Object[] args) throws Exception {
+ Class>[] argTypes = argTypes(args);
+ return ObjectName.class.getMethod(name, argTypes);
+ }
+
+ private static Constructor> constructor(Object[] args) throws Exception {
+ Class>[] argTypes = argTypes(args);
+ return ObjectName.class.getConstructor(argTypes);
+ }
+
+ private static Class>[] argTypes(Object[] args) {
+ Class>[] argTypes = new Class>[args.length];
+ for (int i = 0; i < args.length; i++)
+ argTypes[i] = args[i].getClass();
+ return argTypes;
+ }
+}
--
cgit v1.2.3
From 9e121110d16501a20f18ed055ff1ac0ee20383c3 Mon Sep 17 00:00:00 2001
From: emcmanus
Date: Wed, 10 Sep 2008 14:56:57 +0200
Subject: 6746759: Fix for 6734813 introduced build break Reviewed-by: dfuchs
---
src/share/classes/sun/management/ClassLoadingImpl.java | 2 +-
src/share/classes/sun/management/CompilationImpl.java | 2 +-
src/share/classes/sun/management/HotSpotDiagnostic.java | 2 +-
src/share/classes/sun/management/HotspotInternal.java | 2 +-
src/share/classes/sun/management/ManagementFactoryHelper.java | 4 ++--
src/share/classes/sun/management/MemoryImpl.java | 2 +-
src/share/classes/sun/management/OperatingSystemImpl.java | 2 +-
src/share/classes/sun/management/RuntimeImpl.java | 2 +-
src/share/classes/sun/management/ThreadImpl.java | 2 +-
9 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/share/classes/sun/management/ClassLoadingImpl.java b/src/share/classes/sun/management/ClassLoadingImpl.java
index 2f4b6ed07..9eda58380 100644
--- a/src/share/classes/sun/management/ClassLoadingImpl.java
+++ b/src/share/classes/sun/management/ClassLoadingImpl.java
@@ -71,6 +71,6 @@ class ClassLoadingImpl implements ClassLoadingMXBean {
native static void setVerboseClass(boolean value);
public ObjectName getObjectName() {
- return Util.newObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME);
+ return ObjectName.valueOf(ManagementFactory.CLASS_LOADING_MXBEAN_NAME);
}
}
diff --git a/src/share/classes/sun/management/CompilationImpl.java b/src/share/classes/sun/management/CompilationImpl.java
index d69d9cc64..9c13e67eb 100644
--- a/src/share/classes/sun/management/CompilationImpl.java
+++ b/src/share/classes/sun/management/CompilationImpl.java
@@ -70,7 +70,7 @@ class CompilationImpl implements CompilationMXBean {
}
public ObjectName getObjectName() {
- return Util.newObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME);
+ return ObjectName.valueOf(ManagementFactory.COMPILATION_MXBEAN_NAME);
}
diff --git a/src/share/classes/sun/management/HotSpotDiagnostic.java b/src/share/classes/sun/management/HotSpotDiagnostic.java
index f42188ff1..d33337fcf 100644
--- a/src/share/classes/sun/management/HotSpotDiagnostic.java
+++ b/src/share/classes/sun/management/HotSpotDiagnostic.java
@@ -117,6 +117,6 @@ public class HotSpotDiagnostic implements HotSpotDiagnosticMXBean {
}
public ObjectName getObjectName() {
- return Util.newObjectName("com.sun.management:type=HotSpotDiagnostic");
+ return ObjectName.valueOf("com.sun.management:type=HotSpotDiagnostic");
}
}
diff --git a/src/share/classes/sun/management/HotspotInternal.java b/src/share/classes/sun/management/HotspotInternal.java
index 7006699a4..88f9a8268 100644
--- a/src/share/classes/sun/management/HotspotInternal.java
+++ b/src/share/classes/sun/management/HotspotInternal.java
@@ -41,7 +41,7 @@ public class HotspotInternal
private final static String HOTSPOT_INTERNAL_MBEAN_NAME =
"sun.management:type=HotspotInternal";
- private static ObjectName objName = Util.newObjectName(HOTSPOT_INTERNAL_MBEAN_NAME);
+ private static ObjectName objName = ObjectName.valueOf(HOTSPOT_INTERNAL_MBEAN_NAME);
private MBeanServer server = null;
/**
diff --git a/src/share/classes/sun/management/ManagementFactoryHelper.java b/src/share/classes/sun/management/ManagementFactoryHelper.java
index 9bb4785d7..c07acfdbc 100644
--- a/src/share/classes/sun/management/ManagementFactoryHelper.java
+++ b/src/share/classes/sun/management/ManagementFactoryHelper.java
@@ -220,7 +220,7 @@ public class ManagementFactoryHelper {
*/
private static void addMBean(MBeanServer mbs, Object mbean, String mbeanName) {
try {
- final ObjectName objName = Util.newObjectName(mbeanName);
+ final ObjectName objName = ObjectName.valueOf(mbeanName);
// inner class requires these fields to be final
final MBeanServer mbs0 = mbs;
@@ -280,7 +280,7 @@ public class ManagementFactoryHelper {
private static void unregisterMBean(MBeanServer mbs, String mbeanName) {
try {
- final ObjectName objName = Util.newObjectName(mbeanName);
+ final ObjectName objName = ObjectName.valueOf(mbeanName);
// inner class requires these fields to be final
final MBeanServer mbs0 = mbs;
diff --git a/src/share/classes/sun/management/MemoryImpl.java b/src/share/classes/sun/management/MemoryImpl.java
index 29da467ce..aa56186ae 100644
--- a/src/share/classes/sun/management/MemoryImpl.java
+++ b/src/share/classes/sun/management/MemoryImpl.java
@@ -177,7 +177,7 @@ class MemoryImpl extends NotificationEmitterSupport
}
public ObjectName getObjectName() {
- return Util.newObjectName(ManagementFactory.MEMORY_MXBEAN_NAME);
+ return ObjectName.valueOf(ManagementFactory.MEMORY_MXBEAN_NAME);
}
}
diff --git a/src/share/classes/sun/management/OperatingSystemImpl.java b/src/share/classes/sun/management/OperatingSystemImpl.java
index cfe729688..9ab8b5695 100644
--- a/src/share/classes/sun/management/OperatingSystemImpl.java
+++ b/src/share/classes/sun/management/OperatingSystemImpl.java
@@ -74,7 +74,7 @@ public class OperatingSystemImpl implements OperatingSystemMXBean {
}
}
public ObjectName getObjectName() {
- return Util.newObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+ return ObjectName.valueOf(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
}
}
diff --git a/src/share/classes/sun/management/RuntimeImpl.java b/src/share/classes/sun/management/RuntimeImpl.java
index e58040e83..55bcbdc85 100644
--- a/src/share/classes/sun/management/RuntimeImpl.java
+++ b/src/share/classes/sun/management/RuntimeImpl.java
@@ -149,7 +149,7 @@ class RuntimeImpl implements RuntimeMXBean {
}
public ObjectName getObjectName() {
- return Util.newObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);
+ return ObjectName.valueOf(ManagementFactory.RUNTIME_MXBEAN_NAME);
}
}
diff --git a/src/share/classes/sun/management/ThreadImpl.java b/src/share/classes/sun/management/ThreadImpl.java
index d12258b9e..565966e9d 100644
--- a/src/share/classes/sun/management/ThreadImpl.java
+++ b/src/share/classes/sun/management/ThreadImpl.java
@@ -415,7 +415,7 @@ class ThreadImpl implements ThreadMXBean {
private static native void resetContentionTimes0(long tid);
public ObjectName getObjectName() {
- return Util.newObjectName(ManagementFactory.THREAD_MXBEAN_NAME);
+ return ObjectName.valueOf(ManagementFactory.THREAD_MXBEAN_NAME);
}
}
--
cgit v1.2.3
From 0a7c25b652c7794023624da781f979c40b993104 Mon Sep 17 00:00:00 2001
From: dfuchs
Date: Wed, 10 Sep 2008 16:27:13 +0200
Subject: 6746754: jmx namespace: test for leading separator missing 6669137:
RFE: InstanceNotFoundException should have a constructor that takes an
ObjectName 6746796: jmx namespaces: Several tests are missing an @bug or @run
keyword Summary: Note on 6669137: first implementation of 6669137 was
actually pushed with 5072476 - here we only have a small update and a test
case. Also re-fixes 6737133: Compilation failure of
test/javax/management/eventService/LeaseManagerDeadlockTest.java which had
failed. Reviewed-by: emcmanus, yjoan
---
.../com/sun/jmx/namespace/RoutingProxy.java | 17 +-
.../management/InstanceNotFoundException.java | 2 +-
.../MBeanServer/InstanceNotFoundExceptionTest.java | 76 +++++++
.../MBeanServerFactory/NamedMBeanServerTest.java | 1 +
.../eventService/LeaseManagerDeadlockTest.java | 1 +
.../management/namespace/DomainCreationTest.java | 1 +
.../namespace/EventWithNamespaceControlTest.java | 1 +
.../namespace/EventWithNamespaceTest.java | 2 +-
.../management/namespace/ExportNamespaceTest.java | 1 +
test/javax/management/namespace/JMXDomainTest.java | 1 +
.../namespace/JMXNamespaceSecurityTest.java | 1 +
.../management/namespace/JMXNamespaceTest.java | 1 +
.../management/namespace/JMXNamespaceViewTest.java | 1 +
.../management/namespace/JMXNamespacesTest.java | 1 +
.../namespace/JMXRemoteNamespaceTest.java | 1 +
.../javax/management/namespace/LazyDomainTest.java | 1 +
.../namespace/LeadingSeparatorsTest.java | 227 +++++++++++++++++++++
.../namespace/NamespaceCreationTest.java | 1 +
.../namespace/NamespaceNotificationsTest.java | 1 +
.../management/namespace/NullObjectNameTest.java | 1 +
.../javax/management/namespace/QueryNamesTest.java | 1 +
.../namespace/RemoveNotificationListenerTest.java | 1 +
.../namespace/RoutingServerProxyTest.java | 1 +
.../namespace/SerialParamProcessorTest.java | 1 +
.../management/namespace/SourceNamespaceTest.java | 1 +
.../namespace/VirtualMBeanNotifTest.java | 1 +
.../management/namespace/VirtualMBeanTest.java | 2 +-
.../namespace/VirtualNamespaceQueryTest.java | 1 +
.../management/namespace/VirtualPropsTest.java | 2 +-
29 files changed, 344 insertions(+), 6 deletions(-)
create mode 100644 test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java
create mode 100644 test/javax/management/namespace/LeadingSeparatorsTest.java
diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
index e0635c585..aa35c5bda 100644
--- a/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
@@ -48,6 +48,19 @@ import javax.management.namespace.JMXNamespaces;
* {@link RoutingConnectionProxy}: to narrow down into an
* MBeanServerConnection.
* {@link RoutingServerProxy}: to narrow down into an MBeanServer.
+ *
+ * This class can also be used to "broaden" from a namespace. The same
+ * class is used for both purposes because in both cases all that happens
+ * is that ObjectNames are rewritten in one way on the way in (e.g. the
+ * parameter of getMBeanInfo) and another way on the way out (e.g. the
+ * return value of queryNames).
+ *
+ * Specifically, if you narrow into "a//" then you want to add the
+ * "a//" prefix to ObjectNames on the way in and subtract it on the way
+ * out. But ClientContext uses this class to subtract the
+ * "jmx.context//foo=bar//" prefix on the way in and add it back on the
+ * way out.
+ *
*
* This API is a Sun internal API and is subject to changes without notice.
*
@@ -245,8 +258,8 @@ public abstract class RoutingProxy
throw x;
} catch (MBeanException ex) {
throw new IOException("Failed to get "+attributeName+": "+
- ex,
- ex.getTargetException());
+ ex.getCause(),
+ ex.getCause());
} catch (Exception ex) {
throw new IOException("Failed to get "+attributeName+": "+
ex,ex);
diff --git a/src/share/classes/javax/management/InstanceNotFoundException.java b/src/share/classes/javax/management/InstanceNotFoundException.java
index baeaed095..3a8376f7b 100644
--- a/src/share/classes/javax/management/InstanceNotFoundException.java
+++ b/src/share/classes/javax/management/InstanceNotFoundException.java
@@ -61,6 +61,6 @@ public class InstanceNotFoundException extends OperationsException {
* @since 1.7
*/
public InstanceNotFoundException(ObjectName name) {
- this(name.toString());
+ this(String.valueOf(name));
}
}
diff --git a/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java b/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java
new file mode 100644
index 000000000..300796553
--- /dev/null
+++ b/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 6669137
+ * @summary Test the constructors of InstanceNotFoundExceptionTest.
+ * @author Daniel Fuchs
+ * @compile InstanceNotFoundExceptionTest.java
+ * @run main InstanceNotFoundExceptionTest
+ */
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+public class InstanceNotFoundExceptionTest {
+ public static void main(String[] args) throws Exception {
+ final InstanceNotFoundException x =
+ new InstanceNotFoundException();
+ System.out.println("InstanceNotFoundException(): "+x.getMessage());
+
+ final String msg = "who is toto?";
+ final InstanceNotFoundException x2 =
+ new InstanceNotFoundException(msg);
+ if (!msg.equals(x2.getMessage()))
+ throw new Exception("Bad message: expected "+msg+
+ ", got "+x2.getMessage());
+ System.out.println("InstanceNotFoundException(" +
+ msg+"): "+x2.getMessage());
+
+ final InstanceNotFoundException x3 =
+ new InstanceNotFoundException((String)null);
+ if (x3.getMessage() != null)
+ throw new Exception("Bad message: expected "+null+
+ ", got "+x3.getMessage());
+ System.out.println("InstanceNotFoundException((String)null): "+
+ x3.getMessage());
+
+ final ObjectName n = new ObjectName("who is toto?:type=msg");
+ final InstanceNotFoundException x4 =
+ new InstanceNotFoundException(n);
+ if (!String.valueOf(n).equals(x4.getMessage()))
+ throw new Exception("Bad message: expected "+n+
+ ", got "+x4.getMessage());
+ System.out.println("InstanceNotFoundException(" +
+ n+"): "+x4.getMessage());
+
+ final InstanceNotFoundException x5 =
+ new InstanceNotFoundException((ObjectName)null);
+ if (!String.valueOf((ObjectName)null).equals(x5.getMessage()))
+ throw new Exception("Bad message: expected " +
+ String.valueOf((ObjectName)null)+" got "+x5.getMessage());
+ System.out.println("InstanceNotFoundException((ObjectName)null): "+
+ x5.getMessage());
+ }
+}
diff --git a/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java b/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java
index e26168318..8a8d248cb 100644
--- a/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java
+++ b/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java
@@ -25,6 +25,7 @@
* @test
* @summary Test named MBeanServers.
* @author Daniel Fuchs
+ * @bug 6299231
* @run clean NamedMBeanServerTest
* @run build NamedMBeanServerTest
* @run main NamedMBeanServerTest
diff --git a/test/javax/management/eventService/LeaseManagerDeadlockTest.java b/test/javax/management/eventService/LeaseManagerDeadlockTest.java
index 453aafe4b..ab7d14d54 100644
--- a/test/javax/management/eventService/LeaseManagerDeadlockTest.java
+++ b/test/javax/management/eventService/LeaseManagerDeadlockTest.java
@@ -27,6 +27,7 @@
* @summary Check that a lock is not held when a LeaseManager expires.
* @author Eamonn McManus
* @compile -XDignore.symbol.file=true LeaseManagerDeadlockTest.java
+ * @run main LeaseManagerDeadlockTest
*/
import com.sun.jmx.event.LeaseManager;
diff --git a/test/javax/management/namespace/DomainCreationTest.java b/test/javax/management/namespace/DomainCreationTest.java
index 93a98dc62..02a09868e 100644
--- a/test/javax/management/namespace/DomainCreationTest.java
+++ b/test/javax/management/namespace/DomainCreationTest.java
@@ -23,6 +23,7 @@
/*
*
* @test DomainCreationTest.java
+ * @bug 5072476
* @summary Test the creation and registration of JMXDomain instances.
* @author Daniel Fuchs
* @run clean DomainCreationTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/EventWithNamespaceControlTest.java b/test/javax/management/namespace/EventWithNamespaceControlTest.java
index c1e5a9d46..1e3901104 100644
--- a/test/javax/management/namespace/EventWithNamespaceControlTest.java
+++ b/test/javax/management/namespace/EventWithNamespaceControlTest.java
@@ -27,6 +27,7 @@
* @summary Check -Djmx.remote.use.event.service=true and
* -Djmx.remote.delegate.event.service
* @author Daniel Fuchs
+ * @bug 5072476 5108776
* @run clean EventWithNamespaceTest EventWithNamespaceControlTest
* Wombat WombatMBean JMXRemoteTargetNamespace
* NamespaceController NamespaceControllerMBean
diff --git a/test/javax/management/namespace/EventWithNamespaceTest.java b/test/javax/management/namespace/EventWithNamespaceTest.java
index 44fca88c7..748fdbeff 100644
--- a/test/javax/management/namespace/EventWithNamespaceTest.java
+++ b/test/javax/management/namespace/EventWithNamespaceTest.java
@@ -24,7 +24,7 @@
/*
*
* @test EventWithNamespaceTest.java 1.8
- * @bug 6539857
+ * @bug 6539857 5072476 5108776
* @summary General Namespace & Notifications test.
* @author Daniel Fuchs
* @run clean EventWithNamespaceTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/ExportNamespaceTest.java b/test/javax/management/namespace/ExportNamespaceTest.java
index e73452714..ec49a4c0c 100644
--- a/test/javax/management/namespace/ExportNamespaceTest.java
+++ b/test/javax/management/namespace/ExportNamespaceTest.java
@@ -26,6 +26,7 @@
* @summary Test that you can export a single namespace through a
* JMXConnectorServer.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean ExportNamespaceTest Wombat WombatMBean
* @run build ExportNamespaceTest Wombat WombatMBean
* @run main ExportNamespaceTest
diff --git a/test/javax/management/namespace/JMXDomainTest.java b/test/javax/management/namespace/JMXDomainTest.java
index 4a1a14e96..258cead1a 100644
--- a/test/javax/management/namespace/JMXDomainTest.java
+++ b/test/javax/management/namespace/JMXDomainTest.java
@@ -23,6 +23,7 @@
/*
*
* @test JMXDomainTest.java
+ * @bug 5072476
* @summary Basic test for JMXDomain.
* @author Daniel Fuchs
* @run clean JMXDomainTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/JMXNamespaceSecurityTest.java b/test/javax/management/namespace/JMXNamespaceSecurityTest.java
index b948012f1..213ffbfb6 100644
--- a/test/javax/management/namespace/JMXNamespaceSecurityTest.java
+++ b/test/javax/management/namespace/JMXNamespaceSecurityTest.java
@@ -26,6 +26,7 @@
* @test JMXNamespaceSecurityTest.java
* @summary General JMXNamespaceSecurityTest test.
* @author Daniel Fuchs
+ * @bug 5072476 6299231
* @run clean JMXNamespaceViewTest JMXNamespaceSecurityTest Wombat WombatMBean
* LazyDomainTest
* @run build JMXNamespaceSecurityTest JMXNamespaceViewTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/JMXNamespaceTest.java b/test/javax/management/namespace/JMXNamespaceTest.java
index da553f9c8..1c2ffac9d 100644
--- a/test/javax/management/namespace/JMXNamespaceTest.java
+++ b/test/javax/management/namespace/JMXNamespaceTest.java
@@ -25,6 +25,7 @@
*
* @test JMXNamespaceTest.java
* @summary General JMXNamespace test.
+ * @bug 5072476
* @author Daniel Fuchs
* @run clean JMXNamespaceTest
* Wombat WombatMBean JMXRemoteTargetNamespace
diff --git a/test/javax/management/namespace/JMXNamespaceViewTest.java b/test/javax/management/namespace/JMXNamespaceViewTest.java
index ad51af301..e13496829 100644
--- a/test/javax/management/namespace/JMXNamespaceViewTest.java
+++ b/test/javax/management/namespace/JMXNamespaceViewTest.java
@@ -24,6 +24,7 @@
*
* @test JMXNamespaceViewTest.java
* @summary Test the JMXNamespaceView class.
+ * @bug 5072476
* @author Daniel Fuchs
* @run clean JMXNamespaceViewTest Wombat WombatMBean
* @run build JMXNamespaceViewTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/JMXNamespacesTest.java b/test/javax/management/namespace/JMXNamespacesTest.java
index 4249bf104..4dc7c518a 100644
--- a/test/javax/management/namespace/JMXNamespacesTest.java
+++ b/test/javax/management/namespace/JMXNamespacesTest.java
@@ -24,6 +24,7 @@
* @test JMXNamespacesTest.java
* @summary Test the static method that rewrite ObjectNames in JMXNamespacesTest
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean JMXNamespacesTest
* @compile -XDignore.symbol.file=true JMXNamespacesTest.java
* @run main JMXNamespacesTest
diff --git a/test/javax/management/namespace/JMXRemoteNamespaceTest.java b/test/javax/management/namespace/JMXRemoteNamespaceTest.java
index ccc73bfaf..8e5f795a6 100644
--- a/test/javax/management/namespace/JMXRemoteNamespaceTest.java
+++ b/test/javax/management/namespace/JMXRemoteNamespaceTest.java
@@ -25,6 +25,7 @@
* @test JMXRemoteNamespaceTest.java
* @summary Basic tests on a JMXRemoteNamespace.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean JMXRemoteNamespaceTest Wombat WombatMBean
* @run build JMXRemoteNamespaceTest Wombat WombatMBean
* @run main JMXRemoteNamespaceTest
diff --git a/test/javax/management/namespace/LazyDomainTest.java b/test/javax/management/namespace/LazyDomainTest.java
index 83439011e..eda9b6669 100644
--- a/test/javax/management/namespace/LazyDomainTest.java
+++ b/test/javax/management/namespace/LazyDomainTest.java
@@ -23,6 +23,7 @@
/*
*
* @test LazyDomainTest.java
+ * @bug 5072476
* @summary Basic test for Lazy Domains.
* @author Daniel Fuchs
* @run clean LazyDomainTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/LeadingSeparatorsTest.java b/test/javax/management/namespace/LeadingSeparatorsTest.java
new file mode 100644
index 000000000..5660b2753
--- /dev/null
+++ b/test/javax/management/namespace/LeadingSeparatorsTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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 LeadingSeparatorsTest.java
+ * @summary Test that the semantics of a leading // in ObjectName is respected.
+ * @author Daniel Fuchs
+ * @bug 5072476
+ * @run clean LeadingSeparatorsTest Wombat WombatMBean
+ * @compile -XDignore.symbol.file=true LeadingSeparatorsTest.java
+ * @run build LeadingSeparatorsTest Wombat WombatMBean
+ * @run main LeadingSeparatorsTest
+ */
+
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.logging.Logger;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.JMXRemoteNamespace;
+import javax.management.namespace.JMXNamespace;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ * Class LeadingSeparatorsTest
+ * @author Sun Microsystems, 2005 - All rights reserved.
+ */
+public class LeadingSeparatorsTest {
+
+ /**
+ * A logger for this class.
+ **/
+ private static final Logger LOG =
+ Logger.getLogger(LeadingSeparatorsTest.class.getName());
+
+ /** Creates a new instance of NullObjectNameTest */
+ public LeadingSeparatorsTest() {
+ }
+
+ public static interface MyWombatMBean extends WombatMBean {
+ public Set untrue(ObjectName pat) throws Exception;
+ }
+ public static class MyWombat
+ extends Wombat implements MyWombatMBean {
+ public MyWombat() throws NotCompliantMBeanException {
+ super(MyWombatMBean.class);
+ }
+
+ public Set untrue(ObjectName pat) throws Exception {
+ final Set res=listMatching(pat.withDomain("*"));
+ final Set untrue = new HashSet();
+ for (ObjectName a:res) {
+ untrue.add(a.withDomain(pat.getDomain()+"//"+a.getDomain()));
+ }
+ return untrue;
+ }
+ }
+
+ static String failure=null;
+
+ public static void testRegister() throws Exception {
+ final MBeanServer top = ManagementFactory.getPlatformMBeanServer();
+ final MBeanServer sub = MBeanServerFactory.createMBeanServer();
+ final JMXServiceURL url = new JMXServiceURL("rmi",null,0);
+ final JMXConnectorServer srv =
+ JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub);
+ srv.start();
+
+ try {
+
+ // Create a namespace rmi// that points to 'sub' and flows through
+ // a JMXRemoteNamespace connected to 'srv'
+ // The namespace rmi// will accept createMBean, but not registerMBean.
+ //
+ final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace.
+ newJMXRemoteNamespace(srv.getAddress(),null);
+ top.registerMBean(rmiHandler,
+ JMXNamespaces.getNamespaceObjectName("rmi"));
+ top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"),
+ "connect", null, null);
+
+ // Create a namespace direct// that points to 'sub' and flows
+ // through a direct reference to 'sub'.
+ // The namespace direct// will accept createMBean, and registerMBean.
+ //
+ final JMXNamespace directHandler = new JMXNamespace(sub);
+ top.registerMBean(directHandler,
+ JMXNamespaces.getNamespaceObjectName("direct"));
+
+ final ObjectName n1 = new ObjectName("//direct//w:type=Wombat");
+ final ObjectName n2 = new ObjectName("direct//w:type=Wombat");
+ final ObjectName n3 = new ObjectName("//rmi//w:type=Wombat");
+ final ObjectName n4 = new ObjectName("rmi//w:type=Wombat");
+
+ // register wombat using an object name with a leading //
+ final Object obj = new MyWombat();
+ // check that returned object name doesn't have the leading //
+ assertEquals(n2,top.registerMBean(obj, n1).getObjectName());
+ System.out.println(n1+" registered");
+
+ // check that the registered Wombat can be accessed with all its
+ // names.
+ System.out.println(n2+" mood is: "+top.getAttribute(n2, "Mood"));
+ System.out.println(n1+" mood is: "+top.getAttribute(n1, "Mood"));
+ System.out.println(n4+" mood is: "+top.getAttribute(n4, "Mood"));
+ System.out.println(n3+" mood is: "+top.getAttribute(n3, "Mood"));
+
+ // call listMatching. The result should not contain any prefix.
+ final Set res = (Set)
+ top.invoke(n3, "listMatching",
+ // remove rmi// from rmi//*:*
+ JMXNamespaces.deepReplaceHeadNamespace(
+ new Object[] {ObjectName.WILDCARD.withDomain("rmi//*")},
+ "rmi", ""), new String[] {ObjectName.class.getName()});
+
+ // add rmi// prefix to all names in res.
+ final Set res1 =
+ JMXNamespaces.deepReplaceHeadNamespace(res, "", "rmi");
+ System.out.println("got: "+res1);
+
+ // compute expected result
+ final Set res2 = sub.queryNames(null,null);
+ final Set res3 = new HashSet();
+ for (ObjectName o:res2) {
+ res3.add(o.withDomain("rmi//"+o.getDomain()));
+ }
+ System.out.println("expected: "+res3);
+ assertEquals(res1, res3);
+
+ // invoke "untrue(//niark//niark:*)"
+ // should return a set were all ObjectNames begin with
+ // //niark//niark//
+ //
+ final Set res4 = (Set)
+ top.invoke(n3, "untrue",
+ // remove niark//niark : should remove nothing since
+ // our ObjectName begins with a leading //
+ JMXNamespaces.deepReplaceHeadNamespace(
+ new Object[] {
+ ObjectName.WILDCARD.withDomain("//niark//niark")},
+ "niark//niark", ""),
+ new String[] {ObjectName.class.getName()});
+ System.out.println("got: "+res4);
+
+ // add rmi// should add nothing since the returned names have a
+ // leading //
+ //
+ final Set res5 =
+ JMXNamespaces.deepReplaceHeadNamespace(res4, "", "rmi");
+ System.out.println("got#2: "+res5);
+
+ // compute expected result
+ final Set res6 = new HashSet();
+ for (ObjectName o:res2) {
+ res6.add(o.withDomain("//niark//niark//"+o.getDomain()));
+ }
+ System.out.println("expected: "+res6);
+
+ // both res4 and res5 should be equals to the expected result.
+ assertEquals(res4, res6);
+ assertEquals(res5, res6);
+
+ } finally {
+ srv.stop();
+ }
+
+ if (failure != null)
+ throw new Exception(failure);
+
+
+ }
+ private static void assertEquals(Object x, Object y) {
+ if (!equal(x, y))
+ failed("expected " + string(x) + "; got " + string(y));
+ }
+
+ private static boolean equal(Object x, Object y) {
+ if (x == y)
+ return true;
+ if (x == null || y == null)
+ return false;
+ if (x.getClass().isArray())
+ return Arrays.deepEquals(new Object[] {x}, new Object[] {y});
+ return x.equals(y);
+ }
+
+ private static String string(Object x) {
+ String s = Arrays.deepToString(new Object[] {x});
+ return s.substring(1, s.length() - 1);
+ }
+
+
+ private static void failed(String why) {
+ failure = why;
+ new Throwable("FAILED: " + why).printStackTrace(System.out);
+ }
+
+ public static void main(String[] args) throws Exception {
+ testRegister();
+ }
+}
diff --git a/test/javax/management/namespace/NamespaceCreationTest.java b/test/javax/management/namespace/NamespaceCreationTest.java
index 981cdda42..871bf0220 100644
--- a/test/javax/management/namespace/NamespaceCreationTest.java
+++ b/test/javax/management/namespace/NamespaceCreationTest.java
@@ -25,6 +25,7 @@
* @test NamespaceCreationTest.java
* @summary General JMXNamespace test.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean NamespaceCreationTest Wombat WombatMBean
* @run build NamespaceCreationTest Wombat WombatMBean
* @run main NamespaceCreationTest
diff --git a/test/javax/management/namespace/NamespaceNotificationsTest.java b/test/javax/management/namespace/NamespaceNotificationsTest.java
index ae5bb3c59..9c5a1a04a 100644
--- a/test/javax/management/namespace/NamespaceNotificationsTest.java
+++ b/test/javax/management/namespace/NamespaceNotificationsTest.java
@@ -25,6 +25,7 @@
*
* @test NamespaceNotificationsTest.java 1.12
* @summary General Namespace & Notifications test.
+ * @bug 5072476
* @author Daniel Fuchs
* @run clean NamespaceNotificationsTest
* Wombat WombatMBean JMXRemoteTargetNamespace
diff --git a/test/javax/management/namespace/NullObjectNameTest.java b/test/javax/management/namespace/NullObjectNameTest.java
index 7624fb9d9..156e7661d 100644
--- a/test/javax/management/namespace/NullObjectNameTest.java
+++ b/test/javax/management/namespace/NullObjectNameTest.java
@@ -24,6 +24,7 @@
* @test NullObjectNameTest.java
* @summary Test that null ObjectName are correctly handled in namespaces.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean NullObjectNameTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true NullObjectNameTest.java
* @run build NullObjectNameTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/QueryNamesTest.java b/test/javax/management/namespace/QueryNamesTest.java
index 6e15c9a75..1af597ace 100644
--- a/test/javax/management/namespace/QueryNamesTest.java
+++ b/test/javax/management/namespace/QueryNamesTest.java
@@ -25,6 +25,7 @@
* @test QueryNamesTest.java 1.4
* @summary Test how queryNames works with Namespaces.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean QueryNamesTest Wombat WombatMBean
* @run build QueryNamesTest Wombat WombatMBean
* @run main QueryNamesTest
diff --git a/test/javax/management/namespace/RemoveNotificationListenerTest.java b/test/javax/management/namespace/RemoveNotificationListenerTest.java
index 08375c0db..a8ea2aee3 100644
--- a/test/javax/management/namespace/RemoveNotificationListenerTest.java
+++ b/test/javax/management/namespace/RemoveNotificationListenerTest.java
@@ -25,6 +25,7 @@
* @test RemoveNotificationListenerTest.java 1.8
* @summary General RemoveNotificationListenerTest test.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean RemoveNotificationListenerTest JMXRemoteTargetNamespace
* @compile -XDignore.symbol.file=true JMXRemoteTargetNamespace.java
* @run build RemoveNotificationListenerTest JMXRemoteTargetNamespace
diff --git a/test/javax/management/namespace/RoutingServerProxyTest.java b/test/javax/management/namespace/RoutingServerProxyTest.java
index c0302698c..698021321 100644
--- a/test/javax/management/namespace/RoutingServerProxyTest.java
+++ b/test/javax/management/namespace/RoutingServerProxyTest.java
@@ -25,6 +25,7 @@
* @test RoutingServerProxyTest.java 1.6
* @summary General RoutingServerProxyTest test.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean RoutingServerProxyTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true RoutingServerProxyTest.java
* @run build RoutingServerProxyTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/SerialParamProcessorTest.java b/test/javax/management/namespace/SerialParamProcessorTest.java
index 26dd77572..20df761d0 100644
--- a/test/javax/management/namespace/SerialParamProcessorTest.java
+++ b/test/javax/management/namespace/SerialParamProcessorTest.java
@@ -26,6 +26,7 @@
* @test SerialParamProcessorTest.java 1.8
* @summary General SerialParamProcessorTest test.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean SerialParamProcessorTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true SerialParamProcessorTest.java
* @run build SerialParamProcessorTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/SourceNamespaceTest.java b/test/javax/management/namespace/SourceNamespaceTest.java
index 745564b8c..2335eb297 100644
--- a/test/javax/management/namespace/SourceNamespaceTest.java
+++ b/test/javax/management/namespace/SourceNamespaceTest.java
@@ -24,6 +24,7 @@
*
* @test SourceNamespaceTest.java
* @summary Test how queryNames works with Namespaces.
+ * @bug 5072476
* @author Daniel Fuchs
* @run clean SourceNamespaceTest Wombat WombatMBean
* @run build SourceNamespaceTest Wombat WombatMBean
diff --git a/test/javax/management/namespace/VirtualMBeanNotifTest.java b/test/javax/management/namespace/VirtualMBeanNotifTest.java
index 301af7acd..cc7bbaf95 100644
--- a/test/javax/management/namespace/VirtualMBeanNotifTest.java
+++ b/test/javax/management/namespace/VirtualMBeanNotifTest.java
@@ -25,6 +25,7 @@
* @test VirtualMBeanNotifTest.java
* @bug 5108776
* @build VirtualMBeanNotifTest Wombat WombatMBean
+ * @run main VirtualMBeanNotifTest
* @summary Test that Virtual MBeans can be implemented and emit notifs.
* @author Daniel Fuchs
*/
diff --git a/test/javax/management/namespace/VirtualMBeanTest.java b/test/javax/management/namespace/VirtualMBeanTest.java
index 85860df34..03fd3983e 100644
--- a/test/javax/management/namespace/VirtualMBeanTest.java
+++ b/test/javax/management/namespace/VirtualMBeanTest.java
@@ -23,7 +23,7 @@
/*
* @test VirtualMBeanTest.java
- * @bug 5108776
+ * @bug 5108776 5072476
* @summary Test that Virtual MBeans can be implemented and emit notifs.
* @author Eamonn McManus
*/
diff --git a/test/javax/management/namespace/VirtualNamespaceQueryTest.java b/test/javax/management/namespace/VirtualNamespaceQueryTest.java
index 020c1224f..8af244a7b 100644
--- a/test/javax/management/namespace/VirtualNamespaceQueryTest.java
+++ b/test/javax/management/namespace/VirtualNamespaceQueryTest.java
@@ -26,6 +26,7 @@
* @test VirtualNamespaceQueryTest.java
* @summary General VirtualNamespaceQueryTest test.
* @author Daniel Fuchs
+ * @bug 5072476
* @run clean VirtualNamespaceQueryTest Wombat WombatMBean
* NamespaceController NamespaceControllerMBean
* JMXRemoteTargetNamespace
diff --git a/test/javax/management/namespace/VirtualPropsTest.java b/test/javax/management/namespace/VirtualPropsTest.java
index 8bb57edd5..904cc5359 100644
--- a/test/javax/management/namespace/VirtualPropsTest.java
+++ b/test/javax/management/namespace/VirtualPropsTest.java
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 5108776
+ * @bug 5108776 5072476
* @summary Test the properties use case for Virtual MBeans that is documented
* in MBeanServerSupport.
* @author Eamonn McManus
--
cgit v1.2.3
From 93d284029685169131e764bc0ad929d530230968 Mon Sep 17 00:00:00 2001
From: bristor
Date: Thu, 11 Sep 2008 14:58:57 -0700
Subject: 6440786: Cannot create a ZIP file containing zero entries Summary:
Allow reading and writing of ZIP files with zero entries. Reviewed-by: alanb
---
.../classes/java/util/zip/ZipOutputStream.java | 5 +-
src/share/native/java/util/zip/zip_util.c | 26 +++-
test/java/util/zip/TestEmptyZip.java | 147 +++++++++++++++++++++
3 files changed, 167 insertions(+), 11 deletions(-)
create mode 100644 test/java/util/zip/TestEmptyZip.java
diff --git a/src/share/classes/java/util/zip/ZipOutputStream.java b/src/share/classes/java/util/zip/ZipOutputStream.java
index 653942682..797a37392 100644
--- a/src/share/classes/java/util/zip/ZipOutputStream.java
+++ b/src/share/classes/java/util/zip/ZipOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-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
@@ -317,9 +317,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (current != null) {
closeEntry();
}
- if (xentries.size() < 1) {
- throw new ZipException("ZIP file must have at least one entry");
- }
// write central directory
long off = written;
for (XEntry xentry : xentries)
diff --git a/src/share/native/java/util/zip/zip_util.c b/src/share/native/java/util/zip/zip_util.c
index 1f6e04a1f..5d518cf4c 100644
--- a/src/share/native/java/util/zip/zip_util.c
+++ b/src/share/native/java/util/zip/zip_util.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1995-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
@@ -722,16 +722,22 @@ ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
}
len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END);
- if (len == -1) {
- if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
- *pmsg = errbuf;
+ if (len <= 0) {
+ if (len == 0) { /* zip file is empty */
+ if (pmsg) {
+ *pmsg = "zip file is empty";
+ }
+ } else { /* error */
+ if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
+ *pmsg = errbuf;
+ }
ZFILE_Close(zfd);
freeZip(zip);
return NULL;
}
zip->zfd = zfd;
- if (readCEN(zip, -1) <= 0) {
+ if (readCEN(zip, -1) < 0) {
/* An error occurred while trying to read the zip file */
if (pmsg != 0) {
/* Set the zip error message */
@@ -947,10 +953,15 @@ jzentry *
ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
{
unsigned int hsh = hash(name);
- jint idx = zip->table[hsh % zip->tablelen];
- jzentry *ze;
+ jint idx;
+ jzentry *ze = 0;
ZIP_Lock(zip);
+ if (zip->total == 0) {
+ goto Finally;
+ }
+
+ idx = zip->table[hsh % zip->tablelen];
/*
* This while loop is an optimization where a double lookup
@@ -1025,6 +1036,7 @@ ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
ulen = 0;
}
+Finally:
ZIP_Unlock(zip);
return ze;
}
diff --git a/test/java/util/zip/TestEmptyZip.java b/test/java/util/zip/TestEmptyZip.java
new file mode 100644
index 000000000..d19dee4d4
--- /dev/null
+++ b/test/java/util/zip/TestEmptyZip.java
@@ -0,0 +1,147 @@
+/*
+ * 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 6334003 6440786
+ * @summary Test ability to write and read zip files that have no entries.
+ * @author Dave Bristor
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+public class TestEmptyZip {
+ public static void realMain(String[] args) throws Throwable {
+ String zipName = "foo.zip";
+ File f = new File(System.getProperty("test.scratch", "."), zipName);
+ if (f.exists() && !f.delete()) {
+ throw new Exception("failed to delete " + zipName);
+ }
+
+ // Verify 0-length file cannot be read
+ f.createNewFile();
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(f);
+ fail();
+ } catch (Exception ex) {
+ check(ex.getMessage().contains("zip file is empty"));
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+
+ ZipInputStream zis = null;
+ try {
+ zis = new ZipInputStream(new FileInputStream(f));
+ ZipEntry ze = zis.getNextEntry();
+ check(ze == null);
+ } catch (Exception ex) {
+ unexpected(ex);
+ } finally {
+ if (zis != null) {
+ zis.close();
+ }
+ }
+
+ f.delete();
+
+ // Verify 0-entries file can be written
+ write(f);
+
+ // Verify 0-entries file can be read
+ readFile(f);
+ readStream(f);
+
+ f.delete();
+ }
+
+ static void write(File f) throws Exception {
+ ZipOutputStream zos = null;
+ try {
+ zos = new ZipOutputStream(new FileOutputStream(f));
+ zos.finish();
+ zos.close();
+ pass();
+ } catch (Exception ex) {
+ unexpected(ex);
+ } finally {
+ if (zos != null) {
+ zos.close();
+ }
+ }
+ }
+
+ static void readFile(File f) throws Exception {
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(f);
+
+ Enumeration e = zf.entries();
+ while (e.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry) e.nextElement();
+ fail();
+ }
+ zf.close();
+ pass();
+ } catch (Exception ex) {
+ unexpected(ex);
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+ }
+
+ static void readStream(File f) throws Exception {
+ ZipInputStream zis = null;
+ try {
+ zis = new ZipInputStream(new FileInputStream(f));
+ ZipEntry ze = zis.getNextEntry();
+ check(ze == null);
+ byte[] buf = new byte[1024];
+ check(zis.read(buf, 0, 1024) == -1);
+ } finally {
+ if (zis != null) {
+ zis.close();
+ }
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--
cgit v1.2.3
From 8849a7c0cc976aa9f3d4be842452099ed8891826 Mon Sep 17 00:00:00 2001
From: emcmanus
Date: Fri, 12 Sep 2008 15:17:52 +0200
Subject: 6747411: EventClient causes thread leaks Summary: Reworked thread
management in EventClient and related classes. Reviewed-by: sjiang, dfuchs
---
.../classes/com/sun/jmx/event/LeaseManager.java | 11 +-
.../com/sun/jmx/event/RepeatedSingletonJob.java | 4 +-
.../remote/internal/ClientCommunicatorAdmin.java | 4 +-
.../javax/management/event/EventClient.java | 5 +-
.../javax/management/event/FetchingEventRelay.java | 52 +++---
.../management/event/RMIPushEventForwarder.java | 2 +-
.../javax/management/remote/rmi/RMIConnector.java | 2 +-
.../eventService/EventClientThreadTest.java | 176 +++++++++++++++++++++
.../management/eventService/SharingThreadTest.java | 2 +-
9 files changed, 220 insertions(+), 38 deletions(-)
create mode 100644 test/javax/management/eventService/EventClientThreadTest.java
diff --git a/src/share/classes/com/sun/jmx/event/LeaseManager.java b/src/share/classes/com/sun/jmx/event/LeaseManager.java
index cb1b88bf5..33409a06c 100644
--- a/src/share/classes/com/sun/jmx/event/LeaseManager.java
+++ b/src/share/classes/com/sun/jmx/event/LeaseManager.java
@@ -27,7 +27,6 @@ package com.sun.jmx.event;
import com.sun.jmx.remote.util.ClassLogger;
import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -115,6 +114,7 @@ public class LeaseManager {
scheduled = null;
}
callback.run();
+ executor.shutdown();
}
}
@@ -131,6 +131,13 @@ public class LeaseManager {
logger.trace("stop", "canceling lease");
scheduled.cancel(false);
scheduled = null;
+ try {
+ executor.shutdown();
+ } catch (SecurityException e) {
+ // OK: caller doesn't have RuntimePermission("modifyThread")
+ // which is unlikely in reality but triggers a test failure otherwise
+ logger.trace("stop", "exception from executor.shutdown", e);
+ }
}
private final Runnable callback;
@@ -138,7 +145,7 @@ public class LeaseManager {
private final ScheduledExecutorService executor
= Executors.newScheduledThreadPool(1,
- new DaemonThreadFactory("LeaseManager"));
+ new DaemonThreadFactory("JMX LeaseManager %d"));
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "LeaseManager");
diff --git a/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java b/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java
index 7de1b40e9..2fe4a3a15 100644
--- a/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java
+++ b/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java
@@ -95,7 +95,9 @@ public abstract class RepeatedSingletonJob implements Runnable {
executor.execute(this);
} catch (RejectedExecutionException e) {
logger.warning(
- "setEventReceiver", "Executor threw exception", e);
+ "execute",
+ "Executor threw exception (" + this.getClass().getName() + ")",
+ e);
throw new RejectedExecutionException(
"Executor.execute threw exception -" +
"should not be possible", e);
diff --git a/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java b/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java
index a6635aad8..f90cbc4c5 100644
--- a/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java
+++ b/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java
@@ -32,13 +32,15 @@ import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
public abstract class ClientCommunicatorAdmin {
+ private static volatile long threadNo = 1;
+
public ClientCommunicatorAdmin(long period) {
this.period = period;
if (period > 0) {
checker = new Checker();
- Thread t = new Thread(checker);
+ Thread t = new Thread(checker, "JMX client heartbeat " + ++threadNo);
t.setDaemon(true);
t.start();
} else
diff --git a/src/share/classes/javax/management/event/EventClient.java b/src/share/classes/javax/management/event/EventClient.java
index 4b8101353..10a4df500 100644
--- a/src/share/classes/javax/management/event/EventClient.java
+++ b/src/share/classes/javax/management/event/EventClient.java
@@ -264,11 +264,12 @@ public class EventClient implements EventConsumer, NotificationManager {
new PerThreadGroupPool.Create() {
public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) {
ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
- "EventClient lease renewer %d");
+ "JMX EventClient lease renewer %d");
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(
20, daemonThreadFactory);
- exec.setKeepAliveTime(3, TimeUnit.SECONDS);
+ exec.setKeepAliveTime(1, TimeUnit.SECONDS);
exec.allowCoreThreadTimeOut(true);
+ exec.setRemoveOnCancelPolicy(true);
return exec;
}
};
diff --git a/src/share/classes/javax/management/event/FetchingEventRelay.java b/src/share/classes/javax/management/event/FetchingEventRelay.java
index 2b65f9b12..9aa68df0f 100644
--- a/src/share/classes/javax/management/event/FetchingEventRelay.java
+++ b/src/share/classes/javax/management/event/FetchingEventRelay.java
@@ -31,10 +31,8 @@ import com.sun.jmx.remote.util.ClassLogger;
import java.io.IOException;
import java.io.NotSerializableException;
import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import javax.management.MBeanException;
@@ -215,50 +213,47 @@ public class FetchingEventRelay implements EventRelay {
this.maxNotifs = maxNotifs;
if (executor == null) {
- executor = Executors.newSingleThreadScheduledExecutor(
+ ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(1,
daemonThreadFactory);
- }
+ stpe.setKeepAliveTime(1, TimeUnit.SECONDS);
+ stpe.allowCoreThreadTimeOut(true);
+ executor = stpe;
+ this.defaultExecutor = stpe;
+ } else
+ this.defaultExecutor = null;
this.executor = executor;
- if (executor instanceof ScheduledExecutorService)
- leaseScheduler = (ScheduledExecutorService) executor;
- else {
- leaseScheduler = Executors.newSingleThreadScheduledExecutor(
- daemonThreadFactory);
- }
startSequenceNumber = 0;
fetchingJob = new MyJob();
}
- public void setEventReceiver(EventReceiver eventReceiver) {
+ public synchronized void setEventReceiver(EventReceiver eventReceiver) {
if (logger.traceOn()) {
logger.trace("setEventReceiver", ""+eventReceiver);
}
EventReceiver old = this.eventReceiver;
- synchronized(fetchingJob) {
- this.eventReceiver = eventReceiver;
- if (old == null && eventReceiver != null)
- fetchingJob.resume();
- }
+ this.eventReceiver = eventReceiver;
+ if (old == null && eventReceiver != null)
+ fetchingJob.resume();
}
public String getClientId() {
return clientId;
}
- public void stop() {
+ public synchronized void stop() {
if (logger.traceOn()) {
logger.trace("stop", "");
}
- synchronized(fetchingJob) {
- if (stopped) {
- return;
- }
-
- stopped = true;
- clientId = null;
+ if (stopped) {
+ return;
}
+
+ stopped = true;
+ clientId = null;
+ if (defaultExecutor != null)
+ defaultExecutor.shutdown();
}
private class MyJob extends RepeatedSingletonJob {
@@ -372,10 +367,9 @@ public class FetchingEventRelay implements EventRelay {
private final EventClientDelegateMBean delegate;
private String clientId;
private boolean stopped = false;
- private volatile ScheduledFuture> leaseRenewalFuture;
private final Executor executor;
- private final ScheduledExecutorService leaseScheduler;
+ private final ExecutorService defaultExecutor;
private final MyJob fetchingJob;
private final long timeout;
@@ -385,5 +379,5 @@ public class FetchingEventRelay implements EventRelay {
new ClassLogger("javax.management.event",
"FetchingEventRelay");
private static final ThreadFactory daemonThreadFactory =
- new DaemonThreadFactory("FetchingEventRelay-executor");
+ new DaemonThreadFactory("JMX FetchingEventRelay executor %d");
}
diff --git a/src/share/classes/javax/management/event/RMIPushEventForwarder.java b/src/share/classes/javax/management/event/RMIPushEventForwarder.java
index 2018f98ad..751300d54 100644
--- a/src/share/classes/javax/management/event/RMIPushEventForwarder.java
+++ b/src/share/classes/javax/management/event/RMIPushEventForwarder.java
@@ -185,7 +185,7 @@ public class RMIPushEventForwarder implements EventForwarder {
private static final ExecutorService executor =
Executors.newCachedThreadPool(
- new DaemonThreadFactory("RMIEventForwarder Executor"));
+ new DaemonThreadFactory("JMX RMIEventForwarder Executor"));
private final SendingJob sendingJob = new SendingJob();
private final BlockingQueue buffer;
diff --git a/src/share/classes/javax/management/remote/rmi/RMIConnector.java b/src/share/classes/javax/management/remote/rmi/RMIConnector.java
index bdcbb1568..a620235ac 100644
--- a/src/share/classes/javax/management/remote/rmi/RMIConnector.java
+++ b/src/share/classes/javax/management/remote/rmi/RMIConnector.java
@@ -420,7 +420,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
new PerThreadGroupPool.Create() {
public ThreadPoolExecutor createThreadPool(ThreadGroup group) {
ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
- "RMIConnector listener dispatch %d");
+ "JMX RMIConnector listener dispatch %d");
ThreadPoolExecutor exec = new ThreadPoolExecutor(
1, 10, 1, TimeUnit.SECONDS,
new LinkedBlockingDeque(),
diff --git a/test/javax/management/eventService/EventClientThreadTest.java b/test/javax/management/eventService/EventClientThreadTest.java
new file mode 100644
index 000000000..910bc9cc2
--- /dev/null
+++ b/test/javax/management/eventService/EventClientThreadTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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 6747411
+ * @summary Check that EventClient instances don't leak threads.
+ * @author Eamonn McManus
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerNotification;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+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 EventClientThreadTest {
+ private static final int MAX_TIME_SECONDS = 20;
+
+ private static final BlockingQueue queue =
+ new ArrayBlockingQueue(100);
+
+ private static final NotificationListener queueListener =
+ new NotificationListener() {
+ public void handleNotification(Notification notification,
+ Object handback) {
+ queue.add(notification);
+ }
+ };
+
+ private static final NotificationFilter dummyFilter =
+ new NotificationFilter() {
+ public boolean isNotificationEnabled(Notification notification) {
+ return true;
+ }
+ };
+
+ public static void main(String[] args) throws Exception {
+ long start = System.currentTimeMillis();
+ long deadline = start + MAX_TIME_SECONDS * 1000;
+
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
+ JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+ url, null, mbs);
+ cs.start();
+ JMXServiceURL addr = cs.getAddress();
+ JMXConnector cc = JMXConnectorFactory.connect(addr);
+ MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+ ThreadMXBean threads = ManagementFactory.getThreadMXBean();
+
+ System.out.println("Opening and closing some EventClients...");
+ // If we create a connection, then create and destroy EventClients
+ // over it, then close it, there should be no "JMX *" threads left.
+ for (int i = 0; i < 5; i++)
+ test(mbsc);
+
+ cc.close();
+
+ showTime("opening and closing initial EventClients", start);
+
+ Set jmxThreads = threadsMatching("JMX .*");
+ while (!jmxThreads.isEmpty() && System.currentTimeMillis() < deadline) {
+ Set jmxThreadsNow = threadsMatching("JMX .*");
+ Set gone = new TreeSet(jmxThreads);
+ gone.removeAll(jmxThreadsNow);
+ for (String s : gone)
+ showTime("expiry of \"" + s + "\"", start);
+ jmxThreads = jmxThreadsNow;
+ Thread.sleep(10);
+ }
+ if (System.currentTimeMillis() >= deadline) {
+ showThreads(threads);
+ throw new Exception("Timed out waiting for JMX threads to expire");
+ }
+
+ showTime("waiting for JMX threads to expire", start);
+
+ System.out.println("TEST PASSED");
+ }
+
+ static void showThreads(ThreadMXBean threads) throws Exception {
+ long[] ids = threads.getAllThreadIds();
+ for (long id : ids) {
+ ThreadInfo ti = threads.getThreadInfo(id);
+ String name = (ti == null) ? "(defunct)" : ti.getThreadName();
+ System.out.printf("%4d %s\n", id, name);
+ }
+ }
+
+ static void showTime(String what, long start) {
+ long elapsed = System.currentTimeMillis() - start;
+ System.out.printf("Time after %s: %.3f s\n", what, elapsed / 1000.0);
+ }
+
+ static Set threadsMatching(String pattern) {
+ Set matching = new TreeSet();
+ ThreadMXBean threads = ManagementFactory.getThreadMXBean();
+ long[] ids = threads.getAllThreadIds();
+ for (long id : ids) {
+ ThreadInfo ti = threads.getThreadInfo(id);
+ String name = (ti == null) ? "(defunct)" : ti.getThreadName();
+ if (name.matches(pattern))
+ matching.add(name);
+ }
+ return matching;
+ }
+
+ static void test(MBeanServerConnection mbsc) throws Exception {
+ final ObjectName delegateName = MBeanServerDelegate.DELEGATE_NAME;
+ final ObjectName testName = new ObjectName("test:type=Test");
+ EventClient ec = new EventClient(mbsc);
+ ec.addNotificationListener(delegateName, queueListener, null, null);
+ mbsc.createMBean(MBeanServerDelegate.class.getName(), testName);
+ mbsc.unregisterMBean(testName);
+ final String[] expectedTypes = {
+ MBeanServerNotification.REGISTRATION_NOTIFICATION,
+ MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
+ };
+ for (String s : expectedTypes) {
+ Notification n = queue.poll(3, TimeUnit.SECONDS);
+ if (n == null)
+ throw new Exception("Timed out waiting for notif: " + s);
+ if (!(n instanceof MBeanServerNotification))
+ throw new Exception("Got notif of wrong class: " + n.getClass());
+ if (!n.getType().equals(s)) {
+ throw new Exception("Got notif of wrong type: " + n.getType() +
+ " (expecting " + s + ")");
+ }
+ }
+ ec.removeNotificationListener(delegateName, queueListener);
+
+ ec.addNotificationListener(delegateName, queueListener, dummyFilter, "foo");
+ ec.removeNotificationListener(delegateName, queueListener, dummyFilter, "foo");
+
+ ec.close();
+ }
+}
\ No newline at end of file
diff --git a/test/javax/management/eventService/SharingThreadTest.java b/test/javax/management/eventService/SharingThreadTest.java
index a3d7fd37a..7339d0806 100644
--- a/test/javax/management/eventService/SharingThreadTest.java
+++ b/test/javax/management/eventService/SharingThreadTest.java
@@ -1,4 +1,4 @@
-/*/*
+/*
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
--
cgit v1.2.3
From 126213f6669086ce5252ab9f45872346383c16b2 Mon Sep 17 00:00:00 2001
From: dfuchs
Date: Fri, 12 Sep 2008 17:58:15 +0200
Subject: 6747899: jmx namespaces: hooks for permission checks should be
defined in HandlerInterceptor Reviewed-by: emcmanus
---
.../com/sun/jmx/namespace/HandlerInterceptor.java | 163 ++++++++++++++++++++-
.../namespace/RoutingMBeanServerConnection.java | 162 +++-----------------
2 files changed, 174 insertions(+), 151 deletions(-)
diff --git a/src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java b/src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java
index 7c2f39348..566724419 100644
--- a/src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java
+++ b/src/share/classes/com/sun/jmx/namespace/HandlerInterceptor.java
@@ -135,7 +135,11 @@ public abstract class HandlerInterceptor
public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException {
try {
- return super.getAttributes(name, attributes);
+ final String[] authorized =
+ checkAttributes(name,attributes,"getAttribute");
+ final AttributeList attrList =
+ super.getAttributes(name,authorized);
+ return attrList;
} catch (IOException ex) {
throw handleIOException(ex,"getAttributes",name,attributes);
}
@@ -185,7 +189,8 @@ public abstract class HandlerInterceptor
public void removeNotificationListener(ObjectName name, ObjectName listener)
throws InstanceNotFoundException, ListenerNotFoundException {
try {
- super.removeNotificationListener(name, listener);
+ check(name,null,"removeNotificationListener");
+ super.removeNotificationListener(name,listener);
} catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name,listener);
}
@@ -205,7 +210,9 @@ public abstract class HandlerInterceptor
@Override
public String[] getDomains() {
try {
- return super.getDomains();
+ check(null,null,"getDomains");
+ final String[] domains = super.getDomains();
+ return checkDomains(domains,"getDomains");
} catch (IOException ex) {
throw handleIOException(ex,"getDomains");
}
@@ -228,7 +235,10 @@ public abstract class HandlerInterceptor
InvalidAttributeValueException, MBeanException,
ReflectionException {
try {
- super.setAttribute(name, attribute);
+ check(name,
+ (attribute==null?null:attribute.getName()),
+ "setAttribute");
+ super.setAttribute(name,attribute);
} catch (IOException ex) {
throw handleIOException(ex,"setAttribute",name, attribute);
}
@@ -237,8 +247,10 @@ public abstract class HandlerInterceptor
// From MBeanServerConnection: catch & handles IOException
@Override
public Set queryNames(ObjectName name, QueryExp query) {
+ if (name == null) name=ObjectName.WILDCARD;
try {
- return super.queryNames(name, query);
+ checkPattern(name,null,"queryNames");
+ return super.queryNames(name,query);
} catch (IOException ex) {
throw handleIOException(ex,"queryNames",name, query);
}
@@ -247,8 +259,10 @@ public abstract class HandlerInterceptor
// From MBeanServerConnection: catch & handles IOException
@Override
public Set queryMBeans(ObjectName name, QueryExp query) {
+ if (name == null) name=ObjectName.WILDCARD;
try {
- return super.queryMBeans(name, query);
+ checkPattern(name,null,"queryMBeans");
+ return super.queryMBeans(name,query);
} catch (IOException ex) {
throw handleIOException(ex,"queryMBeans",name, query);
}
@@ -259,6 +273,7 @@ public abstract class HandlerInterceptor
public boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException {
try {
+ check(name, null, "isInstanceOf");
return super.isInstanceOf(name, className);
} catch (IOException ex) {
throw handleIOException(ex,"isInstanceOf",name, className);
@@ -272,6 +287,8 @@ public abstract class HandlerInterceptor
MBeanRegistrationException, MBeanException,
NotCompliantMBeanException {
try {
+ checkCreate(name, className, "instantiate");
+ checkCreate(name, className, "registerMBean");
return super.createMBean(className, name);
} catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name);
@@ -286,6 +303,8 @@ public abstract class HandlerInterceptor
MBeanRegistrationException, MBeanException,
NotCompliantMBeanException, InstanceNotFoundException {
try {
+ checkCreate(name, className, "instantiate");
+ checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, loaderName);
} catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name, loaderName);
@@ -298,6 +317,7 @@ public abstract class HandlerInterceptor
throws MBeanException, AttributeNotFoundException,
InstanceNotFoundException, ReflectionException {
try {
+ check(name, attribute, "getAttribute");
return super.getAttribute(name, attribute);
} catch (IOException ex) {
throw handleIOException(ex,"getAttribute",name, attribute);
@@ -310,6 +330,7 @@ public abstract class HandlerInterceptor
NotificationFilter filter, Object handback)
throws InstanceNotFoundException, ListenerNotFoundException {
try {
+ check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener, filter, handback);
} catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name,
@@ -324,6 +345,7 @@ public abstract class HandlerInterceptor
Object handback)
throws InstanceNotFoundException, ListenerNotFoundException {
try {
+ check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener, filter, handback);
} catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name,
@@ -337,6 +359,7 @@ public abstract class HandlerInterceptor
NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException {
try {
+ check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener);
} catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name,
@@ -350,6 +373,7 @@ public abstract class HandlerInterceptor
NotificationListener listener, NotificationFilter filter,
Object handback) throws InstanceNotFoundException {
try {
+ check(name,null,"addNotificationListener");
super.addNotificationListener(name, listener, filter, handback);
} catch (IOException ex) {
throw handleIOException(ex,"addNotificationListener",name,
@@ -363,6 +387,7 @@ public abstract class HandlerInterceptor
NotificationFilter filter, Object handback)
throws InstanceNotFoundException {
try {
+ check(name,null,"addNotificationListener");
super.addNotificationListener(name, listener, filter, handback);
} catch (IOException ex) {
throw handleIOException(ex,"addNotificationListener",name,
@@ -385,6 +410,7 @@ public abstract class HandlerInterceptor
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException {
try {
+ check(name, null, "unregisterMBean");
super.unregisterMBean(name);
} catch (IOException ex) {
throw handleIOException(ex,"unregisterMBean",name);
@@ -397,6 +423,7 @@ public abstract class HandlerInterceptor
throws InstanceNotFoundException, IntrospectionException,
ReflectionException {
try {
+ check(name, null, "getMBeanInfo");
return super.getMBeanInfo(name);
} catch (IOException ex) {
throw handleIOException(ex,"getMBeanInfo",name);
@@ -408,6 +435,7 @@ public abstract class HandlerInterceptor
public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException {
try {
+ check(name, null, "getObjectInstance");
return super.getObjectInstance(name);
} catch (IOException ex) {
throw handleIOException(ex,"getObjectInstance",name);
@@ -422,6 +450,8 @@ public abstract class HandlerInterceptor
MBeanRegistrationException, MBeanException,
NotCompliantMBeanException {
try {
+ checkCreate(name, className, "instantiate");
+ checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, params, signature);
} catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name,
@@ -437,6 +467,8 @@ public abstract class HandlerInterceptor
MBeanRegistrationException, MBeanException,
NotCompliantMBeanException, InstanceNotFoundException {
try {
+ checkCreate(name, className, "instantiate");
+ checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, loaderName, params,
signature);
} catch (IOException ex) {
@@ -450,7 +482,9 @@ public abstract class HandlerInterceptor
public AttributeList setAttributes(ObjectName name,AttributeList attributes)
throws InstanceNotFoundException, ReflectionException {
try {
- return super.setAttributes(name, attributes);
+ final AttributeList authorized =
+ checkAttributes(name, attributes, "setAttribute");
+ return super.setAttributes(name, authorized);
} catch (IOException ex) {
throw handleIOException(ex,"setAttributes",name, attributes);
}
@@ -462,6 +496,7 @@ public abstract class HandlerInterceptor
String[] signature)
throws InstanceNotFoundException, MBeanException, ReflectionException {
try {
+ check(name, operationName, "invoke");
return super.invoke(name, operationName, params, signature);
} catch (IOException ex) {
throw handleIOException(ex,"invoke",name, operationName,
@@ -582,4 +617,118 @@ public abstract class HandlerInterceptor
"Not supported in this namespace: "+namespace));
}
+ /**
+ * A result might be excluded for security reasons.
+ */
+ @Override
+ boolean excludesFromResult(ObjectName targetName, String queryMethod) {
+ return !checkQuery(targetName, queryMethod);
+ }
+
+
+ //----------------------------------------------------------------------
+ // Hooks for checking permissions
+ //----------------------------------------------------------------------
+
+ /**
+ * This method is a hook to implement permission checking in subclasses.
+ * A subclass may override this method and throw a {@link
+ * SecurityException} if the permission is denied.
+ *
+ * @param routingName The name of the MBean in the enclosing context.
+ * This is of the form {@code //}.
+ * @param member The {@link
+ * javax.management.namespace.JMXNamespacePermission#getMember member}
+ * name.
+ * @param action The {@link
+ * javax.management.namespace.JMXNamespacePermission#getActions action}
+ * name.
+ * @throws SecurityException if the caller doesn't have the permission
+ * to perform the given action on the MBean pointed to
+ * by routingName.
+ */
+ abstract void check(ObjectName routingName,
+ String member, String action);
+
+ // called in createMBean and registerMBean
+ abstract void checkCreate(ObjectName routingName, String className,
+ String action);
+
+ /**
+ * This is a hook to implement permission checking in subclasses.
+ *
+ * Checks that the caller has sufficient permission for returning
+ * information about {@code sourceName} in {@code action}.
+ *
+ * Subclass may override this method and return false if the caller
+ * doesn't have sufficient permissions.
+ *
+ * @param routingName The name of the MBean to include or exclude from
+ * the query, expressed in the enclosing context.
+ * This is of the form {@code //}.
+ * @param action one of "queryNames" or "queryMBeans"
+ * @return true if {@code sourceName} can be returned.
+ */
+ abstract boolean checkQuery(ObjectName routingName, String action);
+
+ /**
+ * This method is a hook to implement permission checking in subclasses.
+ *
+ * @param routingName The name of the MBean in the enclosing context.
+ * This is of the form {@code //}.
+ * @param attributes The list of attributes to check permission for.
+ * @param action one of "getAttribute" or "setAttribute"
+ * @return The list of attributes for which the callers has the
+ * appropriate {@link
+ * javax.management.namespace.JMXNamespacePermission}.
+ * @throws SecurityException if the caller doesn't have the permission
+ * to perform {@code action} on the MBean pointed to by routingName.
+ */
+ abstract String[] checkAttributes(ObjectName routingName,
+ String[] attributes, String action);
+
+ /**
+ * This method is a hook to implement permission checking in subclasses.
+ *
+ * @param routingName The name of the MBean in the enclosing context.
+ * This is of the form {@code //}.
+ * @param attributes The list of attributes to check permission for.
+ * @param action one of "getAttribute" or "setAttribute"
+ * @return The list of attributes for which the callers has the
+ * appropriate {@link
+ * javax.management.namespace.JMXNamespacePermission}.
+ * @throws SecurityException if the caller doesn't have the permission
+ * to perform {@code action} on the MBean pointed to by routingName.
+ */
+ abstract AttributeList checkAttributes(ObjectName routingName,
+ AttributeList attributes, String action);
+
+ /**
+ * This method is a hook to implement permission checking in subclasses.
+ * Checks that the caller as the necessary permissions to view the
+ * given domain. If not remove the domains for which the caller doesn't
+ * have permission from the list.
+ *
+ * By default, this method always returns {@code domains}
+ *
+ * @param domains The domains to return.
+ * @param action "getDomains"
+ * @return a filtered list of domains.
+ */
+ String[] checkDomains(String[] domains, String action) {
+ return domains;
+ }
+
+ // A priori check for queryNames/queryMBeans/
+ void checkPattern(ObjectName routingPattern,
+ String member, String action) {
+ // pattern is checked only at posteriori by checkQuery.
+ // checking it a priori usually doesn't work, because ObjectName.apply
+ // does not work between two patterns.
+ // We only check that we have the permission requested for 'action'.
+ check(null,null,action);
+ }
+
+
+
}
diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java b/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java
index 70df9b504..7022e7e29 100644
--- a/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java
+++ b/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java
@@ -161,11 +161,7 @@ public abstract class RoutingMBeanServerConnection tmp = source().queryNames(sourceName,query);
final Set out = processOutputNames(tmp);
//System.err.println("queryNames: out: "+out);
@@ -467,7 +442,6 @@ public abstract class RoutingMBeanServerConnection//}.
- * @param attributes The list of attributes to check permission for.
- * @param action one of "getAttribute" or "setAttribute"
- * @return The list of attributes for which the callers has the
- * appropriate {@link
- * javax.management.namespace.JMXNamespacePermission}.
- */
- String[] checkAttributes(ObjectName routingName,
- String[] attributes, String action) {
- check(routingName,null,action);
- return attributes;
- }
-
- /**
- * This method is a hook to implement permission checking in subclasses.
- * By default, this method does nothing and simply returns
- * {@code attribute}.
- *
- * @param routingName The name of the MBean in the enclosing context.
- * This is of the form {@code //}.
- * @param attributes The list of attributes to check permission for.
- * @param action one of "getAttribute" or "setAttribute"
- * @return The list of attributes for which the callers has the
- * appropriate {@link
- * javax.management.namespace.JMXNamespacePermission}.
- */
- AttributeList checkAttributes(ObjectName routingName,
- AttributeList attributes, String action) {
- check(routingName,null,action);
- return attributes;
- }
-
- /**
- * This method is a hook to implement permission checking in subclasses.
- * By default, this method does nothing.
- * A subclass may override this method and throw a {@link
- * SecurityException} if the permission is denied.
- *
- * @param routingName The name of the MBean in the enclosing context.
- * This is of the form {@code //}.
- * @param member The {@link
- * javax.management.namespace.JMXNamespacePermission#getMember member}
- * name.
- * @param action The {@link
- * javax.management.namespace.JMXNamespacePermission#getActions action}
- * name.
- */
- void check(ObjectName routingName,
- String member, String action) {
- }
-
- // called in createMBean and registerMBean
- void checkCreate(ObjectName routingName, String className,
- String action) {
- }
-
- // A priori check for queryNames/queryMBeans/
- void checkPattern(ObjectName routingPattern,
- String member, String action) {
- // pattern is checked only at posteriori by checkQuery.
- // checking it a priori usually doesn't work, because ObjectName.apply
- // does not work between two patterns.
- // We only check that we have the permission requested for 'action'.
- check(null,null,action);
- }
-
-
/**
- * This is a hook to implement permission checking in subclasses.
+ * Returns true if the given targetName must be excluded from the
+ * query result.
+ * In this base class, always return {@code false}.
+ * By default all object names returned by the sources are
+ * transmitted to the caller - there is no filtering.
*
- * Checks that the caller has sufficient permission for returning
- * information about {@code sourceName} in {@code action}.
- *
- * By default always return true. Subclass may override this method
- * and return false if the caller doesn't have sufficient permissions.
- *
- * @param routingName The name of the MBean to include or exclude from
- * the query, expressed in the enclosing context.
- * This is of the form {@code //}.
- * @param action one of "queryNames" or "queryMBeans"
- * @return true if {@code sourceName} can be returned.
+ * @param name A target object name expressed in the caller's
+ * context. In the case of cascading, where the source
+ * is a sub agent mounted on e.g. namespace "foo",
+ * that would be a name prefixed by "foo//"...
+ * @param queryMethod either "queryNames" or "queryMBeans".
+ * @return true if the name must be excluded.
*/
- boolean checkQuery(ObjectName routingName, String action) {
- return true;
+ boolean excludesFromResult(ObjectName targetName, String queryMethod) {
+ return false;
}
- /**
- * This method is a hook to implement permission checking in subclasses.
- * Checks that the caller as the necessary permissions to view the
- * given domain. If not remove the domains for which the caller doesn't
- * have permission from the list.
- *
- * By default, this method always returns {@code domains}
- *
- * @param domains The domains to return.
- * @param action "getDomains"
- * @return a filtered list of domains.
- */
- String[] checkDomains(String[] domains, String action) {
- return domains;
- }
}
--
cgit v1.2.3
From 9b1a8c88c10f5f9187861a46dbf70a52583b50f4 Mon Sep 17 00:00:00 2001
From: dfuchs
Date: Fri, 12 Sep 2008 19:06:38 +0200
Subject: 6747983: jmx namespace: unspecified self-link detection logic
Reviewed-by: emcmanus
---
.../sun/jmx/namespace/NamespaceInterceptor.java | 226 +----------------
.../management/namespace/JMXRemoteNamespace.java | 112 +--------
.../management/namespace/JMXNamespaceTest.java | 278 +++------------------
3 files changed, 42 insertions(+), 574 deletions(-)
diff --git a/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java b/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java
index 11afeb2af..6862066d2 100644
--- a/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java
+++ b/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java
@@ -25,22 +25,15 @@
package com.sun.jmx.namespace;
import com.sun.jmx.defaults.JmxProperties;
-import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.Set;
-import java.util.UUID;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServer;
-import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
-import javax.management.QueryExp;
-import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.JMXNamespace;
import javax.management.namespace.JMXNamespacePermission;
@@ -54,8 +47,6 @@ import javax.management.namespace.JMXNamespacePermission;
*/
public class NamespaceInterceptor extends HandlerInterceptor {
- private static final Logger PROBE_LOG = Logger.getLogger(
- JmxProperties.NAMESPACE_LOGGER+".probe");
// The target name space in which the NamepsaceHandler is mounted.
private final String targetNs;
@@ -64,21 +55,6 @@ public class NamespaceInterceptor extends HandlerInterceptor {
private final ObjectNameRouter proc;
- /**
- * Internal hack. The JMXRemoteNamespace can be closed and reconnected.
- * Each time the JMXRemoteNamespace connects, a probe should be sent
- * to detect cycle. The MBeanServer exposed by JMXRemoteNamespace thus
- * implements the DynamicProbe interface, which makes it possible for
- * this handler to know that it should send a new probe.
- *
- * XXX: TODO this probe thing is way too complex and fragile.
- * This *must* go away or be replaced by something simpler.
- * ideas are welcomed.
- **/
- public static interface DynamicProbe {
- public boolean isProbeRequested();
- }
-
/**
* Creates a new instance of NamespaceInterceptor
*/
@@ -100,164 +76,6 @@ public class NamespaceInterceptor extends HandlerInterceptor {
", namespace="+this.targetNs+")";
}
- /*
- * XXX: TODO this probe thing is way too complex and fragile.
- * This *must* go away or be replaced by something simpler.
- * ideas are welcomed.
- */
- private volatile boolean probed = false;
- private volatile ObjectName probe;
-
- // Query Pattern that we will send through the source server in order
- // to detect self-linking namespaces.
- //
- // XXX: TODO this probe thing is way too complex and fragile.
- // This *must* go away or be replaced by something simpler.
- // ideas are welcomed.
- final ObjectName makeProbePattern(ObjectName probe)
- throws MalformedObjectNameException {
-
- // we could probably link the probe pattern with the probe - e.g.
- // using the UUID as key in the pattern - but is it worth it? it
- // also has some side effects on the context namespace - because
- // such a probe may get rejected by the jmx.context// namespace.
- //
- // The trick here is to devise a pattern that is not likely to
- // be blocked by intermediate levels. Querying for all namespace
- // handlers in the source (or source namespace) is more likely to
- // achieve this goal.
- //
- return ObjectName.getInstance("*" +
- JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
- JMXNamespace.TYPE_ASSIGNMENT);
- }
-
- // tell whether the name pattern corresponds to what might have been
- // sent as a probe.
- // XXX: TODO this probe thing is way too complex and fragile.
- // This *must* go away or be replaced by something simpler.
- // ideas are welcomed.
- final boolean isProbePattern(ObjectName name) {
- final ObjectName p = probe;
- if (p == null) return false;
- try {
- return String.valueOf(name).endsWith(targetNs+
- JMXNamespaces.NAMESPACE_SEPARATOR + "*" +
- JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
- JMXNamespace.TYPE_ASSIGNMENT);
- } catch (RuntimeException x) {
- // should not happen.
- PROBE_LOG.finest("Ignoring unexpected exception in self link detection: "+
- x);
- return false;
- }
- }
-
- // The first time a request reaches this NamespaceInterceptor, the
- // interceptor will send a probe to detect whether the underlying
- // JMXNamespace links to itslef.
- //
- // One way to create such self-linking namespace would be for instance
- // to create a JMXNamespace whose getSourceServer() method would return:
- // JMXNamespaces.narrowToNamespace(getMBeanServer(),
- // getObjectName().getDomain())
- //
- // If such an MBeanServer is returned, then any call to that MBeanServer
- // will trigger an infinite loop.
- // There can be even trickier configurations if remote connections are
- // involved.
- //
- // In order to prevent this from happening, the NamespaceInterceptor will
- // send a probe, in an attempt to detect whether it will receive it at
- // the other end. If the probe is received, an exception will be thrown
- // in order to break the recursion. The probe is only sent once - when
- // the first request to the namespace occurs. The DynamicProbe interface
- // can also be used by a Sun JMXNamespace implementation to request the
- // emission of a probe at any time (see JMXRemoteNamespace
- // implementation).
- //
- // Probes work this way: the NamespaceInterceptor sets a flag and sends
- // a queryNames() request. If a queryNames() request comes in when the flag
- // is on, then it deduces that there is a self-linking loop - and instead
- // of calling queryNames() on the source MBeanServer of the JMXNamespace
- // handler (which would cause the loop to go on) it breaks the recursion
- // by returning the probe ObjectName.
- // If the NamespaceInterceptor receives the probe ObjectName as result of
- // its original sendProbe() request it knows that it has been looping
- // back on itslef and throws an IOException...
- //
- //
- // XXX: TODO this probe thing is way too complex and fragile.
- // This *must* go away or be replaced by something simpler.
- // ideas are welcomed.
- //
- final void sendProbe(MBeanServerConnection msc)
- throws IOException {
- try {
- PROBE_LOG.fine("Sending probe");
-
- // This is just to prevent any other thread to modify
- // the probe while the detection cycle is in progress.
- //
- final ObjectName probePattern;
- // we don't want to synchronize on this - we use targetNs
- // because it's non null and final.
- synchronized (targetNs) {
- probed = false;
- if (probe != null) {
- throw new IOException("concurent connection in progress");
- }
- final String uuid = UUID.randomUUID().toString();
- final String endprobe =
- JMXNamespaces.NAMESPACE_SEPARATOR + uuid +
- ":type=Probe,key="+uuid;
- final ObjectName newprobe =
- ObjectName.getInstance(endprobe);
- probePattern = makeProbePattern(newprobe);
- probe = newprobe;
- }
-
- try {
- PROBE_LOG.finer("Probe query: "+probePattern+" expecting: "+probe);
- final Set res = msc.queryNames(probePattern, null);
- final ObjectName expected = probe;
- PROBE_LOG.finer("Probe res: "+res);
- if (res.contains(expected)) {
- throw new IOException("namespace " +
- targetNs + " is linking to itself: " +
- "cycle detected by probe");
- }
- } catch (SecurityException x) {
- PROBE_LOG.finer("Can't check for cycles: " + x);
- // can't do anything....
- } catch (RuntimeException x) {
- PROBE_LOG.finer("Exception raised by queryNames: " + x);
- throw x;
- } finally {
- probe = null;
- }
- } catch (MalformedObjectNameException x) {
- final IOException io =
- new IOException("invalid name space: probe failed");
- io.initCause(x);
- throw io;
- }
- PROBE_LOG.fine("Probe returned - no cycles");
- probed = true;
- }
-
- // allows a Sun implementation JMX Namespace, such as the
- // JMXRemoteNamespace, to control when a probe should be sent.
- //
- // XXX: TODO this probe thing is way too complex and fragile.
- // This *must* go away or be replaced by something simpler.
- // ideas are welcomed.
- private boolean isProbeRequested(Object o) {
- if (o instanceof DynamicProbe)
- return ((DynamicProbe)o).isProbeRequested();
- return false;
- }
-
/**
* This method will send a probe to detect self-linking name spaces.
* A self linking namespace is a namespace that links back directly
@@ -277,29 +95,9 @@ public class NamespaceInterceptor extends HandlerInterceptor {
* (see JMXRemoteNamespace implementation).
*/
private MBeanServer connection() {
- try {
- final MBeanServer c = super.source();
- if (probe != null) // should not happen
- throw new RuntimeException("connection is being probed");
-
- if (probed == false || isProbeRequested(c)) {
- try {
- // Should not happen if class well behaved.
- // Never probed. Force it.
- //System.err.println("sending probe for " +
- // "target="+targetNs+", source="+srcNs);
- sendProbe(c);
- } catch (IOException io) {
- throw new RuntimeException(io.getMessage(), io);
- }
- }
-
- if (c != null) {
- return c;
- }
- } catch (RuntimeException x) {
- throw x;
- }
+ final MBeanServer c = super.source();
+ if (c != null) return c;
+ // should not come here
throw new NullPointerException("getMBeanServerConnection");
}
@@ -315,24 +113,6 @@ public class NamespaceInterceptor extends HandlerInterceptor {
return super.source();
}
- /**
- * Calls {@link MBeanServerConnection#queryNames queryNames}
- * on the underlying
- * {@link #getMBeanServerConnection MBeanServerConnection}.
- **/
- @Override
- public final Set queryNames(ObjectName name, QueryExp query) {
- // XXX: TODO this probe thing is way too complex and fragile.
- // This *must* go away or be replaced by something simpler.
- // ideas are welcomed.
- PROBE_LOG.finer("probe is: "+probe+" pattern is: "+name);
- if (probe != null && isProbePattern(name)) {
- PROBE_LOG.finer("Return probe: "+probe);
- return Collections.singleton(probe);
- }
- return super.queryNames(name, query);
- }
-
@Override
protected ObjectName toSource(ObjectName targetName)
throws MalformedObjectNameException {
diff --git a/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
index 1e877e0ce..6958f57f2 100644
--- a/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
+++ b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
@@ -28,11 +28,9 @@ package javax.management.namespace;
import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.namespace.JMXNamespaceUtils;
-import com.sun.jmx.namespace.NamespaceInterceptor.DynamicProbe;
import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException;
-import java.security.AccessControlException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
@@ -44,9 +42,7 @@ import javax.management.AttributeChangeNotification;
import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
-import javax.management.MBeanPermission;
import javax.management.MBeanServerConnection;
-import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
@@ -118,9 +114,6 @@ public class JMXRemoteNamespace
*/
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
- private static final Logger PROBE_LOG = Logger.getLogger(
- JmxProperties.NAMESPACE_LOGGER_NAME+".probe");
-
// This connection listener is used to listen for connection events from
// the underlying JMXConnector. It is used in particular to maintain the
@@ -153,8 +146,7 @@ public class JMXRemoteNamespace
// because the one that is actually used is the one supplied by the
// override of getMBeanServerConnection().
private static class JMXRemoteNamespaceDelegate
- extends MBeanServerConnectionWrapper
- implements DynamicProbe {
+ extends MBeanServerConnectionWrapper {
private volatile JMXRemoteNamespace parent=null;
JMXRemoteNamespaceDelegate() {
@@ -180,9 +172,6 @@ public class JMXRemoteNamespace
}
- public boolean isProbeRequested() {
- return this.parent.isProbeRequested();
- }
}
private static final MBeanNotificationInfo connectNotification =
@@ -201,7 +190,6 @@ public class JMXRemoteNamespace
private volatile MBeanServerConnection server = null;
private volatile JMXConnector conn = null;
private volatile ClassLoader defaultClassLoader = null;
- private volatile boolean probed;
/**
* Creates a new instance of {@code JMXRemoteNamespace}.
@@ -241,9 +229,6 @@ public class JMXRemoteNamespace
// handles (dis)connection events
this.listener = new ConnectionListener();
-
- // XXX TODO: remove the probe, or simplify it.
- this.probed = false;
}
/**
@@ -274,10 +259,6 @@ public class JMXRemoteNamespace
return optionsMap;
}
- boolean isProbeRequested() {
- return probed==false;
- }
-
public void addNotificationListener(NotificationListener listener,
NotificationFilter filter, Object handback) {
broadcaster.addNotificationListener(listener, filter, handback);
@@ -603,26 +584,7 @@ public class JMXRemoteNamespace
}
public void connect() throws IOException {
- if (conn != null) {
- try {
- // This is much too fragile. It must go away!
- PROBE_LOG.finest("Probing again...");
- triggerProbe(getMBeanServerConnection());
- } catch(Exception x) {
- close();
- Throwable cause = x;
- // if the cause is a security exception - rethrows it...
- while (cause != null) {
- if (cause instanceof SecurityException)
- throw (SecurityException) cause;
- cause = cause.getCause();
- }
- throw new IOException("connection failed: cycle?",x);
- }
- }
LOG.fine("connecting...");
- // TODO remove these traces
- // System.err.println(getInitParameter()+" connecting");
final Map env =
new HashMap(getEnvMap());
try {
@@ -652,79 +614,9 @@ public class JMXRemoteNamespace
throw x;
}
-
- // XXX Revisit here
- // Note from the author: This business of switching connection is
- // incredibly complex. Isn't there any means to simplify it?
- //
switchConnection(conn,aconn,msc);
- try {
- triggerProbe(msc);
- } catch(Exception x) {
- close();
- Throwable cause = x;
- // if the cause is a security exception - rethrows it...
- while (cause != null) {
- if (cause instanceof SecurityException)
- throw (SecurityException) cause;
- cause = cause.getCause();
- }
- throw new IOException("connection failed: cycle?",x);
- }
- LOG.fine("connected.");
- }
- // If this is a self-linking namespace, this method should trigger
- // the emission of a probe in the wrapping NamespaceInterceptor.
- // The first call to source() in the wrapping NamespaceInterceptor
- // causes the emission of the probe.
- //
- // Note: the MBeanServer returned by getSourceServer
- // (our private JMXRemoteNamespaceDelegate inner class)
- // implements a sun private interface (DynamicProbe) which is
- // used by the NamespaceInterceptor to determine whether it should
- // send a probe or not.
- // We needed this interface here because the NamespaceInterceptor
- // has otherwise no means to knows that this object has just
- // connected, and that a new probe should be sent.
- //
- // Probes work this way: the NamespaceInterceptor sets a flag and sends
- // a queryNames() request. If a queryNames() request comes in when the flag
- // is on, then it deduces that there is a self-linking loop - and instead
- // of calling queryNames() on the JMXNamespace (which would cause the
- // loop to go on) it breaks the recursion by returning the probe ObjectName.
- // If the NamespaceInterceptor receives the probe ObjectName as result of
- // its original queryNames() it knows that it has been looping back on
- // itslef and throws an Exception - which will be raised through this
- // method, thus preventing the connection to be established...
- //
- // More info in the com.sun.jmx.namespace.NamespaceInterceptor class
- //
- // XXX: TODO this probe thing is way too complex and fragile.
- // This *must* go away or be replaced by something simpler.
- // ideas are welcomed.
- //
- private void triggerProbe(final MBeanServerConnection msc)
- throws MalformedObjectNameException, IOException {
- // Query Pattern that we will send through the source server in order
- // to detect self-linking namespaces.
- //
- //
- final ObjectName pattern;
- pattern = ObjectName.getInstance("*" +
- JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
- JMXNamespace.TYPE_ASSIGNMENT);
- probed = false;
- try {
- msc.queryNames(pattern, null);
- probed = true;
- } catch (AccessControlException x) {
- // if we have an MBeanPermission missing then do nothing...
- if (!(x.getPermission() instanceof MBeanPermission))
- throw x;
- PROBE_LOG.finer("Can't check for cycles: " + x);
- probed = false; // no need to do it again...
- }
+ LOG.fine("connected.");
}
public void close() throws IOException {
diff --git a/test/javax/management/namespace/JMXNamespaceTest.java b/test/javax/management/namespace/JMXNamespaceTest.java
index 1c2ffac9d..a35377112 100644
--- a/test/javax/management/namespace/JMXNamespaceTest.java
+++ b/test/javax/management/namespace/JMXNamespaceTest.java
@@ -35,7 +35,6 @@
* NamespaceController.java NamespaceControllerMBean.java
* @run main/othervm JMXNamespaceTest
*/
-import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.reflect.InvocationTargetException;
@@ -52,10 +51,10 @@ import javax.management.InvalidAttributeValueException;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
import javax.management.NotificationEmitter;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
-import javax.management.RuntimeOperationsException;
import javax.management.StandardMBean;
import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.JMXNamespace;
@@ -155,7 +154,7 @@ public class JMXNamespaceTest {
}
}
- private static class SimpleTestConf {
+ public static class SimpleTestConf {
public final Wombat wombat;
public final StandardMBean mbean;
public final String dirname;
@@ -457,259 +456,56 @@ public class JMXNamespaceTest {
}
}
- /**
- * Test cycle detection.
- * mkdir test ; cd test ; ln -s . kanga ; ln -s kanga/kanga/roo/kanga roo
- * touch kanga/roo/wombat
- **/
- public static void probeKangaRooTest(String[] args) {
- final SimpleTestConf conf;
+ public static void verySimpleTest(String[] args) {
+ System.err.println("verySimpleTest: starting");
try {
- conf = new SimpleTestConf(args);
- try {
- final JMXServiceURL url =
- new JMXServiceURL("rmi","localHost",0);
- final Map empty = Collections.emptyMap();
- final JMXConnectorServer server =
- JMXConnectorServerFactory.newJMXConnectorServer(url,
- empty,conf.server);
- server.start();
- final JMXServiceURL address = server.getAddress();
- final JMXConnector client =
- JMXConnectorFactory.connect(address,
- empty);
- final String[] signature = {
- JMXServiceURL.class.getName(),
- Map.class.getName(),
- };
-
- final Object[] params = {
- address,
- null,
- };
- final MBeanServerConnection c =
- client.getMBeanServerConnection();
-
- // ln -s . kanga
- final ObjectName dirName1 =
- new ObjectName("kanga//:type=JMXNamespace");
- c.createMBean(JMXRemoteTargetNamespace.class.getName(),
- dirName1, params,signature);
- c.invoke(dirName1, "connect", null, null);
- try {
- // ln -s kanga//kanga//roo//kanga roo
- final JMXNamespace local = new JMXNamespace(
- new MBeanServerConnectionWrapper(null,
- JMXNamespaceTest.class.getClassLoader()){
-
- @Override
- protected MBeanServerConnection getMBeanServerConnection() {
- return JMXNamespaces.narrowToNamespace(c,
- "kanga//kanga//roo//kanga"
- );
- }
-
- });
- final ObjectName dirName2 =
- new ObjectName("roo//:type=JMXNamespace");
- conf.server.registerMBean(local,dirName2);
- System.out.println(dirName2 + " created!");
- try {
- // touch kanga/roo/wombat
- final ObjectName wombatName1 =
- new ObjectName("kanga//roo//"+conf.wombatName);
- final WombatMBean wombat1 =
- JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
- final String newCaption="I am still the same old wombat";
- Exception x = null;
- try {
- wombat1.setCaption(newCaption);
- } catch (RuntimeOperationsException r) {
- x=r.getTargetException();
- System.out.println("Got expected exception: " + x);
- // r.printStackTrace();
- }
- if (x == null)
- throw new RuntimeException("cycle not detected!");
- } finally {
- c.unregisterMBean(dirName2);
- }
- } finally {
- c.unregisterMBean(dirName1);
- client.close();
- server.stop();
- }
- } finally {
- conf.close();
- }
- System.err.println("probeKangaRooTest PASSED");
+ final MBeanServer srv = MBeanServerFactory.createMBeanServer();
+ srv.registerMBean(new JMXNamespace(
+ JMXNamespaces.narrowToNamespace(srv, "foo")),
+ JMXNamespaces.getNamespaceObjectName("foo"));
+ throw new Exception("Excpected IllegalArgumentException not raised.");
+ } catch (IllegalArgumentException x) {
+ System.err.println("verySimpleTest: got expected exception: "+x);
} catch (Exception x) {
- System.err.println("probeKangaRooTest FAILED: " +x);
+ System.err.println("verySimpleTest FAILED: " +x);
x.printStackTrace();
throw new RuntimeException(x);
}
+ System.err.println("verySimpleTest: PASSED");
}
- /**
- * Test cycle detection 2.
- * mkdir test ; cd test ; ln -s . roo ; ln -s roo/roo kanga
- * touch kanga/roo/wombat ; rm roo ; ln -s kanga roo ;
- * touch kanga/roo/wombat
- *
- **/
- public static void probeKangaRooCycleTest(String[] args) {
- final SimpleTestConf conf;
- try {
- conf = new SimpleTestConf(args);
- Exception failed = null;
- try {
- final JMXServiceURL url =
- new JMXServiceURL("rmi","localHost",0);
- final Map empty = Collections.emptyMap();
- final JMXConnectorServer server =
- JMXConnectorServerFactory.newJMXConnectorServer(url,
- empty,conf.server);
- server.start();
- final JMXServiceURL address = server.getAddress();
- final JMXConnector client =
- JMXConnectorFactory.connect(address,
- empty);
- final String[] signature = {
- JMXServiceURL.class.getName(),
- Map.class.getName(),
- };
- final String[] signature2 = {
- JMXServiceURL.class.getName(),
- Map.class.getName(),
- String.class.getName()
- };
- final Object[] params = {
- address,
- Collections.emptyMap(),
- };
- final Object[] params2 = {
- address,
- null,
- "kanga",
- };
- final MBeanServerConnection c =
- client.getMBeanServerConnection();
- // ln -s . roo
- final ObjectName dirName1 =
- new ObjectName("roo//:type=JMXNamespace");
- c.createMBean(JMXRemoteTargetNamespace.class.getName(),
- dirName1, params,signature);
- c.invoke(dirName1, "connect",null,null);
- try {
- final Map emptyMap =
- Collections.emptyMap();
- final JMXNamespace local = new JMXNamespace(
- new MBeanServerConnectionWrapper(
- JMXNamespaces.narrowToNamespace(c,
- "roo//roo//"),
- JMXNamespaceTest.class.getClassLoader())) {
- };
- // ln -s roo/roo kanga
- final ObjectName dirName2 =
- new ObjectName("kanga//:type=JMXNamespace");
- conf.server.registerMBean(local,dirName2);
- System.out.println(dirName2 + " created!");
- try {
- // touch kanga/roo/wombat
- final ObjectName wombatName1 =
- new ObjectName("kanga//roo//"+conf.wombatName);
- final WombatMBean wombat1 =
- JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
- final String newCaption="I am still the same old wombat";
- wombat1.setCaption(newCaption);
- // rm roo
- c.unregisterMBean(dirName1);
- // ln -s kanga roo
- System.err.println("**** Creating " + dirName1 +
- " ****");
- c.createMBean(JMXRemoteTargetNamespace.class.getName(),
- dirName1, params2,signature2);
- System.err.println("**** Created " + dirName1 +
- " ****");
- Exception x = null;
- try {
- // touch kanga/roo/wombat
- wombat1.setCaption(newCaption+" I hope");
- } catch (RuntimeOperationsException r) {
- x=(Exception)r.getCause();
- System.out.println("Got expected exception: " + x);
- //r.printStackTrace();
- }
- if (x == null)
- throw new RuntimeException("should have failed!");
- x = null;
- try {
- // ls kanga/roo/wombat
- System.err.println("**** Connecting " + dirName1 +
- " ****");
- JMX.newMBeanProxy(c,dirName1,
- JMXRemoteNamespaceMBean.class).connect();
- System.err.println("**** Connected " + dirName1 +
- " ****");
- } catch (IOException r) {
- x=r;
- System.out.println("Got expected exception: " + x);
- //r.printStackTrace();
- }
- System.err.println("**** Expected Exception Not Raised ****");
- if (x == null) {
- System.out.println(dirName1+" contains: "+
- c.queryNames(new ObjectName(
- dirName1.getDomain()+"*:*"),null));
- throw new RuntimeException("cycle not detected!");
- }
- } catch (Exception t) {
- if (failed == null) failed = t;
- } finally {
- c.unregisterMBean(dirName2);
- }
- } finally {
- try {
- c.unregisterMBean(dirName1);
- } catch (Exception t) {
- if (failed == null) failed = t;
- System.err.println("Failed to unregister "+dirName1+
- ": "+t);
- }
- try {
- client.close();
- } catch (Exception t) {
- if (failed == null) failed = t;
- System.err.println("Failed to close client: "+t);
- }
- try {
- server.stop();
- } catch (Exception t) {
- if (failed == null) failed = t;
- System.err.println("Failed to stop server: "+t);
- }
- }
- } finally {
- try {
- conf.close();
- } catch (Exception t) {
- if (failed == null) failed = t;
- System.err.println("Failed to stop server: "+t);
- }
- }
- if (failed != null) throw failed;
- System.err.println("probeKangaRooCycleTest PASSED");
+ public static void verySimpleTest2(String[] args) {
+ System.err.println("verySimpleTest2: starting");
+ try {
+ final MBeanServer srv = MBeanServerFactory.createMBeanServer();
+ final JMXConnectorServer cs = JMXConnectorServerFactory.
+ newJMXConnectorServer(new JMXServiceURL("rmi",null,0),
+ null, srv);
+ cs.start();
+ final JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
+
+ srv.registerMBean(new JMXNamespace(
+ new MBeanServerConnectionWrapper(
+ JMXNamespaces.narrowToNamespace(
+ cc.getMBeanServerConnection(),
+ "foo"))),
+ JMXNamespaces.getNamespaceObjectName("foo"));
+ throw new Exception("Excpected IllegalArgumentException not raised.");
+ } catch (IllegalArgumentException x) {
+ System.err.println("verySimpleTest2: got expected exception: "+x);
} catch (Exception x) {
- System.err.println("probeKangaRooCycleTest FAILED: " +x);
+ System.err.println("verySimpleTest2 FAILED: " +x);
x.printStackTrace();
throw new RuntimeException(x);
}
+ System.err.println("verySimpleTest2: PASSED");
}
+
public static void main(String[] args) {
simpleTest(args);
recursiveTest(args);
- probeKangaRooTest(args);
- probeKangaRooCycleTest(args);
+ verySimpleTest(args);
+ verySimpleTest2(args);
}
}
--
cgit v1.2.3