17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*9a70fc3bSMark J. Nelson * Common Development and Distribution License (the "License"). 6*9a70fc3bSMark J. Nelson * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 227c478bd9Sstevel@tonic-gate * Copyright 2001,2003 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 27*9a70fc3bSMark J. Nelson // ServiceLocationAttribute.java : Class for attributes in SLP. 287c478bd9Sstevel@tonic-gate // Author: James Kempf, Erik Guttman 297c478bd9Sstevel@tonic-gate // 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate package com.sun.slp; 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate import java.util.*; 347c478bd9Sstevel@tonic-gate import java.io.*; 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate /** 377c478bd9Sstevel@tonic-gate * The ServiceLocationAttribute class models SLP attributes. 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * @author James Kempf, Erik Guttman 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate public class ServiceLocationAttribute extends Object 437c478bd9Sstevel@tonic-gate implements Serializable { 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate // Characters to escape. 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate final static String RESERVED = "(),\\!<=>~"; 487c478bd9Sstevel@tonic-gate final static String ESCAPED = RESERVED + "*"; 497c478bd9Sstevel@tonic-gate final static char ESCAPE = '\\'; 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate final static char CTL_LOWER = (char)0x00; 527c478bd9Sstevel@tonic-gate final static char CTL_UPPER = (char)0x1F; 537c478bd9Sstevel@tonic-gate final static char DEL = (char)0x7F; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate // Whitespace chars. 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static final String WHITESPACE = " \n\t\r"; 587c478bd9Sstevel@tonic-gate static final char SPACE = ' '; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate // For character escaping. 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate static final char COMMA = ','; 637c478bd9Sstevel@tonic-gate static final char PERCENT = '%'; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate // Bad tag characters. 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate final private static String BAD_TAG_CHARS = "*\n\t\r"; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate // For identifying booleans. 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate final static String TRUE = "true"; 727c478bd9Sstevel@tonic-gate final static String FALSE = "false"; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate // 757c478bd9Sstevel@tonic-gate // Package accessable fields. 767c478bd9Sstevel@tonic-gate // 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate Vector values = null; 797c478bd9Sstevel@tonic-gate String id = null; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate // For V1 compatibility subclass. 827c478bd9Sstevel@tonic-gate ServiceLocationAttribute()837c478bd9Sstevel@tonic-gate ServiceLocationAttribute() {} 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /** 867c478bd9Sstevel@tonic-gate * Construct a service location attribute. 877c478bd9Sstevel@tonic-gate * 887c478bd9Sstevel@tonic-gate * @param id The attribute name 897c478bd9Sstevel@tonic-gate * @param values_in Vector of one or more attribute values. Vector 907c478bd9Sstevel@tonic-gate * contents must be uniform in type and one of 917c478bd9Sstevel@tonic-gate * Integer, String, Boolean, or byte[]. If the attribute 927c478bd9Sstevel@tonic-gate * is a keyword attribute, then values_in should be null. 937c478bd9Sstevel@tonic-gate * @exception IllegalArgumentException Thrown if the 947c478bd9Sstevel@tonic-gate * vector contents is not of the right type or 957c478bd9Sstevel@tonic-gate * an argument is null or syntactically incorrect. 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate ServiceLocationAttribute(String id_in, Vector values_in)987c478bd9Sstevel@tonic-gate public ServiceLocationAttribute(String id_in, Vector values_in) 997c478bd9Sstevel@tonic-gate throws IllegalArgumentException { 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate Assert.nonNullParameter(id_in, "id"); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate id = id_in; 1047c478bd9Sstevel@tonic-gate if (values_in != null && 1057c478bd9Sstevel@tonic-gate values_in.size() > 0) { // null, empty indicate keyword attribute. 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate values = (Vector)values_in.clone(); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate verifyValueTypes(values, false); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /** 1157c478bd9Sstevel@tonic-gate * Construct a service location attribute from a parenthesized expression. 1167c478bd9Sstevel@tonic-gate * The syntax is: 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * exp = "(" id "=" value-list ")" | keyword 1197c478bd9Sstevel@tonic-gate * value-list = value | value "," value-list 1207c478bd9Sstevel@tonic-gate * 1217c478bd9Sstevel@tonic-gate * 1227c478bd9Sstevel@tonic-gate * @param exp The expression 1237c478bd9Sstevel@tonic-gate * @param dontTypeCheck True if multivalued booleans and vectors 1247c478bd9Sstevel@tonic-gate * of varying types are allowed. 1257c478bd9Sstevel@tonic-gate * @exception ServiceLocationException If there are any syntax errors. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate ServiceLocationAttribute(String exp, boolean allowMultiValuedBooleans)1287c478bd9Sstevel@tonic-gate ServiceLocationAttribute(String exp, boolean allowMultiValuedBooleans) 1297c478bd9Sstevel@tonic-gate throws ServiceLocationException { 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate if (exp == null || exp.length() <= 0) { 1327c478bd9Sstevel@tonic-gate new ServiceLocationException(ServiceLocationException.PARSE_ERROR, 1337c478bd9Sstevel@tonic-gate "null_string_parameter", 1347c478bd9Sstevel@tonic-gate new Object[] {exp}); 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate // If start and end paren, then parse out assignment. 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate if (exp.startsWith("(") && exp.endsWith(")")) { 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate StringTokenizer tk = 1437c478bd9Sstevel@tonic-gate new StringTokenizer(exp.substring(1, exp.length() - 1), 1447c478bd9Sstevel@tonic-gate "=", 1457c478bd9Sstevel@tonic-gate true); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate try { 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate // Get the tag. 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate id = 1527c478bd9Sstevel@tonic-gate unescapeAttributeString(tk.nextToken(), true); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (id.length() <= 0) { 1557c478bd9Sstevel@tonic-gate throw 1567c478bd9Sstevel@tonic-gate new ServiceLocationException( 1577c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 1587c478bd9Sstevel@tonic-gate "null_id", 1597c478bd9Sstevel@tonic-gate new Object[] {exp}); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate tk.nextToken(); // get rid of "=" 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate // Gather the rest. 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate String rest = tk.nextToken(""); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate // Parse the comma separated list. 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate values = SrvLocHeader.parseCommaSeparatedListIn(rest, true); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate // Convert to objects. 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate int i, n = values.size(); 1757c478bd9Sstevel@tonic-gate Class vecClass = null; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 1787c478bd9Sstevel@tonic-gate String value = (String)values.elementAt(i); 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate // Need to determine which type to use. 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate Object o = evaluate(value); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate values.setElementAt(o, i); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate } catch (NoSuchElementException ex) { 1897c478bd9Sstevel@tonic-gate throw 1907c478bd9Sstevel@tonic-gate new ServiceLocationException( 1917c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 1927c478bd9Sstevel@tonic-gate "assignment_syntax_err", 1937c478bd9Sstevel@tonic-gate new Object[] {exp}); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate verifyValueTypes(values, allowMultiValuedBooleans); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate } else { 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate // Check to make sure there's no parens. 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if (exp.indexOf('(') != -1 || exp.indexOf(')') != -1) { 2037c478bd9Sstevel@tonic-gate throw 2047c478bd9Sstevel@tonic-gate new ServiceLocationException( 2057c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2067c478bd9Sstevel@tonic-gate "assignment_syntax_err", 2077c478bd9Sstevel@tonic-gate new Object[] {exp}); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate // Unescape the keyword. 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate id = unescapeAttributeString(exp, true); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate evaluate(String value)2177c478bd9Sstevel@tonic-gate static Object evaluate(String value) 2187c478bd9Sstevel@tonic-gate throws ServiceLocationException { 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate Object o = null; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate // If it can be converted into an integer, then convert it. 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate try { 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate o = Integer.valueOf(value); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate } catch (NumberFormatException ex) { 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate // Wasn't an integer. Try boolean. 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate if (value.equalsIgnoreCase(TRUE) || 2337c478bd9Sstevel@tonic-gate value.equalsIgnoreCase(FALSE)) { 2347c478bd9Sstevel@tonic-gate o = Boolean.valueOf(value); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate } else { 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate // Process the string to remove escapes. 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate String val = (String)value; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate // If it begins with the opaque prefix, treat it as an 2437c478bd9Sstevel@tonic-gate // opaque. 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (val.startsWith(Opaque.OPAQUE_HEADER)) { 2467c478bd9Sstevel@tonic-gate o = Opaque.unescapeByteArray(val); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate } else { 2497c478bd9Sstevel@tonic-gate o = unescapeAttributeString(val, false); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate return o; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate // 2607c478bd9Sstevel@tonic-gate // Property accessors. 2617c478bd9Sstevel@tonic-gate // 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /** 2647c478bd9Sstevel@tonic-gate * @return A vector of attribute values, or null if the attribute is 2657c478bd9Sstevel@tonic-gate * a keyword attribute. If the attribute is single-valued, then 2667c478bd9Sstevel@tonic-gate * the vector contains only one object. 2677c478bd9Sstevel@tonic-gate * 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate getValues()2707c478bd9Sstevel@tonic-gate public Vector getValues() { 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate if (values == null) { 2737c478bd9Sstevel@tonic-gate return null; // keyword case. 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate Vector ret = (Vector)values.clone(); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate // Need to process Opaques. 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate int i, n = ret.size(); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 2837c478bd9Sstevel@tonic-gate Object o = ret.elementAt(i); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate if (o instanceof Opaque) { 2867c478bd9Sstevel@tonic-gate o = ((Opaque)o).bytes; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate ret.setElementAt(o, i); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate return ret; 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /** 2977c478bd9Sstevel@tonic-gate * @return The attribute name. 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate getId()3007c478bd9Sstevel@tonic-gate public String getId() { 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate return id; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /** 3077c478bd9Sstevel@tonic-gate * Return an escaped version of the id parameter , suitable for inclusion 3087c478bd9Sstevel@tonic-gate * in a query. 3097c478bd9Sstevel@tonic-gate * 3107c478bd9Sstevel@tonic-gate * @param str The string to escape as an id. 3117c478bd9Sstevel@tonic-gate * @return The string with any reserved characters escaped. 3127c478bd9Sstevel@tonic-gate * @exception IllegalArgumentException Thrown if the 3137c478bd9Sstevel@tonic-gate * string contains bad tag characters. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate escapeId(String str)3167c478bd9Sstevel@tonic-gate static public String escapeId(String str) 3177c478bd9Sstevel@tonic-gate throws IllegalArgumentException { 3187c478bd9Sstevel@tonic-gate String ret = null; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate try { 3217c478bd9Sstevel@tonic-gate ret = escapeAttributeString(str, true); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate } catch (ServiceLocationException ex) { 3247c478bd9Sstevel@tonic-gate throw new IllegalArgumentException(ex.getMessage()); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate return ret; 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /** 3327c478bd9Sstevel@tonic-gate * Return an escaped version of the value parameter, suitable for inclusion 3337c478bd9Sstevel@tonic-gate * in a query. Opaques are stringified. 3347c478bd9Sstevel@tonic-gate * 3357c478bd9Sstevel@tonic-gate * @param val The value to escape. 3367c478bd9Sstevel@tonic-gate * @return The stringified value. 3377c478bd9Sstevel@tonic-gate * @exception IllegalArgumentException Thrown if the object is not 3387c478bd9Sstevel@tonic-gate * one of byte[], Integer, Boolean, or String. 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate escapeValue(Object val)3417c478bd9Sstevel@tonic-gate static public String escapeValue(Object val) 3427c478bd9Sstevel@tonic-gate throws IllegalArgumentException { 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate // Check type first. 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate typeCheckValue(val); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate // Make Opaque out of byte[]. 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate if (val instanceof byte[]) { 3517c478bd9Sstevel@tonic-gate val = new Opaque((byte[])val); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate return escapeValueInternal(val); 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate // Check type to make sure it's OK. 3607c478bd9Sstevel@tonic-gate typeCheckValue(Object obj)3617c478bd9Sstevel@tonic-gate static private void typeCheckValue(Object obj) { 3627c478bd9Sstevel@tonic-gate SLPConfig conf = SLPConfig.getSLPConfig(); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate Assert.nonNullParameter(obj, "attribute value vector element"); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate if (obj.equals("")) { 3677c478bd9Sstevel@tonic-gate throw 3687c478bd9Sstevel@tonic-gate new IllegalArgumentException( 3697c478bd9Sstevel@tonic-gate conf.formatMessage("empty_string_value", 3707c478bd9Sstevel@tonic-gate new Object[0])); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate if (!(obj instanceof Integer) && !(obj instanceof Boolean) && 3747c478bd9Sstevel@tonic-gate !(obj instanceof String) && !(obj instanceof byte[])) { 3757c478bd9Sstevel@tonic-gate throw 3767c478bd9Sstevel@tonic-gate new IllegalArgumentException( 3777c478bd9Sstevel@tonic-gate conf.formatMessage("value_type_error", 3787c478bd9Sstevel@tonic-gate new Object[0])); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate // We know the value's type is OK, so just escape it. 3847c478bd9Sstevel@tonic-gate escapeValueInternal(Object val)3857c478bd9Sstevel@tonic-gate private static String escapeValueInternal(Object val) { 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate String s; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate // Escape any characters needing it. 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate if (val instanceof String) { 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate try { 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate s = escapeAttributeString((String)val, false); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate } catch (ServiceLocationException ex) { 3987c478bd9Sstevel@tonic-gate throw 3997c478bd9Sstevel@tonic-gate new IllegalArgumentException(ex.getMessage()); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate } else { 4047c478bd9Sstevel@tonic-gate s = val.toString(); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate return s; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate // 4127c478bd9Sstevel@tonic-gate // Methods for dealing with the type of attribute values. 4137c478bd9Sstevel@tonic-gate // 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate // Verify the types of incoming attributes. 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate protected void verifyValueTypes(Vector values_in, boolean dontTypeCheck)4187c478bd9Sstevel@tonic-gate verifyValueTypes(Vector values_in, boolean dontTypeCheck) { 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate SLPConfig conf = SLPConfig.getSLPConfig(); 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate // Make sure the types of objects passed in are acceptable 4237c478bd9Sstevel@tonic-gate // and that all objects in the vector have the same type. 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate int i, n = values_in.size(); 4267c478bd9Sstevel@tonic-gate Class cls = null; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 4297c478bd9Sstevel@tonic-gate Object obj = values_in.elementAt(i); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate typeCheckValue(obj); 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate if (i == 0) { 4347c478bd9Sstevel@tonic-gate cls = obj.getClass(); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate } else if (!cls.equals(obj.getClass()) && !dontTypeCheck) { 4377c478bd9Sstevel@tonic-gate throw 4387c478bd9Sstevel@tonic-gate new IllegalArgumentException( 4397c478bd9Sstevel@tonic-gate conf.formatMessage("type_mismatch_error", 4407c478bd9Sstevel@tonic-gate new Object[0])); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate // If it's a boolean and there's more than one, signal error 4447c478bd9Sstevel@tonic-gate // unless multivalued booleans are allowed. 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate if (!dontTypeCheck && i != 0 && obj instanceof Boolean) { 4477c478bd9Sstevel@tonic-gate throw 4487c478bd9Sstevel@tonic-gate new IllegalArgumentException( 4497c478bd9Sstevel@tonic-gate conf.formatMessage("multivalued_boolean", 4507c478bd9Sstevel@tonic-gate new Object[0])); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate // If it's a byte array, create a Opaque object. 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (obj instanceof byte[]) { 4577c478bd9Sstevel@tonic-gate values_in.setElementAt(new Opaque((byte[])obj), i); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate } else if (obj instanceof String) { 4607c478bd9Sstevel@tonic-gate String val = (String)obj; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate // If it's a string and looks like "1" or "true", then 4637c478bd9Sstevel@tonic-gate // append a space onto the end. 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate try { 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate Object obj2 = evaluate(val); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (!(obj2 instanceof String)) { 4707c478bd9Sstevel@tonic-gate values_in.setElementAt((String)val + " ", i); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate } catch (ServiceLocationException ex) { 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate // Ignore for now. 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate // 4857c478bd9Sstevel@tonic-gate // Methods for externalizing attributes. 4867c478bd9Sstevel@tonic-gate // 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate /** 4897c478bd9Sstevel@tonic-gate * Externalize the attribute into a string that can be written 4907c478bd9Sstevel@tonic-gate * to a byte stream. Includes escaping any characters that 4917c478bd9Sstevel@tonic-gate * need to be escaped. 4927c478bd9Sstevel@tonic-gate * 4937c478bd9Sstevel@tonic-gate * @return String with attribute's external representation. 4947c478bd9Sstevel@tonic-gate * @exception ServiceLocationException Thrown if the 4957c478bd9Sstevel@tonic-gate * string contains unencodable characters. 4967c478bd9Sstevel@tonic-gate */ 4977c478bd9Sstevel@tonic-gate externalize()4987c478bd9Sstevel@tonic-gate String externalize() 4997c478bd9Sstevel@tonic-gate throws ServiceLocationException { 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate if (values == null) { // keyword attribute... 5027c478bd9Sstevel@tonic-gate return escapeAttributeString(id, true); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate Vector v = new Vector(); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate for (Enumeration e = values.elements(); e.hasMoreElements(); ) { 5087c478bd9Sstevel@tonic-gate Object o = e.nextElement(); 5097c478bd9Sstevel@tonic-gate String s = null; 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate s = escapeValueInternal(o); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate v.addElement(s); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate StringBuffer buf = 5177c478bd9Sstevel@tonic-gate new StringBuffer("(" + 5187c478bd9Sstevel@tonic-gate escapeAttributeString(id, true) + 5197c478bd9Sstevel@tonic-gate "="); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate buf.append(SrvLocHeader.vectorToCommaSeparatedList(v)); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate buf.append(")"); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate return buf.toString(); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate // 5297c478bd9Sstevel@tonic-gate // Escaping and unescaping strings. 5307c478bd9Sstevel@tonic-gate // 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /** 5337c478bd9Sstevel@tonic-gate * Escape any escapable characters to a 2 character escape 5347c478bd9Sstevel@tonic-gate * in the attribute string. 5357c478bd9Sstevel@tonic-gate * 5367c478bd9Sstevel@tonic-gate * @param string The String. 5377c478bd9Sstevel@tonic-gate * @param badTag Check for bad tag characters if true. 5387c478bd9Sstevel@tonic-gate * @return The escaped string. 5397c478bd9Sstevel@tonic-gate * @exception ServiceLocationException Thrown if the string 5407c478bd9Sstevel@tonic-gate * contains a character that can't be encoded. 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate escapeAttributeString(String string, boolean badTag)5437c478bd9Sstevel@tonic-gate static String escapeAttributeString(String string, 5447c478bd9Sstevel@tonic-gate boolean badTag) 5457c478bd9Sstevel@tonic-gate throws ServiceLocationException { 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate StringBuffer buf = new StringBuffer(); 5487c478bd9Sstevel@tonic-gate int i, n = string.length(); 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 5517c478bd9Sstevel@tonic-gate char c = string.charAt(i); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate // Check for bad tag characters first. 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate if (badTag && BAD_TAG_CHARS.indexOf(c) != -1) { 5567c478bd9Sstevel@tonic-gate throw 5577c478bd9Sstevel@tonic-gate new ServiceLocationException( 5587c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 5597c478bd9Sstevel@tonic-gate "bad_id_char", 5607c478bd9Sstevel@tonic-gate new Object[] {Integer.toHexString(c)}); 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate // Escape if the character is reserved. 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate if (canEscape(c)) { 5667c478bd9Sstevel@tonic-gate buf.append(ESCAPE); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate String str = escapeChar(c); 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate // Pad with zero if less than 2 characters. 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate if (str.length() <= 1) { 5737c478bd9Sstevel@tonic-gate str = "0" + str; 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate buf.append(str); 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate } else { 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate buf.append(c); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate return buf.toString(); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /** 5927c478bd9Sstevel@tonic-gate * Convert any 2 character escapes to the corresponding characters. 5937c478bd9Sstevel@tonic-gate * 5947c478bd9Sstevel@tonic-gate * @param string The string to be processed. 5957c478bd9Sstevel@tonic-gate * @param badTag Check for bad tag characters if true. 5967c478bd9Sstevel@tonic-gate * @return The processed string. 5977c478bd9Sstevel@tonic-gate * @exception ServiceLocationException Thrown if an escape 5987c478bd9Sstevel@tonic-gate * is improperly formatted. 5997c478bd9Sstevel@tonic-gate */ 6007c478bd9Sstevel@tonic-gate unescapeAttributeString(String string, boolean badTag)6017c478bd9Sstevel@tonic-gate static String unescapeAttributeString(String string, 6027c478bd9Sstevel@tonic-gate boolean badTag) 6037c478bd9Sstevel@tonic-gate throws ServiceLocationException { 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate // Process escapes. 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate int i, n = string.length(); 6087c478bd9Sstevel@tonic-gate StringBuffer buf = new StringBuffer(n); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 6117c478bd9Sstevel@tonic-gate char c = string.charAt(i); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate // Check for escaped characters. 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (c == ESCAPE) { 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate // Get the next two characters. 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate if (i >= n - 2) { 6207c478bd9Sstevel@tonic-gate throw 6217c478bd9Sstevel@tonic-gate new ServiceLocationException( 6227c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6237c478bd9Sstevel@tonic-gate "nonterminating_escape", 6247c478bd9Sstevel@tonic-gate new Object[] {string}); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate i++; 6287c478bd9Sstevel@tonic-gate c = unescapeChar(string.substring(i, i+2)); 6297c478bd9Sstevel@tonic-gate i++; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate // Check whether it's reserved. 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate if (!canEscape(c)) { 6347c478bd9Sstevel@tonic-gate throw 6357c478bd9Sstevel@tonic-gate new ServiceLocationException( 6367c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6377c478bd9Sstevel@tonic-gate "char_not_reserved_attr", 6387c478bd9Sstevel@tonic-gate new Object[] {new Character(c), string}); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate } else { 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate // Check whether the character is reserved. 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if (isReserved(c)) { 6467c478bd9Sstevel@tonic-gate throw 6477c478bd9Sstevel@tonic-gate new ServiceLocationException( 6487c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6497c478bd9Sstevel@tonic-gate "reserved_not_escaped", 6507c478bd9Sstevel@tonic-gate new Object[] {new Character(c)}); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate // If we need to check for a bad tag character, do so now. 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate if (badTag && BAD_TAG_CHARS.indexOf(c) != -1) { 6587c478bd9Sstevel@tonic-gate throw 6597c478bd9Sstevel@tonic-gate new ServiceLocationException( 6607c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6617c478bd9Sstevel@tonic-gate "bad_id_char", 6627c478bd9Sstevel@tonic-gate new Object[] {Integer.toHexString(c)}); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate buf.append(c); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate return buf.toString(); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate // Return true if the character c can be escaped. 6747c478bd9Sstevel@tonic-gate canEscape(char c)6757c478bd9Sstevel@tonic-gate private static boolean canEscape(char c) { 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate return ((ESCAPED.indexOf(c) != -1) || 6787c478bd9Sstevel@tonic-gate ((c >= CTL_LOWER && c <= CTL_UPPER) || c == DEL)); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate // Return true if the character c is reserved. 6837c478bd9Sstevel@tonic-gate isReserved(char c)6847c478bd9Sstevel@tonic-gate private static boolean isReserved(char c) { 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate return ((RESERVED.indexOf(c) != -1) || 6877c478bd9Sstevel@tonic-gate ((c >= CTL_LOWER && c <= CTL_UPPER) || c == DEL)); 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /** 6927c478bd9Sstevel@tonic-gate * Return a string of integers giving the character's encoding in 6937c478bd9Sstevel@tonic-gate * the character set passed in as encoding. 6947c478bd9Sstevel@tonic-gate * 6957c478bd9Sstevel@tonic-gate * @param c The character to escape. 6967c478bd9Sstevel@tonic-gate * @return The character as a string of integers for the encoding. 6977c478bd9Sstevel@tonic-gate */ 6987c478bd9Sstevel@tonic-gate escapeChar(char c)6997c478bd9Sstevel@tonic-gate static String escapeChar(char c) { 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate byte[] b = null; 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate try { 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate b = ("" + c).getBytes(Defaults.UTF8); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate } catch (UnsupportedEncodingException ex) { 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate Assert.slpassert(false, "no_utf8", new Object[0]); 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate int code = 0; 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate // Assemble the character code. 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate if (b.length > 3) { 7187c478bd9Sstevel@tonic-gate Assert.slpassert(false, 7197c478bd9Sstevel@tonic-gate "illegal_utf8", 7207c478bd9Sstevel@tonic-gate new Object[] {new Character(c)}); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate code = (int)(b[0] & 0xFF); 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate if (b.length > 1) { 7277c478bd9Sstevel@tonic-gate code = (int)(code | ((b[1] & 0xFF) << 8)); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate if (b.length > 2) { 7317c478bd9Sstevel@tonic-gate code = (int)(code | ((b[2] & 0xFF) << 16)); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate String str = Integer.toHexString(code); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate return str; 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /** 7407c478bd9Sstevel@tonic-gate * Unescape the character encoded as the string. 7417c478bd9Sstevel@tonic-gate * 7427c478bd9Sstevel@tonic-gate * @param ch The character as a string of hex digits. 7437c478bd9Sstevel@tonic-gate * @return The character. 7447c478bd9Sstevel@tonic-gate * @exception ServiceLocationException If the characters can't be 7457c478bd9Sstevel@tonic-gate * converted into a hex string. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate unescapeChar(String ch)7487c478bd9Sstevel@tonic-gate static char unescapeChar(String ch) 7497c478bd9Sstevel@tonic-gate throws ServiceLocationException { 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate int code = 0; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate try { 7547c478bd9Sstevel@tonic-gate code = Integer.parseInt(ch, 16); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate } catch (NumberFormatException ex) { 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate throw 7597c478bd9Sstevel@tonic-gate new ServiceLocationException( 7607c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 7617c478bd9Sstevel@tonic-gate "not_a_character", 7627c478bd9Sstevel@tonic-gate new Object[] {ch}); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate // Convert to bytes. 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate String str = null; 7687c478bd9Sstevel@tonic-gate byte b0 = 0, b1 = 0, b2 = 0, b3 = 0; 7697c478bd9Sstevel@tonic-gate byte b[] = null; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate b0 = (byte) (code & 0xFF); 7727c478bd9Sstevel@tonic-gate b1 = (byte) ((code >> 8) & 0xFF); 7737c478bd9Sstevel@tonic-gate b2 = (byte) ((code >> 16) & 0xFF); 7747c478bd9Sstevel@tonic-gate b3 = (byte) ((code >> 24) & 0xFF); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate // We allow illegal UTF8 encoding so we can decode byte arrays. 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate if (b3 != 0) { 7797c478bd9Sstevel@tonic-gate b = new byte[3]; 7807c478bd9Sstevel@tonic-gate b[3] = b3; 7817c478bd9Sstevel@tonic-gate b[2] = b2; 7827c478bd9Sstevel@tonic-gate b[1] = b1; 7837c478bd9Sstevel@tonic-gate b[0] = b0; 7847c478bd9Sstevel@tonic-gate } else if (b2 != 0) { 7857c478bd9Sstevel@tonic-gate b = new byte[3]; 7867c478bd9Sstevel@tonic-gate b[2] = b2; 7877c478bd9Sstevel@tonic-gate b[1] = b1; 7887c478bd9Sstevel@tonic-gate b[0] = b0; 7897c478bd9Sstevel@tonic-gate } else if (b1 != 0) { 7907c478bd9Sstevel@tonic-gate b = new byte[2]; 7917c478bd9Sstevel@tonic-gate b[1] = b1; 7927c478bd9Sstevel@tonic-gate b[0] = b0; 7937c478bd9Sstevel@tonic-gate } else { 7947c478bd9Sstevel@tonic-gate b = new byte[1]; 7957c478bd9Sstevel@tonic-gate b[0] = b0; 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate // Make a string out of it. 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate try { 8017c478bd9Sstevel@tonic-gate str = new String(b, Defaults.UTF8); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate } catch (UnsupportedEncodingException ex) { 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate Assert.slpassert(false, "no_utf8", new Object[0]); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate int len = str.length(); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate if (str.length() > 1) { 8127c478bd9Sstevel@tonic-gate throw 8137c478bd9Sstevel@tonic-gate new ServiceLocationException( 8147c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 8157c478bd9Sstevel@tonic-gate "more_than_one", 8167c478bd9Sstevel@tonic-gate new Object[] {ch}); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate return (len == 1 ? str.charAt(0):(char)0); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /** 8247c478bd9Sstevel@tonic-gate * Merge the values in newAttr into the attribute in the hashtable 8257c478bd9Sstevel@tonic-gate * if a duplicate attribute, signal error if a type mismatch. 8267c478bd9Sstevel@tonic-gate * Both the return vector and hashtable are updated, but the 8277c478bd9Sstevel@tonic-gate * newAttr parameter is left unchanged. 8287c478bd9Sstevel@tonic-gate * 8297c478bd9Sstevel@tonic-gate * @param attr The ServiceLocationAttribute to check. 8307c478bd9Sstevel@tonic-gate * @param attrHash A Hashtable containing the attribute tags as 8317c478bd9Sstevel@tonic-gate * keys and the attributes as values. 8327c478bd9Sstevel@tonic-gate * @param returns A Vector in which to put the attribute when done. 8337c478bd9Sstevel@tonic-gate * @param dontTypeCheck If this flag is true, the value vector 8347c478bd9Sstevel@tonic-gate * may have two booleans, may 8357c478bd9Sstevel@tonic-gate * contain differently typed objects, or the 8367c478bd9Sstevel@tonic-gate * function may merge a keyword and nonkeyword 8377c478bd9Sstevel@tonic-gate * attribute. 8387c478bd9Sstevel@tonic-gate * @exception ServiceLocationException Thrown if a type mismatch 8397c478bd9Sstevel@tonic-gate * occurs. 8407c478bd9Sstevel@tonic-gate */ 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate static void mergeDuplicateAttributes(ServiceLocationAttribute newAttr, Hashtable attrTable, Vector returns, boolean dontTypeCheck)8437c478bd9Sstevel@tonic-gate mergeDuplicateAttributes(ServiceLocationAttribute newAttr, 8447c478bd9Sstevel@tonic-gate Hashtable attrTable, 8457c478bd9Sstevel@tonic-gate Vector returns, 8467c478bd9Sstevel@tonic-gate boolean dontTypeCheck) 8477c478bd9Sstevel@tonic-gate throws ServiceLocationException { 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate // Look up the attribute 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate String tag = newAttr.getId().toLowerCase(); 8527c478bd9Sstevel@tonic-gate ServiceLocationAttribute attr = 8537c478bd9Sstevel@tonic-gate (ServiceLocationAttribute)attrTable.get(tag); 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate // Don't try this trick with ServerAttributes! 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate Assert.slpassert((!(attr instanceof ServerAttribute) && 8587c478bd9Sstevel@tonic-gate !(newAttr instanceof ServerAttribute)), 8597c478bd9Sstevel@tonic-gate "merge_servattr", 8607c478bd9Sstevel@tonic-gate new Object[0]); 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate // If the attribute isn't in the hashtable, then add to 8637c478bd9Sstevel@tonic-gate // vector and hashtable. 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate if (attr == null) { 8667c478bd9Sstevel@tonic-gate attrTable.put(tag, newAttr); 8677c478bd9Sstevel@tonic-gate returns.addElement(newAttr); 8687c478bd9Sstevel@tonic-gate return; 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate Vector attrNewVals = newAttr.values; 8747c478bd9Sstevel@tonic-gate Vector attrVals = attr.values; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate // If both keywords, nothing further to do. 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate if (attrVals == null && attrNewVals == null) { 8797c478bd9Sstevel@tonic-gate return; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate // If we are not typechecking and one is keyword while the other 8847c478bd9Sstevel@tonic-gate // is not, then simply merge in the nonkeyword. Otherwise, 8857c478bd9Sstevel@tonic-gate // throw a type check exception. 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate if ((attrVals == null && attrNewVals != null) || 8887c478bd9Sstevel@tonic-gate (attrNewVals == null && attrVals != null)) { 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate if (dontTypeCheck) { 8917c478bd9Sstevel@tonic-gate Vector vals = (attrNewVals != null ? attrNewVals:attrVals); 8927c478bd9Sstevel@tonic-gate attr.values = vals; 8937c478bd9Sstevel@tonic-gate newAttr.values = vals; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate } else { 8967c478bd9Sstevel@tonic-gate throw 8977c478bd9Sstevel@tonic-gate new ServiceLocationException( 8987c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 8997c478bd9Sstevel@tonic-gate "attribute_type_mismatch", 9007c478bd9Sstevel@tonic-gate new Object[] {newAttr.getId()}); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate } else { 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate // Merge the two vectors. We type check against the attrVals 9077c478bd9Sstevel@tonic-gate // vector, if we are type checking. 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate int i, n = attrNewVals.size(); 9107c478bd9Sstevel@tonic-gate Object o = attrVals.elementAt(0); 9117c478bd9Sstevel@tonic-gate Class c = o.getClass(); 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 9147c478bd9Sstevel@tonic-gate Object no = attrNewVals.elementAt(i); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate // Check for type mismatch, throw exception if 9177c478bd9Sstevel@tonic-gate // we are type checking. 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate if ((c != no.getClass()) && !dontTypeCheck) { 9207c478bd9Sstevel@tonic-gate throw 9217c478bd9Sstevel@tonic-gate new ServiceLocationException( 9227c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 9237c478bd9Sstevel@tonic-gate "attribute_type_mismatch", 9247c478bd9Sstevel@tonic-gate new Object[] {newAttr.getId()}); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate // If we are typechecking, and we get two opposite 9297c478bd9Sstevel@tonic-gate // booleans, we need to throw an exception. 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate if (no instanceof Boolean && !no.equals(o) && !dontTypeCheck) { 9327c478bd9Sstevel@tonic-gate throw 9337c478bd9Sstevel@tonic-gate new ServiceLocationException( 9347c478bd9Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 9357c478bd9Sstevel@tonic-gate "boolean_incompat", 9367c478bd9Sstevel@tonic-gate new Object[] {newAttr.getId()}); 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate // Add the value if it isn't already there. 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate if (!attrVals.contains(no)) { 9437c478bd9Sstevel@tonic-gate attrVals.addElement(no); 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate // Set the new attribute's values so they are the same as the old. 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate newAttr.values = attrVals; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate // 9567c478bd9Sstevel@tonic-gate // Object overrides. 9577c478bd9Sstevel@tonic-gate // 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /** 9607c478bd9Sstevel@tonic-gate * Return true if the object equals this attribute. 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate equals(Object o)9637c478bd9Sstevel@tonic-gate public boolean equals(Object o) { 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate if (!(o instanceof ServiceLocationAttribute)) { 9667c478bd9Sstevel@tonic-gate return false; 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate if (o == this) { 9717c478bd9Sstevel@tonic-gate return true; 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate ServiceLocationAttribute sla = (ServiceLocationAttribute)o; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate // check equality of contents, deferring check of all values 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate Vector vSLA = sla.values; 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate if (!sla.getId().equalsIgnoreCase(id)) { 9827c478bd9Sstevel@tonic-gate return false; 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate if (values == null && vSLA == null) { 9877c478bd9Sstevel@tonic-gate return true; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate if ((values == null && vSLA != null) || 9927c478bd9Sstevel@tonic-gate (values != null && vSLA == null)) { 9937c478bd9Sstevel@tonic-gate return false; 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate if (values.size() != vSLA.size()) { 9987c478bd9Sstevel@tonic-gate return false; 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate // Check contents. 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate Object oSLA = vSLA.elementAt(0); 10057c478bd9Sstevel@tonic-gate o = values.elementAt(0); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate if (o.getClass() != oSLA.getClass()) { 10087c478bd9Sstevel@tonic-gate return false; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate int i, n = vSLA.size(); 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 10157c478bd9Sstevel@tonic-gate oSLA = vSLA.elementAt(i); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate if (!values.contains(oSLA)) { 10187c478bd9Sstevel@tonic-gate return false; 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate return true; 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate /** 10277c478bd9Sstevel@tonic-gate * Return a human readable string for the attribute. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate toString()10307c478bd9Sstevel@tonic-gate public String toString() { 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate StringBuffer s = new StringBuffer("("); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate s.append(id); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate if (values != null) { 10377c478bd9Sstevel@tonic-gate s.append("="); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate int i, n = values.size(); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 10427c478bd9Sstevel@tonic-gate Object o = values.elementAt(i); 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate // Identify type. 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate if (i == 0) { 10477c478bd9Sstevel@tonic-gate s.append(o.getClass().getName()); 10487c478bd9Sstevel@tonic-gate s.append(":"); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate } else { 10517c478bd9Sstevel@tonic-gate s.append(","); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate // Stringify object. 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate s.append(o.toString()); 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate s.append(")"); 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate return s.toString(); 10657c478bd9Sstevel@tonic-gate } 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate // Overrides Object.hashCode(). 10687c478bd9Sstevel@tonic-gate hashCode()10697c478bd9Sstevel@tonic-gate public int hashCode() { 10707c478bd9Sstevel@tonic-gate return id.toLowerCase().hashCode(); 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate } 1075