How to generate UniqueID concurrently? - java

Hi I have a requirement where I need to generate SessionID like thing but that too concurrently. I am thinking to take the code from tomcat 7 source "SessionIdGenerator". But I am not sure whether will it genetate uniqueID concurrently without any modification.
class itself is here:
public class SessionIdGenerator {
private Logger logger = LoggerFactory.getLogger();
/**
* Queue of random number generator objects to be used when creating session
* identifiers. If the queue is empty when a random number generator is
* required, a new random number generator object is created. This is
* designed this way since random number generators use a sync to make them
* thread-safe and the sync makes using a a single object slow(er).
*/
private Queue<SecureRandom> randoms = new ConcurrentLinkedQueue<SecureRandom>();
/**
* The Java class name of the secure random number generator class to be
* used when generating session identifiers. The random number generator
* class must be self-seeding and have a zero-argument constructor. If not
* specified, an instance of {#link SecureRandom} will be generated.
*/
private String secureRandomClass = null;
/**
* The name of the algorithm to use to create instances of
* {#link SecureRandom} which are used to generate session IDs. If no
* algorithm is specified, SHA1PRNG is used. To use the platform default
* (which may be SHA1PRNG), specify the empty string. If an invalid
* algorithm and/or provider is specified the {#link SecureRandom} instances
* will be created using the defaults. If that fails, the {#link
* SecureRandom} instances will be created using platform defaults.
*/
private String secureRandomAlgorithm = "SHA1PRNG";
/**
* The name of the provider to use to create instances of
* {#link SecureRandom} which are used to generate session IDs. If
* no algorithm is specified the of SHA1PRNG default is used. If an invalid
* algorithm and/or provider is specified the {#link SecureRandom} instances
* will be created using the defaults. If that fails, the {#link
* SecureRandom} instances will be created using platform defaults.
*/
private String secureRandomProvider = null;
/** Node identifier when in a cluster. Defaults to the empty string. */
private String jvmRoute = "";
/** Number of bytes in a session ID. Defaults to 16. */
private int sessionIdLength = 16;
/**
* Specify a non-default #{link {#link SecureRandom} implementation to use.
*
* #param secureRandomClass The fully-qualified class name
*/
public void setSecureRandomClass(String secureRandomClass) {
this.secureRandomClass = secureRandomClass;
}
/**
* Specify a non-default algorithm to use to generate random numbers.
*
* #param secureRandomAlgorithm The name of the algorithm
*/
public void setSecureRandomAlgorithm(String secureRandomAlgorithm) {
this.secureRandomAlgorithm = secureRandomAlgorithm;
}
/**
* Specify a non-default provider to use to generate random numbers.
*
* #param secureRandomProvider The name of the provider
*/
public void setSecureRandomProvider(String secureRandomProvider) {
this.secureRandomProvider = secureRandomProvider;
}
/**
* Specify the node identifier associated with this node which will be
* included in the generated session ID.
*
* #param jvmRoute The node identifier
*/
public void setJvmRoute(String jvmRoute) {
this.jvmRoute = jvmRoute;
}
/**
* Specify the number of bytes for a session ID
*
* #param sessionIdLength Number of bytes
*/
public void setSessionIdLength(int sessionIdLength) {
this.sessionIdLength = sessionIdLength;
}
/**
* Generate and return a new session identifier.
*/
public String generateSessionId() {
byte random[] = new byte[16];
// Render the result as a String of hexadecimal digits
StringBuilder buffer = new StringBuilder();
int resultLenBytes = 0;
while (resultLenBytes < sessionIdLength) {
getRandomBytes(random);
for (int j = 0;
j < random.length && resultLenBytes < sessionIdLength;
j++) {
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
byte b2 = (byte) (random[j] & 0x0f);
if (b1 < 10)
buffer.append((char) ('0' + b1));
else
buffer.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
buffer.append((char) ('0' + b2));
else
buffer.append((char) ('A' + (b2 - 10)));
resultLenBytes++;
}
}
if (jvmRoute != null && jvmRoute.length() > 0) {
buffer.append('.').append(jvmRoute);
}
return buffer.toString();
}
private void getRandomBytes(byte bytes[]) {
SecureRandom random = randoms.poll();
if (random == null) {
random = createSecureRandom();
}
random.nextBytes(bytes);
randoms.add(random);
}
/**
* Create a new random number generator instance we should use for
* generating session identifiers.
*/
private SecureRandom createSecureRandom() {
SecureRandom result = null;
long t1 = System.currentTimeMillis();
if (secureRandomClass != null) {
try {
// Construct and seed a new random number generator
Class<?> clazz = Class.forName(secureRandomClass);
result = (SecureRandom) clazz.newInstance();
} catch (Exception e) {
logger.debug("exception:"+e);
}
}
if (result == null) {
// No secureRandomClass or creation failed. Use SecureRandom.
try {
if (secureRandomProvider != null &&
secureRandomProvider.length() > 0) {
result = SecureRandom.getInstance(secureRandomAlgorithm,
secureRandomProvider);
} else if (secureRandomAlgorithm != null &&
secureRandomAlgorithm.length() > 0) {
result = SecureRandom.getInstance(secureRandomAlgorithm);
}
} catch (NoSuchAlgorithmException e) {
logger.debug("exception:"+e);
} catch (NoSuchProviderException e) {
logger.debug("exception:"+e);
}
}
if (result == null) {
// Invalid provider / algorithm
try {
result = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
logger.debug("exception:"+e);
}
}
if (result == null) {
// Nothing works - use platform default
result = new SecureRandom();
}
// Force seeding to take place
result.nextInt();
long t2=System.currentTimeMillis();
if( (t2-t1) > 100 )
logger.debug("sessionIdGenerator algorithm:"+result.getAlgorithm()+"time taken:" +Long.valueOf(t2-t1));
return result;
}
}

