river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: LookupLocator and ServiceRegistrar
Date Thu, 03 Jan 2013 00:21:29 GMT
Dennis Reedy wrote:
> Hi Peter,
>
> I dont think making the fields final should be a problem. I do think that instead of
having protected fields you should have getters, I prefer that to preserve encapsulation.
>   

Hmm, I agree, perhaps it's worth considering doing that too, the getters 
are already present, but there are no setters so the only use for direct 
access would be for a subclass to mutate the fields, but since they're 
now final...

Done!

Pity the internal state of the object has been published with Serialization.

The invariants aren't checked after deserialisation so it is possible to 
construct an illegal LookupLocator.

Cheers,

Peter.

> Dennis
>
> On Jan 2, 2013, at 557PM, Peter Firmstone wrote:
>
>   
>> Dennis,
>>
>> Is making LookupLocator fields final a breaking change for you?  I've posted it to
the list before, but not sure if you've seen it.
>>
>> The change makes LookupLocator immutable.
>>
>> Regards,
>>
>> Peter.
>>
>>
>> /*
>> * Licensed to the Apache Software Foundation (ASF) under one
>> * or more contributor license agreements.  See the NOTICE file
>> * distributed with this work for additional information
>> * regarding copyright ownership. The ASF licenses this file
>> * to you under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
>> *
>> * Unless required by applicable law or agreed to in writing, software
>> * distributed under the License is distributed on an "AS IS" BASIS,
>> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>> * See the License for the specific language governing permissions and
>> * limitations under the License.
>> */
>> package net.jini.core.discovery;
>>
>> import com.sun.jini.jeri.internal.runtime.Util;
>> import java.io.DataOutputStream;
>> import java.io.IOException;
>> import java.io.ObjectInputStream;
>> import java.io.Serializable;
>> import java.net.InetAddress;
>> import java.net.MalformedURLException;
>> import java.net.Socket;
>> import java.net.SocketException;
>> import java.net.URI;
>> import java.net.URISyntaxException;
>> import java.net.UnknownHostException;
>> import java.rmi.MarshalledObject;
>> import java.security.AccessController;
>> import java.security.PrivilegedAction;
>> import java.util.logging.Level;
>> import java.util.logging.Logger;
>> import javax.net.SocketFactory;
>> import net.jini.core.lookup.ServiceRegistrar;
>> import net.jini.discovery.ConstrainableLookupLocator;
>> import net.jini.discovery.LookupLocatorDiscovery;
>> import org.apache.river.impl.net.UriString;
>>
>> /**
>> * LookupLocator supports unicast discovery, using only version 1 of the
>> * unicast discovery protocol, which is deprecated. * <p>
>> * It's main purpose now is to contain a host name and port number, it is now
>> * immutable, since River 2.2.1, this may break overriding classes.
>> *
>> * <p>
>> * LookupLocator is used as a parameter in LookupLocatorDiscovery constructors. *
LookupLocatorDiscovery has methods to perform Discovery using either
>> * version 1 or 2 with constraints.
>> * ConstrainableLookupLocator is a subclass which uses discovery V1 or V2
>> * and enables the use of constraints.
>> *
>> * @since 1.0
>> * @see LookupLocatorDiscovery
>> * @see ConstrainableLookupLocator
>> */
>> 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 final String host;
>>   /**
>>    * The port number on the host at which to perform discovery.
>>    *
>>    * @serial
>>    */
>>   protected final 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() {
>>       Integer timeout = Integer.valueOf(60 * 1000);
>>       try {
>>           Integer val = Integer.getInteger(
>>                   "net.jini.discovery.timeout",
>>                   timeout);
>>           return (val.intValue() < 0 ? timeout : val);
>>       } catch (SecurityException e) {
>>           return timeout;
>>       }
>>       }
>>   })).intValue();
>>
>>   /**
>>    * Construct a new <code>LookupLocator</code> object, set up to perform
>>    * discovery to the given URL.  The <code>host</code> and <code>port</code>
>>    * fields will be populated with the <i>host</i> and <i>port</i>
>>    * components of the input URL.  No host name resolution is attempted.
>>    * <p>
>>    * The syntax of the URL must be that of a <i>hierarchical</i>
>>    * {@link java.net.URI} with a <i>server-based naming authority</i>.
>>    * Requirements for the components are as follows:
>>    * <ul>
>>    * <li> A <i>scheme</i> of <code>"jini"</code> must
be present.
>>    * <li> A <i>server-based naming authority</i> must be
>>    * present; <i>user-info</i> must not be present. The <i>port</i>,
if
>>    * present, must be between 1 and 65535 (both included). If no port is
>>    * specified, a default value of <code>4160</code> is used.
>>    * <li> A <i>path</i> if present, must be
>>    * <code>"/"</code>; <i>path segment</i>s must not be present.
>>    * <li> There must not be any other components present.
>>    * </ul>
>>    * <p>
>>    * The four allowed forms of the URL are thus:
>>    * <ul>
>>    * <li> <code>jini://</code><i>host</i>
>>    * <li> <code>jini://</code><i>host</i><code>/</code>
>>    * <li> <code>jini://</code><i>host</i><code>:</code><i>port</i>
>>    * <li>
>>    * <code>jini://</code><i>host</i><code>:</code><i>port</i><code>/</code>
>>    *
>>    * @param url the URL to use
>>    * @throws MalformedURLException <code>url</code> could not be parsed
>>    * @throws NullPointerException if <code>url</code> is <code>null</code>
>>    */
>>   public LookupLocator(String url) throws MalformedURLException {
>>   URI uri = parseURI(url);
>>       host = uri.getHost();
>>       port = uri.getPort();
>>   }
>>
>>   /**
>>    * Construct a new <code>LookupLocator</code> object, set to perform
unicast
>>    * discovery to the input <code>host</code> and <code>port</code>.
 The
>>    * <code>host</code> and <code>port</code> fields will
be populated with the
>>    * <code>host</code> and <code>port</code> arguments. 
No host name
>>    * resolution is attempted.
>>    * <p>The <code>host</code>
>>    * argument must meet any one of the following syntactical requirements:
>>    * <ul>
>>    * <li>A host as required by a <i>server-based naming authority</i>
in
>>    * section 3.2.2 of <a href="http://www.ietf.org/rfc/rfc2396.txt">
>>    * <i>RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax</i></a>
>>    * <li>A literal IPv6 address as defined by
>>    * <a href="http://www.ietf.org/rfc/rfc2732.txt">
>>    * <i>RFC 2732: Format for Literal IPv6 Addresses in URL's</i></a>
>>    * <li>A literal IPv6 address as defined by
>>    * <a href="http://www.ietf.org/rfc/rfc3513.txt">
>>    * <i>RFC 3513: Internet Protocol Version 6 (IPv6) Addressing Architecture
>>    * </i></a>
>>    * </ul>
>>    *
>>    * @param host the name of the host to contact
>>    * @param port the number of the port to connect to
>>    * @throws IllegalArgumentException if <code>port</code> is not between
>>    * 1 and 65535 (both included) or if <code>host</code> cannot be parsed.
>>    * @throws NullPointerException if <code>host</code> is <code>null</code>
>>    */
>>   public LookupLocator(String host, int port) {
>>       if (host == null) throw new NullPointerException("null host");
>>   StringBuilder sb = new StringBuilder();
>>       sb.append("jini://").append(host);
>>       if ( port != -1 ) { //URI compliance -1 is converted to discoveryPort.
>>           sb.append(":").append(port);
>>       }
>>       try {
>>           URI uri = parseURI(sb.toString());
>>           this.host = uri.getHost();
>>           this.port = uri.getPort();
>>       } catch (MalformedURLException ex) {
>>           throw new IllegalArgumentException("host cannot be parsed", ex);
>>       }
>>   }
>>     private URI parseURI(String url) throws MalformedURLException{
>>       if (url == null) {
>>       throw new NullPointerException("url is null");
>>   }
>>   URI uri = null;
>>   try {
>>           url = UriString.escapeIllegalCharacters(url);
>>       uri = new URI(url);
>>           uri = UriString.normalise(uri);
>>   } catch (URISyntaxException e) {
>>       MalformedURLException mue =
>>       new MalformedURLException("URI parsing failure: " + url);
>>       mue.initCause(e);
>>       throw mue;
>>   }
>>   if (!uri.isAbsolute()) throw new MalformedURLException("no scheme specified: "
+ url);
>>   if (uri.isOpaque()) throw new MalformedURLException("not a hierarchical url: "
+ url);
>>   if (!uri.getScheme().equals("jini")) throw new MalformedURLException("Invalid URL
scheme: " + url);
>>     String uriPath = uri.getPath();
>>   if ((uriPath.length() != 0) && (!uriPath.equals("/"))) {
>>       throw new MalformedURLException(
>>       "URL path contains path segments: " + url);
>>   }
>>   if (uri.getQuery() != null) throw new MalformedURLException("invalid character,
'?', in URL: " + url);
>>   if (uri.getFragment() != null) throw new MalformedURLException("invalid character,
'#', in URL: " + url);
>>       if (uri.getUserInfo() != null) throw new MalformedURLException("invalid character,
'@', in URL host: " + url);
>>       if ((uri.getHost()) == null) {
>>           // authority component does not exist - not a hierarchical URL
>>           throw new MalformedURLException(
>>               "Not a hierarchical URL: " + url);
>>       }
>>       int poRt = uri.getPort();
>>       if (poRt == -1) {
>>           poRt = discoveryPort;
>>           try {
>>               uri = new URI(uri.getScheme(), uri.getRawUserInfo(), uri.getHost(),
poRt, uri.getRawPath(), uri.getRawQuery(), uri.getRawFragment());
>>           } catch (URISyntaxException e) {
>>               MalformedURLException mue =
>>       new MalformedURLException("recreation of URI with discovery port failed");
>>               mue.initCause(e);
>>               throw mue;
>>           }
>>       }
>>     if ((uri.getPort() <= 0) || (uri.getPort() >= 65536)) {
>>       throw new MalformedURLException("port number out of range: " + url);
>>   }
>>       return uri;
>>   }
>>
>>   /**
>>    * Returns the name of the host that this instance should contact.
>>    * <code>LookupLocator</code> implements this method to return
>>    * the <code>host</code> field.
>>    *
>>    * @return a String representing the host value
>>    */
>>   public String getHost() {
>>   return host;
>>   }
>>
>>   /**
>>    * Returns the number of the port to which this instance should connect.
>>    * <code>LookupLocator</code> implements this method to return the
>>    * <code>port</code> field.
>>    *
>>    * @return an int representing the port value
>>    */
>>   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.
>>    * <code>LookupLocator</code> implements this method to simply invoke
>>    * {@link #getRegistrar(int)} with a timeout value, which is determined
>>    * by the value of the <code>net.jini.discovery.timeout</code> system
>>    * property.  If the property is set, is not negative, and can be parsed as
>>    * an <code>Integer</code>, the value of the property is used as the
timeout
>>    * value. Otherwise, a default value of <code>60</code> seconds is
assumed.
>>    *
>>    * @return the ServiceRegistrar for the lookup service denoted by
>>    * this LookupLocator object
>>    * @throws IOException an error occurred during discovery
>>    * @throws ClassNotFoundException if a class required to unmarshal the
>>    * <code>ServiceRegistrar</code> proxy cannot be found
>>    */
>>   public ServiceRegistrar getRegistrar()
>>   throws IOException, ClassNotFoundException
>>   {
>>   return getRegistrar(defaultTimeout);
>>   }
>>
>>   /**
>>    * Perform unicast discovery and return the ServiceRegistrar
>>    * object for the given lookup service, with the given discovery timeout.
>>    * Unicast discovery is performed anew each time this method is called.
>>    * <code>LookupLocator</code> implements this method to use the values
>>    * of the <code>host</code> and <code>port</code> field
in determining
>>    * the host and port to connect to.
>>    *
>>    * <p>
>>    * 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.  A value of <code>0</code> specifies an infinite timeout.
>>    * @return the ServiceRegistrar for the lookup service denoted by
>>    * this LookupLocator object
>>    * @throws IOException an error occurred during discovery
>>    * @throws ClassNotFoundException if a class required to unmarshal the
>>    * <code>ServiceRegistrar</code> proxy cannot be found
>>    * @throws IllegalArgumentException if <code>timeout</code> is negative
>>    */
>>   public ServiceRegistrar getRegistrar(int timeout)
>>   throws IOException, ClassNotFoundException
>>   {
>>   InetAddress[] addrs = null;
>>   try {
>>       addrs = InetAddress.getAllByName(host);
>>   } catch (UnknownHostException uhe) {
>>       // Cannot resolve the host name, maybe the socket implementation
>>       // can do it for us.
>>       Socket sock = new Socket(host, port);
>>       return getRegistrarFromSocket(sock, timeout);
>>   }
>>   IOException ioEx = null;
>>   SecurityException secEx = null;
>>   ClassNotFoundException cnfEx = null;
>>   for (int i = 0; i < addrs.length; i++) {
>>       try {
>>               Socket sock = new Socket(addrs[i], port);
>>       return getRegistrarFromSocket(sock, timeout);
>>       } catch (ClassNotFoundException ex) {
>>       cnfEx = ex;
>>       } catch (IOException ex) {
>>       ioEx = ex;
>>       } catch (SecurityException ex) {
>>       secEx = ex;
>>       }
>>   }
>>   // All our attempts failed. Throw ClassNotFoundException, IOException,
>>   // SecurityException in that order of preference.
>>   if (cnfEx != null) {
>>       throw cnfEx;
>>   }
>>   if (ioEx != null) {
>>       throw ioEx;
>>   }
>>   assert (secEx != null);
>>   throw secEx;
>>   }
>>
>>   // Convenience method to do unicast discovery on a socket
>>   private static ServiceRegistrar getRegistrarFromSocket(Socket sock,
>>                              int timeout)
>>   throws IOException, ClassNotFoundException
>>   {
>>   try {
>>       sock.setSoTimeout(timeout);
>>       try {
>>       sock.setTcpNoDelay(true);
>>       } catch (SocketException e) {
>>       // ignore possible failures and proceed anyway
>>       }
>>       try {
>>       sock.setKeepAlive(true);
>>       } catch (SocketException e) {
>>       // ignore possible failures and proceed anyway
>>       }
>>       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 URL of scheme
>>    * <code>"jini"</code>.
>>    */
>>   public String toString() {
>> //    if (port != discoveryPort)
>>       return "jini://" + getHost0(host) + ":" + port + "/";
>> //    return "jini://" + getHost0(host) + "/";
>>   }
>>
>>   /**
>>    * Two locators are equal if they have the same <code>host</code> and
>>    * <code>port</code> fields. The case of the <code>host</code>
is ignored.
>>    * Alternative forms of the same IPv6 addresses for the <code>host</code>
>>    * value are treated as being unequal.
>>    */
>>   public boolean equals(Object o) {
>>   if (o == this) {
>>       return true;
>>   }
>>   if (o instanceof LookupLocator) {
>>       LookupLocator oo = (LookupLocator) o;
>>       return port == oo.port && host.equalsIgnoreCase(oo.host);
>>   }
>>   return false;
>>   }
>>
>>   /**
>>    * Returns a hash code value calculated from the <code>host</code>
and
>>    * <code>port</code> field values.
>>    */
>>   public int hashCode() {
>>   return host.toLowerCase().hashCode() ^ port;
>>   }
>>     // Checks if the host is an RFC 3513 IPv6 literal and converts it into
>>   // RFC 2732 form.
>>   private static String getHost0(String host) {
>>   if ((host.indexOf(':') >= 0) && (host.charAt(0) != '[')) {
>>       // This is a 3513 form IPv6 literal
>>       return '[' + host + ']';
>>   } else {
>>       return host;
>>   }
>>   }
>> }
>>
>>     
>
>
>   


Mime
View raw message