package com.netifera.platform.util.addresses.inet;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import com.netifera.platform.util.addresses.AddressFormatException;
import com.netifera.platform.util.addresses.INetworkAddress;
import com.netifera.platform.util.addresses.NetworkFamily;
/**
* This class represents an Internet Protocol (IP) address.
*/
public abstract class InternetAddress implements INetworkAddress, Serializable {
private static final long serialVersionUID = -1585463461457645087L;
/**
* Textual representation of the address family.
*
* @return The textual representation of the address family
*/
public String familyName() {
return getNetworkFamily().toString();
}
/**
* Creates a new instance of this object.
*
* @return A new InternetAddress instance
*/
public InternetAddress newInstance() {
return fromBytes(toBytes());
}
/**
* Returns an <code>InternetAddress</code> object given the raw IP address.
*
* @param bytes IP address in network byte order
*
* @exception AddressFormatException if the array length is not valid
*/
public static InternetAddress fromBytes(final byte[] bytes) {
switch (bytes.length) {
case IPv4Address.BYTESLENGTH:
return new IPv4Address(bytes);
case IPv6Address.BYTESLENGTH:
return new IPv6Address(bytes);
default:
throw new AddressFormatException("Bad address size: "
+ bytes.length);
}
}
/**
* Returns an <code>InternetAddress</code> object given the string.
*
* @param address the specified IP in decimal notation
*
* @exception AddressFormatException
*/
public static InternetAddress fromString(final String address) {
if (address.contains(":")) {
return new IPv6Address(address);
} else {
return new IPv4Address(address);
}
}
/**
* Returns an <code>InternetAddress</code> given an InetAddress object.
*
* @param address the specified IP
*/
public static InternetAddress fromInetAddress(final InetAddress addr) {
return fromBytes(addr.getAddress());
}
/**
* Returns an <code>InternetAddress</code> object given a string in ARPA
* reverse notation.
*
* The in-addr.arpa notation is one way of representing the IP address,
* useful for the practical business of performing lookups.
*
* @param arpa address in ARPA notation.
*/
public static InternetAddress fromARPA(String arpa) {
if (!arpa.matches("^.*\\.arpa\\.?$")) {
throw new AddressFormatException("Bad address format: " + arpa);
}
String[] members = arpa.split("\\.");
String addressString;
switch (members.length) {
case 4 + 2: // IPv4 (in-addr.arpa)
addressString = members[3] + '.' + members[2]
+ '.' + members[1] + '.' + members[0];
break;
case 32 + 2: // IPv6 (ip6.arpa)
StringBuffer sb = new StringBuffer(IPv6Address.MAX_TEXTUAL_LENGTH);
for (int i = 7; i >= 0; i--) {
for (int j = 3; j >= 0; j--) {
sb.append(members[4 * i + j]);
}
if (i > 0) {
sb.append(':');
}
}
addressString = sb.toString();
break;
default:
throw new AddressFormatException("Bad address format: " + arpa);
}
return fromString(addressString);
}
/**
* Converts this IP address to a <code>InetAddress</code>.
*/
public InetAddress toInetAddress() {
try {
return InetAddress.getByAddress(toBytes()); // safe InetAddress call
} catch (UnknownHostException e) {
/* never happens */
return null;
}
}
/**
* Byte array representing the IP address in network by order.
*
* @return A byte array representing the IP address in network by order
*/
public abstract byte[] toBytes();
/**
* Numeric representation of the IP address.
*
* @return A string representing the IP address
*/
@Override
public abstract String toString();
/**
* Literal IP Address Format in URL's Syntax (RFC 2732).
*
* @return A string representing the IP address suitable for URL use.
*/
public String toStringLiteral() {
if (getNetworkFamily() == NetworkFamily.AF_INET6) {
return '[' + toString() + ']';
}
return toString();
}
/**
* Create a network block address containing this address.
*
* @param maskBitCount The netblock prefix length
*
* @exception IllegalArgumentException if the prefix is invalid.
*/
public abstract InternetNetblock createNetblock(int maskBitCount);
/**
* Test if the netblock prefix length is valid for that type of addresses.
*
* @param maskBitCount The netblock prefix length to test
*
* @return a <code>boolean</code> indicating if the prefix length is valid;
* or false otherwise.
*/
public boolean isValidMaskBit(final int maskBitCount) {
return maskBitCount >= 0 && maskBitCount <= getDataSize();
}
/**
* Utility routine to check if the address is an unicast address.
*
* @return a <code>boolean</code> indicating if the address is an unicast
* address; or false otherwise.
*/
// FIXME should we consider IPv4 240/8 as Unicast?
public boolean isUniCast() {
return !isMultiCast();
}
/**
* The unspecified address is used only to indicate the absence of an
* address.
*
* <p>The unspecified address is typically used as a source address for
* packets that are attempting to verify the uniqueness of a tentative
* address.</p>
* <p>The unspecified address is never assigned to an interface or used as a
* destination address.</p>
*/
public abstract boolean isUnspecified();
/**
* Utility routine to check if the address is a multicast address.
*
* @return a <code>boolean</code> indicating if the address is a multicast
* address; or false otherwise.
*/
public abstract boolean isMultiCast();
/**
* Link-local addresses are used by nodes when communicating with
* neighboring nodes on the same link.
*
* <p>The scope of a link-local address is the local link.</p>
*/
public abstract boolean isLinkLocal();
/**
* Utility routine to check if the address is a loopback address.
*
* @return a <code>boolean</code> indicating if the address is
* a loopback address; or false otherwise.
*/
public abstract boolean isLoopback();
/**
* Addresses for private or internal networks.
*
* <p>None of the private address prefixes may be routed in the public
* Internet.</p>
*/
public abstract boolean isPrivate();
}