I'd use java.util.UUID.randomUUID() instead. Very simple and guarantees uniqueness.

Related

Calculator with batches of operations in java

Need to do a java calculator which works with batches. It must take an operation and then, for the next ones, just use the result of the previous operation as the first value of its new operation.
public class Calculator {
/**
* Public constructor of the calculator.
*/
**public Calculator () {/*...*/}**
/**
* Clean the internal state of the calculator
*/
**public void cleanOperations () { /*...*/ }**
/**
* Add a new operation to the internal state of the calculator.
* It is worth mentioning that the calculator behaves in an accumulative way ,
* thus only first operation has two operands.
* The rest of computations work with the accumulated value and only an extra
* new operand. Second input value must be ignored if the operation does not
* correspond to the first one.
*
* #param operation operation to add , as string , "+", "-", "*", "/".
* #param values Operands of the new operation (one or two operands ).
* Uses the varargs feature.
* https :// docs.oracle.com/javase /8/ docs/technotes/guides/language/varargs.html
* #throws IllegalArgumentException If the operation does not exist.
*/
**public void addOperation(String operation , float ... values) { /*...*/ }**
/**
* Execute the set of operations of the internal state of the calculator.
* Once execution is finished , internal state (operands and operations)
* is restored (EVEN if exception occurs ).
* This calculator works with "Batches" of operations.
* #return result of the execution
* #throws ArithmeticException If the operation returns an invalid value
* (division by zero)
*/
**public float executeOperations () { /*...*/ }**
/**
* Current internal state of calculator is printed
* FORMAT:
* "[{+/ -/"/"/*}] value1_value2 [{+/ -/"/"/*}] value1 [{+/ -/"/"/*}] value1 {...}"
* #return String of the internal state of the calculator
*/
#Override
public String toString () { /* ... */ }
}
SOME TEST IT SHOULD PASS:
// Add operations, calculate internal state representation (string pattern) and execute them as a single batch
calculator.addOperation("+", 4.5f, 6.8f);
calculator.addOperation("-", 3.1f);
calculator.addOperation("/", 6f);
assertEquals("[STATE:[+]4.5_6.8[-]3.1[/]6.0]", calculator.toString());
result = calculator.executeOperations();
assertEquals("[STATE:]", calculator.toString()); // state is restored
assertEquals(1.366f, result, EPSILON);//EPSILON = 0.01f
As you can see it must work by doing the first operation with 2 values but the next ones using the value stores from the one before and then execute with the operator and the value, the new operation.
Are you looking for this?
public class Calculator {
private String operation;
private float[] values;
private float answer;
/**
* Public constructor of the calculator.
*/
public Calculator() {
}
/**
* Clean the internal state of the calculator
*/
public void cleanOperations() {
operation = null;
values = null;
answer = 0;
}
/**
* Add a new operation to the internal state of the calculator.
* It is worth mentioning that the calculator behaves in an accumulative way ,
* thus only first operation has two operands.
* The rest of computations work with the accumulated value and only an extra
* new operand. Second input value must be ignored if the operation does not
* correspond to the first one.
*
* #param operation operation to add , as string , "+", "-", "*", "/".
* #param values Operands of the new operation (one or two operands ).
* Uses the varargs feature.
* https :// docs.oracle.com/javase /8/ docs/technotes/guides/language/varargs.html
* #throws IllegalArgumentException If the operation does not exist.
*/
public void addOperation(String operation, float... values) {
if (!(operation.equals("+") || operation.equals("-") || operation.equals("*") || operation.equals("/"))) {
throw new IllegalArgumentException(operation + " is not a valid operator. ( '+', '-', '*', '/')");
}
this.operation = operation;
this.values = values;
}
/**
* Execute the set of operations of the internal state of the calculator.
* Once execution is finished , internal state (operands and operations)
* is restored (EVEN if exception occurs ).
* This calculator works with "Batches" of operations.
*
* #return result of the execution
* #throws ArithmeticException If the operation returns an invalid value
* (division by zero)
*/
public float executeOperations() {
switch (operation) {
case "+":
if (values.length == 1) {
answer += values[0];
} else {
for (float value : values) {
answer += value;
}
}
break;
case "-":
if (values.length == 1) {
answer -= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
answer -= values[i];
}
}
break;
case "*":
if (values.length == 1) {
answer *= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
answer *= values[i];
}
}
break;
case "/":
if (values.length == 1) {
if (values[0] == 0) {
throw new ArithmeticException("Can not divide " + answer + " with " + values[0]);
}
answer /= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
if (values[i] == 0) {
throw new ArithmeticException("Can not divide " + answer + " with " + values[i]);
}
answer /= values[i];
}
}
break;
}
return answer;
}
/**
* Current internal state of calculator is printed
* FORMAT:
* "[{+/ -/"/"/*}] value1_value2 [{+/ -/"/"/*}] value1 [{+/ -/"/"/*}] value1 {...}"
*
* #return String of the internal state of the calculator
*/
#Override
public String toString() {
StringBuilder string = new StringBuilder("values: [");
for (float value: values) {
string.append(value)
.append(" ")
.append(operation)
.append(" ");
}
string.append("] answer = ").append(answer);
return string.toString();
}
}

