/*******************************************************************************
* Copyright (c) 2011 The Board of Trustees of the Leland Stanford Junior University
* as Operator of the SLAC National Accelerator Laboratory.
* Copyright (c) 2011 Brookhaven National Laboratory.
* EPICS archiver appliance is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*******************************************************************************/
package edu.stanford.slac.archiverappliance.PB.data;
import java.nio.ByteBuffer;
import java.util.Collections;
import org.apache.commons.lang3.ArrayUtils;
import org.epics.archiverappliance.common.TimeUtils;
import org.epics.archiverappliance.config.ArchDBRTypes;
import org.epics.archiverappliance.data.ByteBufSampleValue;
import org.epics.archiverappliance.data.SampleValue;
import org.epics.archiverappliance.data.ScalarStringSampleValue;
import org.epics.archiverappliance.data.ScalarValue;
import org.epics.archiverappliance.data.VectorStringSampleValue;
import org.epics.archiverappliance.data.VectorValue;
import org.epics.archiverappliance.utils.simulation.SimulationValueGenerator;
import gov.aps.jca.dbr.DBR;
import gov.aps.jca.dbr.DBR_TIME_Byte;
import gov.aps.jca.dbr.DBR_TIME_Double;
import gov.aps.jca.dbr.DBR_TIME_Enum;
import gov.aps.jca.dbr.DBR_TIME_Float;
import gov.aps.jca.dbr.DBR_TIME_Int;
import gov.aps.jca.dbr.DBR_TIME_Short;
import gov.aps.jca.dbr.DBR_TIME_String;
/**
* Generates a sample value based on secondsintoyear for each DBR_type.
* The value generated is predictable; therefore, it can be used for unit tests.
* @author mshankar
*
*/
public class BoundaryConditionsSimulationValueGenerator implements SimulationValueGenerator{
/**
* Get a value based on the DBR type.
* We should check for boundary conditions here and make sure PB does not throw exceptions when we come close to MIN_ and MAX_ values
* @param type
* @param secondsIntoYear
* @return
*/
public SampleValue getSampleValue(ArchDBRTypes type, int secondsIntoYear) {
switch(type) {
case DBR_SCALAR_STRING:
return new ScalarStringSampleValue(Integer.toString(secondsIntoYear));
case DBR_SCALAR_SHORT:
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
return new ScalarValue<Short>((short) (Short.MIN_VALUE + secondsIntoYear));
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
return new ScalarValue<Short>((short) (Short.MAX_VALUE - (secondsIntoYear-1000)));
} else {
// Check for some numbers around 0
return new ScalarValue<Short>((short) (secondsIntoYear - 2000));
}
case DBR_SCALAR_FLOAT:
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
return new ScalarValue<Float>(Float.MIN_VALUE + secondsIntoYear);
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
return new ScalarValue<Float>(Float.MAX_VALUE - (secondsIntoYear-1000));
} else {
// Check for some numbers around 0. Divide by a large number to make sure we cater to the number of precision digits
return new ScalarValue<Float>((secondsIntoYear - 2000.0f)/secondsIntoYear);
}
case DBR_SCALAR_ENUM:
return new ScalarValue<Short>((short) secondsIntoYear);
case DBR_SCALAR_BYTE:
return new ScalarValue<Byte>(((byte)(secondsIntoYear%255)));
case DBR_SCALAR_INT:
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
return new ScalarValue<Integer>(Integer.MIN_VALUE + secondsIntoYear);
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
return new ScalarValue<Integer>(Integer.MAX_VALUE - (secondsIntoYear-1000));
} else {
// Check for some numbers around 0
return new ScalarValue<Integer>(secondsIntoYear - 2000);
}
case DBR_SCALAR_DOUBLE:
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
return new ScalarValue<Double>(Double.MIN_VALUE + secondsIntoYear);
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
return new ScalarValue<Double>(Double.MAX_VALUE - (secondsIntoYear-1000));
} else {
// Check for some numbers around 0. Divide by a large number to make sure we cater to the number of precision digits
return new ScalarValue<Double>((secondsIntoYear - 2000.0)/(secondsIntoYear*1000000));
}
case DBR_WAVEFORM_STRING:
// Varying number of copies of a typical value
return new VectorStringSampleValue(Collections.nCopies(secondsIntoYear, Integer.toString(secondsIntoYear)));
case DBR_WAVEFORM_SHORT:
return new VectorValue<Short>(Collections.nCopies(1, (short) secondsIntoYear));
case DBR_WAVEFORM_FLOAT:
// Varying number of copies of a typical value
return new VectorValue<Float>(Collections.nCopies(secondsIntoYear, (float) Math.cos(secondsIntoYear*Math.PI/3600)));
case DBR_WAVEFORM_ENUM:
return new VectorValue<Short>(Collections.nCopies(1024, (short) secondsIntoYear));
case DBR_WAVEFORM_BYTE:
// Large number of elements in the array
return new VectorValue<Byte>(Collections.nCopies(65536*secondsIntoYear, ((byte)(secondsIntoYear%255))));
case DBR_WAVEFORM_INT:
// Varying number of copies of a typical value
return new VectorValue<Integer>(Collections.nCopies(secondsIntoYear, secondsIntoYear*secondsIntoYear));
case DBR_WAVEFORM_DOUBLE:
// Varying number of copies of a typical value
return new VectorValue<Double>(Collections.nCopies(secondsIntoYear, Math.sin(secondsIntoYear*Math.PI/3600)));
case DBR_V4_GENERIC_BYTES:
// Varying number of copies of a typical value
ByteBuffer buf = ByteBuffer.allocate(1024*10);
buf.put(Integer.toString(secondsIntoYear).getBytes());
buf.flip();
return new ByteBufSampleValue(buf);
default:
throw new RuntimeException("We seemed to have missed a DBR type when generating sample data");
}
}
public int getNumberOfSamples(ArchDBRTypes type) {
switch(type) {
case DBR_SCALAR_STRING:
return 10000;
case DBR_SCALAR_SHORT:
return 4000;
case DBR_SCALAR_FLOAT:
return 4000;
case DBR_SCALAR_ENUM:
return 10;
case DBR_SCALAR_BYTE:
return 255;
case DBR_SCALAR_INT:
return 4000;
case DBR_SCALAR_DOUBLE:
return 4000;
case DBR_WAVEFORM_STRING:
return 10;
case DBR_WAVEFORM_SHORT:
return 4000;
case DBR_WAVEFORM_FLOAT:
return 4000;
case DBR_WAVEFORM_ENUM:
return 10;
case DBR_WAVEFORM_BYTE:
return 16;
case DBR_WAVEFORM_INT:
return 4000;
case DBR_WAVEFORM_DOUBLE:
return 4000;
case DBR_V4_GENERIC_BYTES:
return 1000;
default:
return 24*60*60;
}
}
public DBR getJCASampleValue(ArchDBRTypes type, int secondsIntoYear) {
switch(type) {
case DBR_SCALAR_STRING:
DBR_TIME_String retvalss = new DBR_TIME_String(new String[] { Integer.toString(secondsIntoYear) });
retvalss.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvalss.setSeverity(1);
retvalss.setStatus(0);
return retvalss;
case DBR_SCALAR_SHORT:
DBR_TIME_Short retvalsh;
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
retvalsh = new DBR_TIME_Short(new short[] { (short) (Short.MIN_VALUE + secondsIntoYear) } );
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
retvalsh = new DBR_TIME_Short(new short[] { (short) (Short.MAX_VALUE - (secondsIntoYear-1000)) } );
} else {
// Check for some numbers around 0
retvalsh = new DBR_TIME_Short(new short[] { (short) (secondsIntoYear - 2000) } );
}
retvalsh.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvalsh.setSeverity(1);
retvalsh.setStatus(0);
return retvalsh;
case DBR_SCALAR_FLOAT:
DBR_TIME_Float retvalfl;
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
retvalfl = new DBR_TIME_Float(new float[] { Float.MIN_VALUE + secondsIntoYear } );
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
retvalfl = new DBR_TIME_Float(new float[] { Float.MAX_VALUE - (secondsIntoYear-1000) } );
} else {
// Check for some numbers around 0. Divide by a large number to make sure we cater to the number of precision digits
retvalfl = new DBR_TIME_Float(new float[] { (secondsIntoYear - 2000.0f)/secondsIntoYear } );
}
retvalfl.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvalfl.setSeverity(1);
retvalfl.setStatus(0);
return retvalfl;
case DBR_SCALAR_ENUM:
DBR_TIME_Enum retvalen;
retvalen = new DBR_TIME_Enum(new short[] { (short) (secondsIntoYear) } );
retvalen.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvalen.setSeverity(1);
retvalen.setStatus(0);
return retvalen;
case DBR_SCALAR_BYTE:
DBR_TIME_Byte retvalby;
retvalby = new DBR_TIME_Byte(new byte[] { ((byte)(secondsIntoYear%255)) } );
retvalby.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvalby.setSeverity(1);
retvalby.setStatus(0);
return retvalby;
case DBR_SCALAR_INT:
DBR_TIME_Int retvalint;
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
retvalint = new DBR_TIME_Int(new int[] { Integer.MIN_VALUE + secondsIntoYear } );
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
retvalint = new DBR_TIME_Int(new int[] { Integer.MAX_VALUE - (secondsIntoYear-1000) } );
} else {
// Check for some numbers around 0
retvalint = new DBR_TIME_Int(new int[] { (secondsIntoYear - 2000) } );
}
retvalint.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvalint.setSeverity(1);
retvalint.setStatus(0);
return retvalint;
case DBR_SCALAR_DOUBLE:
DBR_TIME_Double retvaldb;
if(0 <= secondsIntoYear && secondsIntoYear < 1000) {
// Check for some numbers around the minimum value
retvaldb = new DBR_TIME_Double(new double[] { (Double.MIN_VALUE + secondsIntoYear) } );
} else if (1000 <= secondsIntoYear && secondsIntoYear < 2000) {
// Check for some numbers around the maximum value
retvaldb = new DBR_TIME_Double(new double[] { (Double.MAX_VALUE - (secondsIntoYear-1000)) } );
} else {
// Check for some numbers around 0. Divide by a large number to make sure we cater to the number of precision digits
retvaldb = new DBR_TIME_Double(new double[] { ((secondsIntoYear - 2000.0)/(secondsIntoYear*1000000)) } );
}
retvaldb.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvaldb.setSeverity(1);
retvaldb.setStatus(0);
return retvaldb;
case DBR_WAVEFORM_STRING:
DBR_TIME_String retvst;
// Varying number of copies of a typical value
retvst = new DBR_TIME_String(Collections.nCopies(secondsIntoYear, Integer.toString(secondsIntoYear)).toArray(new String[0]));
retvst.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvst.setSeverity(1);
retvst.setStatus(0);
return retvst;
case DBR_WAVEFORM_SHORT:
DBR_TIME_Short retvsh;
retvsh = new DBR_TIME_Short(ArrayUtils.toPrimitive(Collections.nCopies(1, (short) secondsIntoYear).toArray(new Short[0])));
retvsh.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvsh.setSeverity(1);
retvsh.setStatus(0);
return retvsh;
case DBR_WAVEFORM_FLOAT:
DBR_TIME_Float retvf;
// Varying number of copies of a typical value
retvf = new DBR_TIME_Float(ArrayUtils.toPrimitive(Collections.nCopies(secondsIntoYear, (float) Math.cos(secondsIntoYear*Math.PI/3600)).toArray(new Float[0])));
retvf.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvf.setSeverity(1);
retvf.setStatus(0);
return retvf;
case DBR_WAVEFORM_ENUM:
DBR_TIME_Enum retven;
retven = new DBR_TIME_Enum(ArrayUtils.toPrimitive(Collections.nCopies(1024, (short) secondsIntoYear).toArray(new Short[0])));
retven.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retven.setSeverity(1);
retven.setStatus(0);
return retven;
case DBR_WAVEFORM_BYTE:
DBR_TIME_Byte retvb;
// Large number of elements in the array
retvb = new DBR_TIME_Byte(ArrayUtils.toPrimitive(Collections.nCopies(65536*secondsIntoYear, ((byte)(secondsIntoYear%255))).toArray(new Byte[0])));
retvb.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvb.setSeverity(1);
retvb.setStatus(0);
return retvb;
case DBR_WAVEFORM_INT:
DBR_TIME_Int retvint;
// Varying number of copies of a typical value
retvint = new DBR_TIME_Int(ArrayUtils.toPrimitive(Collections.nCopies(secondsIntoYear, secondsIntoYear*secondsIntoYear).toArray(new Integer[0])));
retvint.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvint.setSeverity(1);
retvint.setStatus(0);
return retvint;
case DBR_WAVEFORM_DOUBLE:
DBR_TIME_Double retvd;
// Varying number of copies of a typical value
retvd = new DBR_TIME_Double(ArrayUtils.toPrimitive(Collections.nCopies(secondsIntoYear, Math.sin(secondsIntoYear*Math.PI/3600)).toArray(new Double[0])));
retvd.setTimeStamp(convertSecondsIntoYear2JCATimeStamp(secondsIntoYear));
retvd.setSeverity(1);
retvd.setStatus(0);
return retvd;
case DBR_V4_GENERIC_BYTES:
throw new RuntimeException("Currently don't support " + type + " when generating sample data");
default:
throw new RuntimeException("We seemed to have missed a DBR type when generating sample data");
}
}
private static gov.aps.jca.dbr.TimeStamp convertSecondsIntoYear2JCATimeStamp(int secondsintoYear) {
return new gov.aps.jca.dbr.TimeStamp(TimeUtils.getStartOfCurrentYearInSeconds() + secondsintoYear);
}
}