xref: /onnv-gate/usr/src/lib/libslp/javalib/com/sun/slp/ServiceURL.java (revision 7298:b69e27387f74)
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