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

Quick Search    Search Deep

Source code: com/voytechs/jnetstream/primitive/address/Address.java


1   /*
2    * File: Address.java
3    * Auth: Mark Bednarczyk
4    * Date: 2001-08-05
5    *   Id: $Id: Address.java,v 1.1.1.1 2003/09/22 16:32:11 voytechs Exp $
6    ********************************************
7    Copyright (C) 2003  Mark Bednarczyk
8   
9    This program is free software; you can redistribute it and/or
10   modify it under the terms of the GNU General Public License
11   as published by the Free Software Foundation; either version 2
12   of the License, or (at your option) any later version.
13  
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18  
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22   ********************************************
23   * $Log: Address.java,v $
24   * Revision 1.1.1.1  2003/09/22 16:32:11  voytechs
25   * Initial import.
26   *
27   * Revision 1.1  2001/09/04 15:33:55  markbe
28   * Initial revision
29   *
30   */
31  package com.voytechs.jnetstream.primitive.address;
32  
33  import com.voytechs.jnetstream.util.NumberUtils;
34  
35  import java.lang.IllegalArgumentException;
36  import java.net.InetAddress;
37  import java.util.*;
38  import java.io.Serializable;
39  
40  /**
41   * A Class for storing IP Addresses
42   * Currently is only designed to utilize IPv4 (32bit) addresses.
43   * There are various functions for converting the IP address to a LONG.
44   * Why would you want to use a long for storage of an IP address, in my
45   * case I store IP address in a database as an UNSIGNED INT, java does not
46   * have unsigned numbers so you have to go to next bigger primitive type to store
47   * it or do like other implementations do store the address in a byte array.
48   */
49  public class Address {
50  
51    public static final int DEFAULT_NUMBER_BASE = 10; // Base is the default.
52    private int defaultNumberBase = DEFAULT_NUMBER_BASE;
53  
54    /* Internal attributes */
55    public static final boolean debug = false;
56  
57    /**
58     * Array which stores the IP address bytes.
59     * This is a variable array so that both v4 and v6 addresses.
60     */
61    protected byte [] address = null;
62  
63    protected char separator = '.';
64    protected char[] format = null;
65  
66    /**
67     * Special internal use only constructor that does not initialize the
68     * Address right away but later.
69     * @param stringAddress takes the IP address as a string.
70     */
71    protected Address() {
72    }
73  
74    /**
75     * Main constructor taking the array of bytes as the address
76     */
77    public Address(byte [] address) {
78  
79      this.address = address;
80  
81    }
82  
83    /**
84     * Main constructor taking the array of bytes as the address
85     */
86    public Address(Address ad) {
87  
88      this.address = ad.address;
89  
90    }
91  
92    public void setAddress(byte[] address) { this.address = address; }
93    public void setSeparator(char separator) { this.separator = separator; format = null;}
94    public void setFormat(String format) { this.format = format.toCharArray(); }
95    public void setFormat(char[] format) { this.format = format; }
96  
97    public void setRadix(int radix) {
98      defaultNumberBase = radix;
99    }
100 
101   public int getRadix() {
102     return(defaultNumberBase);
103   }
104 
105   /**
106    * This method INVERTs (Java statment <CODE>~</CODE>) Address object to another Address object.
107    * Every byte is ANDed with every other byte
108    * in the corresponding object. If number of bytes in the first number
109    * does not match the number in the second object then an IllegalArgumentException
110    * is thrown.
111    */
112   public byte [] INVERT() {
113     return(INVERT(address));
114   }
115 
116   /**
117    * This method ORs Address object to another Address object.
118    * Every byte is ANDed with every other byte
119    * in the corresponding object. If number of bytes in the first number
120    * does not match the number in the second object then an IllegalArgumentException
121    * is thrown.
122    * @return A new byte array is returned with mask applied to the ip number object.
123    */
124   public static byte [] INVERT(byte[] a) {
125 
126     byte [] v = new byte [a.length];
127 
128     for(int i = 0; i < v.length; i ++) {
129       int A = (a[i] < 0 ? a[i] + 256 : a[i]);
130       v[i] = (byte)(~A); // A ~ (tilde) INVERTs the bits inside the integer. A 0 becomes a 1 and 1 a 0.
131     }
132 
133     return(v);
134   }
135 
136   /**
137    * This method EORs (Exclusive OR) Address object to another Address object.
138    * Every byte is ANDed with every other byte
139    * in the corresponding object. If number of bytes in the first number
140    * does not match the number in the second object then an IllegalArgumentException
141    * is thrown.
142    * @return A new byte array is returned with mask applied to the ip number object.
143    */
144   public byte [] EOR(Address b) {
145     return(EOR(address, b.toByteArray()));
146   }
147 
148   /**
149    * This method ORs Address object to another Address object.
150    * Every byte is ANDed with every other byte
151    * in the corresponding object. If number of bytes in the first number
152    * does not match the number in the second object then an IllegalArgumentException
153    * is thrown.
154    * @return A new byte array is returned with mask applied to the ip number object.
155    */
156   public static byte [] EOR(byte[] a, byte[] b) {
157     if(a.length != b.length)
158       throw new IllegalArgumentException("Can AND 2 Address objects. " + 
159                                           "Their byte counts do not match. " + 
160                                           "Excecting Equal number of bytes in each Address object.");
161 
162     byte [] v = new byte [a.length];
163 
164     for(int i = 0; i < v.length; i ++) {
165       int A = (a[i] < 0 ? a[i] + 256 : a[i]);
166       int B = (b[i] < 0 ? b[i] + 256 : b[i]);
167       v[i] = (byte)(B ^ A);
168     }
169 
170     return(v);
171   }
172 
173   /**
174    * This method ORs Address object to another Address object.
175    * Every byte is ANDed with every other byte
176    * in the corresponding object. If number of bytes in the first number
177    * does not match the number in the second object then an IllegalArgumentException
178    * is thrown.
179    * @return A new byte array is returned with mask applied to the ip number object.
180    */
181   public byte [] OR(Address b) {
182     return(OR(address, b.toByteArray()));
183   }
184 
185   /**
186    * This method ORs Address object to another Address object.
187    * Every byte is ANDed with every other byte
188    * in the corresponding object. If number of bytes in the first number
189    * does not match the number in the second object then an IllegalArgumentException
190    * is thrown.
191    * @return A new byte array is returned with mask applied to the ip number object.
192    */
193   public static byte [] OR(byte[] a, byte[] b) {
194     if(a.length != b.length)
195       throw new IllegalArgumentException("Can AND 2 Address objects. " + 
196                                           "Their byte counts do not match. " + 
197                                           "Excecting Equal number of bytes in each Address object.");
198 
199     byte [] v = new byte [a.length];
200 
201     for(int i = 0; i < v.length; i ++) {
202       int A = (a[i] < 0 ? a[i] + 256 : a[i]);
203       int B = (b[i] < 0 ? b[i] + 256 : b[i]);
204       v[i] = (byte)(B | A);
205     }
206 
207     return(v);
208   }
209 
210 
211   /**
212    * This method ANDs Address object to another Address object.
213    * Every byte is ANDed with every other byte
214    * in the corresponding object. If number of bytes in the first number
215    * does not match the number in the second object then an IllegalArgumentException
216    * is thrown.
217    * @return A new byte array is returned with mask applied to the ip number object.
218    */
219   public byte [] AND(Address b) {
220     return(AND(address, b.toByteArray()));
221   }
222 
223   /**
224    * This method ANDs Address object to another Address object.
225    * Every byte is ANDed with every other byte
226    * in the corresponding object. If number of bytes in the first number
227    * does not match the number in the second object then an IllegalArgumentException
228    * is thrown.
229    * @return A new byte array is returned with mask applied to the ip number object.
230    */
231   public static byte [] AND(byte[] a, byte[] b) {
232     if(a.length != b.length)
233       throw new IllegalArgumentException("Can AND 2 Address objects. " + 
234                                           "Their byte counts do not match. " + 
235                                           "Excecting Equal number of bytes in each Address object.");
236 
237     byte [] v = new byte [a.length];
238 
239     for(int i = 0; i < v.length; i ++) {
240       int A = (a[i] < 0 ? a[i] + 256 : a[i]);
241       int B = (b[i] < 0 ? b[i] + 256 : b[i]);
242       v[i] = (byte)(B & A);
243     }
244 
245     return(v);
246   }
247 
248   protected byte getByte(int index) {
249     byte [] ad = address;
250     return( (byte)(ad[index] < 0 ? ad[index] + 256 : ad[index]) ); // Take care of the pescy sign for bytes.
251   }
252 
253   public static byte getByte(byte b) {
254     return( (byte)(b < 0 ? b + 256 : b) ); // Take care of the pescy sign for bytes.
255   }
256 
257 
258 
259   /**
260    * Compare our byte values for IP address to the object's.
261    * If length do not match then the objects are considered unequal.
262    * If byte counts are the same then a byte for byte comparison is made and
263    * appropriate result return.
264    * @param o Address object to campare to.
265    * @return true means both objects are equal. This means both Addresss have the same number
266    * of bytes and each of those bytes is equal (==).
267    * @exception If either object is not of IP v4 or V6. If their byte lengths do not follow the standard.
268    */
269   public boolean equals(Object o) {
270 
271     if( o instanceof Address) {
272 
273       /**
274        * Let the compare function figure it out.
275        */
276       if(compareTo(o) == 0)
277         return(true);
278       else
279         return(false);
280     }
281 
282     return(false);
283   }
284 
285   public int compareTo(Object o) {
286     
287     if(o instanceof Address) {
288       return(compare(this, (Address)o));
289     }
290 
291     throw new ClassCastException();
292   }
293 
294   /**
295    * Compare our byte values for IP address to the object's.
296    * If length do not match then the one with smaller number of bytes
297    * is considered less then the one with more bytes (V6 is always > V4).
298    * If byte counts are the same then a byte for byte comparison is made and
299    * appropriate result return.
300    * @param a Address object to campare to.
301    * @param b Address object to campare with.
302    * @return -1 means we are less then a, 0 means we are equal, 1 means we are greater then a.
303    * @exception If either object is not of IP v4 or V6. If their byte lengths do not follow the standard.
304    */
305   public static int compare(Address a, Address b) throws IllegalArgumentException {
306 
307     if(debug)
308       System.out.println("Address::compare(" + a + ", " + b);
309 
310     /**
311      * First we compare the length of the address. If we
312      * are comparing V6 with V4 type addresses, always return
313      * as V6 is greater then V4, even if the actual data of the shorter
314      * V4 address would indicate otherwise. This will have the affect
315      * of sorters putting V4 address together while V6 separately.
316      *
317      * If length of addresses are the same then do a byte for byte
318      * comparison.
319      */
320     if(a.address.length < b.address.length)
321       return(-1);
322 
323     if(a.address.length > b.address.length)
324       return(1);
325 
326     /**
327      * Lengths are the same.
328      * If length of addresses are the same then do a byte for byte
329      * comparison. At any point if there is a difference in values
330      * immediately stop and return which one makes that bigger.
331      *
332      * Otherwise if all bytes compared equal then return 0.
333      */
334     for(int i = 0; i < a.address.length; i ++) {
335       if(a.getByte(i) < b.getByte(i))
336         return(-1);
337 
338       if(a.getByte(i) > b.getByte(i))
339         return(1);
340     }
341 
342     return(0);
343 
344   }
345 
346   public static int compare(Address a, byte[] b) throws IllegalArgumentException {
347 
348     if(debug)
349       System.out.println("Address::compare(" + a + ", " + b);
350 
351     /**
352      * First we compare the length of the address. If we
353      * are comparing V6 with V4 type addresses, always return
354      * as V6 is greater then V4, even if the actual data of the shorter
355      * V4 address would indicate otherwise. This will have the affect
356      * of sorters putting V4 address together while V6 separately.
357      *
358      * If length of addresses are the same then do a byte for byte
359      * comparison.
360      */
361     if(a.address.length < b.length)
362       return(-1);
363 
364     if(a.address.length > b.length)
365       return(1);
366 
367     /**
368      * Lengths are the same.
369      * If length of addresses are the same then do a byte for byte
370      * comparison. At any point if there is a difference in values
371      * immediately stop and return which one makes that bigger.
372      *
373      * Otherwise if all bytes compared equal then return 0.
374      */
375     for(int i = 0; i < a.address.length; i ++) {
376       if(a.getByte(i) < b[i])
377         return(-1);
378 
379       if(a.getByte(i) > b[i])
380         return(1);
381     }
382 
383     return(0);
384 
385   }
386 
387 
388 
389   /**
390    * Convert a long (32 bits) to byte array (4 bytes).
391    * @param address IP address. Only first 32 bits are important
392    */
393   public static byte[] longToByteArray(long longAddress) {
394 
395     byte [] ba = new byte [4];
396 
397     ba[0] = (byte)((longAddress & 0xFF000000L) >> 24);
398     ba[1] = (byte)((longAddress & 0x00FF0000L) >> 16);
399     ba[2] = (byte)((longAddress & 0x0000FF00L) >> 8);
400     ba[3] = (byte)((longAddress & 0x000000FFL));
401 
402     return(ba);
403   }
404 
405   /**
406    * Returns a byte[] representing this Address.
407    *
408    * @return address of this number.
409    */
410   public byte[] toByteArray() {
411     return(address);
412   }
413 
414   /**
415    * Gets the byte array representation of this address.
416    * @return byte array which is the address. Length determines the type of address.
417    */
418   public byte [] byteArrayValue() {
419     return(address);
420   }
421 
422   /**
423    * Get the Address number value in a dot notation.
424    */
425   public String stringValue() {
426     return(toString() );
427   }
428 
429   /**
430    * Set the internal address array.
431    */
432   protected void setByteArrayAddress(byte [] address) {
433     this.address = address;
434   }
435 
436   /**
437    * Return current IP address as byte array, for V4 that will be 4 bytes
438    * for V6 16.
439    * @param address String representation of IP address. Both V4 and V6 type addresses are accepted.
440    * @return IP Byte array representation of the address. Check Array.length to get the size of the array.
441    */
442   public static byte[] parseByteArray(String address, int size, char separator) throws IllegalArgumentException {
443 
444     StringTokenizer st;
445     byte [] v;
446 
447     st = new StringTokenizer(address, "" + separator);
448     v = new byte [size];
449 
450     for(int i = 0; i < v.length; i ++) {
451       String t = st.nextToken();
452 
453       if(t == null && i != v.length) {
454         throw new IllegalArgumentException("Illegal IP address format. String has too few byte elements.");
455       }
456 
457       v[i] = (byte)Integer.parseInt(t);
458     }
459 
460     return(v);
461   }
462 
463   /**
464    * Convert to dot notation string representation of the address
465    * @return IP address in the dot notation.
466    */
467   public String toString() {
468 
469     if(format != null)
470       return( toString(address, defaultNumberBase, format) );
471     else
472       return( toString(address, defaultNumberBase, separator) );
473 
474   }
475 
476   /**
477    * Convert internal address to a string. Use separator 
478    * to convert to string.
479    */
480   public static String toString(byte [] address, int radix, char separator) {
481     String s = "";
482 
483     for(int i = 0; i < address.length; i ++) {
484       if(i != 0)
485         s += separator;
486 
487       s += ""  + Integer.toString((((int)address[i]) & 0xFF), radix); // Convert signed byte to unsigned integer
488     }
489 
490     return(s);
491   }
492 
493   /**
494    * Convert internal address to a string. Use separator 
495    * to convert to string.
496    */
497   public static String toString(byte [] address, int radix, char[] format) {
498     String s = "";
499 
500     int a = 0;
501     for(int i = 0; i < format.length; i ++) {
502 
503       if(format[i] == 'x') {
504         if( a == address.length)
505           throw new IllegalArgumentException("Format length does not match length of byte array.");
506 
507         if(radix == 16)
508           s += NumberUtils.toHexString(address[a++]);
509         else
510           s += Integer.toString((((int)address[a++]) & 0xFF), radix);
511       }
512       else if(format[i] == 'X') {
513         if( (a +1) == address.length)
514           throw new IllegalArgumentException("Format length does not match length of byte array.");
515 
516         if(radix == 16)
517           s += NumberUtils.toHexString(address[a++]).toUpperCase();
518         else
519           s += Integer.toString((((int)address[a++]) & 0xFF), radix).toUpperCase();
520       }
521       else {
522         s += format[i];
523       }
524     }
525 
526     if(a != address.length)
527       throw new IllegalArgumentException("Format length does not match length of address .");
528 
529     return(s);
530   }
531 
532   /**
533    * Test function for Address
534    * @param args command line arguments
535    */
536   public static void main(String [] args) {
537     
538     Address ip = new Address(new byte[] { (byte)192, (byte)168, 1, 2} );
539     Address ip2 = new Address(new byte[] { (byte)192, (byte)168, 1, 3} );
540     Address ether = new Address(new byte[] { (byte)192, (byte)168, 1, 3, 6, 8} );
541     ether.setFormat("x:x:x:x:x:x");
542     ether.setRadix(16);
543 
544     System.out.println("Converted IP=" + ip.toString());
545     System.out.println("Converted ether=" + ether.toString());
546 
547     System.out.println(ip.toString() + "=" + ip2.toString() + " : " + ip.equals(ip2) + " " + ip2.equals(ip));
548     System.out.println(ip.toString() + "<=>" + ip2.toString() + " : " + ip.compareTo(ip2) + " " + ip2.compareTo(ip));
549   }
550 
551 } /* END OF: Address */