/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2007-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.model.discovery;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.opennms.core.utils.ByteArrayComparator;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.ThreadCategory;
/**
* <P>
* The IPAddressRange object is used to encapsulate the starting and ending
* points of a contiguous IPv4/IPv6 Address range. The class can then generate
* either an Enumeration or Iterator that can be used to cycle through the range
* of addresses by the object's user.
* </P>
*
* @author <A HREF="mailto:sowmya@opennms.org">Sowmya </A>
* @author <A HREF="mailto:weave@oculan.com">Brian Weaver </A>
*/
public final class IPAddrRange implements Iterable<InetAddress> {
/**
* The starting address for the object.
*/
private final byte[] m_begin;
/**
* The ending address for the object.
*/
private final byte[] m_end;
/**
* <P>
* This class is used to enumerate or iterate through one contiguous set of
* IP addresses. The class can either be used as an iterator or as an
* enumeration. In java 1.2 iterators were introduced and are being used in
* favor of enumerations in new classes.
* </P>
*
*/
static class IPAddressRangeGenerator implements Enumeration<InetAddress>, Iterator<InetAddress> {
/**
* The next address in the range.
*/
private BigInteger m_next;
/**
* The last address in the range. The remaining address are in the range
* of [m_next .. m_end].
*/
private final BigInteger m_end;
/**
* Converts an integer to an InetAdrress object and discards any
* exceptions. If the address cannot be constructed then a null
* reference is returned.
*
* @param addr
* The IP address value, in network order.
*
* @return A {@link java.net.InetAddress} object.
*/
static InetAddress make(BigInteger addr) {
InetAddress naddr = null;
try {
naddr = InetAddressUtils.convertBigIntegerIntoInetAddress(addr);
} catch (UnknownHostException uhE) {
naddr = null;
}
return naddr;
}
/**
* <P>
* Creates a generator object that iterates over the range from start to
* end, inclusive.
* </P>
*
* @param start
* The start address.
* @param end
* The ending address.
*
* @exception java.lang.IllegalArgumentException
* Thrown if the start address is greater than the ending
* address.
*
*/
IPAddressRangeGenerator(byte[] start, byte[] end) {
if (new ByteArrayComparator().compare(start, end) > 0)
throw new IllegalArgumentException("start must be less than or equal to end");
m_next = new BigInteger(1, start);
m_end = new BigInteger(1, end);
}
/**
* <P>
* Returns true if the enumeration object has more elements remaining.
* </P>
*/
public boolean hasMoreElements() {
return (m_next.compareTo(m_end) <= 0);
}
/**
* <P>
* Returns the next element in the enumeration. If there is no element
* left in the enumeration an exception will be thrown.
* </P>
*
* @exception java.util.NoSuchElementException
* Thrown if the collection is exhausted.
*/
public InetAddress nextElement() {
if (!hasMoreElements())
throw new NoSuchElementException("End of Range");
InetAddress element = make(m_next);
m_next = m_next.add(new BigInteger("1"));
return element;
}
/**
* <P>
* Returns true if there are more elements in the iteration.
* </P>
*/
public boolean hasNext() {
return hasMoreElements();
}
/**
* <P>
* Returns the next object in the iteration. If there are no objects
* left in the iteration an exception will be thrown.
* </P>
*
* @exception java.util.NoSuchElementException
* Thrown if the collection is exhausted.
*/
public InetAddress next() {
return nextElement();
}
/**
* <P>
* The remove method of the iterator interface is considered optional
* for the implemetor. For the purposes of this class it is not
* implemented and will throw an exception.
* </P>
*
* @exception java.lang.UnsupportedOperationException
* Always thrown by the remove method.
*
*/
public void remove() {
throw new UnsupportedOperationException("The remove operation is not supported by the iterator");
}
} // end class IPAddressRangeGenerator
/**
* <P>
* Creates a new IPAddressRange object that can be used to encapsulate a
* contiguous range of IP Addresses. Once created the object can be used to
* get either an Iterator or Enumeration object to cycle through the list of
* address encapsulated by this object.
* </P>
*
* <P>
* It is important to note that if the address for toIP is greater than
* fromIP, the values will be swapped so that the iteration is always from
* the lowest address to the highest address.
* </P>
*
* @param fromIP
* The starting address, resolved by InetAddress.
* @param toIP
* The ending address, resolved by InetAddress.
*
* @see java.net.InetAddressUtils.addr(java.lang.String)
*
* @exception java.net.UnknownHostException
* Thrown by the InetAddress class if the hostname cannot be
* resolved.
*
*/
IPAddrRange(String fromIP, String toIP) throws java.net.UnknownHostException {
this(InetAddressUtils.addr(fromIP), InetAddressUtils.addr(toIP));
}
/**
* <P>
* Creates a new IPAddressRange object that can be used to encapsulate a
* contiguous range of IP Addresses. Once created the object can be used to
* get either an Iterator or Enumeration object to cycle through the list of
* address encapsulated by this object.
* </P>
*
* <P>
* It is important to note that if the address for start is greater than
* end, the values will be swapped so that the iteration is always from the
* lowest address to the highest address.
* </P>
*
* @param start
* The starting address.
* @param end
* The ending address.
*
*/
IPAddrRange(InetAddress start, InetAddress end) {
byte[] from = start.getAddress();
byte[] to = end.getAddress();
if (new ByteArrayComparator().compare(from, to) > 0) {
ThreadCategory.getInstance(this.getClass()).warn("The beginning of the address range is greater than the end of the address range (" + InetAddressUtils.str(start) + " - " + InetAddressUtils.str(end) + "), swapping values to create a valid IP address range");
m_end = from;
m_begin = to;
} else {
m_begin = from;
m_end = to;
}
}
/**
* This method may be used to determine if the specified IP address is
* contained within the IP address range.
*
* @param ipAddr
* IP address (InetAddress) to compare
*
* @return 'true' if the specified IP address falls within the IP address
* range. 'false' otherwise.
*/
boolean contains(InetAddress ipAddr) {
return InetAddressUtils.isInetAddressInRange(ipAddr.getAddress(), m_begin, m_end);
}
/**
* This method may be used to determine if the specified IP address is
* contained within the IP address range.
*
* @param ipAddr
* IP address (String) to compare
*
* @return 'true' if the specified IP address falls within the IP address
* range. 'false' otherwise.
*/
boolean contains(String ipAddr) throws java.net.UnknownHostException {
return InetAddressUtils.isInetAddressInRange(ipAddr, m_begin, m_end);
}
/**
* <P>
* Returns an Iterator object that can be used to step through all the
* address encapsulated in the object.
* </P>
*
* <P>
* The iterator returns objects of type
* {@link java.net.InetAddress InetAddress}or <code>null</code> if the
* address is unknown.
* </p>
*
* @see java.net.InetAddress
* @return a {@link java.util.Iterator} object.
*/
public Iterator<InetAddress> iterator() {
return new IPAddressRangeGenerator(m_begin, m_end);
}
/**
* <P>
* Returns an Enumeration object that can be used to list out all the
* address contained in the encapsulated range.
* </P>
*
* <P>
* The iterator returns objects of type
* {@link java.net.InetAddress InetAddress}or <code>null</code> if the
* address is unknown.
* </p>
*
* @see java.net.InetAddress
*/
Enumeration<InetAddress> elements() {
return new IPAddressRangeGenerator(m_begin, m_end);
}
}