/* Copyright 2012, UCAR/Unidata.
See the LICENSE file for more information.
*/
package dap4.servlet;
import dap4.core.dmr.*;
import dap4.core.util.DapException;
import dap4.dap4shared.Dap4Util;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Random;
public class RandomValue extends Value
{
//////////////////////////////////////////////////
// Constants
static final long SEED = 37L;
//////////////////////////////////////////////////
// Instance variables
protected Random random = new Random(SEED);
//////////////////////////////////////////////////
// Constructor(s)
public RandomValue()
{
}
//////////////////////////////////////////////////
// Accessors
//////////////////////////////////////////////////
// IValue Interface
public ValueSource source()
{
return ValueSource.RANDOM;
}
public Object
nextValue(DapType basetype)
throws DapException
{
Object value = null;
AtomicType atomtype = basetype.getAtomicType();
if(atomtype.isIntegerType())
value = nextInteger(basetype);
else if(atomtype.isFloatType())
value = nextFloat(basetype);
else switch (atomtype) {
case Int8:
case UInt8:
case Int16:
case UInt16:
case Int32:
case UInt32:
case Int64:
case UInt64:
value = nextInteger(basetype);
break;
case Float32:
case Float64:
value = nextFloat(basetype);
break;
case Char:
value = nextString(random, 1, 32, 127).charAt(0);
break;
case String:
value = nextString(random, MAXSTRINGSIZE, 32, 127);
break;
case URL:
value = nextURL();
break;
case Opaque:
int length = 2 + (random.nextInt(MAXOPAQUESIZE) * 2);
byte[] bytes = new byte[length];
random.nextBytes(bytes);
value = ByteBuffer.wrap(bytes);// order is irrelevant
break;
case Enum:
//Coverity[FB.BC_UNCONFIRMED_CAST]
value = nextEnum(((DapEnum) basetype));
break;
default:
throw new DapException("Unexpected type: " + basetype);
}
if(DEBUG) {
System.err.printf("RandomValue.nextValue: (%s) %s",
atomtype.toString(), value.toString());
if(atomtype.isIntegerType()) {
Number nn = (Number)value;
System.err.printf(" 0x%x\n",nn.longValue());
} else
System.err.println();
}
return value;
}
// return an integer type value (including long, but not floats)
public Object
nextInteger(DapType basetype)
throws DapException
{
AtomicType atomtype = basetype.getAtomicType();
if(!atomtype.isIntegerType())
throw new DapException("Unexpected type: " + basetype);
boolean unsigned = atomtype.isUnsigned();
switch (atomtype) {
case Int8:
return Byte.valueOf((byte) (random.nextInt(1 << 8) - (1 << 7)));
case UInt8:
return Byte.valueOf((byte) (random.nextInt(1 << 8) & 0xFF));
case Int16:
return Short.valueOf((short) (random.nextInt(1 << 16) - (1 << 15)));
case UInt16:
return Short.valueOf((short) (random.nextInt(1 << 16)));
case Int32:
return Integer.valueOf(random.nextInt());
case UInt32:
long l = random.nextLong();
l = l & 0xFFFFFFFF;
return Integer.valueOf((int) l);
case Int64:
return Long.valueOf(random.nextLong());
case UInt64:
return new BigInteger(64, random);
}
throw new DapException("Unexpected type: " + basetype);
}
// return an integer type value (including long, but not floats)
public Object
nextFloat(DapType basetype)
throws DapException
{
AtomicType atomtype = basetype.getAtomicType();
switch (atomtype) {
case Float32:
return random.nextFloat();
case Float64:
return random.nextDouble();
default:
break;
}
throw new DapException("Unexpected type: " + basetype);
}
Object
nextEnum(DapEnum en)
{
long l;
AtomicType basetype = en.getBaseType().getAtomicType();
// Collect the enum const values as BigIntegers
List<String> ecnames = en.getNames();
BigInteger[] econsts = new BigInteger[ecnames.size()];
for(int i = 0;i < econsts.length;i++) {
l = en.lookup(ecnames.get(i));
econsts[i] = BigInteger.valueOf(l);
if(basetype == AtomicType.UInt64)
econsts[i] = econsts[i].and(MASK);
}
int index = random.nextInt(econsts.length);
l = econsts[index].longValue();
Object val = null;
switch (basetype) {
case Int8:
val = new Byte((byte) l);
break;
case UInt8:
val = new Byte((byte) (l & 0xFFL));
break;
case Int16:
val = new Short((short) l);
break;
case UInt16:
val = new Short((short) (l & 0xFFFFL));
break;
case Int32:
val = new Integer((int) l);
break;
case UInt32:
val = new Integer((int) (l & 0xFFFFFFFFL));
break;
case Int64:
val = new Long(l);
break;
case UInt64:
val = new Long(l);
break;
}
return val;
}
String
nextString(Random random, int maxlength, int min, int max)
{
int length = random.nextInt(maxlength) + 1;
StringBuilder buf = new StringBuilder();
if(asciionly && max > 127) max = 127;
int range = (max+1) - min; // min..max+1 -> 0..(max+1)-min
for(int i = 0;i < length;i++) {
int c = random.nextInt(range); // 0..(max+1)-min
c = c + min; // 0..(max+1)-min -> min..max+1
buf.append((char) c);
}
return buf.toString();
}
static final String[] protocols = new String[]{"http", "https"};
static final String legal =
"abcdefghijklmnoqqrstuvwxyz"
+ "ABCDEFGHIJKLMNOQQRSTUVWXYZ"
+ "0123456789"
+ "_";
String
nextURL()
{
StringBuilder url = new StringBuilder();
url.append(protocols[random.nextInt(protocols.length)]);
url.append("://");
for(int i = 0;i < HOSTNSEG;i++) {
if(i > 0) url.append(".");
for(int j = 0;j < MAXSEGSIZE;j++) {
int c;
do {
c = random.nextInt('z');
} while(legal.indexOf(c) < 0);
url.append((char) c);
}
}
if(random.nextBoolean())
url.append(String.format(":%d", random.nextInt(5000) + 1));
for(int i = 0;i < PATHNSEG;i++) {
url.append("/");
for(int j = 0;j < MAXSEGSIZE;j++) {
int c;
do {
c = random.nextInt('z');
} while(legal.indexOf(c) < 0);
url.append((char) c);
}
}
return url.toString();
}
/**
* Return an integer in range 1..max inclusive.
*
* @param max
* @return random integer in range
* @throws DapException
*/
public int
nextCount(int max)
throws DapException
{
int min = 1;
if(max < min || min < 1)
throw new DapException("bad range");
int range = (max + 1) - min; // min..max+1 -> 0..(max+1)-min
int n = random.nextInt(range); // 0..(max+1)-min
n = n + min; // min..(max+1)
if(DEBUG)
System.err.println("RandomValue.nextCount: "+n);
return n;
}
}