Java tutorial
/* * Copyright (C) 2013, DECOIT GmbH * * This file is part of VISA Topology-Editor. * * VISA Topology-Editor 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. * * VISA Topology-Editor 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 * VISA Topology-Editor. If not, see <http://www.gnu.org/licenses/>. */ package de.decoit.visa.net; import java.math.BigInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.json.JSONException; import org.json.JSONObject; import de.decoit.visa.enums.IPVersion; import de.decoit.visa.interfaces.IJSON; /** * This class stores an IPv4 or IPv6 address. The address can be provided as * String or a bit mask stored as a {@link java.math.BigInteger BigInteger} * object. The address will be validated to follow the scheme of the provided IP * version. * * @author Thomas Rix */ public class IPAddress implements IJSON { private String ipAddress; private int[] ipAddressGroups; private IPVersion ipVersion; private boolean isLinkLocal; /** * Construct a new object using the specified IP address and version. The * address will be checked to be valid for the provided version of the IP * protocol. Additionally it will be checked if the address is a link local * address. * * @param pAddress String notation of the IP address, must be valid for the * provided IP version * @param pVersion Version of the Internet Protocol which will be used for * this address */ IPAddress(String pAddress, IPVersion pVersion) { String[] addressParts; Matcher addrMatcher; Matcher linkLocalMatcher; if (pVersion == IPVersion.V4) { // Check if the IP address is valid Pattern ip4pattern = Pattern.compile( "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", Pattern.CASE_INSENSITIVE); addrMatcher = ip4pattern.matcher(pAddress); Pattern linkLocalPattern = Pattern.compile( "^169\\.254\\.(?:25[0-4]|2[0-4][0-9]|1[0-9][0-9]?|[1-9])\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", Pattern.CASE_INSENSITIVE); linkLocalMatcher = linkLocalPattern.matcher(pAddress); } else if (pVersion == IPVersion.V6) { // Check if the IP address is valid Pattern ip6pattern = Pattern.compile( "^(((?=(?>.*?::)(?!.*::)))(::)?([0-9A-F]{1,4}::?){0,5}|([0-9A-F]{1,4}:){6})(\\2([0-9A-F]{1,4}(::?|$)){0,2}|((25[0-5]|(2[0-4]|1\\d|[1-9])?\\d)(\\.|$)){4}|[0-9A-F]{1,4}:[0-9A-F]{1,4})(?<![^:]:|\\.)\\z", Pattern.CASE_INSENSITIVE); addrMatcher = ip6pattern.matcher(pAddress); // Check if this address is a link-local address Pattern linkLocalPattern = Pattern.compile("^FE80(?::0000){3}(?::[0-9A-F]{4}){4}$", Pattern.CASE_INSENSITIVE); linkLocalMatcher = linkLocalPattern.matcher(pAddress); } else { throw new IllegalArgumentException("Invalid IP version provided"); } if (addrMatcher.matches()) { ipAddress = pAddress; ipVersion = pVersion; addressParts = pAddress.split(ipVersion.getNotationSplitRegex()); ipAddressGroups = new int[addressParts.length]; for (int i = 0; i < addressParts.length; i++) { ipAddressGroups[i] = Integer.parseInt(addressParts[i], ipVersion.getNotationRadix()); } // Check if this address is a link-local address isLinkLocal = linkLocalMatcher.matches(); } else { throw new IllegalArgumentException("Malformed IP or network address"); } } /** * Construct a new object from a bit mask stored in a * {@link java.math.BigInteger BigInteger} object. The bit mask will be * translated into a string containing the string notation of the address * and then be passed to the IPAddress(String, IPVersion) constructor. * * @param pMask Object containing the bit mask of the address * @param pVersion Version of the Internet Protocol which will be used for * this address */ IPAddress(BigInteger pMask, IPVersion pVersion) { this(IPAddress.bitmaskToString(pMask, pVersion), pVersion); } /** * Return the string notation of this address * * @return The string notation of this address */ public String getAddressString() { return ipAddress; } /** * Return the Internet Protocol version used for this address * * @return The Internet Protocol version used for this address */ public IPVersion getVersion() { return ipVersion; } /** * Return true if this address is a link-local address, false otherwise * * @return Address is link-local or not */ public boolean isLinkLocal() { return isLinkLocal; } /** * Return a {@link java.math.BigInteger BigInteger} object containing the * bit mask of this address. * * @return Bit mask of this address */ BigInteger toBigIntBitmask() { BigInteger rv = BigInteger.ZERO; for (int i = 0; i < ipAddressGroups.length; i++) { rv = rv.add(BigInteger.valueOf(ipAddressGroups[i])); if (i < ipAddressGroups.length - 1) { rv = rv.shiftLeft(ipVersion.getSegmentBitCount()); } } return rv; } @Override public JSONObject toJSON() throws JSONException { JSONObject rv = new JSONObject(); rv.put("address", ipAddress); rv.put("version", ipVersion.toString()); rv.put("isLinkLocal", isLinkLocal); return rv; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode()); result = prime * result + ((ipVersion == null) ? 0 : ipVersion.hashCode()); result = prime * result + (isLinkLocal ? 1231 : 1237); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj instanceof IPAddress) { IPAddress ipa = (IPAddress) obj; return (ipa.ipAddress.equals(ipAddress) && ipa.ipVersion.toInteger() == ipVersion.toInteger() && ipa.isLinkLocal == isLinkLocal); } else { return false; } } /** * Static utility function to translate a provided bit mask into the IP * version specific string notation. * * @param pMask Object containing the bit mask of the address to translate * @param pVersion Version of the Internet Protocol which will be used for * the address * @return The string notation of the provided IP address */ private static String bitmaskToString(BigInteger pMask, IPVersion pVersion) { byte[] maskBytes = pMask.toByteArray(); StringBuilder rv = new StringBuilder(); boolean ignoreFirstByte; if (pVersion == IPVersion.V4) { // If array length is 5 it contains a sign byte we have to ignore ignoreFirstByte = (maskBytes.length == 5); for (int i = 0; i < maskBytes.length; i++) { if (ignoreFirstByte) { // Skip the first byte, it's the sign byte i++; ignoreFirstByte = false; } rv.append(maskBytes[i] & 0xFF); // Only append the '.' if this is not the last segment if (i < maskBytes.length - 1) { rv.append("."); } } } else if (pVersion == IPVersion.V6) { // If array length is 17 it contains a sign byte we have to ignore ignoreFirstByte = (maskBytes.length == 17); for (int i = 0; i < maskBytes.length; i += 2) { if (ignoreFirstByte) { // Skip the first byte i++; ignoreFirstByte = false; } // Notation segments are made of 2 bytes in IPv6 rv.append(String.format("%02X", maskBytes[i])); rv.append(String.format("%02X", maskBytes[i + 1])); // Only append the ':' if this is not the last segment if (i < maskBytes.length - 2) { rv.append(":"); } } } else { throw new IllegalStateException("Unsupported IP version detected"); } return rv.toString(); } }