2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999 by Sun Microsystems, Inc.
2N/A * All rights reserved.
2N/A *
2N/A */
2N/A
2N/A// ServiceURL.java : The service URL.
2N/A// Author: James Kempf, Erik Guttman
2N/A//
2N/A
2N/Apackage com.sun.slp;
2N/A
2N/Aimport java.util.*;
2N/Aimport java.io.*;
2N/Aimport java.net.*;
2N/A
2N/A/**
2N/A * The ServiceURL object models the SLP service URL. Both service: URLs
2N/A * and regular URLs are handled by this class.
2N/A *
2N/A * @author James Kempf, Erik Guttman
2N/A */
2N/A
2N/Apublic class ServiceURL extends Object implements Serializable {
2N/A
2N/A // Recognized transports.
2N/A
2N/A private final static String IPX = "ipx";
2N/A private final static String AT = "at";
2N/A
2N/A /**
2N/A * Indicates that no port information is required or was returned
2N/A * for this service URL.
2N/A */
2N/A
2N/A public static final int NO_PORT = 0;
2N/A
2N/A /**
2N/A * No life time parameter is given.
2N/A */
2N/A
2N/A public static final int LIFETIME_NONE = 0;
2N/A
2N/A /**
2N/A * Default lifetime, 3 hours.
2N/A */
2N/A
2N/A public static final int LIFETIME_DEFAULT = 10800;
2N/A
2N/A /**
2N/A * Maximum lifetime, approximately 18 hours.
2N/A */
2N/A
2N/A public static final int LIFETIME_MAXIMUM = 0xFFFF;
2N/A
2N/A /**
2N/A * Reregister periodically.
2N/A */
2N/A
2N/A public static final int LIFETIME_PERMANENT = -1;
2N/A
2N/A // Maximum port size.
2N/A
2N/A static final int PORT_MAXIMUM = 0xFFFF;
2N/A
2N/A
2N/A //
2N/A // data fields
2N/A //
2N/A
2N/A private ServiceType serviceType = null;
2N/A private ServiceType originalServiceType = null;
2N/A private String transport = "";
2N/A private String host = "";
2N/A private int port = NO_PORT;
2N/A private String URLPath = "";
2N/A private int lifetime = LIFETIME_DEFAULT;
2N/A private boolean isPermanent = false;
2N/A private boolean noDoubleSlash = false;
2N/A
2N/A /**
2N/A * Construct a service URL object.
2N/A *
2N/A * @param URL The service URL as a string.
2N/A * @param iLifetime The service advertisement lifetime.
2N/A * @exception IllegalArgumentException Thrown if parse
2N/A * errors occur in the
2N/A * parameter.
2N/A */
2N/A
2N/A public ServiceURL(String URL, int iLifetime)
2N/A throws IllegalArgumentException {
2N/A
2N/A Assert.nonNullParameter(URL, "URL");
2N/A
2N/A if ((iLifetime > LIFETIME_MAXIMUM) ||
2N/A (iLifetime < LIFETIME_PERMANENT)) {
2N/A throw
2N/A new IllegalArgumentException(
2N/A SLPConfig.getSLPConfig().formatMessage("lifetime_error",
2N/A new Object[0]));
2N/A }
2N/A
2N/A checkURLString(URL);
2N/A parseURL(URL);
2N/A
2N/A if (iLifetime == LIFETIME_PERMANENT) {
2N/A isPermanent = true;
2N/A iLifetime = LIFETIME_MAXIMUM;
2N/A
2N/A }
2N/A
2N/A lifetime = iLifetime;
2N/A }
2N/A
2N/A //
2N/A // ------------------------------------------------------------------
2N/A // Accessors
2N/A // ------------------------------------------------------------------
2N/A //
2N/A
2N/A /**
2N/A * @return The service type name.
2N/A */
2N/A
2N/A public ServiceType getServiceType() {
2N/A return serviceType;
2N/A
2N/A }
2N/A
2N/A /**
2N/A * Set service type and naming authority if this is not a service: URL.
2N/A *
2N/A * @param type The new ServiceType object.
2N/A * @exception IllegalArgumentException If the service type name or
2N/A * naming authority name is invalid.
2N/A */
2N/A
2N/A public void setServiceType(ServiceType type) {
2N/A if (!serviceType.isServiceURL()) {
2N/A serviceType = type;
2N/A
2N/A }
2N/A
2N/A }
2N/A
2N/A /**
2N/A * @return The machine name or IP address.
2N/A */
2N/A
2N/A public String getHost() {
2N/A return host;
2N/A
2N/A }
2N/A
2N/A /**
2N/A * @return The port number, if any.
2N/A */
2N/A
2N/A public int getPort() {
2N/A return port;
2N/A
2N/A }
2N/A
2N/A /**
2N/A * @return The URL path description, if any.
2N/A */
2N/A
2N/A public String getURLPath() {
2N/A return URLPath;
2N/A
2N/A }
2N/A
2N/A /**
2N/A * @return The service advertisement lifetime.
2N/A */
2N/A
2N/A public int getLifetime() {
2N/A return lifetime;
2N/A
2N/A }
2N/A
2N/A /**
2N/A * Formats the service URL into standard URL form.
2N/A *
2N/A * @return Formatted string with the service URL.
2N/A */
2N/A
2N/A public String toString() { // Overrides Object.toString();
2N/A
2N/A return
2N/A originalServiceType.toString() +
2N/A ":/" + transport + (noDoubleSlash == false ? "/":"") +
2N/A host + (port != NO_PORT ? (":" + port) : "") +
2N/A URLPath;
2N/A
2N/A }
2N/A
2N/A public int hashCode() {
2N/A return
2N/A serviceType.hashCode() +
2N/A transport.hashCode() +
2N/A host.hashCode() +
2N/A port +
2N/A URLPath.hashCode();
2N/A }
2N/A
2N/A public boolean equals(Object obj) {
2N/A
2N/A if (obj == this) {
2N/A return true;
2N/A
2N/A }
2N/A
2N/A if (!(obj instanceof ServiceURL)) {
2N/A return false;
2N/A }
2N/A
2N/A ServiceURL surl = (ServiceURL)obj;
2N/A
2N/A return
2N/A serviceType.equals(surl.serviceType) &&
2N/A transport.equals(surl.transport) &&
2N/A host.equals(surl.host) &&
2N/A (port == surl.port) &&
2N/A (noDoubleSlash == surl.noDoubleSlash) &&
2N/A URLPath.equals(surl.URLPath);
2N/A
2N/A }
2N/A
2N/A // Return permanent status.
2N/A
2N/A boolean getIsPermanent() {
2N/A return isPermanent;
2N/A
2N/A }
2N/A
2N/A // Check URL characters for correctness.
2N/A
2N/A private void checkURLString(String s)
2N/A throws IllegalArgumentException {
2N/A for (int i = 0; i < s.length(); i++) {
2N/A char c = s.charAt(i);
2N/A // allowed by RFC1738
2N/A if (c == '/' || c == ':' || c == '-' || c == ':' ||
2N/A c == '.' || c == '%' || c == '_' || c == '\'' ||
2N/A c == '*' || c == '(' || c == ')' || c == '$' ||
2N/A c == '!' || c == ',' || c == '+' || c == '\\') {
2N/A // defer to Windows
2N/A continue;
2N/A
2N/A }
2N/A
2N/A // reserved by RFC1738, and thus allowed, pg. 20
2N/A if (c == ';' || c == '@' || c == '?' || c == '&' || c == '=') {
2N/A continue;
2N/A
2N/A }
2N/A
2N/A if (Character.isLetterOrDigit(c)) {
2N/A continue;
2N/A }
2N/A
2N/A SLPConfig conf = SLPConfig.getSLPConfig();
2N/A
2N/A throw
2N/A new IllegalArgumentException(
2N/A conf.formatMessage("url_char_error",
2N/A new Object[] {
2N/A new Character(c)}));
2N/A }
2N/A }
2N/A
2N/A // Parse the incoming service URL specification.
2N/A
2N/A private void parseURL(String sURL)
2N/A throws IllegalArgumentException {
2N/A
2N/A StringTokenizer st = new StringTokenizer(sURL, "/", true);
2N/A
2N/A try {
2N/A
2N/A // This loop is a kludgy way to break out of the parse so
2N/A // we only throw at one location in the code.
2N/A
2N/A do {
2N/A String typeName = st.nextToken();
2N/A
2N/A // First token must be service type name.
2N/A
2N/A if (typeName.equals("/")) {
2N/A break; // error!
2N/A
2N/A }
2N/A
2N/A // Check for colon terminator, not part of service
2N/A // type name.
2N/A
2N/A if (!typeName.endsWith(":")) {
2N/A break; // error!
2N/A
2N/A }
2N/A
2N/A // Create service type, remove trailing colon.
2N/A
2N/A serviceType =
2N/A new ServiceType(typeName.substring(0,
2N/A typeName.length() - 1));
2N/A originalServiceType = serviceType;
2N/A
2N/A // Separator between service type name and transport.
2N/A
2N/A String slash1 = st.nextToken();
2N/A
2N/A if (!slash1.equals("/")) {
2N/A break; // error!
2N/A
2N/A }
2N/A
2N/A String slash2 = st.nextToken();
2N/A
2N/A String sAddr = ""; // address...
2N/A
2N/A // Check for abstract type or alternate transport.
2N/A
2N/A if (!slash2.equals("/")) {
2N/A
2N/A // If this is an abstract type, then we could have
2N/A // something like: service:file-printer:file:/foo/bar.
2N/A // This is OK. Also, if this is a non-service: URL,
2N/A // something like file:/foo/bar is OK.
2N/A
2N/A if (!serviceType.isServiceURL()) {
2N/A sAddr = slash2;
2N/A
2N/A noDoubleSlash = true;
2N/A
2N/A } else {
2N/A
2N/A // We only recognize IPX and Appletalk at this point.
2N/A
2N/A if (!slash2.equalsIgnoreCase(IPX) &&
2N/A !slash2.equalsIgnoreCase(AT)) {
2N/A
2N/A // Abstract type is OK. We must check here because
2N/A // something like
2N/A // service:printing:lpr:/ipx/foo/bar
2N/A // is allowed.
2N/A
2N/A if (serviceType.isAbstractType()) {
2N/A sAddr = slash2;
2N/A
2N/A noDoubleSlash = true;
2N/A
2N/A } else {
2N/A
2N/A break; // error!
2N/A
2N/A }
2N/A } else {
2N/A
2N/A transport = slash2.toLowerCase();
2N/A
2N/A // Check for separator between transport and host.
2N/A
2N/A if (!st.nextToken().equals("/")) {
2N/A break; // error!
2N/A
2N/A }
2N/A
2N/A sAddr = st.nextToken();
2N/A }
2N/A }
2N/A } else {
2N/A
2N/A // Not abstract type, no alternate transport. Get host.
2N/A
2N/A sAddr = st.nextToken();
2N/A
2N/A }
2N/A
2N/A if (sAddr.equals("/")) {// no host part
2N/A URLPath = "/" + st.nextToken("");
2N/A return; // we're done!
2N/A
2N/A }
2N/A
2N/A host = sAddr;
2N/A
2N/A // Need to check for port number if this is an IP transport.
2N/A
2N/A if (transport.equals("")) {
2N/A StringTokenizer tk = new StringTokenizer(host, ":");
2N/A
2N/A host = tk.nextToken();
2N/A
2N/A // Get port if any.
2N/A
2N/A if (tk.hasMoreTokens()) {
2N/A String p = tk.nextToken();
2N/A
2N/A if (tk.hasMoreTokens()) {
2N/A break; // error!
2N/A
2N/A }
2N/A
2N/A try {
2N/A
2N/A port = Integer.parseInt(p);
2N/A
2N/A } catch (NumberFormatException ex) {
2N/A break; // error!
2N/A
2N/A }
2N/A
2N/A if (port <= 0 || port > PORT_MAXIMUM) {
2N/A break; // error!
2N/A
2N/A }
2N/A }
2N/A }
2N/A
2N/A //
2N/A // after this point we have to check if there is a token
2N/A // remaining before we read it: It is legal to stop at any
2N/A // point now. Before all the tokens were required, so
2N/A // missing any was an error.
2N/A //
2N/A if (st.hasMoreTokens() == false) {
2N/A // minimal url service:t:// a
2N/A return; // we're done!
2N/A
2N/A }
2N/A
2N/A String sSep = st.nextToken();
2N/A
2N/A if (!sSep.equals("/")) {
2N/A break; // error!
2N/A
2N/A }
2N/A
2N/A // there is a URL path
2N/A // URLPath is all remaining tokens
2N/A URLPath = sSep;
2N/A
2N/A if (st.hasMoreTokens()) {
2N/A URLPath += st.nextToken("");
2N/A
2N/A }
2N/A
2N/A URLPath = URLPath.trim();
2N/A
2N/A return; // done!
2N/A
2N/A } while (false); // done with parse.
2N/A
2N/A } catch (NoSuchElementException ex) {
2N/A throw
2N/A new IllegalArgumentException(
2N/A SLPConfig.getSLPConfig().formatMessage("url_syntax_error",
2N/A new Object[] {sURL}));
2N/A
2N/A }
2N/A
2N/A // The only way to get here is if there was an error in the
2N/A // parse.
2N/A
2N/A throw
2N/A new IllegalArgumentException(
2N/A SLPConfig.getSLPConfig().formatMessage("url_syntax_error",
2N/A new Object[] {sURL}));
2N/A
2N/A }
2N/A
2N/A}