/*
* Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved.
*
* The contents of this file are subject to the Sun Community Source License
* Jini Technology Core Platform, v.1.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of
* the License at http://java.sun.com/products/jini. Software distributed
* under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* CopyrightVersion v1.0_Jini
*/
package net.jini.core.discovery;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.Serializable;
import java.rmi.MarshalledObject;
import java.net.MalformedURLException;
import java.net.Socket;
import java.security.AccessController;
import java.security.PrivilegedAction;
import net.jini.core.lookup.ServiceRegistrar;
/**
* A utility class that performs unicast discovery.
*
* @author Bryan O'Sullivan
*/
public class LookupLocator implements Serializable {
private static final long serialVersionUID = 1448769379829432795L;
/**
* The port for both unicast and multicast boot requests.
*/
private static final short discoveryPort = 4160;
/**
* The current version of the unicast discovery protocol.
*/
private static final int protoVersion = 1;
/**
* The name of the host at which to perform discovery.
*
* @serial
*/
protected String host;
/**
* The port number on the host at which to perform discovery.
*
* @serial
*/
protected int port;
/**
* The timeout after which we give up waiting for a response from
* the lookup service.
*/
static final int defaultTimeout =
((Integer)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
int timeout = 60 * 1000;
try {
return Integer.getInteger("net.jini.discovery.timeout",
timeout);
} catch (SecurityException e) {
return new Integer(timeout);
}
}
})).intValue();
/**
* Construct a new LookupLocator object, set up to perform
* discovery to the given URL.
*
* The URL in question must be of the form jini://host/
* or jini://host:port/.
*
* @param url the URL to use
* @exception MalformedURLException the URL passed in could not be
* parsed
*/
public LookupLocator(String url) throws MalformedURLException {
if (!url.toLowerCase().startsWith("jini://"))
throw new MalformedURLException("not a jini-scheme URL");
int len = url.length();
char c = '\0';
int h;
for (h = 7; h < len && (c = url.charAt(h)) != ':' && c != '/'; h++) {
// do nothing
}
if (h == 7)
throw new MalformedURLException("empty hostname");
host = url.substring(7, h);
if (c == ':') {
int p;
for (p = h + 1; p < len && (c = url.charAt(p)) != '/'; p++) {
// do nothing
}
try {
port = Integer.parseInt(url.substring(h + 1, p));
if (port <= 0 || port >= 65536)
throw new MalformedURLException("port number out of range");
} catch (NumberFormatException e) {
throw new MalformedURLException("malformed port number");
}
} else {
port = discoveryPort;
}
}
/**
* Construct a new LookupLocator object, set to perform unicast
* discovery to the given host and port.
*
* @param host the name of the host to contact
* @param port the number of the port to connect to
*/
public LookupLocator(String host, int port) {
if (host == null)
throw new NullPointerException("null host");
if (port <= 0 || port >= 65536)
throw new IllegalArgumentException("port number out of range");
this.host = host;
this.port = port;
}
/**
* Return the name of the host this LookupLocator object should
* contact.
*/
public String getHost() {
return host;
}
/**
* Return the number of the port to which this LookupLocator
* object should connect.
*/
public int getPort() {
return port;
}
/**
* Perform unicast discovery and return the ServiceRegistrar
* object for the given lookup service. Unicast discovery is
* performed anew each time this method is called.
*
* @return the ServiceRegistrar for the lookup service denoted by
* this LookupLocator object
* @exception IOException an error occurred during discovery
* @exception ClassNotFoundException some discovery-related
* classes could not be found
*/
public ServiceRegistrar getRegistrar()
throws IOException, ClassNotFoundException
{
return getRegistrar(defaultTimeout);
}
/**
* Perform unicast discovery and return the ServiceRegistrar
* object for the given lookup service. Unicast discovery is
* performed anew each time this method is called.
*
* If a connection can be established to start unicast discovery
* but the remote end fails to respond within the given time
* limit, an exception is thrown.
*
* @param timeout the maximum time to wait for a response, in
* milliseconds
* @return the ServiceRegistrar for the lookup service denoted by
* this LookupLocator object
* @exception IOException an error occurred during discovery
* @exception ClassNotFoundException some discovery-related
* classes could not be found
*/
public ServiceRegistrar getRegistrar(int timeout)
throws IOException, ClassNotFoundException
{
Socket sock = new Socket(host, port);
try {
sock.setSoTimeout(timeout);
DataOutputStream dstr =
new DataOutputStream(sock.getOutputStream());
dstr.writeInt(protoVersion);
dstr.flush();
ObjectInputStream istr =
new ObjectInputStream(sock.getInputStream());
ServiceRegistrar registrar =
(ServiceRegistrar)((MarshalledObject)istr.readObject()).get();
for (int grpCount = istr.readInt(); --grpCount >= 0; ) {
istr.readUTF(); // ensure proper format, then discard
}
return registrar;
} finally {
try {
sock.close();
} catch (IOException e) {
// ignore
}
}
}
/**
* Return the string form of this LookupLocator, as a
* jini-scheme URL.
*/
public String toString() {
if (port != discoveryPort)
return "jini://" + host + ":" + port + "/";
return "jini://" + host + "/";
}
/**
* Two locators are equal if they have the same host and port.
*/
public boolean equals(Object o) {
if (o instanceof LookupLocator) {
LookupLocator oo = (LookupLocator) o;
return port == oo.port && host.equalsIgnoreCase(oo.host);
}
return false;
}
public int hashCode() {
return host.toLowerCase().hashCode() ^ port;
}
}