| /* ObjectName.java -- Represent the name of a bean, or a pattern for a name. |
| Copyright (C) 2006, 2007 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath 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 for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package javax.management; |
| |
| import gnu.java.lang.CPStringBuilder; |
| |
| import java.io.Serializable; |
| |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| import java.io.IOException; |
| import java.io.InvalidObjectException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| |
| /** |
| * <p> |
| * An {@link ObjectName} instance represents the name of a management |
| * bean, or a pattern which may match the name of one or more |
| * management beans. Patterns are distinguished from names by the |
| * presence of the '?' and '*' characters (which match a single |
| * character and a series of zero or more characters, respectively). |
| * </p> |
| * <p> |
| * Each name begins with a domain element, which is terminated by |
| * a ':' character. The domain may be empty. If so, it will be |
| * replaced by the default domain of the bean server in certain |
| * contexts. The domain is a pattern, if it contains either '?' |
| * or '*'. To avoid collisions, it is usual to use reverse |
| * DNS names for the domain, as in Java package and property names. |
| * </p> |
| * <p> |
| * Following the ':' character is a series of properties. The list |
| * is separated by commas, and largely consists of unordered key-value |
| * pairs, separated by an equals sign ('='). At most one element may |
| * be an asterisk ('*'), which turns the {@link ObjectName} instance |
| * into a <emph>property list pattern</emph>. In this situation, the pattern |
| * matches a name if the name contains at least those key-value pairs |
| * given and has the same domain. |
| * </p> |
| * <p> |
| * A <emph>key</emph> is a string of characters which doesn't include |
| * any of those used as delimiters or in patterns (':', '=', ',', '?' |
| * and '*'). Keys must be unique. |
| * </p> |
| * <p> |
| * A value may be <emph>quoted</emph> or <emph>unquoted</emph>. Unquoted |
| * values obey the same rules as given for keys above. Quoted values are |
| * surrounded by quotation marks ("), and use a backslash ('\') character |
| * to include quotes ('\"'), backslashes ('\\'), newlines ('\n'), and |
| * the pattern characters ('\?' and '\*'). The quotes and backslashes |
| * (after expansion) are considered part of the value. |
| * </p> |
| * <p> |
| * Both quoted and unquoted values may contain the wildcard characters |
| * '?' and '*'. A name with at least one value containing a wildcard |
| * character is known as a <emph>property value pattern</emph>. A |
| * name is generally a <emph>property pattern</emph> if it is either |
| * a <emph>property list pattern</emph> or <emph>property value pattern</emph>. |
| * </p> |
| * <p> |
| * Spaces are maintained within the different parts of the name. Thus, |
| * '<code>domain: key1 = value1 </code>' has a key ' key1 ' with value |
| * ' value1 '. Newlines are disallowed, except where escaped in quoted |
| * values. |
| * </p> |
| * |
| * @author Andrew John Hughes (gnu_andrew@member.fsf.org) |
| * @since 1.5 |
| */ |
| public class ObjectName |
| implements Serializable, QueryExp |
| { |
| |
| private static final long serialVersionUID = 1081892073854801359L; |
| |
| /** |
| * The wildcard {@link ObjectName} {@code "*:*"} |
| * |
| * @since 1.6 |
| */ |
| public static final ObjectName WILDCARD; |
| |
| /** |
| * The domain of the name. |
| */ |
| private transient String domain; |
| |
| /** |
| * The properties, as key-value pairs. |
| */ |
| private transient TreeMap<String,String> properties; |
| |
| /** |
| * The properties as a string (stored for ordering). |
| */ |
| private transient String propertyListString; |
| |
| /** |
| * True if this object name is a property list pattern. |
| */ |
| private transient boolean propertyListPattern; |
| |
| /** |
| * True if this object name is a property value pattern. |
| */ |
| private transient boolean propertyValuePattern; |
| |
| /** |
| * The management server associated with this object name. |
| */ |
| private transient MBeanServer server; |
| |
| /** |
| * Static initializer to set up the wildcard. |
| */ |
| static |
| { |
| try |
| { |
| WILDCARD = new ObjectName(""); |
| } |
| catch (MalformedObjectNameException e) |
| { |
| throw (InternalError) (new InternalError("A problem occurred " + |
| "initializing the ObjectName " + |
| "wildcard.").initCause(e)); |
| } |
| } |
| |
| /** |
| * Constructs an {@link ObjectName} instance from the given string, |
| * which should be of the form |
| * <domain>:<properties><wild>. <domain> |
| * represents the domain section of the name. <properties> |
| * represents the key-value pairs, as returned by {@link |
| * #getKeyPropertyListString()}. <wild> is the optional |
| * asterisk present in the property list. If the string doesn't |
| * represent a property pattern, it will be empty. If it does, |
| * it will be either ',*' or '*', depending on whether other |
| * properties are present or not, respectively. |
| * |
| * @param name the string to use to construct this instance. |
| * @throws MalformedObjectNameException if the string is of the |
| * wrong format. |
| * @throws NullPointerException if <code>name</code> is |
| * <code>null</code>. |
| */ |
| public ObjectName(String name) |
| throws MalformedObjectNameException |
| { |
| if (name.length() == 0) |
| name = "*:*"; |
| parse(name); |
| } |
| |
| /** |
| * Parse the name in the same form as the constructor. Used by |
| * readObject(). |
| */ |
| private void parse(String name) |
| throws MalformedObjectNameException |
| { |
| int domainSep = name.indexOf(':'); |
| if (domainSep == -1) |
| throw new MalformedObjectNameException("No domain separator was found."); |
| domain = name.substring(0, domainSep); |
| String rest = name.substring(domainSep + 1); |
| properties = new TreeMap<String,String>(); |
| String[] pairs = rest.split(","); |
| if (pairs.length == 0 && !isPattern()) |
| throw new MalformedObjectNameException("A name that is not a " + |
| "pattern must contain at " + |
| "least one key-value pair."); |
| propertyListString = ""; |
| for (int a = 0; a < pairs.length; ++a) |
| { |
| if (pairs[a].equals("*")) |
| { |
| if (propertyListPattern) |
| throw new MalformedObjectNameException("Multiple wildcards " + |
| "in properties."); |
| propertyListPattern = true; |
| continue; |
| } |
| int sep = pairs[a].indexOf('='); |
| if (sep == -1) |
| throw new MalformedObjectNameException("A key must be " + |
| "followed by a value."); |
| String key = pairs[a].substring(0, sep); |
| if (properties.containsKey(key)) |
| throw new MalformedObjectNameException("The same key occurs " + |
| "more than once."); |
| String value = pairs[a].substring(sep+1); |
| properties.put(key, value); |
| propertyListString += key + "=" + value + ","; |
| } |
| if (propertyListString.length() > 0) |
| propertyListString = |
| propertyListString.substring(0, propertyListString.length() - 1); |
| checkComponents(); |
| } |
| |
| /** |
| * Constructs an {@link ObjectName} instance using the given |
| * domain and the one specified property. |
| * |
| * @param domain the domain part of the object name. |
| * @param key the key of the property. |
| * @param value the value of the property. |
| * @throws MalformedObjectNameException the domain, key or value |
| * contains an illegal |
| * character or the value |
| * does not follow the quoting |
| * specifications. |
| * @throws NullPointerException if one of the parameters is |
| * <code>null</code>. |
| */ |
| public ObjectName(String domain, String key, String value) |
| throws MalformedObjectNameException |
| { |
| this.domain = domain; |
| properties = new TreeMap<String,String>(); |
| properties.put(key, value); |
| checkComponents(); |
| } |
| |
| /** |
| * Constructs an {@link ObjectName} instance using the given |
| * domain and properties. |
| * |
| * @param domain the domain part of the object name. |
| * @param properties the key-value property pairs. |
| * @throws MalformedObjectNameException the domain, a key or a value |
| * contains an illegal |
| * character or a value |
| * does not follow the quoting |
| * specifications. |
| * @throws NullPointerException if one of the parameters is |
| * <code>null</code>. |
| */ |
| public ObjectName(String domain, Hashtable<String,String> properties) |
| throws MalformedObjectNameException |
| { |
| this.domain = domain; |
| this.properties = new TreeMap<String,String>(); |
| this.properties.putAll(properties); |
| checkComponents(); |
| } |
| |
| /** |
| * Checks the legality of the domain and the properties. |
| * |
| * @throws MalformedObjectNameException the domain, a key or a value |
| * contains an illegal |
| * character or a value |
| * does not follow the quoting |
| * specifications. |
| */ |
| private void checkComponents() |
| throws MalformedObjectNameException |
| { |
| if (domain.indexOf(':') != -1) |
| throw new MalformedObjectNameException("The domain includes a ':' " + |
| "character."); |
| if (domain.indexOf('\n') != -1) |
| throw new MalformedObjectNameException("The domain includes a newline " + |
| "character."); |
| char[] keychars = new char[] { '\n', ':', ',', '*', '?', '=' }; |
| char[] valchars = new char[] { '\n', ':', ',', '=' }; |
| for (Map.Entry<String,String> entry : properties.entrySet()) |
| { |
| for (int a = 0; a < keychars.length; ++a) |
| if (entry.getKey().indexOf(keychars[a]) != -1) |
| throw new MalformedObjectNameException("A key contains a '" + |
| keychars[a] + "' " + |
| "character."); |
| String value = entry.getValue(); |
| int quote = value.indexOf('"'); |
| if (quote == 0) |
| { |
| try |
| { |
| unquote(value); |
| } |
| catch (IllegalArgumentException e) |
| { |
| throw (MalformedObjectNameException) |
| new MalformedObjectNameException("The quoted value is " + |
| "invalid.").initCause(e); |
| } |
| } |
| else if (quote != -1) |
| throw new MalformedObjectNameException("A value contains " + |
| "a '\"' character."); |
| else |
| { |
| for (int a = 0; a < valchars.length; ++a) |
| if (value.indexOf(valchars[a]) != -1) |
| throw new MalformedObjectNameException("A value contains " + |
| "a '" + valchars[a] + "' " + |
| "character."); |
| |
| } |
| if (value.indexOf('*') != -1 || value.indexOf('?') != -1) |
| propertyValuePattern = true; |
| } |
| } |
| |
| /** |
| * <p> |
| * Attempts to find a match between this name and the one supplied. |
| * The following criteria are used: |
| * </p> |
| * <ul> |
| * <li>If the supplied name is a pattern, <code>false</code> is |
| * returned.</li> |
| * <li>If this name is a pattern, this method returns <code>true</code> |
| * if the supplied name matches the pattern.</li> |
| * <li>If this name is not a pattern, the result of |
| * <code>equals(name)</code> is returned. |
| * </ul> |
| * |
| * @param name the name to find a match with. |
| * @return true if the name either matches this pattern or is |
| * equivalent to this name under the criteria of |
| * {@link #equals(java.lang.Object)} |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. |
| */ |
| public boolean apply(ObjectName name) |
| { |
| if (name.isPattern()) |
| return false; |
| |
| if (!isPattern()) |
| return equals(name); |
| |
| if (isDomainPattern()) |
| { |
| if (!domainMatches(domain, 0, name.getDomain(), 0)) |
| return false; |
| } |
| else |
| { |
| if (!domain.equals(name.getDomain())) |
| return false; |
| } |
| |
| if (isPropertyPattern()) |
| { |
| Hashtable<String,String> oProps = name.getKeyPropertyList(); |
| for (Map.Entry<String,String> entry : properties.entrySet()) |
| { |
| String key = entry.getKey(); |
| if (!(oProps.containsKey(key))) |
| return false; |
| String val = entry.getValue(); |
| if (!(val.equals(oProps.get(key)))) |
| return false; |
| } |
| } |
| else |
| { |
| if (!getCanonicalKeyPropertyListString().equals |
| (name.getCanonicalKeyPropertyListString())) |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Returns true if the domain matches the pattern. |
| * |
| * @param pattern the pattern to match against. |
| * @param patternindex the index into the pattern to start matching. |
| * @param domain the domain to match. |
| * @param domainindex the index into the domain to start matching. |
| * @return true if the domain matches the pattern. |
| */ |
| private static boolean domainMatches(String pattern, int patternindex, |
| String domain, int domainindex) |
| { |
| while (patternindex < pattern.length()) |
| { |
| char c = pattern.charAt(patternindex++); |
| |
| if (c == '*') |
| { |
| for (int i = domain.length(); i >= domainindex; i--) |
| { |
| if (domainMatches(pattern, patternindex, domain, i)) |
| return true; |
| } |
| return false; |
| } |
| |
| if (domainindex >= domain.length()) |
| return false; |
| |
| if (c != '?' && c != domain.charAt(domainindex)) |
| return false; |
| |
| domainindex++; |
| } |
| return true; |
| } |
| |
| /** |
| * Compares the specified object with this one. The two |
| * are judged to be equivalent if the given object is an |
| * instance of {@link ObjectName} and has an equal canonical |
| * form (as returned by {@link #getCanonicalName()}). |
| * |
| * @param obj the object to compare with this. |
| * @return true if the object is also an {@link ObjectName} |
| * with an equivalent canonical form. |
| */ |
| public boolean equals(Object obj) |
| { |
| if (obj instanceof ObjectName) |
| { |
| ObjectName o = (ObjectName) obj; |
| return getCanonicalName().equals(o.getCanonicalName()); |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the property list in canonical form. The keys |
| * are ordered using the lexicographic ordering used by |
| * {@link java.lang.String#compareTo(java.lang.Object)}. |
| * |
| * @return the property list, with the keys in lexicographic |
| * order. |
| */ |
| public String getCanonicalKeyPropertyListString() |
| { |
| CPStringBuilder builder = new CPStringBuilder(); |
| Iterator<Map.Entry<String,String>> i = properties.entrySet().iterator(); |
| while (i.hasNext()) |
| { |
| Map.Entry<String,String> entry = i.next(); |
| builder.append(entry.getKey() + "=" + entry.getValue()); |
| if (i.hasNext()) |
| builder.append(","); |
| } |
| return builder.toString(); |
| } |
| |
| /** |
| * <p> |
| * Returns the name as a string in canonical form. More precisely, |
| * this returns a string of the format |
| * <domain>:<properties><wild>. <properties> |
| * is the same value as returned by |
| * {@link #getCanonicalKeyPropertyListString()}. <wild> |
| * is: |
| * </p> |
| * <ul> |
| * <li>an empty string, if the object name is not a property pattern.</li> |
| * <li>'*' if <properties> is empty.</li> |
| * <li>',*' if there is at least one key-value pair.</li> |
| * </ul> |
| * |
| * @return the canonical string form of the object name, as specified |
| * above. |
| */ |
| public String getCanonicalName() |
| { |
| return domain + ":" + |
| getCanonicalKeyPropertyListString() + |
| (isPropertyPattern() ? (properties.isEmpty() ? "*" : ",*") : ""); |
| } |
| |
| /** |
| * Returns the domain part of the object name. |
| * |
| * @return the domain. |
| */ |
| public String getDomain() |
| { |
| return domain; |
| } |
| |
| /** |
| * Returns an {@link ObjectName} instance that is substitutable for the |
| * one given. The instance returned may be a subclass of {@link ObjectName}, |
| * but is not guaranteed to be of the same type as the given name, if that |
| * should also turn out to be a subclass. The returned instance may or may |
| * not be equivalent to the one given. The purpose of this method is to provide |
| * an instance of {@link ObjectName} with a well-defined semantics, such as may |
| * be used in cases where the given name is not trustworthy. |
| * |
| * @param name the {@link ObjectName} to provide a substitute for. |
| * @return a substitute for the given name, which may or may not be a subclass |
| * of {@link ObjectName}. In either case, the returned object is |
| * guaranteed to have the semantics defined here. |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. |
| */ |
| public static ObjectName getInstance(ObjectName name) |
| { |
| try |
| { |
| return new ObjectName(name.getCanonicalName()); |
| } |
| catch (MalformedObjectNameException e) |
| { |
| throw (InternalError) |
| (new InternalError("The canonical name of " + |
| "the given name is invalid.").initCause(e)); |
| } |
| } |
| |
| /** |
| * Returns an {@link ObjectName} instance for the specified name, represented |
| * as a {@link java.lang.String}. The instance returned may be a subclass of |
| * {@link ObjectName} and may or may not be equivalent to earlier instances |
| * returned by this method for the same string. |
| * |
| * @param name the {@link ObjectName} to provide an instance of. |
| * @return a instance for the given name, which may or may not be a subclass |
| * of {@link ObjectName}. |
| * @throws MalformedObjectNameException the domain, a key or a value |
| * contains an illegal |
| * character or a value |
| * does not follow the quoting |
| * specifications. |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. |
| */ |
| public static ObjectName getInstance(String name) |
| throws MalformedObjectNameException |
| { |
| return new ObjectName(name); |
| } |
| |
| /** |
| * Returns an {@link ObjectName} instance for the specified name, represented |
| * as a series of {@link java.lang.String} objects for the domain and a single |
| * property, as a key-value pair. The instance returned may be a subclass of |
| * {@link ObjectName} and may or may not be equivalent to earlier instances |
| * returned by this method for the same parameters. |
| * |
| * @param domain the domain part of the object name. |
| * @param key the key of the property. |
| * @param value the value of the property. |
| * @return a instance for the given name, which may or may not be a subclass |
| * of {@link ObjectName}. |
| * @throws MalformedObjectNameException the domain, a key or a value |
| * contains an illegal |
| * character or a value |
| * does not follow the quoting |
| * specifications. |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. |
| */ |
| public static ObjectName getInstance(String domain, String key, String value) |
| throws MalformedObjectNameException |
| { |
| return new ObjectName(domain, key, value); |
| } |
| |
| /** |
| * Returns an {@link ObjectName} instance for the specified name, represented |
| * as a domain {@link java.lang.String} and a table of properties. The |
| * instance returned may be a subclass of {@link ObjectName} and may or may |
| * not be equivalent to earlier instances returned by this method for the |
| * same string. |
| * |
| * @param domain the domain part of the object name. |
| * @param properties the key-value property pairs. |
| * @return a instance for the given name, which may or may not be a subclass |
| * of {@link ObjectName}. |
| * @throws MalformedObjectNameException the domain, a key or a value |
| * contains an illegal |
| * character or a value |
| * does not follow the quoting |
| * specifications. |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. |
| */ |
| public static ObjectName getInstance(String domain, |
| Hashtable<String,String> properties) |
| throws MalformedObjectNameException |
| { |
| return new ObjectName(domain, properties); |
| } |
| |
| /** |
| * Returns the property value corresponding to the given key. |
| * |
| * @param key the key of the property to be obtained. |
| * @return the value of the specified property. |
| * @throws NullPointerException if <code>key</code> is <code>null</code>. |
| */ |
| public String getKeyProperty(String key) |
| { |
| if (key == null) |
| throw new NullPointerException("Null key given in request for a value."); |
| return (String) properties.get(key); |
| } |
| |
| /** |
| * Returns the properties in a {@link java.util.Hashtable}. The table |
| * contains each of the properties as keys mapped to their value. The |
| * returned table is not unmodifiable, but changes made to it will not |
| * be reflected in the object name. |
| * |
| * @return a {@link java.util.Hashtable}, containing each of the object |
| * name's properties. |
| */ |
| public Hashtable<String,String> getKeyPropertyList() |
| { |
| return new Hashtable<String,String>(properties); |
| } |
| |
| /** |
| * Returns a {@link java.lang.String} representation of the property |
| * list. If the object name was created using {@link |
| * ObjectName(String)}, then this string will contain the properties |
| * in the same order they were given in at creation. |
| * |
| * @return the property list. |
| */ |
| public String getKeyPropertyListString() |
| { |
| if (propertyListString != null) |
| return propertyListString; |
| return getCanonicalKeyPropertyListString(); |
| } |
| |
| /** |
| * Returns a hash code for this object name. This is calculated as the |
| * summation of the hash codes of the domain and the properties. |
| * |
| * @return a hash code for this object name. |
| */ |
| public int hashCode() |
| { |
| return domain.hashCode() + properties.hashCode(); |
| } |
| |
| /** |
| * Returns true if the domain of this object name is a pattern. |
| * This is the case if it contains one or more wildcard characters |
| * ('*' or '?'). |
| * |
| * @return true if the domain is a pattern. |
| */ |
| public boolean isDomainPattern() |
| { |
| return domain.contains("?") || domain.contains("*"); |
| } |
| |
| /** |
| * Returns true if this is an object name pattern. An object |
| * name pattern has a domain containing a wildcard character |
| * ('*' or '?') and/or a '*' in the list of properties. |
| * This method will return true if either {@link #isDomainPattern()} |
| * or {@link #isPropertyPattern()} does. |
| * |
| * @return true if this is an object name pattern. |
| */ |
| public boolean isPattern() |
| { |
| return isDomainPattern() || isPropertyPattern(); |
| } |
| |
| /** |
| * Returns true if this object name is a property list |
| * pattern, a property value pattern or both. |
| * |
| * @return true if the properties of this name contain a pattern. |
| * @see #isPropertyListPattern |
| * @see #isPropertyValuePattern |
| */ |
| public boolean isPropertyPattern() |
| { |
| return propertyListPattern || propertyValuePattern; |
| } |
| |
| /** |
| * Returns true if this object name is a property list pattern. This is |
| * the case if the list of properties contains an '*'. |
| * |
| * @return true if this is a property list pattern. |
| * @since 1.6 |
| */ |
| public boolean isPropertyListPattern() |
| { |
| return propertyListPattern; |
| } |
| |
| /** |
| * Returns true if this object name is a property value pattern. This is |
| * the case if one of the values contains a wildcard character, |
| * '?' or '*'. |
| * |
| * @return true if this is a property value pattern. |
| * @since 1.6 |
| */ |
| public boolean isPropertyValuePattern() |
| { |
| return propertyValuePattern; |
| } |
| |
| /** |
| * Returns true if the value of the given key is a pattern. This is |
| * the case if the value contains a wildcard character, '?' or '*'. |
| * |
| * @param key the key whose value should be checked. |
| * @return true if the value of the given key is a pattern. |
| * @since 1.6 |
| * @throws NullPointerException if {@code key} is {@code null}. |
| * @throws IllegalArgumentException if {@code key} is not a valid |
| * property. |
| */ |
| public boolean isPropertyValuePattern(String key) |
| { |
| String value = getKeyProperty(key); |
| if (value == null) |
| throw new IllegalArgumentException(key + " is not a valid property."); |
| return value.indexOf('?') != -1 || value.indexOf('*') != -1; |
| } |
| |
| /** |
| * <p> |
| * Returns a quoted version of the supplied string. The string may |
| * contain any character. The resulting quoted version is guaranteed |
| * to be usable as the value of a property, so this method provides |
| * a good way of ensuring that a value is legal. |
| * </p> |
| * <p> |
| * The string is transformed as follows: |
| * </p> |
| * <ul> |
| * <li>The string is prefixed with an opening quote character, '"'. |
| * <li>For each character, s: |
| * <ul> |
| * <li>If s is a quote ('"'), it is replaced by a backslash |
| * followed by a quote.</li> |
| * <li>If s is a star ('*'), it is replaced by a backslash followed |
| * by a star.</li> |
| * <li>If s is a question mark ('?'), it is replaced by a backslash |
| * followed by a question mark.</li> |
| * <li>If s is a backslash ('\'), it is replaced by two backslashes.</li> |
| * <li>If s is a newline character, it is replaced by a backslash followed by |
| * a '\n'.</li> |
| * <li>Otherwise, s is used verbatim. |
| * </ul></li> |
| * <li>The string is terminated with a closing quote character, '"'.</li> |
| * </ul> |
| * |
| * @param string the string to quote. |
| * @return a quoted version of the supplied string. |
| * @throws NullPointerException if <code>string</code> is <code>null</code>. |
| */ |
| public static String quote(String string) |
| { |
| CPStringBuilder builder = new CPStringBuilder(); |
| builder.append('"'); |
| for (int a = 0; a < string.length(); ++a) |
| { |
| char s = string.charAt(a); |
| switch (s) |
| { |
| case '"': |
| builder.append("\\\""); |
| break; |
| case '*': |
| builder.append("\\*"); |
| break; |
| case '?': |
| builder.append("\\?"); |
| break; |
| case '\\': |
| builder.append("\\\\"); |
| break; |
| case '\n': |
| builder.append("\\\n"); |
| break; |
| default: |
| builder.append(s); |
| } |
| } |
| builder.append('"'); |
| return builder.toString(); |
| } |
| |
| /** |
| * Changes the {@link MBeanServer} on which this query is performed. |
| * |
| * @param server the new server to use. |
| */ |
| public void setMBeanServer(MBeanServer server) |
| { |
| this.server = server; |
| } |
| |
| /** |
| * Returns a textual representation of the object name. |
| * |
| * <p>The format is unspecified beyond that equivalent object |
| * names will return the same string from this method, but note |
| * that Tomcat depends on the string returned by this method |
| * being a valid textual representation of the object name and |
| * will fail to start if it is not. |
| * |
| * @return a textual representation of the object name. |
| */ |
| public String toString() |
| { |
| return getCanonicalName(); |
| } |
| |
| |
| /** |
| * Serialize this {@link ObjectName}. The serialized |
| * form is the same as the string parsed by the constructor. |
| * |
| * @param out the output stream to write to. |
| * @throws IOException if an I/O error occurs. |
| */ |
| private void writeObject(ObjectOutputStream out) |
| throws IOException |
| { |
| out.defaultWriteObject(); |
| CPStringBuilder buffer = new CPStringBuilder(getDomain()); |
| buffer.append(':'); |
| String properties = getKeyPropertyListString(); |
| buffer.append(properties); |
| if (isPropertyPattern()) |
| { |
| if (properties.length() == 0) |
| buffer.append("*"); |
| else |
| buffer.append(",*"); |
| } |
| out.writeObject(buffer.toString()); |
| } |
| |
| /** |
| * Reads the serialized form, which is that used |
| * by the constructor. |
| * |
| * @param in the input stream to read from. |
| * @throws IOException if an I/O error occurs. |
| */ |
| private void readObject(ObjectInputStream in) |
| throws IOException, ClassNotFoundException |
| { |
| in.defaultReadObject(); |
| String objectName = (String)in.readObject(); |
| try |
| { |
| parse(objectName); |
| } |
| catch (MalformedObjectNameException x) |
| { |
| throw new InvalidObjectException(x.toString()); |
| } |
| } |
| |
| |
| /** |
| * Unquotes the supplied string. The quotation marks are removed as |
| * are the backslashes preceding the escaped characters ('"', '?', |
| * '*', '\n', '\\'). A one-to-one mapping exists between quoted and |
| * unquoted values. As a result, a string <code>s</code> should be |
| * equal to <code>unquote(quote(s))</code>. |
| * |
| * @param q the quoted string to unquote. |
| * @return the unquoted string. |
| * @throws NullPointerException if <code>q</code> is <code>null</code>. |
| * @throws IllegalArgumentException if the string is not a valid |
| * quoted string i.e. it is not |
| * surrounded by quotation marks |
| * and/or characters are not properly |
| * escaped. |
| */ |
| public static String unquote(String q) |
| { |
| if (q.charAt(0) != '"') |
| throw new IllegalArgumentException("The string does " + |
| "not start with a quote."); |
| if (q.charAt(q.length() - 1) != '"') |
| throw new IllegalArgumentException("The string does " + |
| "not end with a quote."); |
| CPStringBuilder builder = new CPStringBuilder(); |
| for (int a = 1; a < (q.length() - 1); ++a) |
| { |
| char n = q.charAt(a); |
| if (n == '\\') |
| { |
| n = q.charAt(++a); |
| if (n != '"' && n != '?' && n != '*' && |
| n != 'n' && n != '\\') |
| throw new IllegalArgumentException("Illegal escaped character: " |
| + n); |
| } |
| else if (n == '"' || n == '\n') |
| throw new IllegalArgumentException("Illegal character: " + n); |
| builder.append(n); |
| } |
| |
| return builder.toString(); |
| } |
| |
| } |