package com.dooapp.gaedo.finders.root;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import com.dooapp.gaedo.CrudServiceException;
import com.dooapp.gaedo.finders.FieldInformer;
import com.dooapp.gaedo.finders.Informer;
import com.dooapp.gaedo.finders.QueryExpression;
import com.dooapp.gaedo.finders.expressions.EqualsExpression;
import com.dooapp.gaedo.properties.Property;
import com.dooapp.gaedo.properties.PropertyProvider;
public class ReflectionBackedInformer<DataType> implements Informer<DataType> {
public static class NoSuchFieldInHierarchyException extends CrudServiceException {
public NoSuchFieldInHierarchyException(String fieldName) {
super("the field named \""+fieldName+"\" does not seems to exist");
}
}
/**
* Class used when a {@link ReflectionBackedInformer} is seen as a field of another object
* @author ndx
*
*/
public class AsFieldInformer implements Informer<DataType> {
/**
* Field used to see the containing {@link ReflectionBackedInformer}
*/
private Property field;
public AsFieldInformer(Property field) {
this.field = field;
}
@Override
public FieldInformer get(String string) {
return ReflectionBackedInformer.this.get(string);
}
@Override
public QueryExpression equalsTo(Object value) {
return new EqualsExpression(field, value);
}
@Override
public Informer asField(Property field) {
return ReflectionBackedInformer.this.asField(field);
}
@Override
public Property getField() {
return field;
}
@Override
public Collection<FieldInformer> getAllFieldInformers() {
return ReflectionBackedInformer.this.getAllFieldInformers();
}
@Override
public Collection<Property> getAllFields() {
return ReflectionBackedInformer.this.getAllFields();
}
}
/**
* Informer for super class
*/
private Informer<? super DataType> parent;
/**
* Local class, used for getting fields and properties
*/
private Class<DataType> clazz;
private Map<Property, FieldInformer> fields = new HashMap<Property, FieldInformer>();
private PropertyProvider propertyProvider;
public ReflectionBackedInformer(Class<DataType> clazz,
ReflectionBackedInformerFactory reflectionBackedInformerFactory,
PropertyProvider provider) {
// Immediatly load parent infos
if(!clazz.isAssignableFrom(Object.class)) {
parent = reflectionBackedInformerFactory.get(clazz.getSuperclass());
}
// Now, get all fields
this.clazz = clazz;
this.propertyProvider = provider;
loadFieldsInformers(reflectionBackedInformerFactory);
}
/**
* Load all fields informers from the class fields
* @param reflectionBackedInformerFactory
*/
private void loadFieldsInformers(ReflectionBackedInformerFactory reflectionBackedInformerFactory) {
Property[] fieldsArray = propertyProvider.get(clazz);
for(Property f : fieldsArray) {
try {
fields.put(f, reflectionBackedInformerFactory.getInformerFor(f));
} catch(UnsupportedOperationException e) {
e.printStackTrace();
}
}
}
public FieldInformer get(String string) {
for(Map.Entry<Property, FieldInformer> f : fields.entrySet()) {
if(f.getKey().getName().equals(string)) {
return f.getValue();
} else if((clazz.getSimpleName()+"."+f.getKey().getName()).equals(string)) {
return f.getValue();
}
}
if(parent!=null) {
return parent.get(string);
} else {
throw new NoSuchFieldInHierarchyException(string);
}
}
/**
* The equalsTo method, as implemented by {@link Informer}, checks that the informer reference is equals to the reference given.
* As a consequence, a null value is given for the field (which is an error since it does not allows model navigation)
*/
@Override
public QueryExpression equalsTo(Object value) {
return new EqualsExpression(null, value);
}
@Override
public Informer asField(Property field) {
return new AsFieldInformer(field);
}
/**
* There is no field associated with object informer. As a consequence, an exception is thrown
*/
@Override
public Property getField() {
throw new UnsupportedOperationException("No field can be associated to a ReflectionBackedInformer, which only describes a root object");
}
/**
* Get all fields of this object. This method creates a short lifetime collection containing all fields of this object (coming from this class and from superclass)
* @return
*/
public Collection<FieldInformer> getAllFieldInformers() {
Collection<FieldInformer> toReturn = new LinkedList<FieldInformer>();
if(parent!=null) {
toReturn.addAll(parent.getAllFieldInformers());
}
toReturn.addAll(fields.values());
return toReturn;
}
@Override
public Collection<Property> getAllFields() {
Collection<Property> toReturn = new LinkedList<Property>();
if(parent!=null) {
toReturn.addAll(parent.getAllFields());
}
toReturn.addAll(fields.keySet());
return toReturn;
}
}