User: squirest Date: 01/12/20 19:01:45 Modified: src/main/javax/management ObjectName.java Log: made it pass all the testcases Revision Changes Path 1.3 +240 -72 jmx/src/main/javax/management/ObjectName.java Index: ObjectName.java =================================================================== RCS file: /cvsroot/jboss/jmx/src/main/javax/management/ObjectName.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ObjectName.java 2001/12/07 00:19:49 1.2 +++ ObjectName.java 2001/12/21 03:01:45 1.3 @@ -6,105 +6,111 @@ */ package javax.management; -import java.util.Map; -import java.util.Hashtable; -import java.util.HashMap; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; import java.util.ArrayList; +import java.util.Collections; +import java.util.Hashtable; import java.util.Iterator; import java.util.StringTokenizer; - /** * Object name represents the MBean reference. * * @see javax.management.MBeanServer * * @author <a href="mailto:[EMAIL PROTECTED]">Juha Lindfors</a>. - * @version $Revision: 1.2 $ - * + * @author <a href="mailto:[EMAIL PROTECTED]">Trevor Squires</a>. + * @version $Revision: 1.3 $ + * */ public class ObjectName implements java.io.Serializable { + + // Attributes ---------------------------------------------------- + private boolean hasPattern = false; + private boolean hasPropertyPattern = false; + private Hashtable propertiesHash = null; + + private String domain = null; + private String keyProperties = null; + private String canonicalKeyProperties = null; - // Attributes ---------------------------------------------------- - private boolean isPattern = false; - private boolean isPropertyPattern = false; - private Map keyMap = new HashMap(); - private String domain = ""; - private String canonicalName = null; + private int precompHashCode; - // Constructors -------------------------------------------------- + // Constructors -------------------------------------------------- public ObjectName(String name) throws MalformedObjectNameException { if (name == null) throw new MalformedObjectNameException("null name"); + + int domainSep = name.indexOf(':'); - if (name.indexOf(':') == -1) + if (-1 == domainSep) throw new MalformedObjectNameException("missing domain"); - if (!(name.startsWith(":"))) - this.domain = name.substring(0, name.indexOf(':')); + initDomain(name.substring(0, domainSep)); + initProperties(name.substring(domainSep + 1)); + } - String keys = name.substring(name.indexOf(':') + 1, name.length()); - StringTokenizer tokenizer = new StringTokenizer(keys, ","); + public ObjectName(String domain, String key, String value) + throws MalformedObjectNameException + { + initDomain(domain); - while(tokenizer.hasMoreTokens()) + if (null == key || null == value) { - String key = tokenizer.nextToken(); - keyMap.put(key.substring(0, key.indexOf('=')), - key.substring(key.indexOf('=') + 1, key.length())); + throw new MalformedObjectNameException("properties key or value cannot be null"); } - this.canonicalName = getDomain() + ":" + getCanonicalKeyPropertyListString(); - } + Hashtable ptable = new Hashtable(); + ptable.put(key, value); - public ObjectName(String domain, String key, String value) - throws MalformedObjectNameException - { - this.domain = domain; - this.keyMap.put(key, value); - this.canonicalName = domain + ":" + key + "=" + value; + initProperties(ptable); + + this.keyProperties = key + "=" + value; } public ObjectName(String domain, Hashtable table) throws MalformedObjectNameException { - this.domain = domain; - this.keyMap.putAll(table); - this.canonicalName = domain + ":" + getCanonicalKeyPropertyListString(); + if (null == table || table.size() < 1) + { + throw new MalformedObjectNameException("null or empty properties"); + } + + initDomain(domain); + initProperties((Hashtable) table.clone()); + + this.keyProperties = canonicalKeyProperties; } - // Public ------------------------------------------------------ + // Public ------------------------------------------------------ public boolean equals(Object object) { if (!(object instanceof ObjectName)) return false; - ObjectName oname = (ObjectName)object; + ObjectName oname = (ObjectName) object; - return (oname.getCanonicalName().equals(canonicalName)); + return (oname.hashCode() == this.precompHashCode); } public int hashCode() { - return canonicalName.hashCode(); + return precompHashCode; } public String toString() { - return canonicalName; + return this.domain + ":" + keyProperties; } public boolean isPattern() { - return isPattern; + return hasPattern; } public String getCanonicalName() { - return canonicalName; + return this.domain + ":" + canonicalKeyProperties; } public String getDomain() @@ -114,63 +120,225 @@ public String getKeyProperty(String property) { - return (String)keyMap.get(property); + return (String) propertiesHash.get(property); } public Hashtable getKeyPropertyList() { - return new Hashtable(keyMap); + return (Hashtable) propertiesHash.clone(); } public String getKeyPropertyListString() { - // FIXME: its immutable object, build this only once - String[] keys = (String[])keyMap.keySet().toArray(new String[0]); - StringBuffer strBuffer = new StringBuffer(1000); - - for (int i = 0; i < keys.length; ++i) - { - String key = keys[i]; - strBuffer.append(key); - strBuffer.append('='); - strBuffer.append(keyMap.get(key)); - strBuffer.append(','); - } - strBuffer.deleteCharAt(strBuffer.length() - 1); - return strBuffer.toString(); + return keyProperties; } public String getCanonicalKeyPropertyListString() { - // FIXME: its immutable object, build this only once - Iterator it = keyMap.keySet().iterator(); + return canonicalKeyProperties; + } + + public boolean isPropertyPattern() + { + // FIXME: patterns not implemented + return hasPropertyPattern; + } + + // Private ----------------------------------------------------- + + /** + * checks for domain patterns and illegal characters + */ + private void initDomain(String dstring) throws MalformedObjectNameException + { + if (null == dstring) + { + throw new MalformedObjectNameException("null domain"); + } + + if (dstring.indexOf(',') > -1 || dstring.indexOf('=') > -1) + { + throw new MalformedObjectNameException("domain contains illegal characters"); + } + + if (dstring.indexOf('*') > -1 || dstring.indexOf('?') > -1) + { + this.hasPattern = true; + } + + this.domain = dstring; + } + + /** + * takes the properties string and breaks it up into key/value pairs for + * insertion into a newly created hashtable. + * + * minimal validation is performed so that it doesn't blow up when + * constructing the kvp strings. + * + * checks for duplicate keys + * + * detects property patterns + * + */ + private void initProperties(String properties) throws MalformedObjectNameException + { + if (null == properties || properties.length() < 1) + { + throw new MalformedObjectNameException("null or empty properties"); + } + + // The StringTokenizer below hides malformations such as ',,' in the + // properties string or ',' as the first or last character. + // Rather than asking for tokens and building a state machine I'll + // just manually check for those 3 scenarios. + + if (properties.startsWith(",") || properties.endsWith(",") || properties.indexOf(",,") != -1) + { + throw new MalformedObjectNameException("empty key/value pair in properties string"); + } + + Hashtable ptable = new Hashtable(); + + StringTokenizer tokenizer = new StringTokenizer(properties, ","); + while (tokenizer.hasMoreTokens()) + { + String chunk = tokenizer.nextToken(); + + if (chunk.equals("*")) + { + this.hasPropertyPattern = true; + this.hasPattern = true; + continue; + } + + int keylen = chunk.length(); + int eqpos = chunk.indexOf('='); + + // test below: as in '=value' or 'key=' so that our substrings don't blow up + if (eqpos < 1 || (keylen == eqpos + 1)) + { + throw new MalformedObjectNameException("malformed key/value pair: " + chunk); + } + + String key = chunk.substring(0, eqpos); + if (ptable.containsKey(key)) + { + throw new MalformedObjectNameException("duplicate key: " + key); + } + + ptable.put(key, chunk.substring(eqpos + 1, keylen)); + } + + initProperties(ptable); + + // if it's not a propertyPattern then preserve the original string + if (!this.hasPropertyPattern) + { + this.keyProperties = properties; + } + else + { + this.keyProperties = canonicalKeyProperties; + } + } + + /** + * validates incoming properties hashtable + * + * builds canonical string + * + * precomputes the hashcode + */ + private void initProperties(Hashtable properties) throws MalformedObjectNameException + { + if (null == properties || (!this.hasPropertyPattern && properties.size() < 1)) + { + throw new MalformedObjectNameException("null or empty properties"); + } + + Iterator it = properties.keySet().iterator(); ArrayList list = new ArrayList(); - while(it.hasNext()) + while (it.hasNext()) { - String key = (String)it.next(); - list.add(new String(key + "=" + keyMap.get(key))); + String key = null; + try + { + key = (String) it.next(); + } + catch (ClassCastException e) + { + throw new MalformedObjectNameException("key is not a string"); + } + + String val = null; + try + { + val = (String) properties.get(key); + } + catch (ClassCastException e) + { + throw new MalformedObjectNameException("value is not a string"); + } + + if (isIllegalKeyOrValue(key) || isIllegalKeyOrValue(val)) + { + throw new MalformedObjectNameException("malformed key/value pair: " + key + "=" + val); + } + list.add(new String(key + "=" + val)); } Collections.sort(list); StringBuffer strBuffer = new StringBuffer(); it = list.iterator(); - while(it.hasNext()) + while (it.hasNext()) { strBuffer.append(it.next()); - strBuffer.append(','); + if (it.hasNext()) + { + strBuffer.append(','); + } } - strBuffer.deleteCharAt(strBuffer.length() -1); - return strBuffer.toString(); + + this.propertiesHash = properties; + this.canonicalKeyProperties = strBuffer.toString(); + + // now precompute the hashcode + // just need it to be unique + strBuffer.append(':').append(this.domain).append(':'); + strBuffer.append(isPattern()).append(isPropertyPattern()); + this.precompHashCode = strBuffer.toString().hashCode(); } - public boolean isPropertyPattern() + /** + * returns true if the key or value string is zero length or contains illegal characters + */ + private boolean isIllegalKeyOrValue(String keyOrValue) { - // FIXME: patterns not implemented - return isPropertyPattern; - } + char[] chars = keyOrValue.toCharArray(); + + if (chars.length == 0) + { + return true; + } + for (int i = 0; i < chars.length; i++) + { + switch (chars[i]) + { + case ':': + case ',': + case '=': + case '*': + case '?': + return true; + } + } + + return false; + } }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development