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/IpNumber.java


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