/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
*/
package org.opensolaris.os.rad;
import java.util.*;
import java.util.logging.*;
import javax.management.*;
public class ADRName {
private String domain_;
private TreeMap<String, String> kvs_ = new TreeMap<String, String>();
/* Wire-ordered keys to play jconsole's silly collation game */
private List<String> keys_ = new ArrayList<String>();
public ADRName(ObjectName on) {
domain_ = on.getDomain();
Hashtable<String, String> keys = on.getKeyPropertyList();
for (Map.Entry<String, String> e : keys.entrySet()) {
String value = e.getValue();
try {
value = ObjectName.unquote(value);
} catch (IllegalArgumentException ex) {
}
kvs_.put(e.getKey(), value);
}
}
public ADRName(String domain, String[] keys, String[] values) {
domain_ = domain;
if (keys != null && values != null) {
if (keys.length != values.length)
throw new IllegalArgumentException(
"Unequal number of keys and values");
} else if (keys != null || values != null) {
throw new IllegalArgumentException(
"Only one of keys and values specified");
}
for (int i = 0; i < keys.length; i++)
kvs_.put(keys[i], values[i]);
}
public ADRName(String str) {
String[] pieces = str.split(":", 2);
domain_ = pieces[0];
if (pieces.length != 2)
throw new IllegalArgumentException("No keys/values: " + str);
int pos, start = 0, dst = 0;
boolean inkey = true;
char[] c = pieces[1].toCharArray();
String key = null;
char[] scratch = new char[str.length()];
for (pos = 0; pos < c.length; pos++) {
char ochar = c[pos];
if (ochar == ',') {
if (pos == start || inkey)
throw new IllegalArgumentException("Empty value: " + str);
kvs_.put(key, new String(scratch, 0, dst));
keys_.add(key);
dst = 0;
inkey = true;
start = pos + 1;
continue;
} else if (ochar == '=') {
if (pos == start || !inkey)
throw new IllegalArgumentException("Empty key: " + str);
key = new String(scratch, 0, dst);
dst = 0;
inkey = false;
start = pos + 1;
continue;
} else if (ochar == '\\') {
if (++pos >= c.length)
throw new IllegalArgumentException("Ends with \\: " + str);
switch (c[pos]) {
case 'S':
ochar = '\\';
break;
case 'E':
ochar = '=';
break;
case 'C':
ochar = ',';
break;
default:
throw new IllegalArgumentException("Bad sequence: " +
ochar + c[pos]);
}
}
scratch[dst++] = ochar;
}
if (pos == start || inkey)
throw new IllegalArgumentException("Empty value: " + str);
kvs_.put(key, new String(scratch, 0, dst));
keys_.add(key);
}
public ObjectName toObjectName() throws MalformedObjectNameException {
/*
* In theory, ObjectName keys are unordered. In practice, their
* order is used as a hint to improve the appearance of jconsole.
* Discordant as this is, the end result is actually pretty nice.
*
* Unfortunately, the only ObjectName constructor that chooses
* practice over theory is the one that takes the string form, so
* below we cons up a String so that ObjectName(String) can then
* immediately undo our work and parse it.
*/
StringBuilder sb = new StringBuilder(domain_).append(':');
boolean first = true;
for (String key : keys_) {
if (first)
first = false;
else
sb.append(',');
sb.append(key).append('=').append(ObjectName.quote(kvs_.get(key)));
}
return (new ObjectName(sb.toString()));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(domain_);
char sep = ':';
for (Map.Entry<String, String> e : kvs_.entrySet()) {
sb.append(sep);
quote(sb, e.getKey());
sb.append('=');
quote(sb, e.getValue());
sep = ',';
}
return (sb.toString());
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ADRName))
return false;
ADRName a = (ADRName)o;
return domain_.equals(a.domain_) && kvs_.equals(a.kvs_);
}
@Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + (domain_ != null ? domain_.hashCode() : 0);
hash = 53 * hash + (kvs_ != null ? kvs_.hashCode() : 0);
return hash;
}
private static void quote(StringBuilder sb, String s) {
char[] sarray = s.toCharArray();
char[] c = new char[s.length() * 2];
int to, from;
for (to = 0, from = 0; from < sarray.length; from++) {
char ochar = sarray[from];
switch (ochar) {
case '\\':
ochar = 'S';
c[to++] = '\\';
break;
case '=':
ochar = 'E';
c[to++] = '\\';
break;
case ',':
ochar = 'C';
c[to++] = '\\';
break;
}
c[to++] = ochar;
}
sb.append(c, 0, to);
}
public static void main(String[] argv) {
ADRName n = new ADRName("foo.bar:name=value");
System.out.println("Name: " + n);
try {
System.out.println("ObjectName: " + n.toObjectName().toString());
System.out.println("UnObjectName: " +
new ADRName(n.toObjectName()));
} catch (MalformedObjectNameException ex) {
Logger.getLogger(ADRName.class.getName()).log(
Level.SEVERE, null, ex);
}
}
}