Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: edu/mit/media/hive/support/CellAddress.java


1   // $Id: CellAddress.java,v 2.1 1999/10/22 19:50:03 tucker Exp $
2   // Hive. Copyright (c) 1998-1999, The Massachusetts Institute of Technology.
3   // All rights reserved. Distributed with no warranty, without even the
4   // implied warranty of merchantability or fitness for a particular purpose.
5   // For more details see COPYING.GPL, the GNU General Public License.
6   
7   
8   package edu.mit.media.hive.support;
9   import java.net.*;
10  import java.io.Serializable;
11  import java.rmi.Naming;
12  
13  import edu.mit.media.hive.Global;
14  import edu.mit.media.hive.cell.RemoteCell;
15  
16  
17  /** This immutable class represents the URL of a Hive Cell. The
18   *protocol portion of the url is defined to be "hive", and will not
19   *allow the construction of urls with a different
20   *protocol. CellAddress follows the CISS (Common Internet Scheme
21   *Standard) Spec, although currently the file and ref portions of the
22   *URL are not used by the Hive system.
23   *
24   * WARNING: Java deviates from it's spec (at least on windows) in the
25   * DNS lookup behavior. Doing a
26   * InetAdderss.getByName(host).getHostName() does NOT return the fully
27   * qualified hostname as it should. Rather, some wierd caching
28   * behavior is causing the original argument to be returned. To work
29   * around this, we do a lookup to an IP Address and then do a lookup
30   * from that. This requires one more DNS lookup and is hence lower
31   * performance.
32  
33   * Also, hostnames are internally represented as they are returned by
34   * the DNS Cell, but for the purposes of equal and hashCode, the 
35   * hostname is converted to lowercase, because some DNS servers return
36   * inconsistent case information.
37  
38   * ANOTHER WARNING: Because this class is specified in the RemoteCell
39   * interface that is absolutely core to Hive, any changes in the
40   * SerialVersionID of this class will cause an incompatibility with
41   * any existing Hive cells. So think very carefully before performing
42   * even 'minor' modifications to this class.
43  
44   *  */
45  public class CellAddress implements Serializable {
46      
47      /** This is the default port that is assumed if one is not
48       * specified, or if -1 is used as an argument.
49       *  */
50      public static final int DEFAULT_PORT = Global.defaultPort;
51  
52      /** The fixed string representing the protocol used in Hive cells. 
53       * 
54       */
55      public static final String PROTOCOL = "hive";
56      public static final String RMI_NAME = "server";
57  
58      /** The port of the URL.
59       * 
60       */
61      private int port;
62  
63      /** The Host of the URL. Canonicalized at construction.
64       * 
65       */
66      private String host;
67  
68      /** The file of the URL.
69       * 
70       */
71      private String file; // Currently ignored.
72  
73      /** The Reference or Anchor of the URL.
74       * 
75       */
76      private String ref; // Currently ignored.
77  
78      /** The Hashcode of the URL. Created at construction.
79       * 
80       */
81      private int hashCode;
82  
83      /** This rather grotesque method does all the parsing of the
84       * string necessary to construct an URL. Anything that is
85       * unparsable, including URLs with a protocol other than "hive"
86       * will be rejected with a MalformedHiveURLException.  The
87       * constructor does a lot of work up front, including
88       * canonicalizing the hostname (which requires two DNS lookups,
89       * and calculating the hashcode.) Hosts that are not in DNS will
90       * throw a MalformedHiveURLException.
91       * 
92       * @param cellAddress String to be parsed into a CellAddress */
93      public CellAddress(String cellAddress) throws MalformedHiveURLException {
94    int hostIndex = 0; // First char of the host if present.
95    boolean portPresent = true; // Is there a port specified.
96    int portIndex; // The delimeter between host and port.
97    boolean filePresent = true; // Is there a file present?
98    int fileIndex; // First char of the file if present.
99    boolean refPresent = true; // Is there an ref specified.
100   int refIndex; // The delimeter between file and ref.
101 
102         if (cellAddress == null)
103             throw new MalformedHiveURLException();
104         
105   if (cellAddress.indexOf("://") >= 0) {
106       if (cellAddress.indexOf(PROTOCOL + "://") != 0) {
107     throw new MalformedHiveURLException();
108       }
109       else {
110     hostIndex = 7;
111       }
112   }
113   else /* Require the hostname to be prepended with hive://.  This prevents strings like 
114     "--nojoin" and "nowhere" from causing a DNS lookup, which locks hive if 
115     the network is down.  such things as hive://ivy:9999 still work though.
116        */
117       throw new MalformedHiveURLException();
118 
119   try {
120       fileIndex = cellAddress.indexOf('/', hostIndex);
121       refIndex = cellAddress.indexOf('#', hostIndex) + 1;
122   }
123   catch (StringIndexOutOfBoundsException e) {
124       throw new MalformedHiveURLException();
125       // There is no URL after the protocol which is not valid.
126   }
127   if (refIndex == 0) {
128       refIndex = cellAddress.length();
129       refPresent = false;
130   }
131   if ((fileIndex == -1) || ((refPresent) && (refIndex < fileIndex))) {
132       fileIndex = refIndex;
133       filePresent = false;
134   }
135   if (refIndex == 0) {
136       refPresent = false;
137       refIndex = fileIndex + 1;
138   }
139   portIndex = cellAddress.indexOf(':', hostIndex) + 1;  
140   if ((portIndex == 0) || (portIndex > fileIndex) || (portIndex > refIndex)) {
141       portIndex = fileIndex;
142       portPresent = false;
143   }
144 
145   /*
146     System.out.println("hostIndex: " + hostIndex);
147     if (portPresent)
148     System.out.println("portPresent");
149     else 
150     System.out.println("!portPresent");
151 
152     System.out.println("portIndex: " + portIndex);
153     if (filePresent)
154     System.out.println("filePresent");
155     else 
156     System.out.println("!filePresent");
157     System.out.println("fileIndex: " + fileIndex);
158     if (refPresent)
159     System.out.println("refPresent");
160     else 
161     System.out.println("!refPresent");
162     System.out.println("refIndex: " + refIndex);
163   */
164 
165   try {
166       if (portPresent) {
167     host = cellAddress.substring(hostIndex, portIndex - 1);
168     int endPort;
169     if ((!filePresent) && (!refPresent)) {
170         port = Integer.parseInt(cellAddress.substring(portIndex));
171     }
172     else if (fileIndex < refIndex)
173         port = Integer.parseInt(cellAddress.substring(portIndex,
174                   fileIndex));
175     else
176         port = Integer.parseInt(cellAddress.
177               substring(portIndex, refIndex - 1));
178       }
179       else {
180     host = cellAddress.substring(hostIndex, portIndex);
181     port = DEFAULT_PORT;
182       }
183       if (filePresent) {
184     if (refPresent) {
185         file = cellAddress.substring(fileIndex, refIndex - 1);
186         ref = cellAddress.substring(refIndex);
187     }
188     else {
189         file = cellAddress.substring(fileIndex, refIndex);
190         ref = "";
191     }
192       }
193       else {
194     file = "";
195     if (refPresent) {
196         ref = cellAddress.substring(refIndex);
197     }
198     else {
199         ref = "";
200     }
201       }    
202   }
203   catch (NumberFormatException e) {
204       throw new MalformedHiveURLException(); // Bad port specification.
205   }
206   catch(StringIndexOutOfBoundsException e) {
207       throw new MalformedHiveURLException(); // Missing port specification
208   }
209 
210   try {
211       String address = InetAddress.getByName(host).getHostAddress();
212       host = InetAddress.getByName(address).getHostName();
213       // Canonicalize hostname. Requires two DNS lookups.
214   }
215   catch (UnknownHostException e) {
216       throw new MalformedHiveURLException("Bad hostname");
217   }
218   if (port == -1) {
219       port = DEFAULT_PORT; // This matches the URL spec.
220   }
221   else if (port < -1) {
222       throw new MalformedHiveURLException(); // No negative ports other than -1 allowed.
223   }
224   calculateHashCode();
225     }
226 
227     /** This Constructor allows the creation of a CellAddress with individual arguments rather than a parseable string.
228      * 
229      * @param port 
230      * @param file 
231      * @param ref 
232      * @param host 
233      */
234     public CellAddress(String host, int port, String file, String ref) throws MalformedHiveURLException {
235   if ((host == null) || (host.equals(""))) {
236       throw new MalformedHiveURLException();
237   }
238   try {
239       String address = InetAddress.getByName(host).getHostAddress();
240       this.host = InetAddress.getByName(address).getHostName();
241   }
242   catch (UnknownHostException e) {
243       throw new MalformedHiveURLException("Bad hostname");
244   }
245   ;
246   if (port == -1) {
247       port = DEFAULT_PORT; // This matches the URL spec.
248   }
249   else if (port < -1) {
250       throw new MalformedHiveURLException();
251   }
252   this.port = port;  
253   if (file == null) {
254       this.file = "";
255   }
256   else {
257       this.file = file;
258   }
259   if (ref == null) {
260       this.ref = "";
261   }
262   else {
263       this.ref = ref;
264   }
265   calculateHashCode();
266     }
267 
268     /** A convenience method for the most common types of CellAddress
269      * 
270      * @param port 
271      * @param host 
272      */
273     public CellAddress(String host, int port) throws MalformedHiveURLException {
274   this(host, port, null, null);
275     }
276 
277     /** Returns a cell address for the local machine and the specified port.
278      */
279 
280     public static CellAddress createLocalCellAddress(int port) {
281   String host;
282 
283   try {
284       host = InetAddress.getByName(InetAddress.getLocalHost().getHostAddress()).getHostName();
285   }
286   catch (UnknownHostException e) {
287       Debug.error("Unable to lookup own address.");
288       return null;
289   }
290   try {
291       return new CellAddress(host, port);
292   }
293   catch (MalformedHiveURLException e) {
294       Debug.error("Somehow cannot create a CellAddress for the local machine.");
295       return null;
296   }
297     }
298 
299     /** Returns a cell address for the local machine and the default port.
300      */
301     public static CellAddress createLocalCellAddress() {
302   return createLocalCellAddress(DEFAULT_PORT);
303     }
304 
305     /** This method calculates the hashcode. All the fields must be valid before this
306      *  method is called.
307      */
308     private void calculateHashCode() {  
309   hashCode = getProtocol().hashCode() ^ getHost().toLowerCase().hashCode() ^ getPort() ^ file.hashCode() ^ ref.hashCode();
310     }
311 
312     /** Return the host of the CellAddress
313      * 
314      */
315     public String getHost() {
316   return host;
317     }
318 
319     /** return the port number of the CellAdress
320      * 
321      */
322     public int getPort() {
323   return port;
324     }
325 
326     /** Return the file of the cell address. May return the empty string.
327      * 
328      */
329     public String getFile() {
330   return file;
331     }
332 
333     /** Return the reference of the CellAdress. May return the empty string.
334      * 
335      */
336     public String getRef() {
337   return ref;
338     }
339 
340     /** Returns the protocol of the URL. (Always "hive")
341      * 
342      */
343     public String getProtocol() {
344   return PROTOCOL;
345     }
346 
347     /** Returns true if the argument refers to the same cell as the
348      * one defined.
349      * 
350      * @param obj */
351     public boolean equals(Object obj) {
352   if (obj instanceof CellAddress) {
353       CellAddress ca = (CellAddress) obj;
354       return (host.equalsIgnoreCase(ca.getHost()) &&
355         (port == ca.getPort()) &&
356         (file.equals(ca.getFile())) &&
357         (ref.equals(ca.getRef())));
358   }
359   return false;
360     }
361 
362     /** Returns a hashcode for the CellAddress.
363      *  */
364     public int hashCode() {
365   return hashCode;
366     }
367 
368     /** Returns the string representation of the CellAddress.
369      * 
370      */
371     public String toString() {
372   StringBuffer sb = new StringBuffer();
373   sb.append(PROTOCOL);
374   sb.append("://");
375   sb.append(host);
376   if (port != DEFAULT_PORT) {
377       sb.append(":");
378       sb.append(port);
379   }
380   if (!file.equals("")) {
381       sb.append(file);
382   }
383   if (!ref.equals("")) {
384       sb.append("#");
385       sb.append(ref);
386   }
387   return sb.toString();
388     }
389 
390     /** Returns true if the address is determined to specify the
391      * local machine.
392      * 
393      */
394     public boolean isLocal() {
395   try {
396       return InetAddress.getByName(host).equals(InetAddress.getLocalHost());
397   }
398   catch (UnknownHostException e) {
399       return false;
400   }
401     } 
402 
403     /** 
404      * Find the Cell on the specified remote host.
405      * @param address The host:port address
406      * @return the RemoteCell, or else null if not found.
407      */
408     public RemoteCell getRemoteCell() throws CellConnectException {
409   String name = "//" + host + ":" + port + "/" + RMI_NAME;
410   try {
411       RemoteCell rs = (RemoteCell)Naming.lookup( name );
412       return rs;
413   } 
414   catch( Exception error ) {
415       //      Debug.warning( "Couldn't find server at " + name );
416       throw new CellConnectException( error );
417   }
418     }
419 
420     /** Private testing method for test cases.
421      * 
422      * @param str 
423      */
424     private static void test(String str) {
425   System.out.println("Attempting to parse: " + str);
426   try{
427       CellAddress ca = new CellAddress(str);
428       System.out.println("Protocol: " + ca.getProtocol());
429       System.out.println("Host: " + ca.getHost());
430       System.out.println("Port: " + ca.getPort());
431       System.out.println("File: " + ca.getFile());
432       System.out.println("Ref: " + ca.getRef());
433       System.out.println(ca.toString());
434       System.out.println();
435   }
436   catch(MalformedHiveURLException e) {
437       System.out.println("Unparseable: " + str);
438       e.printStackTrace();
439   }
440     }
441 
442     /** Test cases to check the complicated parsing method.
443      * 
444      * @param args 
445      */
446     public static final void main(String[] args) {
447   try {
448       System.out.println(InetAddress.getByName("18.244.1.37").getHostName());
449   }
450   catch(Throwable e) {
451   }
452   CellAddress.test("hive://oroup:23235/");
453   CellAddress.test("hive://oroup:23237");
454   CellAddress.test("oroup:23237/");
455   CellAddress.test("oroup");
456   CellAddress.test("oroup/");
457   CellAddress.test("oroup/sds#dfsdf");
458   CellAddress.test("hive://oroup.mit.edu:23235/34:53#21:24");
459   CellAddress.test("hive://oroup:23/sdfdf#sdfdf");
460   CellAddress.test("hi://oroup:23235/");
461   CellAddress.test("hive://oroup:232435");
462   CellAddress.test("hive://oroup:232435#sdffd");
463   CellAddress.test("4334:232435#sd/ffd");
464     }
465 
466 }