Is there any function to split CIDR block into IP start and IP end without using Parse_IP in snowflake [duplicate]

This question already has an answer here:
How to find start and End IP address for CIDR in snowflake
(1 answer)
Closed 1 year ago.
for example For cidr 2c0f:eb00:400::/40 (jw.org) ip_start should be - 2c0f:eb00:400:: ip_end will be - 2c0f:eb00:4ff:ffff:ffff:ffff:ffff:ffff
I filed an internal bug to fix the PARSE_IP() internal function for this edge case (SNOW-374145).
In the meantime, you can use a Java UDF, like:
select ipv6range('FF02:0:0:0:0:1:FF00::/104');
Returns:
[
"/ff02:0:0:0:0:1:ff00:0",
"/ff02:0:0:0:0:1:ffff:ffff"
]
With code taken from https://github.com/edazdarevic/CIDRUtils:
create or replace function ipv6range(s string)
returns array
language java
handler='MyClass.x'
as $$
/*
* The MIT License
*
* Copyright (c) 2013 Edin Dazdarevic (edin.dazdarevic#gmail.com)
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* */
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class MyClass{
public static String[] x(String x) throws Exception{
CIDRUtils cidr = new CIDRUtils(x);
return new String[]{cidr.startAddress.toString(), cidr.endAddress.toString()};
}
}
/**
* A class that enables to get an IP range from CIDR specification. It supports
* both IPv4 and IPv6.
*/
public class CIDRUtils {
private final String cidr;
private InetAddress inetAddress;
InetAddress startAddress;
InetAddress endAddress;
private final int prefixLength;
public CIDRUtils(String cidr) throws UnknownHostException {
this.cidr = cidr;
/* split CIDR to address and prefix part */
if (this.cidr.contains("/")) {
int index = this.cidr.indexOf("/");
String addressPart = this.cidr.substring(0, index);
String networkPart = this.cidr.substring(index + 1);
inetAddress = InetAddress.getByName(addressPart);
prefixLength = Integer.parseInt(networkPart);
calculate();
} else {
throw new IllegalArgumentException("not an valid CIDR format!");
}
}
private void calculate() throws UnknownHostException {
ByteBuffer maskBuffer;
int targetSize;
if (inetAddress.getAddress().length == 4) {
maskBuffer =
ByteBuffer
.allocate(4)
.putInt(-1);
targetSize = 4;
} else {
maskBuffer = ByteBuffer.allocate(16)
.putLong(-1L)
.putLong(-1L);
targetSize = 16;
}
BigInteger mask = (new BigInteger(1, maskBuffer.array())).not().shiftRight(prefixLength);
ByteBuffer buffer = ByteBuffer.wrap(inetAddress.getAddress());
BigInteger ipVal = new BigInteger(1, buffer.array());
BigInteger startIp = ipVal.and(mask);
BigInteger endIp = startIp.add(mask.not());
byte[] startIpArr = toBytes(startIp.toByteArray(), targetSize);
byte[] endIpArr = toBytes(endIp.toByteArray(), targetSize);
this.startAddress = InetAddress.getByAddress(startIpArr);
this.endAddress = InetAddress.getByAddress(endIpArr);
}
private byte[] toBytes(byte[] array, int targetSize) {
int counter = 0;
List<Byte> newArr = new ArrayList<Byte>();
while (counter < targetSize && (array.length - 1 - counter >= 0)) {
newArr.add(0, array[array.length - 1 - counter]);
counter++;
}
int size = newArr.size();
for (int i = 0; i < (targetSize - size); i++) {
newArr.add(0, (byte) 0);
}
byte[] ret = new byte[newArr.size()];
for (int i = 0; i < newArr.size(); i++) {
ret[i] = newArr.get(i);
}
return ret;
}
public String getNetworkAddress() {
return this.startAddress.getHostAddress();
}
public String getBroadcastAddress() {
return this.endAddress.getHostAddress();
}
public boolean isInRange(String ipAddress) throws UnknownHostException {
InetAddress address = InetAddress.getByName(ipAddress);
BigInteger start = new BigInteger(1, this.startAddress.getAddress());
BigInteger end = new BigInteger(1, this.endAddress.getAddress());
BigInteger target = new BigInteger(1, address.getAddress());
int st = start.compareTo(target);
int te = target.compareTo(end);
return (st == -1 || st == 0) && (te == -1 || te == 0);
}
}
$$
;
Btw, the error shown by PARSE_IP() (until fixed) is "Error parsing IP: Invalid IPv6 address. IP address includes too many fields."

