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
59a70fc3bSMark J. Nelson  * Common Development and Distribution License (the "License").
69a70fc3bSMark 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 (c) 1999 by Sun Microsystems, Inc.
237c478bd9Sstevel@tonic-gate  * All rights reserved.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate //  SLPV1SSrvMsg.java: SLPv1 server side service rqst/reply.
287c478bd9Sstevel@tonic-gate //  Author:           James Kempf
297c478bd9Sstevel@tonic-gate //  Created On:       Thu Sep 10 15:33:58 1998
307c478bd9Sstevel@tonic-gate //  Last Modified By: James Kempf
317c478bd9Sstevel@tonic-gate //  Last Modified On: Fri Nov  6 14:03:00 1998
327c478bd9Sstevel@tonic-gate //  Update Count:     41
337c478bd9Sstevel@tonic-gate //
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate package com.sun.slp;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate import java.util.*;
397c478bd9Sstevel@tonic-gate import java.io.*;
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /**
437c478bd9Sstevel@tonic-gate  * The SLPV1SSrvMsg class models the SLP server side service request message.
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  * @author James Kempf
467c478bd9Sstevel@tonic-gate  */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate class SLPV1SSrvMsg extends SSrvMsg {
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate     // For eating whitespace.
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate     final static char SPACE = ' ';
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate     // Comma for list parsing.
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate     final static char COMMA = ',';
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate     // Logical operators.
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate     final static char OR_OP = '|';
617c478bd9Sstevel@tonic-gate     final static char AND_OP = '&';
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate     // Logical operator corner case needs this.
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate     final static char HASH = '#';
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate     // Comparison/Assignment operators.
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate     final static char EQUAL_OP = '=';
707c478bd9Sstevel@tonic-gate     final static char NOT_OP = '!';
717c478bd9Sstevel@tonic-gate     final static char LESS_OP = '<';
727c478bd9Sstevel@tonic-gate     final static char GREATER_OP = '>';
737c478bd9Sstevel@tonic-gate     final static char GEQUAL_OP = 'g';
747c478bd9Sstevel@tonic-gate     final static char LEQUAL_OP = 'l';
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate     // Parens.
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate     final static char OPEN_PAREN = '(';
797c478bd9Sstevel@tonic-gate     final static char CLOSE_PAREN = ')';
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate     // LDAP present operator
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate     final static char PRESENT = '*';
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate     // Wildcard operator.
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate     final static String WILDCARD = "*";
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate     // Character code for parsing.
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate     String charCode = IANACharCode.UTF8;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate     // For creating a null reply.
947c478bd9Sstevel@tonic-gate 
SLPV1SSrvMsg()957c478bd9Sstevel@tonic-gate     protected SLPV1SSrvMsg() {}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate     // Construct a SLPV1SSrvMsg from the input stream.
987c478bd9Sstevel@tonic-gate 
SLPV1SSrvMsg(SrvLocHeader hdr, DataInputStream dis)997c478bd9Sstevel@tonic-gate     SLPV1SSrvMsg(SrvLocHeader hdr, DataInputStream dis)
1007c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
1017c478bd9Sstevel@tonic-gate 	super(hdr, dis);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate     }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate     // Construct an empty SLPV1SSrvMsg, for monolingual off.
1067c478bd9Sstevel@tonic-gate 
makeEmptyReply(SLPHeaderV1 hdr)1077c478bd9Sstevel@tonic-gate     static SrvLocMsg makeEmptyReply(SLPHeaderV1 hdr)
1087c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	SLPV1SSrvMsg msg = new SLPV1SSrvMsg();
1117c478bd9Sstevel@tonic-gate 	msg.hdr = hdr;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	msg.makeReply(new Hashtable(), null);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	return msg;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate     }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate     // Initialize the message from the input stream.
1207c478bd9Sstevel@tonic-gate 
initialize(DataInputStream dis)1217c478bd9Sstevel@tonic-gate     void initialize(DataInputStream dis)
1227c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	SLPHeaderV1 hdr = (SLPHeaderV1)getHeader();
1257c478bd9Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	// First get the previous responder.
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	hdr.parsePreviousRespondersIn(dis);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	// Now get the raw query.
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	hdr.getString(buf, dis);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	String rq = buf.toString();
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	// Parse the raw query to pull out the service type, scope,
1387c478bd9Sstevel@tonic-gate 	//  and query.
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	StringTokenizer st = new StringTokenizer(rq, "/", true);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	try {
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	    String type =
1457c478bd9Sstevel@tonic-gate 		Defaults.SERVICE_PREFIX + ":" +
1467c478bd9Sstevel@tonic-gate 		st.nextToken().trim().toLowerCase() + ":";
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	    serviceType =
1497c478bd9Sstevel@tonic-gate 		hdr.checkServiceType(type);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	    st.nextToken();  // get rid of slash.
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	    // Get the scope.
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	    String scope = st.nextToken().trim().toLowerCase();
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	    // Special case if scope is empty (meaning the next
1587c478bd9Sstevel@tonic-gate 	    //  token will be a slash).
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	    if (scope.equals("/")) {
1617c478bd9Sstevel@tonic-gate 		scope = "";
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	    } else {
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 		st.nextToken();  // get rid of slash.
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		if (scope.length() > 0) {
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 		    // Validate the scope name.
170*55fea89dSDan Cross 
1717c478bd9Sstevel@tonic-gate 		    hdr.validateScope(scope);
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 	    }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	    // Set up scopes vector.
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	    hdr.scopes = new Vector();
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	    // Substitute default scope here.
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	    if (scope.length() <= 0) {
1827c478bd9Sstevel@tonic-gate 		scope = Defaults.DEFAULT_SCOPE;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	    }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	    hdr.scopes.addElement(scope.toLowerCase().trim());
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	    // Parsing the query is complicated by opaques having slashes.
189*55fea89dSDan Cross 
1907c478bd9Sstevel@tonic-gate 	    String q = "";
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	    while (st.hasMoreTokens()) {
1937c478bd9Sstevel@tonic-gate 		q = q + st.nextToken();
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	    }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	    // Drop off the final backslash, error if none.
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	    if (!q.endsWith("/")) {
2007c478bd9Sstevel@tonic-gate 		throw
2017c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
2027c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
2037c478bd9Sstevel@tonic-gate 				"v1_query_error",
2047c478bd9Sstevel@tonic-gate 				new Object[] {rq});
2057c478bd9Sstevel@tonic-gate 	    }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	    query = q.substring(0, q.length()-1);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	    // Save header char code for parsing.
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	    charCode = hdr.charCode;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	    // Convert the query into a V2 query.
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	    convertQuery();
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	    // If the query is for "service:directory-agent", then we
2187c478bd9Sstevel@tonic-gate 	    //  mark it as having been multicast, because that is the
2197c478bd9Sstevel@tonic-gate 	    //  only kind of multicast that we accept for SLPv1. Anybody
2207c478bd9Sstevel@tonic-gate 	    //  who unicasts this to us will time out.
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	    if (serviceType.equals(Defaults.DA_SERVICE_TYPE.toString())) {
2237c478bd9Sstevel@tonic-gate 		hdr.mcast = true;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	    }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	    // Construct description.
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	    hdr.constructDescription("SrvRqst",
2307c478bd9Sstevel@tonic-gate 				     "        service type=``" +
2317c478bd9Sstevel@tonic-gate 				     serviceType + "''\n" +
2327c478bd9Sstevel@tonic-gate 				     "        query=``" +
2337c478bd9Sstevel@tonic-gate 				     query + "''");
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	}  catch (NoSuchElementException ex) {
2367c478bd9Sstevel@tonic-gate 	    throw
2377c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
2387c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
2397c478bd9Sstevel@tonic-gate 				"v1_query_error",
2407c478bd9Sstevel@tonic-gate 				new Object[] {rq});
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate     }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate     // Make a reply message.
2457c478bd9Sstevel@tonic-gate 
makeReply(Hashtable urltable, Hashtable URLSignatures)2467c478bd9Sstevel@tonic-gate     SrvLocMsg makeReply(Hashtable urltable,
2477c478bd9Sstevel@tonic-gate 			Hashtable URLSignatures)
2487c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	SLPHeaderV1 hdr =
2517c478bd9Sstevel@tonic-gate 	    ((SLPHeaderV1)getHeader()).makeReplyHeader();
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	ByteArrayOutputStream baos = new ByteArrayOutputStream();
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	// Edit out abstract types and nonService: URLs.
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	Enumeration en = urltable.keys();
2587c478bd9Sstevel@tonic-gate 	Vector urls = new Vector();
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	while (en.hasMoreElements()) {
2617c478bd9Sstevel@tonic-gate 	    ServiceURL surl = (ServiceURL)en.nextElement();
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	    // Reject if abstract type or nonservice: URL.
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	    ServiceType type = surl.getServiceType();
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	    if (!type.isAbstractType() && type.isServiceURL()) {
2687c478bd9Sstevel@tonic-gate 		urls.addElement(surl);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	    }
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	hdr.iNumReplies = urls.size();
2747c478bd9Sstevel@tonic-gate 	// keep this info so SAs can drop 0 replies
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	int n = urls.size();
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	// Write out the size of the list.
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	hdr.putInt(n, baos);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	en = urls.elements();
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	// Write out the size of the list.
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	while (en.hasMoreElements()) {
2877c478bd9Sstevel@tonic-gate 	    ServiceURL surl = (ServiceURL)en.nextElement();
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	    hdr.parseServiceURLOut(surl, true, baos);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	// We ignore the signatures because we only do V1 compatibility
2947c478bd9Sstevel@tonic-gate 	//  for nonprotected scopes.
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	hdr.payload = baos.toByteArray();
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	hdr.constructDescription("SrvRply",
2997c478bd9Sstevel@tonic-gate 				 "        service URLs=``" + urls + "''\n");
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	return hdr;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate     }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate     // Convert the query to a V2 query.
3067c478bd9Sstevel@tonic-gate 
convertQuery()3077c478bd9Sstevel@tonic-gate     void convertQuery()
3087c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	// Check for empty query.
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	query = query.trim();
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	if (query.length() <= 0) {
3157c478bd9Sstevel@tonic-gate 	    return;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	// Check for query join.
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (!(query.startsWith("(") && query.endsWith(")"))) {
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	    // Rewrite to a standard query.
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	    query = rewriteQueryJoin(query);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	// Now rewrite the query into v2 format.
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	query = rewriteQuery(query);
3327c478bd9Sstevel@tonic-gate     }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate     // Rewrite a query join as a conjunction.
3367c478bd9Sstevel@tonic-gate 
rewriteQueryJoin(String query)3377c478bd9Sstevel@tonic-gate     private String rewriteQueryJoin(String query)
3387c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	// Turn infix expression into prefix.
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	StringBuffer sbuf = new StringBuffer();
3437c478bd9Sstevel@tonic-gate 	StringTokenizer tk = new StringTokenizer(query, ",", true);
3447c478bd9Sstevel@tonic-gate 	boolean lastTokComma = true;
3457c478bd9Sstevel@tonic-gate 	int numEx = 0;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	while (tk.hasMoreElements()) {
3487c478bd9Sstevel@tonic-gate 	    String exp = tk.nextToken().trim();
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	    if (exp.equals(",")) {
3517c478bd9Sstevel@tonic-gate 		if (lastTokComma) {
3527c478bd9Sstevel@tonic-gate 		    throw
3537c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
3547c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3557c478bd9Sstevel@tonic-gate 				"v1_query_error",
3567c478bd9Sstevel@tonic-gate 				new Object[] {query});
3577c478bd9Sstevel@tonic-gate 
358*55fea89dSDan Cross 		} else {
3597c478bd9Sstevel@tonic-gate 		    lastTokComma = true;
3607c478bd9Sstevel@tonic-gate 		}
361*55fea89dSDan Cross 
3627c478bd9Sstevel@tonic-gate 	    } else {
3637c478bd9Sstevel@tonic-gate 		lastTokComma = false;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		if (exp.length() <= 0) {
3667c478bd9Sstevel@tonic-gate 		    throw
3677c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
3687c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3697c478bd9Sstevel@tonic-gate 				"v1_query_error",
3707c478bd9Sstevel@tonic-gate 				new Object[] {query});
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		// Put in parens
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		sbuf.append("(");
3777c478bd9Sstevel@tonic-gate 		sbuf.append(exp);
3787c478bd9Sstevel@tonic-gate 		sbuf.append(")");
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		numEx++;
3817c478bd9Sstevel@tonic-gate 	    }
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	if (lastTokComma || numEx == 0) {
3857c478bd9Sstevel@tonic-gate 	    throw
3867c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
3877c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3887c478bd9Sstevel@tonic-gate 				"v1_query_error",
3897c478bd9Sstevel@tonic-gate 				new Object[] {query});
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if (numEx > 1) {
3947c478bd9Sstevel@tonic-gate 	    sbuf.insert(0, "(&");
3957c478bd9Sstevel@tonic-gate 	    sbuf.append(")");
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	return sbuf.toString();
4007c478bd9Sstevel@tonic-gate     }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate     // Rewrite a v1 query into v2 format. This includes character escaping.
4037c478bd9Sstevel@tonic-gate 
rewriteQuery(String whereList)4047c478bd9Sstevel@tonic-gate     private String rewriteQuery(String whereList)
4057c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	// Parse a logical expression.
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	StreamTokenizer tk =
4107c478bd9Sstevel@tonic-gate 	    new StreamTokenizer(new StringReader(whereList));
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	tk.resetSyntax();  		// make all chars ordinary...
4137c478bd9Sstevel@tonic-gate 	tk.whitespaceChars('\000','\037');
4147c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(SPACE);		// but beware of embedded whites...
4157c478bd9Sstevel@tonic-gate 	tk.wordChars('!', '%');
4167c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(AND_OP);
4177c478bd9Sstevel@tonic-gate 	tk.wordChars('\'', '\'');
4187c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(OPEN_PAREN);
4197c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(CLOSE_PAREN);
4207c478bd9Sstevel@tonic-gate 	tk.wordChars('*', '{');
4217c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(OR_OP);
4227c478bd9Sstevel@tonic-gate 	tk.wordChars('}', '~');
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	// Initialize parse tables in terminal.
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(EQUAL_OP);
4277c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(NOT_OP);
4287c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(LESS_OP);
4297c478bd9Sstevel@tonic-gate 	tk.ordinaryChar(GREATER_OP);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	// Parse through the expression.
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	try {
4377c478bd9Sstevel@tonic-gate 	    parseInternal(tk, buf, true);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
4407c478bd9Sstevel@tonic-gate 	    throw
4417c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
4427c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
4437c478bd9Sstevel@tonic-gate 				"v1_query_error",
4447c478bd9Sstevel@tonic-gate 				new Object[] {query});
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	return buf.toString();
4497c478bd9Sstevel@tonic-gate     }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate     // Do the actual parsing, using the passed-in stream tokenizer.
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate     private void
parseInternal(StreamTokenizer tk, StringBuffer buf, boolean start)4547c478bd9Sstevel@tonic-gate 	parseInternal(StreamTokenizer tk, StringBuffer buf, boolean start)
4557c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	int tok = 0;
4587c478bd9Sstevel@tonic-gate 	boolean ret = true;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	do {
4617c478bd9Sstevel@tonic-gate 	    tok = eatWhite(tk);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	    // We should be at the beginning a parenthesized
4647c478bd9Sstevel@tonic-gate 	    //  where list.
465*55fea89dSDan Cross 
4667c478bd9Sstevel@tonic-gate 	    if (tok == OPEN_PAREN) {
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 		// Get the next token. Eat whitespace in the process.
469*55fea89dSDan Cross 
4707c478bd9Sstevel@tonic-gate 		tok = eatWhite(tk);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		// If it's a logOp, then process as a logical expression.
4737c478bd9Sstevel@tonic-gate 		//  This handles the following nasty case:
4747c478bd9Sstevel@tonic-gate 		//
4757c478bd9Sstevel@tonic-gate 		//  	(&#44;&#45==the rest of it)
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		int logOp = tok;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 		if (logOp == AND_OP) {
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		    // Need to check for escape as first thing.
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		    tok = tk.nextToken();
4847c478bd9Sstevel@tonic-gate 		    String str = tk.sval; // not used if token not a string...
4857c478bd9Sstevel@tonic-gate 		    tk.pushBack();
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		    if (tok == StreamTokenizer.TT_WORD) {
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 			if (str.charAt(0) != HASH) {
4907c478bd9Sstevel@tonic-gate 			    parseLogicalExpression(logOp, tk, buf);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 			} else {
4937c478bd9Sstevel@tonic-gate 			    parse(tk, buf, true);
4947c478bd9Sstevel@tonic-gate 					// cause we can't push back twice
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 			}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		    } else {
4997c478bd9Sstevel@tonic-gate 			parseLogicalExpression(logOp, tk, buf);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		    }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		    break;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 		} else if (logOp == OR_OP) {
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 		    parseLogicalExpression(logOp, tk, buf);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		    break;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		} else {
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 		    // It's a terminal expression. Push back the last token
5147c478bd9Sstevel@tonic-gate 		    //  and parse the terminal.
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 		    tk.pushBack();
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		    parse(tk, buf, false);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		    break;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	    } else {
5257c478bd9Sstevel@tonic-gate 		throw
5267c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
5277c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5287c478bd9Sstevel@tonic-gate 				"v1_query_error",
5297c478bd9Sstevel@tonic-gate 				new Object[] {query});
5307c478bd9Sstevel@tonic-gate 	    }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	} while (true);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	// Since terminals are allowed alone at the top level,
5357c478bd9Sstevel@tonic-gate 	//  we need to check here whether anything else is
5367c478bd9Sstevel@tonic-gate 	//  in the query.
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	if (start) {
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	    tok = eatWhite(tk);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	    if (tok != StreamTokenizer.TT_EOF) {
543*55fea89dSDan Cross 
5447c478bd9Sstevel@tonic-gate 		// The line should have ended by now.
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 		throw
5477c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
5487c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5497c478bd9Sstevel@tonic-gate 				"v1_query_error",
5507c478bd9Sstevel@tonic-gate 				new Object[] {query});
5517c478bd9Sstevel@tonic-gate 	    }
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate     }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate     // Rewrite a logical expression.
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate     private void
parseLogicalExpression(int logOp, StreamTokenizer tk, StringBuffer buf)5597c478bd9Sstevel@tonic-gate 	parseLogicalExpression(int logOp, StreamTokenizer tk, StringBuffer buf)
5607c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	// Append paren and operator to buffer.
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	buf.append((char)OPEN_PAREN);
5657c478bd9Sstevel@tonic-gate 	buf.append((char)logOp);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	int tok = 0;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	do {
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	    tok = eatWhite(tk);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	    if (tok == OPEN_PAREN) {
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		// So parseInternal() sees a parenthesized list.
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 		tk.pushBack();
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 		// Go back to parseInternal.
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		parseInternal(tk, buf, false);
582*55fea89dSDan Cross 
5837c478bd9Sstevel@tonic-gate 	    } else if (tok == CLOSE_PAREN) {
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 		// Append the character to the buffer and return.
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 		buf.append((char)tok);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		return;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	    } else {
5927c478bd9Sstevel@tonic-gate 		throw
5937c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
5947c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5957c478bd9Sstevel@tonic-gate 				"v1_query_error",
5967c478bd9Sstevel@tonic-gate 				new Object[] {query});
5977c478bd9Sstevel@tonic-gate 	    }
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	} while (tok != StreamTokenizer.TT_EOF);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	// Error if we've not caught ourselves before this.
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	throw
6047c478bd9Sstevel@tonic-gate 	    new ServiceLocationException(
6057c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
6067c478bd9Sstevel@tonic-gate 				"v1_query_error",
6077c478bd9Sstevel@tonic-gate 				new Object[] {query});
6087c478bd9Sstevel@tonic-gate     }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate     // Parse a terminal. Opening paren has been got.
6117c478bd9Sstevel@tonic-gate 
parse(StreamTokenizer tk, StringBuffer buf, boolean firstEscaped)6127c478bd9Sstevel@tonic-gate     private void parse(StreamTokenizer tk,
6137c478bd9Sstevel@tonic-gate 		       StringBuffer buf,
6147c478bd9Sstevel@tonic-gate 		       boolean firstEscaped)
6157c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	String tag = "";
6187c478bd9Sstevel@tonic-gate 	int tok = 0;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	tok = eatWhite(tk);
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	// Gather the tag and value.
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (tok != StreamTokenizer.TT_WORD) {
6257c478bd9Sstevel@tonic-gate 	    throw
6267c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
6277c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
6287c478bd9Sstevel@tonic-gate 				"v1_query_error",
6297c478bd9Sstevel@tonic-gate 				new Object[] {query});
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	// Parse the tag.
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	tag = parseTag(tk, firstEscaped);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if (tag.length() <= 0) {
6377c478bd9Sstevel@tonic-gate 	    throw
6387c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
6397c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
6407c478bd9Sstevel@tonic-gate 				"v1_query_error",
6417c478bd9Sstevel@tonic-gate 				new Object[] {query});
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	// Unescape tag.
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	tag = ServiceLocationAttributeV1.unescapeAttributeString(tag,
6477c478bd9Sstevel@tonic-gate 								 charCode);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	// Now escape in v2 format,
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	tag = ServiceLocationAttribute.escapeAttributeString(tag, true);
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	// Parse the operator.
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	char compOp = parseOperator(tk);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	// If this was a keyword operator, then add present
6587c478bd9Sstevel@tonic-gate 	// operator and closing paren and return.
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	if (compOp == PRESENT) {
6617c478bd9Sstevel@tonic-gate 	    buf.append(OPEN_PAREN);
6627c478bd9Sstevel@tonic-gate 	    buf.append(tag);
6637c478bd9Sstevel@tonic-gate 	    buf.append(EQUAL_OP);
6647c478bd9Sstevel@tonic-gate 	    buf.append(PRESENT);
6657c478bd9Sstevel@tonic-gate 	    buf.append(CLOSE_PAREN);
6667c478bd9Sstevel@tonic-gate 	    return;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	// Parse value by reading up to the next close paren.
6717c478bd9Sstevel@tonic-gate 	//  Returned value will be in v2 format.
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	String valTok = parseValue(tk);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	// Construct the comparision depending on the operator.
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	if (compOp == NOT_OP) {
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	    // If the value is an integer, we can construct a query
6807c478bd9Sstevel@tonic-gate 	    //  that will exclude the number.
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	    try {
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 		int n = Integer.parseInt(valTok);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 		// Bump the integer up and down to catch numbers on both
6877c478bd9Sstevel@tonic-gate 		//  sides of the required number. Be careful not to
6887c478bd9Sstevel@tonic-gate 		//  overstep bounds.
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 		if (n < Integer.MAX_VALUE) {
6917c478bd9Sstevel@tonic-gate 		    buf.append(OPEN_PAREN);
6927c478bd9Sstevel@tonic-gate 		    buf.append(tag);
6937c478bd9Sstevel@tonic-gate 		    buf.append(GREATER_OP);
6947c478bd9Sstevel@tonic-gate 		    buf.append(EQUAL_OP);
6957c478bd9Sstevel@tonic-gate 		    buf.append(n + 1);
6967c478bd9Sstevel@tonic-gate 		    buf.append(CLOSE_PAREN);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 		}
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 		if (n > Integer.MIN_VALUE) {
7017c478bd9Sstevel@tonic-gate 		    buf.append(OPEN_PAREN);
7027c478bd9Sstevel@tonic-gate 		    buf.append(tag);
7037c478bd9Sstevel@tonic-gate 		    buf.append(LESS_OP);
7047c478bd9Sstevel@tonic-gate 		    buf.append(EQUAL_OP);
7057c478bd9Sstevel@tonic-gate 		    buf.append(n - 1);
7067c478bd9Sstevel@tonic-gate 		    buf.append(CLOSE_PAREN);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 		if ((n < Integer.MAX_VALUE) && (n > Integer.MIN_VALUE)) {
7117c478bd9Sstevel@tonic-gate 		    buf.insert(0, OR_OP);
7127c478bd9Sstevel@tonic-gate 		    buf.insert(0, OPEN_PAREN);
7137c478bd9Sstevel@tonic-gate 		    buf.append(CLOSE_PAREN);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 		}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	    } catch (NumberFormatException ex) {
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 		// It's not an integer. We can construct a query expression
7207c478bd9Sstevel@tonic-gate 		// that will not always work. The query rules out advertisments
7217c478bd9Sstevel@tonic-gate 		// where the attribute value doesn't match and there are
7227c478bd9Sstevel@tonic-gate 		// no other attributes or values, and advertisements
7237c478bd9Sstevel@tonic-gate 		// that don't contain the attribute, but it doesn't rule out
7247c478bd9Sstevel@tonic-gate 		// a multivalued attribute with other values or if there
7257c478bd9Sstevel@tonic-gate 		// are other attributes. The format of the query is:
7267c478bd9Sstevel@tonic-gate 		// "(&(<tag>=*)(!(<tag>=<value>))).
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		buf.append(OPEN_PAREN);
7297c478bd9Sstevel@tonic-gate 		buf.append(AND_OP);
7307c478bd9Sstevel@tonic-gate 		buf.append(OPEN_PAREN);
7317c478bd9Sstevel@tonic-gate 		buf.append(tag);
7327c478bd9Sstevel@tonic-gate 		buf.append(EQUAL_OP);
7337c478bd9Sstevel@tonic-gate 		buf.append(PRESENT);
7347c478bd9Sstevel@tonic-gate 		buf.append(CLOSE_PAREN);
7357c478bd9Sstevel@tonic-gate 		buf.append(OPEN_PAREN);
7367c478bd9Sstevel@tonic-gate 		buf.append(NOT_OP);
7377c478bd9Sstevel@tonic-gate 		buf.append(OPEN_PAREN);
7387c478bd9Sstevel@tonic-gate 		buf.append(tag);
7397c478bd9Sstevel@tonic-gate 		buf.append(EQUAL_OP);
7407c478bd9Sstevel@tonic-gate 		buf.append(valTok);
7417c478bd9Sstevel@tonic-gate 		buf.append(CLOSE_PAREN);
7427c478bd9Sstevel@tonic-gate 		buf.append(CLOSE_PAREN);
7437c478bd9Sstevel@tonic-gate 		buf.append(CLOSE_PAREN);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	    }
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	} else if ((compOp == LESS_OP) || (compOp == GREATER_OP)) {
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	    int n = 0;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	    try {
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 		n = Integer.parseInt(valTok);
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	    } catch (NumberFormatException ex) {
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 		// It's a parse error here.
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 		throw
7607c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
7617c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
7627c478bd9Sstevel@tonic-gate 				"v1_query_error",
7637c478bd9Sstevel@tonic-gate 				new Object[] {query});
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	    }
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	    // We don't attempt to handle something that would cause
7687c478bd9Sstevel@tonic-gate 	    // arithmetic overflow.
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	    if ((n == Integer.MAX_VALUE) || (n == Integer.MIN_VALUE)) {
7717c478bd9Sstevel@tonic-gate 		throw
7727c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
7737c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
7747c478bd9Sstevel@tonic-gate 				"v1_query_error",
7757c478bd9Sstevel@tonic-gate 				new Object[] {query});
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	    }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	    // Construct a query that includes everything
7807c478bd9Sstevel@tonic-gate 	    //  to the correct side.
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	    buf.append(OPEN_PAREN);
7837c478bd9Sstevel@tonic-gate 	    buf.append(tag);
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	    if (compOp == LESS_OP) {
7867c478bd9Sstevel@tonic-gate 		buf.append(LESS_OP);
7877c478bd9Sstevel@tonic-gate 		buf.append(EQUAL_OP);
7887c478bd9Sstevel@tonic-gate 		buf.append(n - 1);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	    } else {
7917c478bd9Sstevel@tonic-gate 		buf.append(GREATER_OP);
7927c478bd9Sstevel@tonic-gate 		buf.append(EQUAL_OP);
7937c478bd9Sstevel@tonic-gate 		buf.append(n + 1);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	    }
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	    buf.append(CLOSE_PAREN);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	} else {
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	    // Simple, single operator. Just add it with the
8027c478bd9Sstevel@tonic-gate 	    //  value.
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	    buf.append(OPEN_PAREN);
8057c478bd9Sstevel@tonic-gate 	    buf.append(tag);
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	    // Need to distinguish less and greater equal.
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	    if (compOp == LEQUAL_OP) {
8107c478bd9Sstevel@tonic-gate 		buf.append(LESS_OP);
8117c478bd9Sstevel@tonic-gate 		buf.append(EQUAL_OP);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	    } else if (compOp == GEQUAL_OP) {
8147c478bd9Sstevel@tonic-gate 		buf.append(GREATER_OP);
8157c478bd9Sstevel@tonic-gate 		buf.append(EQUAL_OP);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	    } else {
8187c478bd9Sstevel@tonic-gate 		buf.append(compOp);
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	    }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	    buf.append(valTok);
8237c478bd9Sstevel@tonic-gate 	    buf.append(CLOSE_PAREN);
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate     }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate     // Gather tokens with embedded whitespace and return.
8307c478bd9Sstevel@tonic-gate 
parseTag(StreamTokenizer tk, boolean ampStart)8317c478bd9Sstevel@tonic-gate     private String parseTag(StreamTokenizer tk, boolean ampStart)
8327c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	String value = "";
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	// Take care of corner case here.
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	if (ampStart) {
8397c478bd9Sstevel@tonic-gate 	    value = value +"&";
8407c478bd9Sstevel@tonic-gate 	    ampStart = false;
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	do {
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	    if (tk.ttype == StreamTokenizer.TT_WORD) {
8467c478bd9Sstevel@tonic-gate 		value += tk.sval;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	    } else if ((char)tk.ttype == SPACE) {
8497c478bd9Sstevel@tonic-gate 		value = value + " ";
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	    } else if ((char)tk.ttype == AND_OP) {
8527c478bd9Sstevel@tonic-gate 		value = value + "&";
853*55fea89dSDan Cross 
8547c478bd9Sstevel@tonic-gate 	    } else {
8557c478bd9Sstevel@tonic-gate 		break;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	    }
8587c478bd9Sstevel@tonic-gate 	    tk.nextToken();
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	} while (true);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	return value.trim();  // removes trailing whitespace...
8637c478bd9Sstevel@tonic-gate     }
8647c478bd9Sstevel@tonic-gate 
parseOperator(StreamTokenizer tk)8657c478bd9Sstevel@tonic-gate     private char parseOperator(StreamTokenizer tk)
8667c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	int tok = tk.ttype;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	// If the token is a close paren, then this was a keyword
8717c478bd9Sstevel@tonic-gate 	// (e.g. "(foo)". Return the present operator.
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	if ((char)tok == CLOSE_PAREN) {
8747c478bd9Sstevel@tonic-gate 	    return PRESENT;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	if (tok != EQUAL_OP && tok != NOT_OP &&
8797c478bd9Sstevel@tonic-gate 	    tok != LESS_OP && tok != GREATER_OP) {
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	    throw
8827c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
8837c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
8847c478bd9Sstevel@tonic-gate 				"v1_query_error",
8857c478bd9Sstevel@tonic-gate 				new Object[] {query});
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	char compOp = (char)tok;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	// Get the next token.
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	tok = tk.nextToken();
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	// Look for dual character operators.
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	if ((char)tok == EQUAL_OP) {
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	    // Here, we can have either "!=", "<=", ">=", or "==".
9007c478bd9Sstevel@tonic-gate 	    //  Anything else is wrong.
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	    if (compOp != LESS_OP && compOp != GREATER_OP &&
9037c478bd9Sstevel@tonic-gate 		compOp != EQUAL_OP && compOp != NOT_OP) {
9047c478bd9Sstevel@tonic-gate 		throw
9057c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
9067c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9077c478bd9Sstevel@tonic-gate 				"v1_query_error",
9087c478bd9Sstevel@tonic-gate 				new Object[] {query});
9097c478bd9Sstevel@tonic-gate 	    }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	    // Assign the right dual operator.
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	    if (compOp == LESS_OP) {
9147c478bd9Sstevel@tonic-gate 		compOp = LEQUAL_OP;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	    } else if (compOp == GREATER_OP) {
9177c478bd9Sstevel@tonic-gate 		compOp = GEQUAL_OP;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	    }
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	} else if (compOp != LESS_OP && compOp != GREATER_OP) {
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	    // Error if the comparison operator was something other
9247c478bd9Sstevel@tonic-gate 	    //  than ``<'' or ``>'' and there is no equal. This
9257c478bd9Sstevel@tonic-gate 	    //  rules out ``!'' or ``='' alone.
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	    throw
9287c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
9297c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9307c478bd9Sstevel@tonic-gate 				"v1_query_error",
9317c478bd9Sstevel@tonic-gate 				new Object[] {query});
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	} else {
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	    // Push back the last token if it wasn't a two character operator.
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	    tk.pushBack();
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	return compOp;
9427c478bd9Sstevel@tonic-gate     }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 
parseValue(StreamTokenizer tk)9457c478bd9Sstevel@tonic-gate     private String parseValue(StreamTokenizer tk)
9467c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	int tok = 0;
9497c478bd9Sstevel@tonic-gate 	StringBuffer valTok = new StringBuffer();
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	// Eat leading whitespace.
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	tok = eatWhite(tk);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	// If the first value is a paren, then we've got an
9567c478bd9Sstevel@tonic-gate 	//  opaque.
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	if ((char)tok == OPEN_PAREN) {
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	    valTok.append("(");
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	    // Collect all tokens up to the closing paren.
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	    do {
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		tok = tk.nextToken();
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		// It's a closing paren. break out of the loop.
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		if ((char)tok == CLOSE_PAREN) {
9717c478bd9Sstevel@tonic-gate 		    valTok.append(")");
9727c478bd9Sstevel@tonic-gate 		    break;
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		} else if ((char)tok == EQUAL_OP) {
9757c478bd9Sstevel@tonic-gate 		    valTok.append("=");
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 		} else if (tok == StreamTokenizer.TT_WORD) {
9787c478bd9Sstevel@tonic-gate 		    valTok.append(tk.sval);
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		} else {
9817c478bd9Sstevel@tonic-gate 		    throw
9827c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
9837c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9847c478bd9Sstevel@tonic-gate 				"v1_query_error",
9857c478bd9Sstevel@tonic-gate 				new Object[] {query});
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	    } while (true);
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	    // Eat whitespace until closing paren.
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	    tok = eatWhite(tk);
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	    if ((char)tok != CLOSE_PAREN) {
9967c478bd9Sstevel@tonic-gate 		throw
9977c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
9987c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9997c478bd9Sstevel@tonic-gate 				"v1_query_error",
10007c478bd9Sstevel@tonic-gate 				new Object[] {query});
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	    }
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	} else {
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	    // Error if just a closed paren.
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	    if (tok == CLOSE_PAREN) {
10097c478bd9Sstevel@tonic-gate 		throw
10107c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
10117c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
10127c478bd9Sstevel@tonic-gate 				"v1_query_error",
10137c478bd9Sstevel@tonic-gate 				new Object[] {query});
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	    }
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	    do {
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 		// Append the token if a WORD
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		if (tok == StreamTokenizer.TT_WORD) {
10227c478bd9Sstevel@tonic-gate 		    valTok.append(tk.sval);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 		} else if ((tok != StreamTokenizer.TT_EOF) &&
10257c478bd9Sstevel@tonic-gate 			   (tok != StreamTokenizer.TT_EOL) &&
10267c478bd9Sstevel@tonic-gate 			   (tok != CLOSE_PAREN)) {
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 		    // Otherwise, it's a token char, so append.
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 		    valTok.append((char)tok);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 		}
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 		tok = tk.nextToken();
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	    } while (tok != CLOSE_PAREN);
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	// If a wildcard, remove wildcard stars here for later re-insertion.
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	String strval = valTok.toString().trim();
10427c478bd9Sstevel@tonic-gate 	boolean wildstart = false;
10437c478bd9Sstevel@tonic-gate 	boolean wildend = false;
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	if (strval.startsWith(WILDCARD)) {
10467c478bd9Sstevel@tonic-gate 	    wildstart = true;
10477c478bd9Sstevel@tonic-gate 	    strval = strval.substring(1, strval.length());
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	}
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	if (strval.endsWith(WILDCARD)) {
10527c478bd9Sstevel@tonic-gate 	    wildend = true;
10537c478bd9Sstevel@tonic-gate 	    strval = strval.substring(0, strval.length()-1);
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	// Evaluate the value.
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	Object val =
10607c478bd9Sstevel@tonic-gate 	    ServiceLocationAttributeV1.evaluate(strval, charCode);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	// Now convert to v2 format, and return.
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	if (val instanceof String) {
10657c478bd9Sstevel@tonic-gate 	    strval =
10667c478bd9Sstevel@tonic-gate 		ServiceLocationAttribute.escapeAttributeString(val.toString(),
10677c478bd9Sstevel@tonic-gate 							       false);
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	    // Add wildcards back in.
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	    if (wildstart) {
10727c478bd9Sstevel@tonic-gate 		strval = WILDCARD + strval;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	    }
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	    if (wildend) {
10777c478bd9Sstevel@tonic-gate 		strval = strval + WILDCARD;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	    }
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	} else {
10827c478bd9Sstevel@tonic-gate 	    strval = val.toString();
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	return strval;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate     }
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate     // Eat whitespace.
10917c478bd9Sstevel@tonic-gate 
eatWhite(StreamTokenizer tk)10927c478bd9Sstevel@tonic-gate     private int eatWhite(StreamTokenizer tk)
10937c478bd9Sstevel@tonic-gate 	throws IOException {
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	int tok = tk.nextToken();
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	while (tok == SPACE) {
10987c478bd9Sstevel@tonic-gate 	    tok = tk.nextToken();
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	}
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	return tok;
11037c478bd9Sstevel@tonic-gate     }
11047c478bd9Sstevel@tonic-gate }
1105