FileDocCategorySizeDatePackage
JMXServiceURL.javaAPI DocJava SE 5 API22050Fri Aug 26 14:57:38 BST 2005javax.management.remote

JMXServiceURL

public class JMXServiceURL extends Object implements Serializable

The address of a JMX API connector server. Instances of this class are immutable.

The address is an Abstract Service URL for SLP, as defined in RFC 2609 and amended by RFC 3111. It must look like this:

service:jmx:protocol:sap

Here, protocol is the transport protocol to be used to connect to the connector server. It is a string of one or more ASCII characters, each of which is a letter, a digit, or one of the characters + or -. The first character must be a letter. Uppercase letters are converted into lowercase ones.

sap is the address at which the connector server is found. This address uses a subset of the syntax defined by RFC 2609 for IP-based protocols. It is a subset because the user@host syntax is not supported.

The other syntaxes defined by RFC 2609 are not currently supported by this class.

The supported syntax is:

//[host[:port]][url-path]

Square brackets [] indicate optional parts of the address. Not all protocols will recognize all optional parts.

The host is a host name, an IPv4 numeric host address, or an IPv6 numeric address enclosed in square brackets.

The port is a decimal port number. 0 means a default or anonymous port, depending on the protocol.

The host and port can be omitted. The port cannot be supplied without a host.

The url-path, if any, begins with a slash (/) or a semicolon (;) and continues to the end of the address. It can contain attributes using the semicolon syntax specified in RFC 2609. Those attributes are not parsed by this class and incorrect attribute syntax is not detected.

Although it is legal according to RFC 2609 to have a url-path that begins with a semicolon, not all implementations of SLP allow it, so it is recommended to avoid that syntax.

Case is not significant in the initial service:jmx:protocol string or in the host part of the address. Depending on the protocol, case can be significant in the url-path.

see
RFC 2609, "Service Templates and Service: Schemes"
see
RFC 3111, "Service Location Protocol Modifications for IPv6"
since
1.5
since.unbundled
1.0

