package simple.escp.data;
import simple.escp.exception.InvalidPlaceholder;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;
/**
* A <code>BeanDataSource</code> is a <code>DataSource</code> that obtains its value from a Java Bean object.
*/
public class BeanDataSource implements DataSource {
private static final Logger LOG = Logger.getLogger("simple.escp");
private Object source;
private PropertyDescriptor[] propertyDescriptors;
private MethodDescriptor[] methodDescriptors;
/**
* Create a new <code>BeanDataSource</code>.
*
* @param source the Java Bean object that contains the value for this <code>DataSource</code>.
*/
public BeanDataSource(Object source) {
this.source = source;
try {
BeanInfo beanInfo = Introspector.getBeanInfo(source.getClass());
propertyDescriptors = beanInfo.getPropertyDescriptors();
methodDescriptors = beanInfo.getMethodDescriptors();
} catch (IntrospectionException e) {
throw new RuntimeException("Can't read information from object.", e);
}
}
/**
* Find and return a method in this data source.
*
* @param methodName search for this method's name.
* @return a <code>MethodDescriptor</code> or <code>null</code> if this data source doesn't have
* the specified method name.
*/
public MethodDescriptor getMethod(String methodName) {
for (MethodDescriptor methodDescriptor : methodDescriptors) {
if (methodDescriptor.getName().equals(methodName)) {
return methodDescriptor;
}
}
LOG.fine("Can't find method [" + methodName + "] in this bean.");
return null;
}
/**
* Find and return a property in this data source.
*
* @param propertyName search for this property's name.
* @return a <code>PropertyDescriptor</code> or <code>null</code> if this data source doesn't have
* the specified property name.
*/
public PropertyDescriptor getProperty(String propertyName) {
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
if (propertyDescriptor.getName().equals(propertyName)) {
return propertyDescriptor;
}
}
LOG.fine("Can't find property [" + propertyName + "] in this bean.");
return null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean has(String member) {
if (member.contains(".")) {
String[] memberParts = member.split("\\.", 2);
String curentPart = memberParts[0];
String compositePart = memberParts[1];
if (!has(curentPart)) {
return false;
} else {
return (new BeanDataSource(get(curentPart))).has(compositePart);
}
} else {
if (member.startsWith("@")) {
return getMethod(member.substring(1)) != null ? true : false;
} else {
return getProperty(member) != null ? true : false;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Object get(String member) throws InvalidPlaceholder {
if (!has(member)) {
throw new InvalidPlaceholder("Can't find [" + member + "] in this data source.");
}
if (member.contains(".")) {
String[] memberParts = member.split("\\.", 2);
String curentPart = memberParts[0];
String compositePart = memberParts[1];
return (new BeanDataSource(get(curentPart))).get(compositePart);
} else {
if (member.startsWith("@")) {
try {
return getMethod(member.substring(1)).getMethod().invoke(source);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new InvalidPlaceholder("Can't execute [" + member + "].", e);
}
} else {
try {
return getProperty(member).getReadMethod().invoke(source);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new InvalidPlaceholder("Can't read [" + member + "].", e);
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Object getSource() {
return source;
}
/**
* {@inheritDoc}
*/
@Override
public String[] getMembers() {
String[] result = new String[propertyDescriptors.length];
int i = 0;
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
result[i++] = propertyDescriptor.getName();
}
return result;
}
}