|
Java example source code file (ObjectName.java)
The ObjectName.java Java example source code/* * Copyright (c) 1999, 2013, Oracle and/or its affiliates. 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.management; import com.sun.jmx.mbeanserver.GetPropertyAction; import com.sun.jmx.mbeanserver.Util; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.security.AccessController; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; /** * <p>Represents the object name of an MBean, or a pattern that can * match the names of several MBeans. Instances of this class are * immutable.</p> * * <p>An instance of this class can be used to represent: * <ul> * <li>An object name * <li>An object name pattern, within the context of a query * </ul> * * <p>An object name consists of two parts, the domain and the key * properties.</p> * * <p>The domain is a string of characters not including * the character colon (<code>:). It is recommended that the domain * should not contain the string "{@code //}", which is reserved for future use. * * <p>If the domain includes at least one occurrence of the wildcard * characters asterisk (<code>*) or question mark * (<code>?), then the object name is a pattern. The asterisk * matches any sequence of zero or more characters, while the question * mark matches any single character.</p> * * <p>If the domain is empty, it will be replaced in certain contexts * by the <em>default domain of the MBean server in which the * ObjectName is used.</p> * * <p>The key properties are an unordered set of keys and * associated values.</p> * * <p>Each key is a nonempty string of characters which may * not contain any of the characters comma (<code>,), equals * (<code>=), colon, asterisk, or question mark. The same key * may not occur twice in a given ObjectName.</p> * * <p>Each value associated with a key is a string of * characters that is either unquoted or quoted.</p> * * <p>An unquoted value is a possibly empty string of * characters which may not contain any of the characters comma, * equals, colon, or quote.</p> * * <p>If the unquoted value contains at least one occurrence * of the wildcard characters asterisk or question mark, then the object * name is a <em>property value pattern. The asterisk matches any * sequence of zero or more characters, while the question mark matches * any single character.</p> * * <p>A quoted value consists of a quote (* <p>key starts at startKey (included), and ends at endKey (excluded). * If (startKey == endKey), then the key is empty. * * @param s The char array of the original string. * @param startKey index at which to begin parsing. * @return The index following the last character of the key. **/ private static int parseKey(final char[] s, final int startKey) throws MalformedObjectNameException { int next = startKey; int endKey = startKey; final int len = s.length; while (next < len) { final char k = s[next++]; switch (k) { case '*': case '?': case ',': case ':': case '\n': final String ichar = ((k=='\n')?"\\n":""+k); throw new MalformedObjectNameException("Invalid character in key: `" + ichar + "'"); case '=': // we got the key. endKey = next-1; break; default: if (next < len) continue; else endKey=next; } break; } return endKey; } /** * Parse a value. * <pre>final int endVal=parseValue(s,startVal); * <p>value starts at startVal (included), and ends at endVal (excluded). * If (startVal == endVal), then the key is empty. * * @param s The char array of the original string. * @param startValue index at which to begin parsing. * @return The first element of the int array indicates the index * following the last character of the value. The second * element of the int array indicates that the value is * a pattern when its value equals 1. **/ private static int[] parseValue(final char[] s, final int startValue) throws MalformedObjectNameException { boolean value_pattern = false; int next = startValue; int endValue = startValue; final int len = s.length; final char q=s[startValue]; if (q == '"') { // quoted value if (++next == len) throw new MalformedObjectNameException("Invalid quote"); while (next < len) { char last = s[next]; if (last == '\\') { if (++next == len) throw new MalformedObjectNameException( "Invalid unterminated quoted character sequence"); last = s[next]; switch (last) { case '\\' : case '?' : case '*' : case 'n' : break; case '\"' : // We have an escaped quote. If this escaped // quote is the last character, it does not // qualify as a valid termination quote. // if (next+1 == len) throw new MalformedObjectNameException( "Missing termination quote"); break; default: throw new MalformedObjectNameException( "Invalid quoted character sequence '\\" + last + "'"); } } else if (last == '\n') { throw new MalformedObjectNameException( "Newline in quoted value"); } else if (last == '\"') { next++; break; } else { switch (last) { case '?' : case '*' : value_pattern = true; break; } } next++; // Check that last character is a termination quote. // We have already handled the case were the last // character is an escaped quote earlier. // if ((next >= len) && (last != '\"')) throw new MalformedObjectNameException("Missing termination quote"); } endValue = next; if (next < len) { if (s[next++] != ',') throw new MalformedObjectNameException("Invalid quote"); } } else { // Non quoted value. while (next < len) { final char v=s[next++]; switch(v) { case '*': case '?': value_pattern = true; if (next < len) continue; else endValue=next; break; case '=': case ':': case '\n' : final String ichar = ((v=='\n')?"\\n":""+v); throw new MalformedObjectNameException("Invalid character `" + ichar + "' in value"); case ',': endValue = next-1; break; default: if (next < len) continue; else endValue=next; } break; } } return new int[] { endValue, value_pattern ? 1 : 0 }; } /** * Check if the supplied value is a valid value. * * @return true if the value is a pattern, otherwise false. */ private static boolean checkValue(String val) throws MalformedObjectNameException { if (val == null) throw new NullPointerException("Invalid value (null)"); final int len = val.length(); if (len == 0) return false; final char[] s = val.toCharArray(); final int[] result = parseValue(s,0); final int endValue = result[0]; final boolean value_pattern = result[1] == 1; if (endValue < len) throw new MalformedObjectNameException("Invalid character in value: `" + s[endValue] + "'"); return value_pattern; } /** * Check if the supplied key is a valid key. */ private static void checkKey(String key) throws MalformedObjectNameException { if (key == null) throw new NullPointerException("Invalid key (null)"); final int len = key.length(); if (len == 0) throw new MalformedObjectNameException("Invalid key (empty)"); final char[] k=key.toCharArray(); final int endKey = parseKey(k,0); if (endKey < len) throw new MalformedObjectNameException("Invalid character in value: `" + k[endKey] + "'"); } // Category : Internal utilities <============================== // Category : Internal accessors ------------------------------> /** * Check if domain is a valid domain. Set _domain_pattern if appropriate. */ private boolean isDomain(String domain) { if (domain == null) return true; final int len = domain.length(); int next = 0; while (next < len) { final char c = domain.charAt(next++); switch (c) { case ':' : case '\n' : return false; case '*' : case '?' : _domain_pattern = true; break; } } return true; } // Category : Internal accessors <============================== // Category : Serialization -----------------------------------> /** * Deserializes an {@link ObjectName} from an {@link ObjectInputStream}. * @serialData <ul> * <li>In the current serial form (value of property * <code>jmx.serial.form differs from * <code>1.0): the string * "<domain>:<properties><wild>", * where: <ul> * <li><domain> represents the domain part * of the {@link ObjectName}</li> * <li><properties> represents the list of * properties, as returned by * {@link #getKeyPropertyListString} * <li><wild> is empty if not * <code>isPropertyPattern, or * is the character "<code>*" if * <code>isPropertyPattern * and <properties> is empty, or * is "<code>,*" if * <code>isPropertyPattern and * <properties> is not empty. * </li> * </ul> * The intent is that this string could be supplied * to the {@link #ObjectName(String)} constructor to * produce an equivalent {@link ObjectName}. * </li> * <li>In the old serial form (value of property * <code>jmx.serial.form is * <code>1.0): <domain> <propertyList> * <propertyListString> <canonicalName> * <pattern> <propertyPattern>, * where: <ul> * <li><domain> represents the domain part * of the {@link ObjectName}</li> * <li><propertyList> is the * {@link Hashtable} that contains all the * pairs (key,value) for this * {@link ObjectName}</li> * <li><propertyListString> is the * {@link String} representation of the * list of properties in any order (not * mandatorily a canonical representation) * </li> * <li><canonicalName> is the * {@link String} containing this * {@link ObjectName}'s canonical name</li> * <li><pattern> is a boolean which is * <code>true if this * {@link ObjectName} contains a pattern</li> * <li><propertyPattern> is a boolean which * is <code>true if this * {@link ObjectName} contains a pattern in * the list of properties</li> * </ul> * </li> * </ul> */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { String cn; if (compat) { // Read an object serialized in the old serial form // //in.defaultReadObject(); final ObjectInputStream.GetField fields = in.readFields(); String propListString = (String)fields.get("propertyListString", ""); // 6616825: take care of property patterns final boolean propPattern = fields.get("propertyPattern" , false); if (propPattern) { propListString = (propListString.length()==0?"*":(propListString+",*")); } cn = (String)fields.get("domain", "default")+ ":"+ propListString; } else { // Read an object serialized in the new serial form // in.defaultReadObject(); cn = (String)in.readObject(); } try { construct(cn); } catch (NullPointerException e) { throw new InvalidObjectException(e.toString()); } catch (MalformedObjectNameException e) { throw new InvalidObjectException(e.toString()); } } /** * Serializes an {@link ObjectName} to an {@link ObjectOutputStream}. * @serialData <ul> * <li>In the current serial form (value of property * <code>jmx.serial.form differs from * <code>1.0): the string * "<domain>:<properties><wild>", * where: <ul> * <li><domain> represents the domain part * of the {@link ObjectName}</li> * <li><properties> represents the list of * properties, as returned by * {@link #getKeyPropertyListString} * <li><wild> is empty if not * <code>isPropertyPattern, or * is the character "<code>*" if * this <code>isPropertyPattern * and <properties> is empty, or * is "<code>,*" if * <code>isPropertyPattern and * <properties> is not empty. * </li> * </ul> * The intent is that this string could be supplied * to the {@link #ObjectName(String)} constructor to * produce an equivalent {@link ObjectName}. * </li> * <li>In the old serial form (value of property * <code>jmx.serial.form is * <code>1.0): <domain> <propertyList> * <propertyListString> <canonicalName> * <pattern> <propertyPattern>, * where: <ul> * <li><domain> represents the domain part * of the {@link ObjectName}</li> * <li><propertyList> is the * {@link Hashtable} that contains all the * pairs (key,value) for this * {@link ObjectName}</li> * <li><propertyListString> is the * {@link String} representation of the * list of properties in any order (not * mandatorily a canonical representation) * </li> * <li><canonicalName> is the * {@link String} containing this * {@link ObjectName}'s canonical name</li> * <li><pattern> is a boolean which is * <code>true if this * {@link ObjectName} contains a pattern</li> * <li><propertyPattern> is a boolean which * is <code>true if this * {@link ObjectName} contains a pattern in * the list of properties</li> * </ul> * </li> * </ul> */ private void writeObject(ObjectOutputStream out) throws IOException { if (compat) { // Serializes this instance in the old serial form // Read CR 6441274 before making any changes to this code ObjectOutputStream.PutField fields = out.putFields(); fields.put("domain", _canonicalName.substring(0, _domain_length)); fields.put("propertyList", getKeyPropertyList()); fields.put("propertyListString", getKeyPropertyListString()); fields.put("canonicalName", _canonicalName); fields.put("pattern", (_domain_pattern || _property_list_pattern)); fields.put("propertyPattern", _property_list_pattern); out.writeFields(); } else { // Serializes this instance in the new serial form // out.defaultWriteObject(); out.writeObject(getSerializedNameString()); } } // Category : Serialization <=================================== // Private methods <======================================== // Public methods ----------------------------------------> // Category : ObjectName Construction ------------------------------> /** * <p>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.</p> * * @param name A string representation of the object name. * * @return an ObjectName corresponding to the given String. * * @exception MalformedObjectNameException The string passed as a * parameter does not have the right format. * @exception NullPointerException The <code>name parameter * is null. * */ public static ObjectName getInstance(String name) throws MalformedObjectNameException, NullPointerException { return new ObjectName(name); } /** * <p>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.</p> * * @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 MalformedObjectNameException The * <code>domain, key , or value
* contains an illegal character, or <code>value does not
* follow the rules for quoting.
* @exception NullPointerException One of the parameters is null.
*
*/
public static ObjectName getInstance(String domain, String key,
String value)
throws MalformedObjectNameException {
return new ObjectName(domain, key, value);
}
/**
* <p>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.</p>
*
* @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 MalformedObjectNameException The <code>domain
* contains an illegal character, or one of the keys or values in
* <code>table contains an illegal character, or one of the
* values in <code>table does not follow the rules for
* quoting.
* @exception NullPointerException One of the parameters is null.
*
*/
public static ObjectName getInstance(String domain,
Hashtable<String,String> table)
throws MalformedObjectNameException {
return new ObjectName(domain, table);
}
/**
* <p>Return an instance of ObjectName that can be used anywhere
* the given object can be used. The returned object may be of a
* subclass of ObjectName. If <code>name is of a subclass
* of ObjectName, it is not guaranteed that the returned object
* will be of the same class.</p>
*
* <p>The returned value may or may not be identical to
* <code>name. Calling this method twice with the same
* parameters may return the same object or two equal but not
* identical objects.</p>
*
* <p>Since ObjectName is immutable, it is not usually useful to
* make a copy of an ObjectName. The principal use of this method
* is to guard against a malicious caller who might pass an
* instance of a subclass with surprising behavior to sensitive
* code. Such code can call this method to obtain an ObjectName
* that is known not to have surprising behavior.</p>
*
* @param name an instance of the ObjectName class or of a subclass
*
* @return an instance of ObjectName or a subclass that is known to
* have the same semantics. If <code>name respects the
* semantics of ObjectName, then the returned object is equal
* (though not necessarily identical) to <code>name.
*
* @exception NullPointerException The <code>name is null.
*
*/
public static ObjectName getInstance(ObjectName name) {
if (name.getClass().equals(ObjectName.class))
return name;
return Util.newObjectName(name.getSerializedNameString());
}
/**
* Construct an object name from the given string.
*
* @param name A string representation of the object name.
*
* @exception MalformedObjectNameException The string passed as a
* parameter does not have the right format.
* @exception NullPointerException The <code>name parameter
* is null.
*/
public ObjectName(String name)
throws MalformedObjectNameException {
construct(name);
}
/**
* Construct an object name with exactly one key property.
*
* @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.
*
* @exception MalformedObjectNameException The
* <code>domain, key , or value
* contains an illegal character, or <code>value does not
* follow the rules for quoting.
* @exception NullPointerException One of the parameters is null.
*/
public ObjectName(String domain, String key, String value)
throws MalformedObjectNameException {
// If key or value are null a NullPointerException
// will be thrown by the put method in Hashtable.
//
Map<String,String> table = Collections.singletonMap(key, value);
construct(domain, table);
}
/**
* Construct an object name with several key properties from a Hashtable.
*
* @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.
*
* @exception MalformedObjectNameException The <code>domain
* contains an illegal character, or one of the keys or values in
* <code>table contains an illegal character, or one of the
* values in <code>table does not follow the rules for
* quoting.
* @exception NullPointerException One of the parameters is null.
*/
public ObjectName(String domain, Hashtable<String,String> table)
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
MalformedObjectNameException. This was not previously
specified. */
}
// Category : ObjectName Construction <==============================
// Category : Getter methods ------------------------------>
/**
* Checks whether the object name is a pattern.
* <p>
* An object name is a pattern if its domain contains a
* wildcard or if the object name is a property pattern.
*
* @return True if the name is a pattern, otherwise false.
*/
public boolean isPattern() {
return (_domain_pattern ||
_property_list_pattern ||
_property_value_pattern);
}
/**
* Checks whether the object name is a pattern on the domain part.
*
* @return True if the name is a domain pattern, otherwise false.
*
*/
public boolean isDomainPattern() {
return _domain_pattern;
}
/**
* Checks whether the object name is a pattern on the key properties.
* <p>
* An object name is a pattern on the key properties if it is a
* pattern on the key property list (e.g. "d:k=v,*") or on the
* property values (e.g. "d:k=*") or on both (e.g. "d:k=*,*").
*
* @return True if the name is a property pattern, otherwise false.
*/
public boolean isPropertyPattern() {
return _property_list_pattern || _property_value_pattern;
}
/**
* Checks whether the object name is a pattern on the key property list.
* <p>
* For example, "d:k=v,*" and "d:k=*,*" are key property list patterns
* whereas "d:k=*" is not.
*
* @return True if the name is a property list pattern, otherwise false.
*
* @since 1.6
*/
public boolean isPropertyListPattern() {
return _property_list_pattern;
}
/**
* Checks whether the object name is a pattern on the value part
* of at least one of the key properties.
* <p>
* For example, "d:k=*" and "d:k=*,*" are property value patterns
* whereas "d:k=v,*" is not.
*
* @return True if the name is a property value pattern, otherwise false.
*
* @since 1.6
*/
public boolean isPropertyValuePattern() {
return _property_value_pattern;
}
/**
* Checks whether the value associated with a key in a key
* property is a pattern.
*
* @param property The property whose value is to be checked.
*
* @return True if the value associated with the given key property
* is a pattern, otherwise false.
*
* @exception NullPointerException If <code>property is null.
* @exception IllegalArgumentException If <code>property is not
* a valid key property for this ObjectName.
*
* @since 1.6
*/
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++) {
Property prop = _ca_array[i];
String key = prop.getKeyString(_canonicalName);
if (key.equals(property))
return (prop instanceof PatternProperty);
}
throw new IllegalArgumentException("key property not found");
}
/**
* <p>Returns the canonical form of the name; that is, a string
* representation where the properties are sorted in lexical
* order.</p>
*
* <p>More precisely, the canonical form of the name is a String
* consisting of the <em>domain part, a colon
* (<code>:), the canonical key property list, and
* a <em>pattern indication.
*
* <p>The canonical key property list is the same string
* as described for {@link #getCanonicalKeyPropertyListString()}.</p>
*
* <p>The pattern indication is:
* <ul>
* <li>empty for an ObjectName
* that is not a property list pattern;
* <li>an asterisk for an ObjectName
* that is a property list pattern with no keys; or
* <li>a comma and an
* asterisk (<code>,*) for an ObjectName that is a property
* list pattern with at least one key.
* </ul>
*
* @return The canonical form of the name.
*/
public String getCanonicalName() {
return _canonicalName;
}
/**
* Returns the domain part.
*
* @return The domain.
*/
public String getDomain() {
return _canonicalName.substring(0, _domain_length);
}
/**
* Obtains the value associated with a key in a key property.
*
* @param property The property whose value is to be obtained.
*
* @return The value of the property, or null if there is no such
* property in this ObjectName.
*
* @exception NullPointerException If <code>property is null.
*/
public String getKeyProperty(String property) {
return _getKeyPropertyList().get(property);
}
/**
* <p>Returns the key properties as a Map. The returned
* value is a Map in which each key is a key in the
* ObjectName's key property list and each value is the associated
* value.</p>
*
* <p>The returned value must not be modified.
*
* @return The table of key properties.
*/
private Map<String,String> _getKeyPropertyList() {
synchronized (this) {
if (_propertyList == null) {
// build (lazy eval) the property list from the canonical
// properties array
_propertyList = new HashMap<String,String>();
int len = _ca_array.length;
Property prop;
for (int i = len - 1; i >= 0; i--) {
prop = _ca_array[i];
_propertyList.put(prop.getKeyString(_canonicalName),
prop.getValueString(_canonicalName));
}
}
}
return _propertyList;
}
/**
* <p>Returns the key properties as a Hashtable. The returned
* value is a Hashtable in which each key is a key in the
* ObjectName's key property list and each value is the associated
* value.</p>
*
* <p>The returned value may be unmodifiable. If it is
* modifiable, changing it has no effect on this ObjectName.</p>
*
* @return The table of key properties.
*/
// CR 6441274 depends on the modification property defined above
public Hashtable<String,String> getKeyPropertyList() {
return new Hashtable<String,String>(_getKeyPropertyList());
}
/**
* <p>Returns a string representation of the list of key
* properties specified at creation time. If this ObjectName was
* constructed with the constructor {@link #ObjectName(String)},
* the key properties in the returned String will be in the same
* order as in the argument to the constructor.</p>
*
* @return The key property list string. This string is
* independent of whether the ObjectName is a pattern.
*/
public String getKeyPropertyListString() {
// BEWARE : we rebuild the propertyliststring at each call !!
if (_kp_array.length == 0) return "";
// the size of the string is the canonical one minus domain
// part and pattern part
final int total_size = _canonicalName.length() - _domain_length - 1
- (_property_list_pattern?2:0);
final char[] dest_chars = new char[total_size];
final char[] value = _canonicalName.toCharArray();
writeKeyPropertyListString(value,dest_chars,0);
return new String(dest_chars);
}
/**
* <p>Returns the serialized string of the ObjectName.
* properties specified at creation time. If this ObjectName was
* constructed with the constructor {@link #ObjectName(String)},
* the key properties in the returned String will be in the same
* order as in the argument to the constructor.</p>
*
* @return The key property list string. This string is
* independent of whether the ObjectName is a pattern.
*/
private String getSerializedNameString() {
// the size of the string is the canonical one
final int total_size = _canonicalName.length();
final char[] dest_chars = new char[total_size];
final char[] value = _canonicalName.toCharArray();
final int offset = _domain_length+1;
// copy "domain:" into dest_chars
//
System.arraycopy(value, 0, dest_chars, 0, offset);
// Add property list string
final int end = writeKeyPropertyListString(value,dest_chars,offset);
// Add ",*" if necessary
if (_property_list_pattern) {
if (end == offset) {
// Property list string is empty.
dest_chars[end] = '*';
} else {
// Property list string is not empty.
dest_chars[end] = ',';
dest_chars[end+1] = '*';
}
}
return new String(dest_chars);
}
/**
* <p>Write a string representation of the list of key
* properties specified at creation time in the given array, starting
* at the specified offset. If this ObjectName was
* constructed with the constructor {@link #ObjectName(String)},
* the key properties in the returned String will be in the same
* order as in the argument to the constructor.</p>
*
* @return offset + #of chars written
*/
private int writeKeyPropertyListString(char[] canonicalChars,
char[] data, int offset) {
if (_kp_array.length == 0) return offset;
final char[] dest_chars = data;
final char[] value = canonicalChars;
int index = offset;
final int len = _kp_array.length;
final int last = len - 1;
for (int i = 0; i < len; i++) {
final Property prop = _kp_array[i];
final int prop_len = prop._key_length + prop._value_length + 1;
System.arraycopy(value, prop._key_index, dest_chars, index,
prop_len);
index += prop_len;
if (i < last ) dest_chars[index++] = ',';
}
return index;
}
/**
* Returns a string representation of the list of key properties,
* in which the key properties are sorted in lexical order. This
* is used in lexicographic comparisons performed in order to
* select MBeans based on their key property list. Lexical order
* is the order implied by {@link String#compareTo(String)
* String.compareTo(String)}.
*
* @return The canonical key property list string. This string is
* independent of whether the ObjectName is a pattern.
*/
public String getCanonicalKeyPropertyListString() {
if (_ca_array.length == 0) return "";
int len = _canonicalName.length();
if (_property_list_pattern) len -= 2;
return _canonicalName.substring(_domain_length +1, len);
}
// Category : Getter methods <===================================
// Category : Utilities ---------------------------------------->
/**
* <p>Returns a string representation of the object name. The
* format of this string is not specified, but users can expect
* that two ObjectNames return the same string if and only if they
* are equal.</p>
*
* @return a string representation of this object name.
*/
@Override
public String toString() {
return getSerializedNameString();
}
/**
* Compares the current object name with another object name. Two
* ObjectName instances are equal if and only if their canonical
* forms are equal. The canonical form is the string described
* for {@link #getCanonicalName()}.
*
* @param object The object name that the current object name is to be
* compared with.
*
* @return True if <code>object is an ObjectName whose
* canonical form is equal to that of this ObjectName.
*/
@Override
public boolean equals(Object object) {
// same object case
if (this == object) return true;
// object is not an object name case
if (!(object instanceof ObjectName)) return false;
// equality when canonical names are the same
// (because usage of intern())
ObjectName on = (ObjectName) object;
String on_string = on._canonicalName;
if (_canonicalName == on_string) return true; // ES: OK
// Because we are sharing canonical form between object names,
// we have finished the comparison at this stage ==> unequal
return false;
}
/**
* Returns a hash code for this object name.
*
*/
@Override
public int hashCode() {
return _canonicalName.hashCode();
}
/**
* <p>Returns a quoted form of the given String, suitable for
* inclusion in an ObjectName. The returned value can be used as
* the value associated with a key in an ObjectName. The String
* <code>s may contain any character. Appropriate quoting
* ensures that the returned value is legal in an ObjectName.</p>
*
* <p>The returned value consists of a quote ('"'), a sequence of
* characters corresponding to the characters of <code>s,
* and another quote. Characters in <code>s appear
* unchanged within the returned value except:</p>
*
* <ul>
* <li>A quote ('"') is replaced by a backslash (\) followed by a quote.
* <li>An asterisk ('*') is replaced by a backslash (\) followed by an
* asterisk.</li>
* <li>A question mark ('?') is replaced by a backslash (\) followed by
* a question mark.</li>
* <li>A backslash ('\') is replaced by two backslashes.
* <li>A newline character (the character '\n' in Java) is replaced
* by a backslash followed by the character '\n'.</li>
* </ul>
*
* @param s the String to be quoted.
*
* @return the quoted String.
*
* @exception NullPointerException if <code>s is null.
*
*/
public static String quote(String s) {
final StringBuilder buf = new StringBuilder("\"");
final int len = s.length();
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
switch (c) {
case '\n':
c = 'n';
buf.append('\\');
break;
case '\\':
case '\"':
case '*':
case '?':
buf.append('\\');
break;
}
buf.append(c);
}
buf.append('"');
return buf.toString();
}
/**
* <p>Returns an unquoted form of the given String. If
* <code>q is a String returned by {@link #quote quote(s)},
* then <code>unquote(q).equals(s). If there is no String
* <code>s for which quote(s).equals(q) , then
* unquote(q) throws an IllegalArgumentException.</p>
*
* <p>These rules imply that there is a one-to-one mapping between
* quoted and unquoted forms.</p>
*
* @param q the String to be unquoted.
*
* @return the unquoted String.
*
* @exception IllegalArgumentException if <code>q could not
* have been returned by the {@link #quote} method, for instance
* if it does not begin and end with a quote (").
*
* @exception NullPointerException if <code>q is null.
*
*/
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) != '"')
throw new IllegalArgumentException("Argument not quoted");
for (int i = 1; i < len - 1; i++) {
char c = q.charAt(i);
if (c == '\\') {
if (i == len - 2)
throw new IllegalArgumentException("Trailing backslash");
c = q.charAt(++i);
switch (c) {
case 'n':
c = '\n';
break;
case '\\':
case '\"':
case '*':
case '?':
break;
default:
throw new IllegalArgumentException(
"Bad character '" + c + "' after backslash");
}
} else {
switch (c) {
case '*' :
case '?' :
case '\"':
case '\n':
throw new IllegalArgumentException(
"Invalid unescaped character '" + c +
"' in the string to unquote");
}
}
buf.append(c);
}
return buf.toString();
}
/**
* Defines the wildcard "*:*" ObjectName.
*
* @since 1.6
*/
public static final ObjectName WILDCARD = Util.newObjectName("*:*");
// Category : Utilities <===================================
// Category : QueryExp Interface ---------------------------------------->
/**
* <p>Test whether this ObjectName, which may be a pattern,
* matches another ObjectName. If <code>name is a pattern,
* the result is false. If this ObjectName is a pattern, the
* result is true if and only if <code>name matches the
* pattern. If neither this ObjectName nor <code>name is
* a pattern, the result is true if and only if the two
* ObjectNames are equal as described for the {@link
* #equals(Object)} method.</p>
*
* @param name The name of the MBean to compare to.
*
* @return True if <code>name matches this ObjectName.
*
* @exception NullPointerException if <code>name is null.
*
*/
public boolean apply(ObjectName name) {
if (name == null) throw new NullPointerException();
if (name._domain_pattern ||
name._property_list_pattern ||
name._property_value_pattern)
return false;
// No pattern
if (!_domain_pattern &&
!_property_list_pattern &&
!_property_value_pattern)
return _canonicalName.equals(name._canonicalName);
return matchDomains(name) && matchKeys(name);
}
private final boolean matchDomains(ObjectName name) {
if (_domain_pattern) {
// wildmatch domains
// This ObjectName is the pattern
// The other ObjectName is the string.
return Util.wildmatch(name.getDomain(),getDomain());
}
return getDomain().equals(name.getDomain());
}
private final boolean matchKeys(ObjectName name) {
// If key property value pattern but not key property list
// pattern, then the number of key properties must be equal
//
if (_property_value_pattern &&
!_property_list_pattern &&
(name._ca_array.length != _ca_array.length))
return false;
// If key property value pattern or key property list pattern,
// then every property inside pattern should exist in name
//
if (_property_value_pattern || _property_list_pattern) {
final Map<String,String> nameProps = name._getKeyPropertyList();
final Property[] props = _ca_array;
final String cn = _canonicalName;
for (int i = props.length - 1; i >= 0 ; i--) {
// Find value in given object name for key at current
// index in receiver
//
final Property p = props[i];
final String k = p.getKeyString(cn);
final String v = nameProps.get(k);
// Did we find a value for this key ?
//
if (v == null) return false;
// If this property is ok (same key, same value), go to next
//
if (_property_value_pattern && (p instanceof PatternProperty)) {
// wildmatch key property values
// p is the property pattern, v is the string
if (Util.wildmatch(v,p.getValueString(cn)))
continue;
else
return false;
}
if (v.equals(p.getValueString(cn))) continue;
return false;
}
return true;
}
// If no pattern, then canonical names must be equal
//
final String p1 = name.getCanonicalKeyPropertyListString();
final String p2 = getCanonicalKeyPropertyListString();
return (p1.equals(p2));
}
/* Method inherited from QueryExp, no implementation needed here
because ObjectName is not relative to an MBeanServer and does
not contain a subquery.
*/
public void setMBeanServer(MBeanServer mbs) { }
// Category : QueryExp Interface <=========================
// Category : Comparable Interface ---------------------------------------->
/**
* <p>Compares two ObjectName instances. The ordering relation between
* ObjectNames is not completely specified but is intended to be such
* that a sorted list of ObjectNames will appear in an order that is
* convenient for a person to read.</p>
*
* <p>In particular, if the two ObjectName instances have different
* domains then their order is the lexicographical order of the domains.
* The ordering of the key property list remains unspecified.</p>
*
* <p>For example, the ObjectName instances below:
* <ul>
* <li>Shapes:type=Square,name=3
* <li>Colors:type=Red,name=2
* <li>Shapes:type=Triangle,side=isosceles,name=2
* <li>Colors:type=Red,name=1
* <li>Shapes:type=Square,name=1
* <li>Colors:type=Blue,name=1
* <li>Shapes:type=Square,name=2
* <li>JMImplementation:type=MBeanServerDelegate
* <li>Shapes:type=Triangle,side=scalene,name=1
* </ul>
* <p>could be ordered as follows:
* <ul>
* <li>Colors:type=Blue,name=1
* <li>Colors:type=Red,name=1
* <li>Colors:type=Red,name=2
* <li>JMImplementation:type=MBeanServerDelegate
* <li>Shapes:type=Square,name=1
* <li>Shapes:type=Square,name=2
* <li>Shapes:type=Square,name=3
* <li>Shapes:type=Triangle,side=scalene,name=1
* <li>Shapes:type=Triangle,side=isosceles,name=2
* </ul>
*
* @param name the ObjectName to be compared.
*
* @return a negative integer, zero, or a positive integer as this
* ObjectName is less than, equal to, or greater than the
* specified ObjectName.
*
* @since 1.6
*/
public int compareTo(ObjectName name) {
// Quick optimization:
//
if (name == this) return 0;
// (1) Compare domains
//
int domainValue = this.getDomain().compareTo(name.getDomain());
if (domainValue != 0)
return domainValue;
// (2) Compare "type=" keys
//
// Within a given domain, all names with missing or empty "type="
// come before all names with non-empty type.
//
// When both types are missing or empty, canonical-name ordering
// applies which is a total order.
//
String thisTypeKey = this.getKeyProperty("type");
String anotherTypeKey = name.getKeyProperty("type");
if (thisTypeKey == null)
thisTypeKey = "";
if (anotherTypeKey == null)
anotherTypeKey = "";
int typeKeyValue = thisTypeKey.compareTo(anotherTypeKey);
if (typeKeyValue != 0)
return typeKeyValue;
// (3) Compare canonical names
//
return this.getCanonicalName().compareTo(name.getCanonicalName());
}
// Category : Comparable Interface <=========================
// Public methods <========================================
}
Other Java examples (source code examples)Here is a short list of links related to this Java ObjectName.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.