10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7298SMark.J.Nelson@Sun.COM * Common Development and Distribution License (the "License"). 6*7298SMark.J.Nelson@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 220Sstevel@tonic-gate * Copyright 2001,2003 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 27*7298SMark.J.Nelson@Sun.COM // ServiceLocationAttribute.java : Class for attributes in SLP. 280Sstevel@tonic-gate // Author: James Kempf, Erik Guttman 290Sstevel@tonic-gate // 300Sstevel@tonic-gate 310Sstevel@tonic-gate package com.sun.slp; 320Sstevel@tonic-gate 330Sstevel@tonic-gate import java.util.*; 340Sstevel@tonic-gate import java.io.*; 350Sstevel@tonic-gate 360Sstevel@tonic-gate /** 370Sstevel@tonic-gate * The ServiceLocationAttribute class models SLP attributes. 380Sstevel@tonic-gate * 390Sstevel@tonic-gate * @author James Kempf, Erik Guttman 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate public class ServiceLocationAttribute extends Object 430Sstevel@tonic-gate implements Serializable { 440Sstevel@tonic-gate 450Sstevel@tonic-gate // Characters to escape. 460Sstevel@tonic-gate 470Sstevel@tonic-gate final static String RESERVED = "(),\\!<=>~"; 480Sstevel@tonic-gate final static String ESCAPED = RESERVED + "*"; 490Sstevel@tonic-gate final static char ESCAPE = '\\'; 500Sstevel@tonic-gate 510Sstevel@tonic-gate final static char CTL_LOWER = (char)0x00; 520Sstevel@tonic-gate final static char CTL_UPPER = (char)0x1F; 530Sstevel@tonic-gate final static char DEL = (char)0x7F; 540Sstevel@tonic-gate 550Sstevel@tonic-gate // Whitespace chars. 560Sstevel@tonic-gate 570Sstevel@tonic-gate static final String WHITESPACE = " \n\t\r"; 580Sstevel@tonic-gate static final char SPACE = ' '; 590Sstevel@tonic-gate 600Sstevel@tonic-gate // For character escaping. 610Sstevel@tonic-gate 620Sstevel@tonic-gate static final char COMMA = ','; 630Sstevel@tonic-gate static final char PERCENT = '%'; 640Sstevel@tonic-gate 650Sstevel@tonic-gate // Bad tag characters. 660Sstevel@tonic-gate 670Sstevel@tonic-gate final private static String BAD_TAG_CHARS = "*\n\t\r"; 680Sstevel@tonic-gate 690Sstevel@tonic-gate // For identifying booleans. 700Sstevel@tonic-gate 710Sstevel@tonic-gate final static String TRUE = "true"; 720Sstevel@tonic-gate final static String FALSE = "false"; 730Sstevel@tonic-gate 740Sstevel@tonic-gate // 750Sstevel@tonic-gate // Package accessable fields. 760Sstevel@tonic-gate // 770Sstevel@tonic-gate 780Sstevel@tonic-gate Vector values = null; 790Sstevel@tonic-gate String id = null; 800Sstevel@tonic-gate 810Sstevel@tonic-gate // For V1 compatibility subclass. 820Sstevel@tonic-gate ServiceLocationAttribute()830Sstevel@tonic-gate ServiceLocationAttribute() {} 840Sstevel@tonic-gate 850Sstevel@tonic-gate /** 860Sstevel@tonic-gate * Construct a service location attribute. 870Sstevel@tonic-gate * 880Sstevel@tonic-gate * @param id The attribute name 890Sstevel@tonic-gate * @param values_in Vector of one or more attribute values. Vector 900Sstevel@tonic-gate * contents must be uniform in type and one of 910Sstevel@tonic-gate * Integer, String, Boolean, or byte[]. If the attribute 920Sstevel@tonic-gate * is a keyword attribute, then values_in should be null. 930Sstevel@tonic-gate * @exception IllegalArgumentException Thrown if the 940Sstevel@tonic-gate * vector contents is not of the right type or 950Sstevel@tonic-gate * an argument is null or syntactically incorrect. 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate ServiceLocationAttribute(String id_in, Vector values_in)980Sstevel@tonic-gate public ServiceLocationAttribute(String id_in, Vector values_in) 990Sstevel@tonic-gate throws IllegalArgumentException { 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate Assert.nonNullParameter(id_in, "id"); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate id = id_in; 1040Sstevel@tonic-gate if (values_in != null && 1050Sstevel@tonic-gate values_in.size() > 0) { // null, empty indicate keyword attribute. 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate values = (Vector)values_in.clone(); 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate verifyValueTypes(values, false); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /** 1150Sstevel@tonic-gate * Construct a service location attribute from a parenthesized expression. 1160Sstevel@tonic-gate * The syntax is: 1170Sstevel@tonic-gate * 1180Sstevel@tonic-gate * exp = "(" id "=" value-list ")" | keyword 1190Sstevel@tonic-gate * value-list = value | value "," value-list 1200Sstevel@tonic-gate * 1210Sstevel@tonic-gate * 1220Sstevel@tonic-gate * @param exp The expression 1230Sstevel@tonic-gate * @param dontTypeCheck True if multivalued booleans and vectors 1240Sstevel@tonic-gate * of varying types are allowed. 1250Sstevel@tonic-gate * @exception ServiceLocationException If there are any syntax errors. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate ServiceLocationAttribute(String exp, boolean allowMultiValuedBooleans)1280Sstevel@tonic-gate ServiceLocationAttribute(String exp, boolean allowMultiValuedBooleans) 1290Sstevel@tonic-gate throws ServiceLocationException { 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate if (exp == null || exp.length() <= 0) { 1320Sstevel@tonic-gate new ServiceLocationException(ServiceLocationException.PARSE_ERROR, 1330Sstevel@tonic-gate "null_string_parameter", 1340Sstevel@tonic-gate new Object[] {exp}); 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate // If start and end paren, then parse out assignment. 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate if (exp.startsWith("(") && exp.endsWith(")")) { 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate StringTokenizer tk = 1430Sstevel@tonic-gate new StringTokenizer(exp.substring(1, exp.length() - 1), 1440Sstevel@tonic-gate "=", 1450Sstevel@tonic-gate true); 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate try { 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate // Get the tag. 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate id = 1520Sstevel@tonic-gate unescapeAttributeString(tk.nextToken(), true); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate if (id.length() <= 0) { 1550Sstevel@tonic-gate throw 1560Sstevel@tonic-gate new ServiceLocationException( 1570Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 1580Sstevel@tonic-gate "null_id", 1590Sstevel@tonic-gate new Object[] {exp}); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate tk.nextToken(); // get rid of "=" 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate // Gather the rest. 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate String rest = tk.nextToken(""); 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate // Parse the comma separated list. 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate values = SrvLocHeader.parseCommaSeparatedListIn(rest, true); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate // Convert to objects. 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate int i, n = values.size(); 1750Sstevel@tonic-gate Class vecClass = null; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate for (i = 0; i < n; i++) { 1780Sstevel@tonic-gate String value = (String)values.elementAt(i); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate // Need to determine which type to use. 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate Object o = evaluate(value); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate values.setElementAt(o, i); 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate } 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate } catch (NoSuchElementException ex) { 1890Sstevel@tonic-gate throw 1900Sstevel@tonic-gate new ServiceLocationException( 1910Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 1920Sstevel@tonic-gate "assignment_syntax_err", 1930Sstevel@tonic-gate new Object[] {exp}); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate verifyValueTypes(values, allowMultiValuedBooleans); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate } else { 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate // Check to make sure there's no parens. 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate if (exp.indexOf('(') != -1 || exp.indexOf(')') != -1) { 2030Sstevel@tonic-gate throw 2040Sstevel@tonic-gate new ServiceLocationException( 2050Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2060Sstevel@tonic-gate "assignment_syntax_err", 2070Sstevel@tonic-gate new Object[] {exp}); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate // Unescape the keyword. 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate id = unescapeAttributeString(exp, true); 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate evaluate(String value)2170Sstevel@tonic-gate static Object evaluate(String value) 2180Sstevel@tonic-gate throws ServiceLocationException { 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate Object o = null; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate // If it can be converted into an integer, then convert it. 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate try { 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate o = Integer.valueOf(value); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate } catch (NumberFormatException ex) { 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate // Wasn't an integer. Try boolean. 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate if (value.equalsIgnoreCase(TRUE) || 2330Sstevel@tonic-gate value.equalsIgnoreCase(FALSE)) { 2340Sstevel@tonic-gate o = Boolean.valueOf(value); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate } else { 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate // Process the string to remove escapes. 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate String val = (String)value; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate // If it begins with the opaque prefix, treat it as an 2430Sstevel@tonic-gate // opaque. 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate if (val.startsWith(Opaque.OPAQUE_HEADER)) { 2460Sstevel@tonic-gate o = Opaque.unescapeByteArray(val); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate } else { 2490Sstevel@tonic-gate o = unescapeAttributeString(val, false); 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate return o; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate // 2600Sstevel@tonic-gate // Property accessors. 2610Sstevel@tonic-gate // 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate /** 2640Sstevel@tonic-gate * @return A vector of attribute values, or null if the attribute is 2650Sstevel@tonic-gate * a keyword attribute. If the attribute is single-valued, then 2660Sstevel@tonic-gate * the vector contains only one object. 2670Sstevel@tonic-gate * 2680Sstevel@tonic-gate */ 2690Sstevel@tonic-gate getValues()2700Sstevel@tonic-gate public Vector getValues() { 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate if (values == null) { 2730Sstevel@tonic-gate return null; // keyword case. 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate Vector ret = (Vector)values.clone(); 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate // Need to process Opaques. 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate int i, n = ret.size(); 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate for (i = 0; i < n; i++) { 2830Sstevel@tonic-gate Object o = ret.elementAt(i); 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate if (o instanceof Opaque) { 2860Sstevel@tonic-gate o = ((Opaque)o).bytes; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate ret.setElementAt(o, i); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate return ret; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /** 2970Sstevel@tonic-gate * @return The attribute name. 2980Sstevel@tonic-gate */ 2990Sstevel@tonic-gate getId()3000Sstevel@tonic-gate public String getId() { 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate return id; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate /** 3070Sstevel@tonic-gate * Return an escaped version of the id parameter , suitable for inclusion 3080Sstevel@tonic-gate * in a query. 3090Sstevel@tonic-gate * 3100Sstevel@tonic-gate * @param str The string to escape as an id. 3110Sstevel@tonic-gate * @return The string with any reserved characters escaped. 3120Sstevel@tonic-gate * @exception IllegalArgumentException Thrown if the 3130Sstevel@tonic-gate * string contains bad tag characters. 3140Sstevel@tonic-gate */ 3150Sstevel@tonic-gate escapeId(String str)3160Sstevel@tonic-gate static public String escapeId(String str) 3170Sstevel@tonic-gate throws IllegalArgumentException { 3180Sstevel@tonic-gate String ret = null; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate try { 3210Sstevel@tonic-gate ret = escapeAttributeString(str, true); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate } catch (ServiceLocationException ex) { 3240Sstevel@tonic-gate throw new IllegalArgumentException(ex.getMessage()); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate return ret; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /** 3320Sstevel@tonic-gate * Return an escaped version of the value parameter, suitable for inclusion 3330Sstevel@tonic-gate * in a query. Opaques are stringified. 3340Sstevel@tonic-gate * 3350Sstevel@tonic-gate * @param val The value to escape. 3360Sstevel@tonic-gate * @return The stringified value. 3370Sstevel@tonic-gate * @exception IllegalArgumentException Thrown if the object is not 3380Sstevel@tonic-gate * one of byte[], Integer, Boolean, or String. 3390Sstevel@tonic-gate */ 3400Sstevel@tonic-gate escapeValue(Object val)3410Sstevel@tonic-gate static public String escapeValue(Object val) 3420Sstevel@tonic-gate throws IllegalArgumentException { 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate // Check type first. 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate typeCheckValue(val); 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate // Make Opaque out of byte[]. 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate if (val instanceof byte[]) { 3510Sstevel@tonic-gate val = new Opaque((byte[])val); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate return escapeValueInternal(val); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate // Check type to make sure it's OK. 3600Sstevel@tonic-gate typeCheckValue(Object obj)3610Sstevel@tonic-gate static private void typeCheckValue(Object obj) { 3620Sstevel@tonic-gate SLPConfig conf = SLPConfig.getSLPConfig(); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate Assert.nonNullParameter(obj, "attribute value vector element"); 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate if (obj.equals("")) { 3670Sstevel@tonic-gate throw 3680Sstevel@tonic-gate new IllegalArgumentException( 3690Sstevel@tonic-gate conf.formatMessage("empty_string_value", 3700Sstevel@tonic-gate new Object[0])); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate if (!(obj instanceof Integer) && !(obj instanceof Boolean) && 3740Sstevel@tonic-gate !(obj instanceof String) && !(obj instanceof byte[])) { 3750Sstevel@tonic-gate throw 3760Sstevel@tonic-gate new IllegalArgumentException( 3770Sstevel@tonic-gate conf.formatMessage("value_type_error", 3780Sstevel@tonic-gate new Object[0])); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate // We know the value's type is OK, so just escape it. 3840Sstevel@tonic-gate escapeValueInternal(Object val)3850Sstevel@tonic-gate private static String escapeValueInternal(Object val) { 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate String s; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate // Escape any characters needing it. 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate if (val instanceof String) { 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate try { 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate s = escapeAttributeString((String)val, false); 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate } catch (ServiceLocationException ex) { 3980Sstevel@tonic-gate throw 3990Sstevel@tonic-gate new IllegalArgumentException(ex.getMessage()); 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate } else { 4040Sstevel@tonic-gate s = val.toString(); 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate return s; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate // 4120Sstevel@tonic-gate // Methods for dealing with the type of attribute values. 4130Sstevel@tonic-gate // 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate // Verify the types of incoming attributes. 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate protected void verifyValueTypes(Vector values_in, boolean dontTypeCheck)4180Sstevel@tonic-gate verifyValueTypes(Vector values_in, boolean dontTypeCheck) { 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate SLPConfig conf = SLPConfig.getSLPConfig(); 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate // Make sure the types of objects passed in are acceptable 4230Sstevel@tonic-gate // and that all objects in the vector have the same type. 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate int i, n = values_in.size(); 4260Sstevel@tonic-gate Class cls = null; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate for (i = 0; i < n; i++) { 4290Sstevel@tonic-gate Object obj = values_in.elementAt(i); 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate typeCheckValue(obj); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate if (i == 0) { 4340Sstevel@tonic-gate cls = obj.getClass(); 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate } else if (!cls.equals(obj.getClass()) && !dontTypeCheck) { 4370Sstevel@tonic-gate throw 4380Sstevel@tonic-gate new IllegalArgumentException( 4390Sstevel@tonic-gate conf.formatMessage("type_mismatch_error", 4400Sstevel@tonic-gate new Object[0])); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate // If it's a boolean and there's more than one, signal error 4440Sstevel@tonic-gate // unless multivalued booleans are allowed. 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate if (!dontTypeCheck && i != 0 && obj instanceof Boolean) { 4470Sstevel@tonic-gate throw 4480Sstevel@tonic-gate new IllegalArgumentException( 4490Sstevel@tonic-gate conf.formatMessage("multivalued_boolean", 4500Sstevel@tonic-gate new Object[0])); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate // If it's a byte array, create a Opaque object. 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate if (obj instanceof byte[]) { 4570Sstevel@tonic-gate values_in.setElementAt(new Opaque((byte[])obj), i); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate } else if (obj instanceof String) { 4600Sstevel@tonic-gate String val = (String)obj; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate // If it's a string and looks like "1" or "true", then 4630Sstevel@tonic-gate // append a space onto the end. 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate try { 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate Object obj2 = evaluate(val); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate if (!(obj2 instanceof String)) { 4700Sstevel@tonic-gate values_in.setElementAt((String)val + " ", i); 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate } catch (ServiceLocationException ex) { 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate // Ignore for now. 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate // 4850Sstevel@tonic-gate // Methods for externalizing attributes. 4860Sstevel@tonic-gate // 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /** 4890Sstevel@tonic-gate * Externalize the attribute into a string that can be written 4900Sstevel@tonic-gate * to a byte stream. Includes escaping any characters that 4910Sstevel@tonic-gate * need to be escaped. 4920Sstevel@tonic-gate * 4930Sstevel@tonic-gate * @return String with attribute's external representation. 4940Sstevel@tonic-gate * @exception ServiceLocationException Thrown if the 4950Sstevel@tonic-gate * string contains unencodable characters. 4960Sstevel@tonic-gate */ 4970Sstevel@tonic-gate externalize()4980Sstevel@tonic-gate String externalize() 4990Sstevel@tonic-gate throws ServiceLocationException { 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate if (values == null) { // keyword attribute... 5020Sstevel@tonic-gate return escapeAttributeString(id, true); 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate Vector v = new Vector(); 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate for (Enumeration e = values.elements(); e.hasMoreElements(); ) { 5080Sstevel@tonic-gate Object o = e.nextElement(); 5090Sstevel@tonic-gate String s = null; 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate s = escapeValueInternal(o); 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate v.addElement(s); 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate StringBuffer buf = 5170Sstevel@tonic-gate new StringBuffer("(" + 5180Sstevel@tonic-gate escapeAttributeString(id, true) + 5190Sstevel@tonic-gate "="); 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate buf.append(SrvLocHeader.vectorToCommaSeparatedList(v)); 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate buf.append(")"); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate return buf.toString(); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate // 5290Sstevel@tonic-gate // Escaping and unescaping strings. 5300Sstevel@tonic-gate // 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /** 5330Sstevel@tonic-gate * Escape any escapable characters to a 2 character escape 5340Sstevel@tonic-gate * in the attribute string. 5350Sstevel@tonic-gate * 5360Sstevel@tonic-gate * @param string The String. 5370Sstevel@tonic-gate * @param badTag Check for bad tag characters if true. 5380Sstevel@tonic-gate * @return The escaped string. 5390Sstevel@tonic-gate * @exception ServiceLocationException Thrown if the string 5400Sstevel@tonic-gate * contains a character that can't be encoded. 5410Sstevel@tonic-gate */ 5420Sstevel@tonic-gate escapeAttributeString(String string, boolean badTag)5430Sstevel@tonic-gate static String escapeAttributeString(String string, 5440Sstevel@tonic-gate boolean badTag) 5450Sstevel@tonic-gate throws ServiceLocationException { 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate StringBuffer buf = new StringBuffer(); 5480Sstevel@tonic-gate int i, n = string.length(); 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate for (i = 0; i < n; i++) { 5510Sstevel@tonic-gate char c = string.charAt(i); 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate // Check for bad tag characters first. 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate if (badTag && BAD_TAG_CHARS.indexOf(c) != -1) { 5560Sstevel@tonic-gate throw 5570Sstevel@tonic-gate new ServiceLocationException( 5580Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 5590Sstevel@tonic-gate "bad_id_char", 5600Sstevel@tonic-gate new Object[] {Integer.toHexString(c)}); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate // Escape if the character is reserved. 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate if (canEscape(c)) { 5660Sstevel@tonic-gate buf.append(ESCAPE); 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate String str = escapeChar(c); 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate // Pad with zero if less than 2 characters. 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate if (str.length() <= 1) { 5730Sstevel@tonic-gate str = "0" + str; 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate buf.append(str); 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate } else { 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate buf.append(c); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate return buf.toString(); 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate /** 5920Sstevel@tonic-gate * Convert any 2 character escapes to the corresponding characters. 5930Sstevel@tonic-gate * 5940Sstevel@tonic-gate * @param string The string to be processed. 5950Sstevel@tonic-gate * @param badTag Check for bad tag characters if true. 5960Sstevel@tonic-gate * @return The processed string. 5970Sstevel@tonic-gate * @exception ServiceLocationException Thrown if an escape 5980Sstevel@tonic-gate * is improperly formatted. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate unescapeAttributeString(String string, boolean badTag)6010Sstevel@tonic-gate static String unescapeAttributeString(String string, 6020Sstevel@tonic-gate boolean badTag) 6030Sstevel@tonic-gate throws ServiceLocationException { 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate // Process escapes. 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate int i, n = string.length(); 6080Sstevel@tonic-gate StringBuffer buf = new StringBuffer(n); 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate for (i = 0; i < n; i++) { 6110Sstevel@tonic-gate char c = string.charAt(i); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate // Check for escaped characters. 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate if (c == ESCAPE) { 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate // Get the next two characters. 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if (i >= n - 2) { 6200Sstevel@tonic-gate throw 6210Sstevel@tonic-gate new ServiceLocationException( 6220Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6230Sstevel@tonic-gate "nonterminating_escape", 6240Sstevel@tonic-gate new Object[] {string}); 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate i++; 6280Sstevel@tonic-gate c = unescapeChar(string.substring(i, i+2)); 6290Sstevel@tonic-gate i++; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate // Check whether it's reserved. 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate if (!canEscape(c)) { 6340Sstevel@tonic-gate throw 6350Sstevel@tonic-gate new ServiceLocationException( 6360Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6370Sstevel@tonic-gate "char_not_reserved_attr", 6380Sstevel@tonic-gate new Object[] {new Character(c), string}); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate } else { 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate // Check whether the character is reserved. 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate if (isReserved(c)) { 6460Sstevel@tonic-gate throw 6470Sstevel@tonic-gate new ServiceLocationException( 6480Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6490Sstevel@tonic-gate "reserved_not_escaped", 6500Sstevel@tonic-gate new Object[] {new Character(c)}); 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate // If we need to check for a bad tag character, do so now. 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate if (badTag && BAD_TAG_CHARS.indexOf(c) != -1) { 6580Sstevel@tonic-gate throw 6590Sstevel@tonic-gate new ServiceLocationException( 6600Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6610Sstevel@tonic-gate "bad_id_char", 6620Sstevel@tonic-gate new Object[] {Integer.toHexString(c)}); 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate buf.append(c); 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate return buf.toString(); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate // Return true if the character c can be escaped. 6740Sstevel@tonic-gate canEscape(char c)6750Sstevel@tonic-gate private static boolean canEscape(char c) { 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate return ((ESCAPED.indexOf(c) != -1) || 6780Sstevel@tonic-gate ((c >= CTL_LOWER && c <= CTL_UPPER) || c == DEL)); 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate // Return true if the character c is reserved. 6830Sstevel@tonic-gate isReserved(char c)6840Sstevel@tonic-gate private static boolean isReserved(char c) { 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate return ((RESERVED.indexOf(c) != -1) || 6870Sstevel@tonic-gate ((c >= CTL_LOWER && c <= CTL_UPPER) || c == DEL)); 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /** 6920Sstevel@tonic-gate * Return a string of integers giving the character's encoding in 6930Sstevel@tonic-gate * the character set passed in as encoding. 6940Sstevel@tonic-gate * 6950Sstevel@tonic-gate * @param c The character to escape. 6960Sstevel@tonic-gate * @return The character as a string of integers for the encoding. 6970Sstevel@tonic-gate */ 6980Sstevel@tonic-gate escapeChar(char c)6990Sstevel@tonic-gate static String escapeChar(char c) { 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate byte[] b = null; 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate try { 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate b = ("" + c).getBytes(Defaults.UTF8); 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate } catch (UnsupportedEncodingException ex) { 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate Assert.slpassert(false, "no_utf8", new Object[0]); 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate int code = 0; 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate // Assemble the character code. 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate if (b.length > 3) { 7180Sstevel@tonic-gate Assert.slpassert(false, 7190Sstevel@tonic-gate "illegal_utf8", 7200Sstevel@tonic-gate new Object[] {new Character(c)}); 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate code = (int)(b[0] & 0xFF); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (b.length > 1) { 7270Sstevel@tonic-gate code = (int)(code | ((b[1] & 0xFF) << 8)); 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate if (b.length > 2) { 7310Sstevel@tonic-gate code = (int)(code | ((b[2] & 0xFF) << 16)); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate String str = Integer.toHexString(code); 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate return str; 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate /** 7400Sstevel@tonic-gate * Unescape the character encoded as the string. 7410Sstevel@tonic-gate * 7420Sstevel@tonic-gate * @param ch The character as a string of hex digits. 7430Sstevel@tonic-gate * @return The character. 7440Sstevel@tonic-gate * @exception ServiceLocationException If the characters can't be 7450Sstevel@tonic-gate * converted into a hex string. 7460Sstevel@tonic-gate */ 7470Sstevel@tonic-gate unescapeChar(String ch)7480Sstevel@tonic-gate static char unescapeChar(String ch) 7490Sstevel@tonic-gate throws ServiceLocationException { 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate int code = 0; 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate try { 7540Sstevel@tonic-gate code = Integer.parseInt(ch, 16); 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate } catch (NumberFormatException ex) { 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate throw 7590Sstevel@tonic-gate new ServiceLocationException( 7600Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 7610Sstevel@tonic-gate "not_a_character", 7620Sstevel@tonic-gate new Object[] {ch}); 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate // Convert to bytes. 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate String str = null; 7680Sstevel@tonic-gate byte b0 = 0, b1 = 0, b2 = 0, b3 = 0; 7690Sstevel@tonic-gate byte b[] = null; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate b0 = (byte) (code & 0xFF); 7720Sstevel@tonic-gate b1 = (byte) ((code >> 8) & 0xFF); 7730Sstevel@tonic-gate b2 = (byte) ((code >> 16) & 0xFF); 7740Sstevel@tonic-gate b3 = (byte) ((code >> 24) & 0xFF); 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate // We allow illegal UTF8 encoding so we can decode byte arrays. 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate if (b3 != 0) { 7790Sstevel@tonic-gate b = new byte[3]; 7800Sstevel@tonic-gate b[3] = b3; 7810Sstevel@tonic-gate b[2] = b2; 7820Sstevel@tonic-gate b[1] = b1; 7830Sstevel@tonic-gate b[0] = b0; 7840Sstevel@tonic-gate } else if (b2 != 0) { 7850Sstevel@tonic-gate b = new byte[3]; 7860Sstevel@tonic-gate b[2] = b2; 7870Sstevel@tonic-gate b[1] = b1; 7880Sstevel@tonic-gate b[0] = b0; 7890Sstevel@tonic-gate } else if (b1 != 0) { 7900Sstevel@tonic-gate b = new byte[2]; 7910Sstevel@tonic-gate b[1] = b1; 7920Sstevel@tonic-gate b[0] = b0; 7930Sstevel@tonic-gate } else { 7940Sstevel@tonic-gate b = new byte[1]; 7950Sstevel@tonic-gate b[0] = b0; 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate // Make a string out of it. 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate try { 8010Sstevel@tonic-gate str = new String(b, Defaults.UTF8); 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate } catch (UnsupportedEncodingException ex) { 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate Assert.slpassert(false, "no_utf8", new Object[0]); 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate int len = str.length(); 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate if (str.length() > 1) { 8120Sstevel@tonic-gate throw 8130Sstevel@tonic-gate new ServiceLocationException( 8140Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 8150Sstevel@tonic-gate "more_than_one", 8160Sstevel@tonic-gate new Object[] {ch}); 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate return (len == 1 ? str.charAt(0):(char)0); 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /** 8240Sstevel@tonic-gate * Merge the values in newAttr into the attribute in the hashtable 8250Sstevel@tonic-gate * if a duplicate attribute, signal error if a type mismatch. 8260Sstevel@tonic-gate * Both the return vector and hashtable are updated, but the 8270Sstevel@tonic-gate * newAttr parameter is left unchanged. 8280Sstevel@tonic-gate * 8290Sstevel@tonic-gate * @param attr The ServiceLocationAttribute to check. 8300Sstevel@tonic-gate * @param attrHash A Hashtable containing the attribute tags as 8310Sstevel@tonic-gate * keys and the attributes as values. 8320Sstevel@tonic-gate * @param returns A Vector in which to put the attribute when done. 8330Sstevel@tonic-gate * @param dontTypeCheck If this flag is true, the value vector 8340Sstevel@tonic-gate * may have two booleans, may 8350Sstevel@tonic-gate * contain differently typed objects, or the 8360Sstevel@tonic-gate * function may merge a keyword and nonkeyword 8370Sstevel@tonic-gate * attribute. 8380Sstevel@tonic-gate * @exception ServiceLocationException Thrown if a type mismatch 8390Sstevel@tonic-gate * occurs. 8400Sstevel@tonic-gate */ 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate static void mergeDuplicateAttributes(ServiceLocationAttribute newAttr, Hashtable attrTable, Vector returns, boolean dontTypeCheck)8430Sstevel@tonic-gate mergeDuplicateAttributes(ServiceLocationAttribute newAttr, 8440Sstevel@tonic-gate Hashtable attrTable, 8450Sstevel@tonic-gate Vector returns, 8460Sstevel@tonic-gate boolean dontTypeCheck) 8470Sstevel@tonic-gate throws ServiceLocationException { 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate // Look up the attribute 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate String tag = newAttr.getId().toLowerCase(); 8520Sstevel@tonic-gate ServiceLocationAttribute attr = 8530Sstevel@tonic-gate (ServiceLocationAttribute)attrTable.get(tag); 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate // Don't try this trick with ServerAttributes! 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate Assert.slpassert((!(attr instanceof ServerAttribute) && 8580Sstevel@tonic-gate !(newAttr instanceof ServerAttribute)), 8590Sstevel@tonic-gate "merge_servattr", 8600Sstevel@tonic-gate new Object[0]); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate // If the attribute isn't in the hashtable, then add to 8630Sstevel@tonic-gate // vector and hashtable. 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate if (attr == null) { 8660Sstevel@tonic-gate attrTable.put(tag, newAttr); 8670Sstevel@tonic-gate returns.addElement(newAttr); 8680Sstevel@tonic-gate return; 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate Vector attrNewVals = newAttr.values; 8740Sstevel@tonic-gate Vector attrVals = attr.values; 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate // If both keywords, nothing further to do. 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate if (attrVals == null && attrNewVals == null) { 8790Sstevel@tonic-gate return; 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate // If we are not typechecking and one is keyword while the other 8840Sstevel@tonic-gate // is not, then simply merge in the nonkeyword. Otherwise, 8850Sstevel@tonic-gate // throw a type check exception. 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate if ((attrVals == null && attrNewVals != null) || 8880Sstevel@tonic-gate (attrNewVals == null && attrVals != null)) { 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate if (dontTypeCheck) { 8910Sstevel@tonic-gate Vector vals = (attrNewVals != null ? attrNewVals:attrVals); 8920Sstevel@tonic-gate attr.values = vals; 8930Sstevel@tonic-gate newAttr.values = vals; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate } else { 8960Sstevel@tonic-gate throw 8970Sstevel@tonic-gate new ServiceLocationException( 8980Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 8990Sstevel@tonic-gate "attribute_type_mismatch", 9000Sstevel@tonic-gate new Object[] {newAttr.getId()}); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate } 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate } else { 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate // Merge the two vectors. We type check against the attrVals 9070Sstevel@tonic-gate // vector, if we are type checking. 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate int i, n = attrNewVals.size(); 9100Sstevel@tonic-gate Object o = attrVals.elementAt(0); 9110Sstevel@tonic-gate Class c = o.getClass(); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate for (i = 0; i < n; i++) { 9140Sstevel@tonic-gate Object no = attrNewVals.elementAt(i); 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate // Check for type mismatch, throw exception if 9170Sstevel@tonic-gate // we are type checking. 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate if ((c != no.getClass()) && !dontTypeCheck) { 9200Sstevel@tonic-gate throw 9210Sstevel@tonic-gate new ServiceLocationException( 9220Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 9230Sstevel@tonic-gate "attribute_type_mismatch", 9240Sstevel@tonic-gate new Object[] {newAttr.getId()}); 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate // If we are typechecking, and we get two opposite 9290Sstevel@tonic-gate // booleans, we need to throw an exception. 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate if (no instanceof Boolean && !no.equals(o) && !dontTypeCheck) { 9320Sstevel@tonic-gate throw 9330Sstevel@tonic-gate new ServiceLocationException( 9340Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 9350Sstevel@tonic-gate "boolean_incompat", 9360Sstevel@tonic-gate new Object[] {newAttr.getId()}); 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate } 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate // Add the value if it isn't already there. 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate if (!attrVals.contains(no)) { 9430Sstevel@tonic-gate attrVals.addElement(no); 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate } 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate // Set the new attribute's values so they are the same as the old. 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate newAttr.values = attrVals; 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate // 9560Sstevel@tonic-gate // Object overrides. 9570Sstevel@tonic-gate // 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate /** 9600Sstevel@tonic-gate * Return true if the object equals this attribute. 9610Sstevel@tonic-gate */ 9620Sstevel@tonic-gate equals(Object o)9630Sstevel@tonic-gate public boolean equals(Object o) { 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate if (!(o instanceof ServiceLocationAttribute)) { 9660Sstevel@tonic-gate return false; 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate if (o == this) { 9710Sstevel@tonic-gate return true; 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate ServiceLocationAttribute sla = (ServiceLocationAttribute)o; 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate // check equality of contents, deferring check of all values 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate Vector vSLA = sla.values; 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate if (!sla.getId().equalsIgnoreCase(id)) { 9820Sstevel@tonic-gate return false; 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate if (values == null && vSLA == null) { 9870Sstevel@tonic-gate return true; 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate if ((values == null && vSLA != null) || 9920Sstevel@tonic-gate (values != null && vSLA == null)) { 9930Sstevel@tonic-gate return false; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate if (values.size() != vSLA.size()) { 9980Sstevel@tonic-gate return false; 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate // Check contents. 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate Object oSLA = vSLA.elementAt(0); 10050Sstevel@tonic-gate o = values.elementAt(0); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate if (o.getClass() != oSLA.getClass()) { 10080Sstevel@tonic-gate return false; 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate } 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate int i, n = vSLA.size(); 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate for (i = 0; i < n; i++) { 10150Sstevel@tonic-gate oSLA = vSLA.elementAt(i); 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate if (!values.contains(oSLA)) { 10180Sstevel@tonic-gate return false; 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate return true; 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate /** 10270Sstevel@tonic-gate * Return a human readable string for the attribute. 10280Sstevel@tonic-gate */ 10290Sstevel@tonic-gate toString()10300Sstevel@tonic-gate public String toString() { 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate StringBuffer s = new StringBuffer("("); 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate s.append(id); 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate if (values != null) { 10370Sstevel@tonic-gate s.append("="); 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate int i, n = values.size(); 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate for (i = 0; i < n; i++) { 10420Sstevel@tonic-gate Object o = values.elementAt(i); 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate // Identify type. 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate if (i == 0) { 10470Sstevel@tonic-gate s.append(o.getClass().getName()); 10480Sstevel@tonic-gate s.append(":"); 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate } else { 10510Sstevel@tonic-gate s.append(","); 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate // Stringify object. 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate s.append(o.toString()); 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate s.append(")"); 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate return s.toString(); 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate // Overrides Object.hashCode(). 10680Sstevel@tonic-gate hashCode()10690Sstevel@tonic-gate public int hashCode() { 10700Sstevel@tonic-gate return id.toLowerCase().hashCode(); 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate } 1075