package com.sun.slp;
import java.util.*;
import java.io.*;
public class ServiceLocationAttribute extends Object
implements Serializable {
final static String RESERVED = "(),\\!<=>~";
final static String ESCAPED = RESERVED + "*";
final static char ESCAPE = '\\';
final static char CTL_LOWER = (char)0x00;
final static char CTL_UPPER = (char)0x1F;
final static char DEL = (char)0x7F;
static final String WHITESPACE = " \n\t\r";
static final char SPACE = ' ';
static final char COMMA = ',';
static final char PERCENT = '%';
final private static String BAD_TAG_CHARS = "*\n\t\r";
final static String TRUE = "true";
final static String FALSE = "false";
Vector values = null;
String id = null;
ServiceLocationAttribute() {}
public ServiceLocationAttribute(String id_in, Vector values_in)
throws IllegalArgumentException {
Assert.nonNullParameter(id_in, "id");
id = id_in;
if (values_in != null &&
values_in.size() > 0) {
values = (Vector)values_in.clone();
verifyValueTypes(values, false);
}
}
ServiceLocationAttribute(String exp, boolean allowMultiValuedBooleans)
throws ServiceLocationException {
if (exp == null || exp.length() <= 0) {
new ServiceLocationException(ServiceLocationException.PARSE_ERROR,
"null_string_parameter",
new Object[] {exp});
}
if (exp.startsWith("(") && exp.endsWith(")")) {
StringTokenizer tk =
new StringTokenizer(exp.substring(1, exp.length() - 1),
"=",
true);
try {
id =
unescapeAttributeString(tk.nextToken(), true);
if (id.length() <= 0) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"null_id",
new Object[] {exp});
}
tk.nextToken();
String rest = tk.nextToken("");
values = SrvLocHeader.parseCommaSeparatedListIn(rest, true);
int i, n = values.size();
Class vecClass = null;
for (i = 0; i < n; i++) {
String value = (String)values.elementAt(i);
Object o = evaluate(value);
values.setElementAt(o, i);
}
} catch (NoSuchElementException ex) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"assignment_syntax_err",
new Object[] {exp});
}
verifyValueTypes(values, allowMultiValuedBooleans);
} else {
if (exp.indexOf('(') != -1 || exp.indexOf(')') != -1) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"assignment_syntax_err",
new Object[] {exp});
}
id = unescapeAttributeString(exp, true);
}
}
static Object evaluate(String value)
throws ServiceLocationException {
Object o = null;
try {
o = Integer.valueOf(value);
} catch (NumberFormatException ex) {
if (value.equalsIgnoreCase(TRUE) ||
value.equalsIgnoreCase(FALSE)) {
o = Boolean.valueOf(value);
} else {
String val = (String)value;
if (val.startsWith(Opaque.OPAQUE_HEADER)) {
o = Opaque.unescapeByteArray(val);
} else {
o = unescapeAttributeString(val, false);
}
}
}
return o;
}
public Vector getValues() {
if (values == null) {
return null;
}
Vector ret = (Vector)values.clone();
int i, n = ret.size();
for (i = 0; i < n; i++) {
Object o = ret.elementAt(i);
if (o instanceof Opaque) {
o = ((Opaque)o).bytes;
}
ret.setElementAt(o, i);
}
return ret;
}
public String getId() {
return id;
}
static public String escapeId(String str)
throws IllegalArgumentException {
String ret = null;
try {
ret = escapeAttributeString(str, true);
} catch (ServiceLocationException ex) {
throw new IllegalArgumentException(ex.getMessage());
}
return ret;
}
static public String escapeValue(Object val)
throws IllegalArgumentException {
typeCheckValue(val);
if (val instanceof byte[]) {
val = new Opaque((byte[])val);
}
return escapeValueInternal(val);
}
static private void typeCheckValue(Object obj) {
SLPConfig conf = SLPConfig.getSLPConfig();
Assert.nonNullParameter(obj, "attribute value vector element");
if (obj.equals("")) {
throw
new IllegalArgumentException(
conf.formatMessage("empty_string_value",
new Object[0]));
}
if (!(obj instanceof Integer) && !(obj instanceof Boolean) &&
!(obj instanceof String) && !(obj instanceof byte[])) {
throw
new IllegalArgumentException(
conf.formatMessage("value_type_error",
new Object[0]));
}
}
private static String escapeValueInternal(Object val) {
String s;
if (val instanceof String) {
try {
s = escapeAttributeString((String)val, false);
} catch (ServiceLocationException ex) {
throw
new IllegalArgumentException(ex.getMessage());
}
} else {
s = val.toString();
}
return s;
}
protected void
verifyValueTypes(Vector values_in, boolean dontTypeCheck) {
SLPConfig conf = SLPConfig.getSLPConfig();
int i, n = values_in.size();
Class cls = null;
for (i = 0; i < n; i++) {
Object obj = values_in.elementAt(i);
typeCheckValue(obj);
if (i == 0) {
cls = obj.getClass();
} else if (!cls.equals(obj.getClass()) && !dontTypeCheck) {
throw
new IllegalArgumentException(
conf.formatMessage("type_mismatch_error",
new Object[0]));
}
if (!dontTypeCheck && i != 0 && obj instanceof Boolean) {
throw
new IllegalArgumentException(
conf.formatMessage("multivalued_boolean",
new Object[0]));
}
if (obj instanceof byte[]) {
values_in.setElementAt(new Opaque((byte[])obj), i);
} else if (obj instanceof String) {
String val = (String)obj;
try {
Object obj2 = evaluate(val);
if (!(obj2 instanceof String)) {
values_in.setElementAt((String)val + " ", i);
}
} catch (ServiceLocationException ex) {
}
}
}
}
String externalize()
throws ServiceLocationException {
if (values == null) {
return escapeAttributeString(id, true);
}
Vector v = new Vector();
for (Enumeration e = values.elements(); e.hasMoreElements(); ) {
Object o = e.nextElement();
String s = null;
s = escapeValueInternal(o);
v.addElement(s);
}
StringBuffer buf =
new StringBuffer("(" +
escapeAttributeString(id, true) +
"=");
buf.append(SrvLocHeader.vectorToCommaSeparatedList(v));
buf.append(")");
return buf.toString();
}
static String escapeAttributeString(String string,
boolean badTag)
throws ServiceLocationException {
StringBuffer buf = new StringBuffer();
int i, n = string.length();
for (i = 0; i < n; i++) {
char c = string.charAt(i);
if (badTag && BAD_TAG_CHARS.indexOf(c) != -1) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"bad_id_char",
new Object[] {Integer.toHexString(c)});
}
if (canEscape(c)) {
buf.append(ESCAPE);
String str = escapeChar(c);
if (str.length() <= 1) {
str = "0" + str;
}
buf.append(str);
} else {
buf.append(c);
}
}
return buf.toString();
}
static String unescapeAttributeString(String string,
boolean badTag)
throws ServiceLocationException {
int i, n = string.length();
StringBuffer buf = new StringBuffer(n);
for (i = 0; i < n; i++) {
char c = string.charAt(i);
if (c == ESCAPE) {
if (i >= n - 2) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"nonterminating_escape",
new Object[] {string});
}
i++;
c = unescapeChar(string.substring(i, i+2));
i++;
if (!canEscape(c)) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"char_not_reserved_attr",
new Object[] {Character.valueOf(c), string});
}
} else {
if (isReserved(c)) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"reserved_not_escaped",
new Object[] {Character.valueOf(c)});
}
}
if (badTag && BAD_TAG_CHARS.indexOf(c) != -1) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"bad_id_char",
new Object[] {Integer.toHexString(c)});
}
buf.append(c);
}
return buf.toString();
}
private static boolean canEscape(char c) {
return ((ESCAPED.indexOf(c) != -1) ||
((c >= CTL_LOWER && c <= CTL_UPPER) || c == DEL));
}
private static boolean isReserved(char c) {
return ((RESERVED.indexOf(c) != -1) ||
((c >= CTL_LOWER && c <= CTL_UPPER) || c == DEL));
}
static String escapeChar(char c) {
byte[] b = null;
try {
b = ("" + c).getBytes(Defaults.UTF8);
} catch (UnsupportedEncodingException ex) {
Assert.slpassert(false, "no_utf8", new Object[0]);
}
int code = 0;
if (b.length > 3) {
Assert.slpassert(false,
"illegal_utf8",
new Object[] {Character.valueOf(c)});
}
code = (int)(b[0] & 0xFF);
if (b.length > 1) {
code = (int)(code | ((b[1] & 0xFF) << 8));
}
if (b.length > 2) {
code = (int)(code | ((b[2] & 0xFF) << 16));
}
String str = Integer.toHexString(code);
return str;
}
static char unescapeChar(String ch)
throws ServiceLocationException {
int code = 0;
try {
code = Integer.parseInt(ch, 16);
} catch (NumberFormatException ex) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"not_a_character",
new Object[] {ch});
}
String str = null;
byte b0 = 0, b1 = 0, b2 = 0, b3 = 0;
byte b[] = null;
b0 = (byte) (code & 0xFF);
b1 = (byte) ((code >> 8) & 0xFF);
b2 = (byte) ((code >> 16) & 0xFF);
b3 = (byte) ((code >> 24) & 0xFF);
if (b3 != 0) {
b = new byte[3];
b[3] = b3;
b[2] = b2;
b[1] = b1;
b[0] = b0;
} else if (b2 != 0) {
b = new byte[3];
b[2] = b2;
b[1] = b1;
b[0] = b0;
} else if (b1 != 0) {
b = new byte[2];
b[1] = b1;
b[0] = b0;
} else {
b = new byte[1];
b[0] = b0;
}
try {
str = new String(b, Defaults.UTF8);
} catch (UnsupportedEncodingException ex) {
Assert.slpassert(false, "no_utf8", new Object[0]);
}
int len = str.length();
if (str.length() > 1) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"more_than_one",
new Object[] {ch});
}
return (len == 1 ? str.charAt(0):(char)0);
}
static void
mergeDuplicateAttributes(ServiceLocationAttribute newAttr,
Hashtable attrTable,
Vector returns,
boolean dontTypeCheck)
throws ServiceLocationException {
String tag = newAttr.getId().toLowerCase();
ServiceLocationAttribute attr =
(ServiceLocationAttribute)attrTable.get(tag);
Assert.slpassert((!(attr instanceof ServerAttribute) &&
!(newAttr instanceof ServerAttribute)),
"merge_servattr",
new Object[0]);
if (attr == null) {
attrTable.put(tag, newAttr);
returns.addElement(newAttr);
return;
}
Vector attrNewVals = newAttr.values;
Vector attrVals = attr.values;
if (attrVals == null && attrNewVals == null) {
return;
}
if ((attrVals == null && attrNewVals != null) ||
(attrNewVals == null && attrVals != null)) {
if (dontTypeCheck) {
Vector vals = (attrNewVals != null ? attrNewVals:attrVals);
attr.values = vals;
newAttr.values = vals;
} else {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"attribute_type_mismatch",
new Object[] {newAttr.getId()});
}
} else {
int i, n = attrNewVals.size();
Object o = attrVals.elementAt(0);
Class c = o.getClass();
for (i = 0; i < n; i++) {
Object no = attrNewVals.elementAt(i);
if ((c != no.getClass()) && !dontTypeCheck) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"attribute_type_mismatch",
new Object[] {newAttr.getId()});
}
if (no instanceof Boolean && !no.equals(o) && !dontTypeCheck) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"boolean_incompat",
new Object[] {newAttr.getId()});
}
if (!attrVals.contains(no)) {
attrVals.addElement(no);
}
}
newAttr.values = attrVals;
}
}
public boolean equals(Object o) {
if (!(o instanceof ServiceLocationAttribute)) {
return false;
}
if (o == this) {
return true;
}
ServiceLocationAttribute sla = (ServiceLocationAttribute)o;
Vector vSLA = sla.values;
if (!sla.getId().equalsIgnoreCase(id)) {
return false;
}
if (values == null && vSLA == null) {
return true;
}
if ((values == null && vSLA != null) ||
(values != null && vSLA == null)) {
return false;
}
if (values.size() != vSLA.size()) {
return false;
}
Object oSLA = vSLA.elementAt(0);
o = values.elementAt(0);
if (o.getClass() != oSLA.getClass()) {
return false;
}
int i, n = vSLA.size();
for (i = 0; i < n; i++) {
oSLA = vSLA.elementAt(i);
if (!values.contains(oSLA)) {
return false;
}
}
return true;
}
public String toString() {
StringBuffer s = new StringBuffer("(");
s.append(id);
if (values != null) {
s.append("=");
int i, n = values.size();
for (i = 0; i < n; i++) {
Object o = values.elementAt(i);
if (i == 0) {
s.append(o.getClass().getName());
s.append(":");
} else {
s.append(",");
}
s.append(o.toString());
}
}
s.append(")");
return s.toString();
}
public int hashCode() {
return id.toLowerCase().hashCode();
}
}