10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7298SMark.J.Nelson@Sun.COM * Common Development and Distribution License (the "License"). 6*7298SMark.J.Nelson@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 220Sstevel@tonic-gate * Copyright (c) 1999 by Sun Microsystems, Inc. 230Sstevel@tonic-gate * All rights reserved. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 27*7298SMark.J.Nelson@Sun.COM // ServiceURL.java : The service URL. 280Sstevel@tonic-gate // Author: James Kempf, Erik Guttman 290Sstevel@tonic-gate // 300Sstevel@tonic-gate 310Sstevel@tonic-gate package com.sun.slp; 320Sstevel@tonic-gate 330Sstevel@tonic-gate import java.util.*; 340Sstevel@tonic-gate import java.io.*; 350Sstevel@tonic-gate import java.net.*; 360Sstevel@tonic-gate 370Sstevel@tonic-gate /** 380Sstevel@tonic-gate * The ServiceURL object models the SLP service URL. Both service: URLs 390Sstevel@tonic-gate * and regular URLs are handled by this class. 400Sstevel@tonic-gate * 410Sstevel@tonic-gate * @author James Kempf, Erik Guttman 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate public class ServiceURL extends Object implements Serializable { 450Sstevel@tonic-gate 460Sstevel@tonic-gate // Recognized transports. 470Sstevel@tonic-gate 480Sstevel@tonic-gate private final static String IPX = "ipx"; 490Sstevel@tonic-gate private final static String AT = "at"; 500Sstevel@tonic-gate 510Sstevel@tonic-gate /** 520Sstevel@tonic-gate * Indicates that no port information is required or was returned 530Sstevel@tonic-gate * for this service URL. 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate 560Sstevel@tonic-gate public static final int NO_PORT = 0; 570Sstevel@tonic-gate 580Sstevel@tonic-gate /** 590Sstevel@tonic-gate * No life time parameter is given. 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate 620Sstevel@tonic-gate public static final int LIFETIME_NONE = 0; 630Sstevel@tonic-gate 640Sstevel@tonic-gate /** 650Sstevel@tonic-gate * Default lifetime, 3 hours. 660Sstevel@tonic-gate */ 670Sstevel@tonic-gate 680Sstevel@tonic-gate public static final int LIFETIME_DEFAULT = 10800; 690Sstevel@tonic-gate 700Sstevel@tonic-gate /** 710Sstevel@tonic-gate * Maximum lifetime, approximately 18 hours. 720Sstevel@tonic-gate */ 730Sstevel@tonic-gate 740Sstevel@tonic-gate public static final int LIFETIME_MAXIMUM = 0xFFFF; 750Sstevel@tonic-gate 760Sstevel@tonic-gate /** 770Sstevel@tonic-gate * Reregister periodically. 780Sstevel@tonic-gate */ 790Sstevel@tonic-gate 800Sstevel@tonic-gate public static final int LIFETIME_PERMANENT = -1; 810Sstevel@tonic-gate 820Sstevel@tonic-gate // Maximum port size. 830Sstevel@tonic-gate 840Sstevel@tonic-gate static final int PORT_MAXIMUM = 0xFFFF; 850Sstevel@tonic-gate 860Sstevel@tonic-gate 870Sstevel@tonic-gate // 880Sstevel@tonic-gate // data fields 890Sstevel@tonic-gate // 900Sstevel@tonic-gate 910Sstevel@tonic-gate private ServiceType serviceType = null; 920Sstevel@tonic-gate private ServiceType originalServiceType = null; 930Sstevel@tonic-gate private String transport = ""; 940Sstevel@tonic-gate private String host = ""; 950Sstevel@tonic-gate private int port = NO_PORT; 960Sstevel@tonic-gate private String URLPath = ""; 970Sstevel@tonic-gate private int lifetime = LIFETIME_DEFAULT; 980Sstevel@tonic-gate private boolean isPermanent = false; 990Sstevel@tonic-gate private boolean noDoubleSlash = false; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate /** 1020Sstevel@tonic-gate * Construct a service URL object. 1030Sstevel@tonic-gate * 1040Sstevel@tonic-gate * @param URL The service URL as a string. 1050Sstevel@tonic-gate * @param iLifetime The service advertisement lifetime. 1060Sstevel@tonic-gate * @exception IllegalArgumentException Thrown if parse 1070Sstevel@tonic-gate * errors occur in the 1080Sstevel@tonic-gate * parameter. 1090Sstevel@tonic-gate */ 1100Sstevel@tonic-gate ServiceURL(String URL, int iLifetime)1110Sstevel@tonic-gate public ServiceURL(String URL, int iLifetime) 1120Sstevel@tonic-gate throws IllegalArgumentException { 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate Assert.nonNullParameter(URL, "URL"); 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate if ((iLifetime > LIFETIME_MAXIMUM) || 1170Sstevel@tonic-gate (iLifetime < LIFETIME_PERMANENT)) { 1180Sstevel@tonic-gate throw 1190Sstevel@tonic-gate new IllegalArgumentException( 1200Sstevel@tonic-gate SLPConfig.getSLPConfig().formatMessage("lifetime_error", 1210Sstevel@tonic-gate new Object[0])); 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate checkURLString(URL); 1250Sstevel@tonic-gate parseURL(URL); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if (iLifetime == LIFETIME_PERMANENT) { 1280Sstevel@tonic-gate isPermanent = true; 1290Sstevel@tonic-gate iLifetime = LIFETIME_MAXIMUM; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate lifetime = iLifetime; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate // 1370Sstevel@tonic-gate // ------------------------------------------------------------------ 1380Sstevel@tonic-gate // Accessors 1390Sstevel@tonic-gate // ------------------------------------------------------------------ 1400Sstevel@tonic-gate // 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate /** 1430Sstevel@tonic-gate * @return The service type name. 1440Sstevel@tonic-gate */ 1450Sstevel@tonic-gate getServiceType()1460Sstevel@tonic-gate public ServiceType getServiceType() { 1470Sstevel@tonic-gate return serviceType; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /** 1520Sstevel@tonic-gate * Set service type and naming authority if this is not a service: URL. 1530Sstevel@tonic-gate * 1540Sstevel@tonic-gate * @param type The new ServiceType object. 1550Sstevel@tonic-gate * @exception IllegalArgumentException If the service type name or 1560Sstevel@tonic-gate * naming authority name is invalid. 1570Sstevel@tonic-gate */ 1580Sstevel@tonic-gate setServiceType(ServiceType type)1590Sstevel@tonic-gate public void setServiceType(ServiceType type) { 1600Sstevel@tonic-gate if (!serviceType.isServiceURL()) { 1610Sstevel@tonic-gate serviceType = type; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /** 1680Sstevel@tonic-gate * @return The machine name or IP address. 1690Sstevel@tonic-gate */ 1700Sstevel@tonic-gate getHost()1710Sstevel@tonic-gate public String getHost() { 1720Sstevel@tonic-gate return host; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /** 1770Sstevel@tonic-gate * @return The port number, if any. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate getPort()1800Sstevel@tonic-gate public int getPort() { 1810Sstevel@tonic-gate return port; 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /** 1860Sstevel@tonic-gate * @return The URL path description, if any. 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate getURLPath()1890Sstevel@tonic-gate public String getURLPath() { 1900Sstevel@tonic-gate return URLPath; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /** 1950Sstevel@tonic-gate * @return The service advertisement lifetime. 1960Sstevel@tonic-gate */ 1970Sstevel@tonic-gate getLifetime()1980Sstevel@tonic-gate public int getLifetime() { 1990Sstevel@tonic-gate return lifetime; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /** 2040Sstevel@tonic-gate * Formats the service URL into standard URL form. 2050Sstevel@tonic-gate * 2060Sstevel@tonic-gate * @return Formatted string with the service URL. 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate toString()2090Sstevel@tonic-gate public String toString() { // Overrides Object.toString(); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate return 2120Sstevel@tonic-gate originalServiceType.toString() + 2130Sstevel@tonic-gate ":/" + transport + (noDoubleSlash == false ? "/":"") + 2140Sstevel@tonic-gate host + (port != NO_PORT ? (":" + port) : "") + 2150Sstevel@tonic-gate URLPath; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate hashCode()2190Sstevel@tonic-gate public int hashCode() { 2200Sstevel@tonic-gate return 2210Sstevel@tonic-gate serviceType.hashCode() + 2220Sstevel@tonic-gate transport.hashCode() + 2230Sstevel@tonic-gate host.hashCode() + 2240Sstevel@tonic-gate port + 2250Sstevel@tonic-gate URLPath.hashCode(); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate equals(Object obj)2280Sstevel@tonic-gate public boolean equals(Object obj) { 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate if (obj == this) { 2310Sstevel@tonic-gate return true; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate if (!(obj instanceof ServiceURL)) { 2360Sstevel@tonic-gate return false; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate ServiceURL surl = (ServiceURL)obj; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate return 2420Sstevel@tonic-gate serviceType.equals(surl.serviceType) && 2430Sstevel@tonic-gate transport.equals(surl.transport) && 2440Sstevel@tonic-gate host.equals(surl.host) && 2450Sstevel@tonic-gate (port == surl.port) && 2460Sstevel@tonic-gate (noDoubleSlash == surl.noDoubleSlash) && 2470Sstevel@tonic-gate URLPath.equals(surl.URLPath); 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate // Return permanent status. 2520Sstevel@tonic-gate getIsPermanent()2530Sstevel@tonic-gate boolean getIsPermanent() { 2540Sstevel@tonic-gate return isPermanent; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate // Check URL characters for correctness. 2590Sstevel@tonic-gate checkURLString(String s)2600Sstevel@tonic-gate private void checkURLString(String s) 2610Sstevel@tonic-gate throws IllegalArgumentException { 2620Sstevel@tonic-gate for (int i = 0; i < s.length(); i++) { 2630Sstevel@tonic-gate char c = s.charAt(i); 2640Sstevel@tonic-gate // allowed by RFC1738 2650Sstevel@tonic-gate if (c == '/' || c == ':' || c == '-' || c == ':' || 2660Sstevel@tonic-gate c == '.' || c == '%' || c == '_' || c == '\'' || 2670Sstevel@tonic-gate c == '*' || c == '(' || c == ')' || c == '$' || 2680Sstevel@tonic-gate c == '!' || c == ',' || c == '+' || c == '\\') { 2690Sstevel@tonic-gate // defer to Windows 2700Sstevel@tonic-gate continue; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate // reserved by RFC1738, and thus allowed, pg. 20 2750Sstevel@tonic-gate if (c == ';' || c == '@' || c == '?' || c == '&' || c == '=') { 2760Sstevel@tonic-gate continue; 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if (Character.isLetterOrDigit(c)) { 2810Sstevel@tonic-gate continue; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate SLPConfig conf = SLPConfig.getSLPConfig(); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate throw 2870Sstevel@tonic-gate new IllegalArgumentException( 2880Sstevel@tonic-gate conf.formatMessage("url_char_error", 2890Sstevel@tonic-gate new Object[] { 2900Sstevel@tonic-gate new Character(c)})); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate // Parse the incoming service URL specification. 2950Sstevel@tonic-gate parseURL(String sURL)2960Sstevel@tonic-gate private void parseURL(String sURL) 2970Sstevel@tonic-gate throws IllegalArgumentException { 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate StringTokenizer st = new StringTokenizer(sURL, "/", true); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate try { 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate // This loop is a kludgy way to break out of the parse so 3040Sstevel@tonic-gate // we only throw at one location in the code. 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate do { 3070Sstevel@tonic-gate String typeName = st.nextToken(); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate // First token must be service type name. 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate if (typeName.equals("/")) { 3120Sstevel@tonic-gate break; // error! 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate // Check for colon terminator, not part of service 3170Sstevel@tonic-gate // type name. 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate if (!typeName.endsWith(":")) { 3200Sstevel@tonic-gate break; // error! 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate // Create service type, remove trailing colon. 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate serviceType = 3270Sstevel@tonic-gate new ServiceType(typeName.substring(0, 3280Sstevel@tonic-gate typeName.length() - 1)); 3290Sstevel@tonic-gate originalServiceType = serviceType; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate // Separator between service type name and transport. 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate String slash1 = st.nextToken(); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (!slash1.equals("/")) { 3360Sstevel@tonic-gate break; // error! 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate String slash2 = st.nextToken(); 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate String sAddr = ""; // address... 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate // Check for abstract type or alternate transport. 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate if (!slash2.equals("/")) { 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate // If this is an abstract type, then we could have 3490Sstevel@tonic-gate // something like: service:file-printer:file:/foo/bar. 3500Sstevel@tonic-gate // This is OK. Also, if this is a non-service: URL, 3510Sstevel@tonic-gate // something like file:/foo/bar is OK. 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate if (!serviceType.isServiceURL()) { 3540Sstevel@tonic-gate sAddr = slash2; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate noDoubleSlash = true; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate } else { 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate // We only recognize IPX and Appletalk at this point. 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (!slash2.equalsIgnoreCase(IPX) && 3630Sstevel@tonic-gate !slash2.equalsIgnoreCase(AT)) { 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate // Abstract type is OK. We must check here because 3660Sstevel@tonic-gate // something like 3670Sstevel@tonic-gate // service:printing:lpr:/ipx/foo/bar 3680Sstevel@tonic-gate // is allowed. 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate if (serviceType.isAbstractType()) { 3710Sstevel@tonic-gate sAddr = slash2; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate noDoubleSlash = true; 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate } else { 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate break; // error! 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate } else { 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate transport = slash2.toLowerCase(); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate // Check for separator between transport and host. 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate if (!st.nextToken().equals("/")) { 3870Sstevel@tonic-gate break; // error! 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate sAddr = st.nextToken(); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate } else { 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate // Not abstract type, no alternate transport. Get host. 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate sAddr = st.nextToken(); 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if (sAddr.equals("/")) {// no host part 4030Sstevel@tonic-gate URLPath = "/" + st.nextToken(""); 4040Sstevel@tonic-gate return; // we're done! 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate host = sAddr; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate // Need to check for port number if this is an IP transport. 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate if (transport.equals("")) { 4130Sstevel@tonic-gate StringTokenizer tk = new StringTokenizer(host, ":"); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate host = tk.nextToken(); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate // Get port if any. 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate if (tk.hasMoreTokens()) { 4200Sstevel@tonic-gate String p = tk.nextToken(); 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate if (tk.hasMoreTokens()) { 4230Sstevel@tonic-gate break; // error! 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate try { 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate port = Integer.parseInt(p); 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate } catch (NumberFormatException ex) { 4320Sstevel@tonic-gate break; // error! 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate if (port <= 0 || port > PORT_MAXIMUM) { 4370Sstevel@tonic-gate break; // error! 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate // 4440Sstevel@tonic-gate // after this point we have to check if there is a token 4450Sstevel@tonic-gate // remaining before we read it: It is legal to stop at any 4460Sstevel@tonic-gate // point now. Before all the tokens were required, so 4470Sstevel@tonic-gate // missing any was an error. 4480Sstevel@tonic-gate // 4490Sstevel@tonic-gate if (st.hasMoreTokens() == false) { 4500Sstevel@tonic-gate // minimal url service:t:// a 4510Sstevel@tonic-gate return; // we're done! 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate String sSep = st.nextToken(); 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate if (!sSep.equals("/")) { 4580Sstevel@tonic-gate break; // error! 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate // there is a URL path 4630Sstevel@tonic-gate // URLPath is all remaining tokens 4640Sstevel@tonic-gate URLPath = sSep; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate if (st.hasMoreTokens()) { 4670Sstevel@tonic-gate URLPath += st.nextToken(""); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate URLPath = URLPath.trim(); 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate return; // done! 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate } while (false); // done with parse. 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate } catch (NoSuchElementException ex) { 4780Sstevel@tonic-gate throw 4790Sstevel@tonic-gate new IllegalArgumentException( 4800Sstevel@tonic-gate SLPConfig.getSLPConfig().formatMessage("url_syntax_error", 4810Sstevel@tonic-gate new Object[] {sURL})); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate // The only way to get here is if there was an error in the 4860Sstevel@tonic-gate // parse. 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate throw 4890Sstevel@tonic-gate new IllegalArgumentException( 4900Sstevel@tonic-gate SLPConfig.getSLPConfig().formatMessage("url_syntax_error", 4910Sstevel@tonic-gate new Object[] {sURL})); 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate } 496