/* IterableNumericProperty.java created 2007-12-05
*
*/
package org.signalml.method.iterator;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.apache.log4j.Logger;
import org.signalml.exception.SanityCheckException;
import org.signalml.method.InputDataException;
/** IterableNumericProperty
*
*
* @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o.
*/
public class IterableNumericProperty implements IterableNumericParameter {
protected static final Logger logger = Logger.getLogger(IterableNumericProperty.class);
private static HashMap<Class<?>, NumberCaster> casterMap = new HashMap<Class<?>, NumberCaster>();
static {
NumberCaster byteCaster = new ToByteNumberCaster();
NumberCaster shortCaster = new ToShortNumberCaster();
NumberCaster integerCaster = new ToIntegerNumberCaster();
NumberCaster longCaster = new ToLongNumberCaster();
NumberCaster floatCaster = new ToFloatNumberCaster();
NumberCaster doubleCaster = new ToDoubleNumberCaster();
casterMap.put(byte.class, byteCaster);
casterMap.put(Byte.class, byteCaster);
casterMap.put(short.class, shortCaster);
casterMap.put(Short.class, shortCaster);
casterMap.put(int.class, integerCaster);
casterMap.put(Integer.class, integerCaster);
casterMap.put(long.class, longCaster);
casterMap.put(Long.class, longCaster);
casterMap.put(float.class, floatCaster);
casterMap.put(Float.class, floatCaster);
casterMap.put(double.class, doubleCaster);
casterMap.put(Double.class, doubleCaster);
}
private Object subject;
private String propertyName;
private Class<?> propertyType;
private Method getter = null;
private Method setter = null;
private Comparable<? extends Number> minimum;
private Comparable<? extends Number> maximum;
private Number stepSize;
private Number defaultStartValue;
private Number defaultEndValue;
private NumberCaster caster;
public IterableNumericProperty(Object subject, String propertyName) throws IntrospectionException {
if (subject == null) {
throw new NullPointerException("No subject");
}
this.subject = subject;
this.propertyName = propertyName;
PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, subject.getClass());
propertyType = descriptor.getPropertyType();
if (propertyType.isPrimitive()) {
if (propertyType.equals(boolean.class) || propertyType.equals(char.class)) {
throw new IntrospectionException("Not a number primitive");
}
} else {
if (!Number.class.isAssignableFrom(descriptor.getPropertyType())) {
throw new IntrospectionException("Not a number class");
}
}
getter = descriptor.getReadMethod();
setter = descriptor.getWriteMethod();
caster = casterMap.get(propertyType);
if (caster == null) {
throw new SanityCheckException("No caster for class [" + propertyType + "]");
}
}
@Override
public Comparable<? extends Number> getMinimum() {
return minimum;
}
public void setMinimum(Comparable<? extends Number> minimum) {
this.minimum = minimum;
}
@Override
public Comparable<? extends Number> getMaximum() {
return maximum;
}
public void setMaximum(Comparable<? extends Number> maximum) {
this.maximum = maximum;
}
@Override
public Number getStepSize() {
return stepSize;
}
public void setStepSize(Number stepSize) {
this.stepSize = stepSize;
}
@Override
public Number getDefaultStartValue() {
return defaultStartValue;
}
public void setDefaultStartValue(Number defaultStartValue) {
this.defaultStartValue = defaultStartValue;
}
@Override
public Number getDefaultEndValue() {
return defaultEndValue;
}
public void setDefaultEndValue(Number defaultEndValue) {
this.defaultEndValue = defaultEndValue;
}
@Override
public String getName() {
return propertyName;
}
@Override
public Class<?> getValueClass() {
return propertyType;
}
@Override
public Object getValue() {
Object value;
try {
value = getter.invoke(subject, new Object[0]);
} catch (Exception ex) {
logger.error("Failed to get value", ex);
value = null;
}
return value;
}
@Override
public void setValue(Object value) throws InputDataException {
try {
setter.invoke(subject, new Object[] { value });
} catch (Exception ex) {
InputDataException exception = new InputDataException(subject, "data");
exception.rejectValue(propertyName, "error.setIteratedValueFailed", new Object[] { ex.getMessage() }, "error.setIteratedValueFailed");
throw exception;
}
}
@Override
public Object setIterationValue(Object startValue, Object endValue, int iteration, int totalIterations) {
double start = ((Number) startValue).doubleValue();
double end = ((Number) endValue).doubleValue();
double step = (end-start) / totalIterations;
double value = start + (step * iteration);
Object object = caster.cast(value);
try {
setValue(object);
} catch (InputDataException ex) {
logger.error("Failed to set iterated value", ex);
}
return object;
}
@Override
public Object[] getArguments() {
return new Object[] { propertyName };
}
@Override
public String[] getCodes() {
return new String[] { "iterableNumericProperty." + propertyName, "iterableNumericProperty" };
}
@Override
public String getDefaultMessage() {
return propertyName;
}
static interface NumberCaster {
Number cast(double value);
}
static class ToByteNumberCaster implements NumberCaster {
@Override
public Number cast(double value) {
return new Byte((byte) Math.round(value));
}
}
static class ToShortNumberCaster implements NumberCaster {
@Override
public Number cast(double value) {
return new Short((short) Math.round(value));
}
}
static class ToIntegerNumberCaster implements NumberCaster {
@Override
public Number cast(double value) {
return new Integer((int) Math.round(value));
}
}
static class ToLongNumberCaster implements NumberCaster {
@Override
public Number cast(double value) {
return new Long(Math.round(value));
}
}
static class ToFloatNumberCaster implements NumberCaster {
@Override
public Number cast(double value) {
return new Float((float) value);
}
}
static class ToDoubleNumberCaster implements NumberCaster {
@Override
public Number cast(double value) {
return new Double(value);
}
}
}