Fields Summary
private static final long
serialVersionUID
private static final Exception
randomException
private static final BitSet
alphaBitSet
private static final BitSet
numericBitSet
private static final BitSet
alphaNumericBitSet
private static final BitSet
protocolBitSet
private static final BitSet
hostNameBitSet
private final String
protocol
The value returned by {@link #getProtocol()}.
private final String
host
The value returned by {@link #getHost()}.
private final int
port
The value returned by {@link #getPort()}.
private final String
urlPath
The value returned by {@link #getURLPath()}.
private transient String
toString
Cached result of {@link #toString()}.
private static final ClassLogger
logger
Constructors Summary
public JMXServiceURL(String serviceURL)

Constructs a JMXServiceURL by parsing a Service URL string.

param
serviceURL the URL string to be parsed.
exception
NullPointerException if serviceURL is null.
exception
MalformedURLException if serviceURL does not conform to the syntax for an Abstract Service URL or if it is not a valid name for a JMX Remote API service. A JMXServiceURL must begin with the string "service:jmx:" (case-insensitive). It must not contain any characters that are not printable ASCII characters.


                                                                                    
         
	final int serviceURLLength = serviceURL.length();

	/* Check that there are no non-ASCII characters in the URL,
	   following RFC 2609.  */
	for (int i = 0; i < serviceURLLength; i++) {
	    char c = serviceURL.charAt(i);
	    if (c < 32 || c >= 127) {
		throw new MalformedURLException("Service URL contains " +
						"non-ASCII character 0x" +
						Integer.toHexString(c));
	    }
	}

	// Parse the required prefix
	final String requiredPrefix = "service:jmx:";
	final int requiredPrefixLength = requiredPrefix.length();
	if (!serviceURL.regionMatches(true, // ignore case
				      0,    // serviceURL offset
				      requiredPrefix,
				      0,    // requiredPrefix offset
				      requiredPrefixLength)) {
	    throw new MalformedURLException("Service URL must start with " +
					    requiredPrefix);
	}

	int[] ptr = new int[1];

	// Parse the protocol name
	final int protoStart = requiredPrefixLength;
	final int protoEnd = indexOf(serviceURL, ':", protoStart);
	this.protocol =
	    serviceURL.substring(protoStart, protoEnd).toLowerCase();

	if (!serviceURL.regionMatches(protoEnd, "://", 0, 3)) {
	    throw new MalformedURLException("Missing \"://\" after " +
					    "protocol name");
	}

	// Parse the host name
	final int hostStart = protoEnd + 3;
	final int hostEnd;
	if (hostStart < serviceURLLength
	    && serviceURL.charAt(hostStart) == '[") {
	    hostEnd = serviceURL.indexOf(']", hostStart) + 1;
	    if (hostEnd == 0)
		throw new MalformedURLException("Bad host name: [ without ]");
	    this.host = serviceURL.substring(hostStart + 1, hostEnd - 1);
	    if (!isNumericIPv6Address(this.host)) {
		throw new MalformedURLException("Address inside [...] must " +
						"be numeric IPv6 address");
	    }
	} else {
	    hostEnd =
		indexOfFirstNotInSet(serviceURL, hostNameBitSet, hostStart);
	    this.host = serviceURL.substring(hostStart, hostEnd);
	}

	// Parse the port number
	final int portEnd;
	if (hostEnd < serviceURLLength && serviceURL.charAt(hostEnd) == ':") {
	    if (this.host.length() == 0) {
		throw new MalformedURLException("Cannot give port number " +
						"without host name");
	    }
	    final int portStart = hostEnd + 1;
	    portEnd =
		indexOfFirstNotInSet(serviceURL, numericBitSet, portStart);
	    final String portString = serviceURL.substring(portStart, portEnd);
	    try {
		this.port = Integer.parseInt(portString);
	    } catch (NumberFormatException e) {
		throw new MalformedURLException("Bad port number: \"" +
						portString + "\": " + e);
	    }
	} else {
	    portEnd = hostEnd;
	    this.port = 0;
	}

	// Parse the URL path
	final int urlPathStart = portEnd;
	if (urlPathStart < serviceURLLength)
	    this.urlPath = serviceURL.substring(urlPathStart);
	else
	    this.urlPath = "";

	validate();
    
public JMXServiceURL(String protocol, String host, int port)

Constructs a JMXServiceURL with the given protocol, host, and port. This constructor is equivalent to {@link #JMXServiceURL(String, String, int, String) JMXServiceURL(protocol, host, port, null)}.

param
protocol the protocol part of the URL. If null, defaults to jmxmp.
param
host the host part of the URL. If null, defaults to the local host name, as determined by InetAddress.getLocalHost().getHostName(). If it is a numeric IPv6 address, it can optionally be enclosed in square brackets [].
param
port the port part of the URL.
exception
MalformedURLException if one of the parts is syntactically incorrect, or if host is null and it is not possible to find the local host name, or if port is negative.

	this(protocol, host, port, null);
    
public JMXServiceURL(String protocol, String host, int port, String urlPath)

Constructs a JMXServiceURL with the given parts.

param
protocol the protocol part of the URL. If null, defaults to jmxmp.
param
host the host part of the URL. If null, defaults to the local host name, as determined by InetAddress.getLocalHost().getHostName(). If it is a numeric IPv6 address, it can optionally be enclosed in square brackets [].
param
port the port part of the URL.
param
urlPath the URL path part of the URL. If null, defaults to the empty string.
exception
MalformedURLException if one of the parts is syntactically incorrect, or if host is null and it is not possible to find the local host name, or if port is negative.

	if (protocol == null)
	    protocol = "jmxmp";

	if (host == null) {
	    InetAddress local;
	    try {
		local = InetAddress.getLocalHost();
	    } catch (UnknownHostException e) {
		throw new MalformedURLException("Local host name unknown: " +
						e);
	    }

	    host = local.getHostName();

	    /* We might have a hostname that violates DNS naming
	       rules, for example that contains an `_'.  While we
	       could be strict and throw an exception, this is rather
	       user-hostile.  Instead we use its numerical IP address.
	       We can only reasonably do this for the host==null case.
	       If we're given an explicit host name that is illegal we
	       have to reject it.  (Bug 5057532.)  */
	    try {
		validateHost(host);
	    } catch (MalformedURLException e) {
		if (logger.fineOn()) {
		    logger.fine("JMXServiceURL",
				"Replacing illegal local host name " +
				host + " with numeric IP address " +
				"(see RFC 1034)", e);
		}
		host = local.getHostAddress();
		/* Use the numeric address, which could be either IPv4
		   or IPv6.  validateHost will accept either.  */
	    }
	}

	if (host.startsWith("[")) {
	    if (!host.endsWith("]")) {
		throw new MalformedURLException("Host starts with [ but " +
						"does not end with ]");
	    }
	    host = host.substring(1, host.length() - 1);
	    if (!isNumericIPv6Address(host)) {
		throw new MalformedURLException("Address inside [...] must " +
						"be numeric IPv6 address");
	    }
	    if (host.startsWith("["))
		throw new MalformedURLException("More than one [[...]]");
	}

	this.protocol = protocol.toLowerCase();
	this.host = host;
	this.port = port;

	if (urlPath == null)
	    urlPath = "";
	this.urlPath = urlPath;

	validate();
    
Methods Summary
private static voidaddCharsToBitSet(java.util.BitSet set, java.lang.String chars)

     
	/* J2SE 1.4 adds lots of handy methods to BitSet that would
	   allow us to simplify here, e.g. by not writing loops, but
	   we want to work on J2SE 1.3 too.  */

	for (char c = '0"; c <= '9"; c++)
	    numericBitSet.set(c);

	for (char c = 'A"; c <= 'Z"; c++)
	    alphaBitSet.set(c);
	for (char c = 'a"; c <= 'z"; c++)
	    alphaBitSet.set(c);

	alphaNumericBitSet.or(alphaBitSet);
	alphaNumericBitSet.or(numericBitSet);

	protocolBitSet.or(alphaNumericBitSet);
	protocolBitSet.set('+");
	protocolBitSet.set('-");

	hostNameBitSet.or(alphaNumericBitSet);
	hostNameBitSet.set('-");
	hostNameBitSet.set('.");
    
	for (int i = 0; i < chars.length(); i++)
	    set.set(chars.charAt(i));
    
public booleanequals(java.lang.Object obj)

Indicates whether some other object is equal to this one. This method returns true if and only if obj is an instance of JMXServiceURL whose {@link #getProtocol()}, {@link #getHost()}, {@link #getPort()}, and {@link #getURLPath()} methods return the same values as for this object. The values for {@link #getProtocol()} and {@link #getHost()} can differ in case without affecting equality.

param
obj the reference object with which to compare.
return
true if this object is the same as the obj argument; false otherwise.

	if (!(obj instanceof JMXServiceURL))
	    return false;
	JMXServiceURL u = (JMXServiceURL) obj;
	return
	    (u.getProtocol().equalsIgnoreCase(getProtocol()) &&
	     u.getHost().equalsIgnoreCase(getHost()) &&
	     u.getPort() == getPort() &&
	     u.getURLPath().equals(getURLPath()));
    
public java.lang.StringgetHost()

The host part of the Service URL. If the Service URL was constructed with the constructor that takes a URL string parameter, the result is the substring specifying the host in that URL. If the Service URL was constructed with a constructor that takes a separate host parameter, the result is the string that was specified. If that string was null, the result is InetAddress.getLocalHost().getHostName().

In either case, if the host was specified using the [...] syntax for numeric IPv6 addresses, the square brackets are not included in the return value here.

return
the host part of the Service URL. This is never null.

	return host;
    
public intgetPort()

The port of the Service URL. If no port was specified, the returned value is 0.

return
the port of the Service URL, or 0 if none.

	return port;
    
public java.lang.StringgetProtocol()

The protocol part of the Service URL.

return
the protocol part of the Service URL. This is never null.



                             
       
	return protocol;
    
public java.lang.StringgetURLPath()

The URL Path part of the Service URL. This is an empty string, or a string beginning with a slash (/), or a string beginning with a semicolon (;).

return
the URL Path part of the Service URL. This is never null.

	return urlPath;
    
public inthashCode()

	return toString().hashCode();
    
private static intindexOf(java.lang.String s, char c, int fromIndex)

	int index = s.indexOf(c, fromIndex);
	if (index < 0)
	    return s.length();
	else
	    return index;
    
private static intindexOfFirstNotInSet(java.lang.String s, java.util.BitSet set, int fromIndex)

	final int slen = s.length();
	int i = fromIndex;
	while (true) {
	    if (i >= slen)
		break;
	    char c = s.charAt(i);
	    if (c >= 128)
		break; // not ASCII
	    if (!set.get(c))
		break;
	    i++;
	}
	return i;
    
private static booleanisNumericIPv6Address(java.lang.String s)

	// address contains colon iff it's a numeric IPv6 address
	return (s.indexOf(':") >= 0);
    
public java.lang.StringtoString()

The string representation of this Service URL. If the value returned by this method is supplied to the JMXServiceURL constructor, the resultant object is equal to this one.

The host part of the returned string is the value returned by {@link #getHost()}. If that value specifies a numeric IPv6 address, it is surrounded by square brackets [].

The port part of the returned string is the value returned by {@link #getPort()} in its shortest decimal form. If the value is zero, it is omitted.

return
the string representation of this Service URL.

	/* We don't bother synchronizing the access to toString.  At worst,
	   n threads will independently compute and store the same value.  */
	if (toString != null)
	    return toString;
	StringBuffer buf = new StringBuffer("service:jmx:");
	buf.append(getProtocol()).append("://");
	final String getHost = getHost();
	if (isNumericIPv6Address(getHost))
	    buf.append('[").append(getHost).append(']");
	else
	    buf.append(getHost);
	final int getPort = getPort();
	if (getPort != 0)
	    buf.append(':").append(getPort);
	buf.append(getURLPath());
	toString = buf.toString();
	return toString;
    
private voidvalidate()


	// Check protocol

	final int protoEnd = indexOfFirstNotInSet(protocol, protocolBitSet, 0);
	if (protoEnd == 0 || protoEnd < protocol.length()
	    || !alphaBitSet.get(protocol.charAt(0))) {
	    throw new MalformedURLException("Missing or invalid protocol " +
					    "name: \"" + protocol + "\"");
	}

	// Check host

	validateHost();

	// Check port

	if (port < 0)
	    throw new MalformedURLException("Bad port: " + port);

	// Check URL path

	if (urlPath.length() > 0) {
	    if (!urlPath.startsWith("/") && !urlPath.startsWith(";"))
		throw new MalformedURLException("Bad URL path: " + urlPath);
	}
    
private voidvalidateHost()

	if (host.length() == 0) {
	    if (port != 0) {
		throw new MalformedURLException("Cannot give port number " +
						"without host name");
	    }
	    return;
	}

	validateHost(host);
    
private static voidvalidateHost(java.lang.String h)


	if (isNumericIPv6Address(h)) {
	    /* We assume J2SE >= 1.4 here.  Otherwise you can't
	       use the address anyway.  We can't call
	       InetAddress.getByName without checking for a
	       numeric IPv6 address, because we mustn't try to do
	       a DNS lookup in case the address is not actually
	       numeric.  */
	    try {
		InetAddress.getByName(h);
	    } catch (Exception e) {
		/* We should really catch UnknownHostException
		   here, but a bug in JDK 1.4 causes it to throw
		   ArrayIndexOutOfBoundsException, e.g. if the
		   string is ":".  */
		MalformedURLException bad =
		    new MalformedURLException("Bad IPv6 address: " + h);
		EnvHelp.initCause(bad, e);
		throw bad;
	    }
	} else {
	    /* Tiny state machine to check valid host name.  This
	       checks the hostname grammar from RFC 1034 (DNS),
	       page 11.  A hostname is a dot-separated list of one
	       or more labels, where each label consists of
	       letters, numbers, or hyphens.  A label cannot begin
	       or end with a hyphen.  Empty hostnames are not
	       allowed.  Note that numeric IPv4 addresses are a
	       special case of this grammar.

	       The state is entirely captured by the last
	       character seen, with a virtual `.' preceding the
	       name.  We represent any alphanumeric character by
	       `a'.
		
	       We need a special hack to check, as required by the
	       RFC 2609 (SLP) grammar, that the last component of
	       the hostname begins with a letter.  Respecting the
	       intent of the RFC, we only do this if there is more
	       than one component.  If your local hostname begins
	       with a digit, we don't reject it.  */
	    final int hostLen = h.length();
	    char lastc = '.";
	    boolean sawDot = false;
	    char componentStart = 0;

	    loop:
	    for (int i = 0; i < hostLen; i++) {
		char c = h.charAt(i);
		boolean isAlphaNumeric = alphaNumericBitSet.get(c);
		if (lastc == '.")
		    componentStart = c;
		if (isAlphaNumeric)
		    lastc = 'a";
		else if (c == '-") {
		    if (lastc == '.")
			break; // will throw exception
		    lastc = '-";
		} else if (c == '.") {
		    sawDot = true;
		    if (lastc != 'a")
			break; // will throw exception
		    lastc = '.";
		} else {
		    lastc = '."; // will throw exception
		    break;
		}
	    }

	    try {
		if (lastc != 'a")
		    throw randomException;
		if (sawDot && !alphaBitSet.get(componentStart)) {
		    /* Must be a numeric IPv4 address.  In addition to
		       the explicitly-thrown exceptions, we can get
		       NoSuchElementException from the calls to
		       tok.nextToken and NumberFormatException from
		       the call to Integer.parseInt.  Using exceptions
		       for control flow this way is a bit evil but it
		       does simplify things enormously.  */
		    StringTokenizer tok = new StringTokenizer(h, ".", true);
		    for (int i = 0; i < 4; i++) {
			String ns = tok.nextToken();
			int n = Integer.parseInt(ns);
			if (n < 0 || n > 255)
			    throw randomException;
			if (i < 3 && !tok.nextToken().equals("."))
			    throw randomException;
		    }
		    if (tok.hasMoreTokens())
			throw randomException;
		}
	    } catch (Exception e) {
		throw new MalformedURLException("Bad host: \"" + h + "\"");
	    }
	}