/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.beans;
import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;
import org.obiba.magma.AbstractVariableValueSource;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.Value;
import org.obiba.magma.ValueSet;
import org.obiba.magma.ValueType;
import org.obiba.magma.Variable;
import org.obiba.magma.VariableValueSource;
import org.obiba.magma.VectorSource;
import org.obiba.magma.VectorSourceNotSupportedException;
import org.springframework.beans.InvalidPropertyException;
import org.springframework.beans.NullValueInNestedPathException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.util.Assert;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* Connects a {@code Variable} to a bean property.
*/
public class BeanPropertyVariableValueSource extends AbstractVariableValueSource implements VariableValueSource {
private final Variable variable;
private final Class<?> beanClass;
private final String propertyPath;
public BeanPropertyVariableValueSource(Variable variable, Class<?> beanClass, String propertyPath) {
Assert.notNull(variable, "variable cannot be null");
Assert.notNull(beanClass, "beanClass cannot be null");
Assert.notNull(propertyPath, "propertyPath cannot be null");
this.variable = variable;
this.beanClass = beanClass;
this.propertyPath = propertyPath;
}
@NotNull
@Override
public Variable getVariable() {
return variable;
}
@NotNull
@Override
public ValueType getValueType() {
return variable.getValueType();
}
@Override
@NotNull
public Value getValue(ValueSet valueSet) {
Object bean = ((BeanValueSet) valueSet).resolve(beanClass, valueSet, variable);
if(bean == null) {
return variable.isRepeatable() ? getValueType().nullSequence() : getValueType().nullValue();
}
if(variable.isRepeatable()) {
Iterable<Value> values = Iterables.transform((Iterable<?>) bean, new Function<Object, Value>() {
@Override
public Value apply(Object bean) {
Object object = getPropertyValue(bean);
return getValueType().valueOf(object);
}
});
return getValueType().sequenceOf(ImmutableList.copyOf(values));
}
Object object = getPropertyValue(bean);
return getValueType().valueOf(object);
}
@Override
public boolean supportVectorSource() {
return false;
}
@NotNull
@Override
public VectorSource asVectorSource() {
throw new VectorSourceNotSupportedException(getClass());
}
@Nullable
protected Object getPropertyValue(Object bean) {
try {
return PropertyAccessorFactory.forBeanPropertyAccess(bean).getPropertyValue(propertyPath);
} catch(NullValueInNestedPathException e) {
return null;
} catch(InvalidPropertyException e) {
throw new MagmaRuntimeException(
"Invalid definition of variable " + getVariable().getName() + ". Cannot obtain value for property '" +
e.getPropertyName() + "' on bean of class " + e.getBeanClass(), e);
}
}
}