trying to use another properties key value in another properties key by using a subclass of Properties to override getProperty() method

im trying to use another properties key value in another properties key by using a subclass of Properties class to ovveride getProperty() method but im not able to get the expected key value i wanted from the properties file. this is where i got the sub class code https://coderanch.com/t/469713/java/reference-defined-property-key-properties
sub class
import java.util.Properties;
/**
*
* A subclass of Properties that allows recursive
* references for property values. For example,
*
* <pre><code>
* A=12345678
* B={A}90
* C={B} plus more
* </code></pre>
*
* will result in <code>getProperty("C")</code>
* returning the value "1234567890 plus more".
*
* #author: Chris Mair
*
* Copied from: http://www2.sys-con.com/ITSG/virtualcd/Java/archives/0612/mair/index.html
*/
//#SuppressWarnings("serial")
public class XProperties extends Properties {
private static final long serialVersionUID = 1L;
private static final String START_DELIMITER = "${";
private static final String END_DELIMITER = "}";
#Override
public String getProperty(String key) {
String value = super.getProperty(key);
if (value != null) {
int startIndex = 0;
int endIndex = 0;
while ( (startIndex = value.indexOf(START_DELIMITER, endIndex)) >= 0
&& (endIndex = value.indexOf(END_DELIMITER, startIndex) ) >= 0) {
String variableName = value.substring(startIndex + START_DELIMITER.length(), endIndex);
// now call getProperty recursively to have this looked up
String variableValue = null;
if (!variableName.equals(key)) {
// only recurse if the variable does not equal our own original key
variableValue = this.getProperty(variableName);
}
if (variableValue == null) {
// when unable to find the variable value, just return it as the variable name
variableValue = START_DELIMITER + variableName + END_DELIMITER;
}
value = value.replace(START_DELIMITER + variableName + END_DELIMITER, variableValue);
} // while matches.
}
return value;
}
}
Properties file
ROOTDIR=C:/test_PROJECT
LOCALDIRWEB=${ROOTDIR}/cfo_web
LOCALDIRSERVER=${ROOTDIR}/cfo_server
implemetation of the above class
import java.util.Properties;
public class GitClone {
static XProperties a = new XProperties();
Properties prop = new Properties();
try {
a.load(GitClone.class.getClassLoader().getResourceAsStream("config.properties"));
} catch (IOException e) {
e.printStackTrace();
}
File cfoWebDir = new File (a.getProperty("LOCALDIRWEB"));
System.out.println(cfoWebDir);
Output when printed out
NOTHING PRINTED OUT
Expected output
C:\test_PROJECT\cfo_web
Any help with this? Im i doing the implementation wrong?

Java Proxy Discovering Bot

I have written a class, ProxyFinder which connects to random ips and first pings them, and if they respond, attempts to create a http proxy connection through common proxy ports.
Currently, it is set up just connecting to random ips. This is relatively fast, discovering a few proxys an hour. However, I would like to somehow check if I have already previously connected to an ip. First I tried keeping them in a list, but that was using over 10GB of ram.. I included a method that I tried in the code below which writes the data to a cache using a RandomAccessFile, but this is incredibly slow to search through the entire file for each connection as it gets larger.
I am storing the data in as small of format as possible, simply four bytes for each ip. Even though, this is 4 * 256 * 256 *256 * 256 bytes.. = 16gb of raw ram.. or a 16gb file to search each time you want to test another ip.
I also tried creating a separate thread to generate ips, check them against the file, and then add them to a queue that the probe threads could pull from. It could not keep up with the probe threads either.
How can I quickly check if I have already connected to an IP or not, without being incredibly slow or using ridiculous amounts of memory?
package net;
import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* #author Colby
*/
public class ProxyFinder {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws Exception {
int[] ports = {
1080, 3128, 3128, 8080
};
System.out.println("Starting network probe");
AtomicInteger counter = new AtomicInteger();
for (int i = 0; i < 500; i++) {
new Thread(() -> {
do {
try {
byte[] addrBytes = randomAddress();//could be getNextAddress also
if (addrBytes == null) {
break;
}
InetAddress addr = InetAddress.getByAddress(addrBytes);
if (ping(addr)) {
float percent = (float) ((counter.get() / (256f * 256f * 256f * 256f)) * 100F);
if (counter.incrementAndGet() % 10000 == 0) {
System.out.println("Searching " + percent + "% network search");
}
for (int port : ports) {
try {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(addr, port));
HttpURLConnection con = (HttpURLConnection) new URL("http://google.com").openConnection(proxy);
con.setConnectTimeout(1000);
con.setReadTimeout(1000);
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
con.getContent();
con.disconnect();
System.out.println("Proxy found!" + addr.getHostAddress() + ":" + port + " Found at " + percent + "% network search");
} catch (Exception e) {
}
}
//
//System.out.println("Ping response: --" + addr.getHostAddress() + "-- Attempt: " + counter.get() + " Percent: " + percent + "%");
} else {
//System.out.println("Ping response failed: " + addr.getHostAddress() + " attempt " + counter.incrementAndGet());
}
} catch (Exception e) {
//e.printStackTrace();
}
} while (true);
}).start();
}
}
private static RandomAccessFile cache;
private static byte[] getNextAddress() throws Exception {
if (cache == null) {
cache = new RandomAccessFile(File.createTempFile("abc", ".tmp"), "rw");
}
byte[] check;
checkFile:
{
byte[] addr = new byte[4];
do {
check = randomAddress();
inner:
{
cache.seek(0);
while (cache.length() - cache.getFilePointer() > 0) {
cache.readFully(addr);
if (Arrays.equals(check, addr)) {
break inner;
}
}
cache.write(check);
break checkFile;
}
} while (true);
}
return check;
}
private static byte[] randomAddress() {
return new byte[]{(byte) (Math.random() * 256), (byte) (Math.random() * 256), (byte) (Math.random() * 256), (byte) (Math.random() * 256)};
}
private static boolean ping(InetAddress addr) throws Exception {
return addr.isReachable(500);
}
}
Also in case anyone is wondering, I've had this running for 12 hours now and it's discovered about 50 proxys, and pinged about 2.09664E-4% of the ip range which is about 1.2 million ips. not bad for the bandwidth allocated (0.5Mbps)
EDIT: I am starting to think that maybe the overhead of storing and checking all of these IPs would be even greater than simply connecting to many duplicates near the end of searching the ip range..
I would not store the whole IP address because of the amount of data. To store them in a array of BitSet would consume less memory.
edit previous code version removed, it was not correct
The version below generates random addresses and persist them in a file. If the persistence file of a previous run is found, the information of the seen addresses is restored from that file.
Following case was not handled correctly in the initial version:
assuming that no address was already seen
1.0.0.1 - seen false
2.0.0.2 - seen false
2.0.0.1 - seen true, which was wrong and is correctly handled by code below
See the comments in the code for further information.
public class KeepSeenAddresses {
static final int FILE_BUFFER_SIZE = 81_920;
static final int RANGES_SIZE = 256;
// to store 256 ranges of 255*255*255+1 addresses
static BitSet[] ranges;
// Random(1) is taken only for demonstration purpose, so the second
// application run will find the same seen addresses from previous run
static Random random = new Random(1);
// for normal use it's better to have better randomness
//static Random random = new Random(System.currentTimeMillis());
public static void main(String[] args)
throws IOException, ClassNotFoundException {
if (!readRanges()) {
initRanges();
}
// this case was failing in the initial solution
// uncomment this block to see how all edge cases
// which where mentioned in other comments are handled
/*
byte[][] addresses = {
{1, 0, 0, 1},
{2, 0, 0, 2},
{2, 0, 0, 1},
{1, 2, 3, 4},
{4, 3, 2, 1},
{(byte)128, 0, 0, 0},
{(byte)255, (byte)255, (byte)255, (byte)255}
};
seenAddress(addresses[0]);
seenAddress(addresses[1]);
seenAddress(addresses[3]);
seenAddress(addresses[5]);
seenAddress(addresses[6]);
for (byte[] addressBytes : addresses) {
System.out.printf("seen %s before: %s%n",
prettyAddress(addressBytes),
seenBefore(addressBytes)
);
}
*/
processAddresses();
persistRanges();
}
/**
* Read the seen addresses from a file.
*
* #return <code>true</code> if the file was found and has the expected
* number of ranges, otherwise <code>false</code>
* #throws IOException
* #throws ClassNotFoundException
*/
private static boolean readRanges() throws IOException, ClassNotFoundException {
File rangesStore = new File("addresses.bin");
if (!rangesStore.exists()) {
return false;
}
System.out.print("found previous rangesStore... ");
try (ObjectInputStream ois = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream(rangesStore), FILE_BUFFER_SIZE
)
)) {
ranges = (BitSet[]) ois.readObject();
}
if (ranges.length != RANGES_SIZE) {
System.out.printf("wrong size of rangesStore: expected %d"
+ " found: %d%n", RANGES_SIZE, ranges.length);
return false;
} else {
System.out.printf("restored ranges: %d%n", ranges.length);
return true;
}
}
/**
* Initialize the address ranges array. All address flags will be set to
* <code>false</code>.
*/
private static void initRanges() {
System.out.print("initialize new rangesStore... ");
ranges = new BitSet[RANGES_SIZE];
for (int i = 0; i < RANGES_SIZE; i++) {
BitSet bitSet = new BitSet(255 * 255 * 255 + 1);
for (int j = 0; j < 255 * 255 * 255 + 1; j++) {
bitSet.clear(j);
}
ranges[i] = bitSet;
}
System.out.printf("initialized ranges: %d%n", RANGES_SIZE);
}
/**
* For demonstration purpose.<br>
* Generates some random IPv4 addresses. If the address was not seen before
* the flag for this address will be set to <code>true</code>.
*/
private static void processAddresses() {
for (int i = 0; i < 10; i++) {
byte[] addrBytes = randomAddress();
boolean seenBefore = seenBefore(addrBytes);
if (!seenBefore) {
seenAddress(addrBytes);
seenBefore = false;
}
System.out.printf("seen %s before: %s%n",
prettyAddress(addrBytes),
seenBefore
);
}
}
/**
* Persist the address ranges array. The file size is around 500MB.
*
* #throws IOException
*/
private static void persistRanges() throws IOException {
System.out.print("persist rangesStore... ");
try (ObjectOutputStream oos = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream("addresses.bin"), FILE_BUFFER_SIZE)
)) {
oos.writeObject(ranges);
}
System.out.printf("written ranges: %d%n", ranges.length);
}
/**
* Keep a flag which address has been seen already.
*
* #param addrBytes IPv4 address in four bytes
*/
static void seenAddress(byte[] addrBytes) {
int rangeIndex = (int) addrBytes[0] & 0xff;
int rangeOffset = ((int) addrBytes[1] & 0xff * 0xffff)
+ ((int) addrBytes[2] & 0xff * 0xff)
+ ((int) addrBytes[3] & 0xff);
ranges[rangeIndex].set(rangeOffset);
}
/**
* Check if the passed address was seen before.
*
* #param addrBytes IPv4 address in four bytes
* #return <code>true</code> if the address was seen before, otherwise
* <code>false</code>
*/
static boolean seenBefore(byte[] addrBytes) {
int rangeIndex = (int) addrBytes[0] & 0xff;
int rangeOffset = ((int) addrBytes[1] & 0xff * 0xffff) + ((int) addrBytes[2] & 0xff * 0xff) + ((int) addrBytes[3] & 0xff);
return ranges[rangeIndex].get(rangeOffset);
}
/**
* Convert the IPv4 address into pretty string.
*
* #param addrBytes IPv4 address in four bytes
* #return pretty String of the IPv4 address
*/
static String prettyAddress(byte[] addrBytes) {
return String.format("%03d.%03d.%03d.%03d",
(int) addrBytes[0] & 0xff,
(int) addrBytes[1] & 0xff,
(int) addrBytes[2] & 0xff,
(int) addrBytes[3] & 0xff);
}
/**
* Generate a random IPv4 address.
*
* #return four bytes of a random generated IPv4 address
*/
private static byte[] randomAddress() {
byte[] bytes = new byte[4];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) random.nextInt(256);
}
return bytes;
}
}
I have ported code from another solution here to fit this problem:
Java- Mapping multi-dimensional arrays to single
The answer to the above question gives an in depth explanation of how the following code works. If anyone else would like to post a more in depth answer on this thread I will award it the answer.
static BitSet set;
static int pos(int i, int j, int k, int m) {
return ((256*256*256) * i) + ((256*256) * j) + (256 * k) + m;
}
static boolean get(byte[] addr) {
return set.get(pos(addr[0], addr[1], addr[2], addr[3]));
}
static void set(byte[] addr, boolean flag) {
set.set(pos(addr[0], addr[1], addr[2], addr[3]), flag);
}
Use a data base like MySql and hibernarte with level 1 & 2 cache.
It will be faster than RAM if u configure a cache with hibernate and tune ur db to use few gb of cache too. i think they all do. can configure an external cache like ehcahe when an be configured to live on another process + file with limits on size and time. Db knows how to index and seek things faster than even pure RAM - at such sizes as your IP
Plus you can improve by partitioning table data & index by first char, 2nd char etc

Direction with JUnit Testing

I am trying to wrap my head around Junit testing and have read examples and what not, but still finding it difficult to understand how and what to test. Below is the Class with methods that I am creating my test cases from (as well as my test case Class).
import java.util.Iterator;
/**
* The Probability class understands the likelihood that something will happen.
* <p>
* (c) Copyright Fred George 2008. All right reserved. Adapted and used for
* educational purposes with permission from Fred George.
* </p>
*
* #author Fred George
*/
public class Probability {
/** Value of receiver. */
private final double value;
/** Cannot happen. */
private static final double IMPOSSIBLE_VALUE = 0.0;
/** Will happen. */
private static final double CERTAIN_VALUE = 1.0;
/** Instance that represents outcome that will happen. */
public static final Probability CERTAIN = new Probability(CERTAIN_VALUE);
/**
* Answer a new instance of the receiver with the specified value as the
* likelihood that it occurs.
*
* #param valueAsFraction
* value between 0.0 and 1.0
* #throws
*/
public Probability(final double valueAsFraction) {
if (valueAsFraction < IMPOSSIBLE_VALUE || valueAsFraction > CERTAIN_VALUE) {
throw new IllegalArgumentException("Specified value of "
+ valueAsFraction + " is not between 0.0 and 1.0");
}
value = valueAsFraction;
}
/**
* Answer the liklihood that the receiver will occur and the specified other
* Probability will occur.
*
* #return "and" of receiver and other Probability
* #param other
* Probability being and'ed to receiver
*/
public final Probability and(final Probability other) {
return new Probability(this.value * other.value);
}
/**
* Answer the value of the receiver as a scaled double between 0.0
* (impossible) to 1.0 (certain).
* <p>
* This method is modeled after those in Double, Integer, and the rest of
* the wrapper classes.
*
* #return value of receiver as double between 0.0 and 1.0
*/
public final double doubleValue() {
return value;
}
/**
* Answer true if the receiver has the same value as the other (assuming
* other is a Probability).
*
* #return true if receiver's value equals other's value
* #param other
* Object (assumed to be Probability) to compare
*/
public final boolean equals(final Object other) {
if (!(other instanceof Probability)) {
return false;
}
return this.value == ((Probability) other).value;
}
/**
* Answers with a hashcode for the receiver.
* #return the hash
*/
public final int hashCode() {
return (new Double(this.value)).hashCode();
}
/**
* Answer true if the combined likelihoods of the specified Collection of
* Probabilities sums to certain (100%).
*
* #return true if combined likelihoods is 100%
* #param probabilities
* Collection of likelihoods to sum
*/
public static final boolean isTotalCertain(final java.util.Collection probabilities) {
double sum = 0;
for (Iterator i = probabilities.iterator(); i.hasNext();) {
sum += ((Probability) i.next()).value;
}
return sum == CERTAIN_VALUE;
}
/**
* Answer the liklihood that the receiver will not occur.
*
* #return "not" of receiver
*/
public final Probability not() {
return new Probability(CERTAIN_VALUE - value);
}
/**
* Answer the liklihood that the receiver will occur or the specified other
* Probability will occur, or both.
*
* #return "or" of receiver and other Probability
* #param other
* Probability being or'ed to receiver
*/
public final Probability or(final Probability other) {
return this.not().and(other.not()).not(); // DeMorgan's Law
}
/** Multiplier from double to percentage. */
private static final int PERCENTAGE_MULTIPLIER = 100;
/**
* Answers a String representation of the receiver suitable for debugging.
*
* #return String representation of the receiver
*/
public final String toString() {
int percentage = (int) (value * PERCENTAGE_MULTIPLIER);
return percentage + "%";
}
}
And here is what I've attempted for some of the test cases. I haven't tried them all, but am stuck on the "equals" method.
package edu.psu.ist.probability;
import edu.psu.ist.decision.Decision;
import junit.framework.TestCase;
import junit.framework.*;
public class ProbabilityTest extends TestCase {
private Probability p1;
private Probability p2;
private Probability p3;
private Decision d1;
protected void setUp() {
p1 = new Probability(.6);
p2 = new Probability(.7);
p3 = new Probability(.6);
d1 = new Decision("No decision made");
}
public void testHashCode() {
fail("Not yet implemented");
}
public void testProbability() {
assertEquals(p1.doubleValue(), .6);
try{
p1 = p3;
//get here, bad
fail("Should raise an IllegalArgumentException");
}catch (IllegalArgumentException e){
//good!
}
}
public void testAnd() {
assertEquals((p1.and(p2)).doubleValue(), .42);
}
public void testDoubleValue() {
assertEquals(p1.doubleValue(), .6);
}
public void testEqualsObject() {
assertEquals(p1, p3);
//assertEquals(p1, p2);
assertTrue(!p1.equals(p2));
assertTrue(p1.equals(p3));
/*Probability p1 = new Probability (.7);
Probability p2 = new Probability (.6);
Decision d1 = new Decision();
boolean TRUE = p1.equals(p2);
boolean FALSE = p1.equals(d1);
try {
p1.equals(p2);
p1.equals(d1);
p1.equals(null);
} catch (NullPointerException ex){
// exception should be thrown
}
// assertEquals("Return true if theses values are the same",p1.doubleValue(), p2.doubleValue());
// assertEquals("Return false if not equal", p1.doubleValue(), d1.equals(p1.doubleValue()));
// assertNotSame("Objects are not the same", p1, d1);
*/
}
public void testIsTotalCertain() {
fail("Not yet implemented");
}
public void testNot() {
fail("Not yet implemented");
}
public void testOr() {
fail("Not yet implemented");
}
public void testToString() {
fail("Not yet implemented");
}
}
Maybe someone can shed some light that will help me understand this process more clearly.
You've chosen a somewhat hairy first step, comparing floating point numbers can be non-intuitive. You want to make sure you use the assertXXX methods with a delta:
double x = 1.3;
double y = 13.0 / 10.0;
double acceptable_difference = 0.05;
assertEquals(x,y, acceptable_difference);
That should return true as you're unlikely to make your value match.
In terms of writing your tests just think what you want to make sure of, being careful to test the boundary conditions, like if one Probability is 0.
Speaking of floating point I bet you could find uses of not that get you below 0.0, if ever so slightly. That's something to take a look at.
In your particular case, the code seems straight forward for the most part. Try to focus on testing the behavior of the code.
Here are some test scenarios for equals method.
Pass in a non-Probability object
String test = "foo";
assertTrue(!p1.equals(test));
Should the test pass? Should the test expect an exception?
Pass in null
assertTrue(!p1.equals(null));
Should the test pass? Should the test expect an exception?

Categories