package com.google.code.joto.ast.valueholder;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.google.code.joto.util.attr.DefaultAttributeSupport;
import com.google.code.joto.util.attr.IAttributeSupport;
import com.google.code.joto.util.attr.IAttributeSupportDelegate;
import com.thoughtworks.xstream.converters.reflection.FieldDictionary;
/**
* base class of AST hierarchy for object tree values (or fragment of values)
*
* This is an in-memory replacement of real objects by generic ones:
* transform real java Object => Map < Map < Field,Value> >
*
* This is done for several purpose:
* <ul>
* <li> Objects graph can be traversed in both direction : every object records the list of pointer to itself</li>
* <li> Object elements (instance, fields, array elements) are all first-class-citizen objects, and can be annotated with key=values markers for internal algorithms</li>
* <li> The reflection api is called only once, to build the generic equivalent form. </li>
* <li> The reflection API is rather complex to access private field (using native call to jdk specific methods, using XStream implementation helpers) </li>
* </ul>
*
* It allows treating similar objects like List,ArrayList,UnmodifiableList...
*/
public abstract class ValueHolderAST implements IAttributeSupportDelegate {
private IAttributeSupport attributeSupport;
protected ValueHolderAST() {
}
public abstract void visit(ValueHolderVisitor v);
public abstract <R,A> R visit(ValueHolderVisitor2<R,A> v, A arg);
public IAttributeSupport getAttributeSupport() {
if (attributeSupport == null) {
attributeSupport = new DefaultAttributeSupport();
}
return attributeSupport;
}
public static Class<?> wrapperTypeFor(Class<?> primitiveType) {
if (primitiveType == Boolean.TYPE) return Boolean.class;
if (primitiveType == Byte.TYPE) return Byte.class;
if (primitiveType == Character.TYPE) return Character.class;
if (primitiveType == Short.TYPE) return Short.class;
if (primitiveType == Integer.TYPE) return Integer.class;
if (primitiveType == Long.TYPE) return Long.class;
if (primitiveType == Float.TYPE) return Float.class;
if (primitiveType == Double.TYPE) return Double.class;
if (primitiveType == Void.TYPE) return Void.class;
return null;
}
private static void checkValueWrapperForPrimitiveType(Object value, Class<?> type) {
if (value != null) {
Class<?> valueClass = value.getClass();
if (valueClass != wrapperTypeFor(type)) {
throw new IllegalArgumentException();
}
} else {
// no check or throw ??
}
}
// -------------------------------------------------------------------------
public static abstract class AbstractObjectValueHolder extends ValueHolderAST {
protected final Class<?> objClass;
private List<RefObjectValueHolder> linksFrom = new ArrayList<RefObjectValueHolder>();
protected AbstractObjectValueHolder(Class<?> objClass) {
this.objClass = objClass;
}
public Class<?> getObjClass() {
return objClass;
}
public List<RefObjectValueHolder> getLinksFrom() {
return linksFrom;
}
/*pp*/ void _inv_removeLinkFrom(RefObjectValueHolder p) {
linksFrom.remove(p);
}
/*pp*/ void _inv_addLinkFrom(RefObjectValueHolder p) {
linksFrom.add(p);
}
}
/**
* This class is the parent-classes for all kind of "pointer" in the ValueHolder hierarchy
*/
public static abstract class RefObjectValueHolder extends ValueHolderAST {
private final AbstractObjectValueHolder from;
private AbstractObjectValueHolder to;
public RefObjectValueHolder(AbstractObjectValueHolder from) {
this.from = from;
}
public RefObjectValueHolder(AbstractObjectValueHolder from, AbstractObjectValueHolder to) {
this(from);
setTo(to);
}
public final AbstractObjectValueHolder getTo() {
return to;
}
public final AbstractObjectValueHolder getFrom() {
return from;
}
public final void setTo(AbstractObjectValueHolder p) {
if (p == to) return;
if (to != null) {
to._inv_removeLinkFrom(this);
}
this.to = p;
if (to != null) {
to._inv_addLinkFrom(this);
}
}
public String toString() {
return "RefVH[ to:" + to + "]";
}
}
// /**
// *
// */
// public static class NullValueHolder extends AbstractObjectValueHolder {
//
// public static final NullValueHolder INSTANCE = new NullValueHolder();
//
// public static final NullValueHolder getInstance() { return INSTANCE; }
//
// private NullValueHolder() {
// super(Void.class);
// }
//
// @Override
// public void visit(ValueHolderVisitor v) {
// v.caseNull();
// }
//
// @Override
// public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
// return v.caseNull(a);
// }
//
// }
// -------------------------------------------------------------------------
/**
*
*/
public static class ObjectValueHolder extends AbstractObjectValueHolder {
private Map<Field,FieldValueHolder> fieldsValuesMap = new LinkedHashMap<Field,FieldValueHolder>();
public ObjectValueHolder(Class<?> objClass) {
super(objClass);
}
public void visit(ValueHolderVisitor v) {
v.caseObject(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.caseObject(this, a);
}
public Map<Field,FieldValueHolder> getFieldsValuesMap() {
return fieldsValuesMap;
}
public FieldValueHolder getFieldValue(FieldDictionary fieldDictionary, String fieldName, Class<?> fieldType) {
Field field;
try {
// does not work: only public fields are found
//... field = objClass.getField(fieldName);
field = fieldDictionary.field(objClass, fieldName, null);
} catch(Exception ex) {
throw new RuntimeException(ex);
}
return getFieldValue(field);
}
public FieldValueHolder getFieldValue(Field field) {
FieldValueHolder res = fieldsValuesMap.get(field);
if (res == null) {
// instanciate proer sub-class for Field
res = newFieldValue(field);
fieldsValuesMap.put(field, res);
}
return res;
}
protected FieldValueHolder newFieldValue(Field field) {
FieldValueHolder res;
Class<?> fieldType = field.getType();
if (fieldType.isPrimitive()) {
res = new PrimitiveFieldValueHolder(this, field);
} else {
res = new RefFieldValueHolder(this, field);
}
return res;
}
}
/**
* this interface is a technical atifact to do emulate "multiple inheritance":
* PrimitiveField .. extends ValueHolderAST
* RefField .. extends RefValueHolder
*/
public static interface FieldValueHolder {
ValueHolderAST getThisValueHolder();
// helper for getThisValueHolder().visit(v)
public void visit(ValueHolderVisitor v);
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A arg);
public ObjectValueHolder getParent();
public Field getField();
public Class<?> getFieldType(); // helper for getField().getType()
}
// /**
// *
// */
// public static abstract class AbstractFieldValueHolder extends ValueHolderAST {
//
// protected AbstractObjectValueHolder parent;
// protected final Field field;
//
// public AbstractFieldValueHolder(AbstractObjectValueHolder parent, Field field) {
// super();
// this.parent = parent;
// this.field = field;
// }
//
//
// public AbstractObjectValueHolder getParent() {
// return parent;
// }
//
// public Field getField() {
// return field;
// }
//
// public Class<?> getFieldType() {
// return field.getType();
// }
//
// }
// -------------------------------------------------------------------------
/**
*
*/
public static class PrimitiveFieldValueHolder extends ValueHolderAST implements FieldValueHolder { // extends AbstractFieldValueHolder
protected final ObjectValueHolder parent;
protected final Field field;
private Object value;
public PrimitiveFieldValueHolder(ObjectValueHolder parent, Field field) {
this.parent = parent;
this.field = field;
}
public void visit(ValueHolderVisitor v) {
v.casePrimitiveField(this);
}
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.casePrimitiveField(this, a);
}
public ValueHolderAST getThisValueHolder() {
return this;
}
public ObjectValueHolder getParent() {
return parent;
}
public Field getField() {
return field;
}
public Class<?> getFieldType() {
return field.getType();
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
checkValueWrapperForPrimitiveType(value, field.getType());
this.value = value;
}
}
/**
*
*/
public static class RefFieldValueHolder extends RefObjectValueHolder implements FieldValueHolder {
protected final Field field;
public RefFieldValueHolder(ObjectValueHolder parent, Field field) {
super(parent);
this.field = field;
}
public void visit(ValueHolderVisitor v) {
v.caseRefField(this);
}
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.caseRefField(this, a);
}
public ValueHolderAST getThisValueHolder() {
return this;
}
public ObjectValueHolder getParent() {
return (ObjectValueHolder) getFrom();
}
public Field getField() {
return field;
}
public Class<?> getFieldType() {
return field.getType();
}
}
// -------------------------------------------------------------------------
/**
*
*/
public static class ImmutableObjectValueHolder extends AbstractObjectValueHolder {
private final Object value;
public ImmutableObjectValueHolder(Object value) {
super(value.getClass());
this.value = value;
}
@Override
public void visit(ValueHolderVisitor v) {
v.caseImmutableObjectValue(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.caseImmutableObjectValue(this, a);
}
public Object getValue() {
return value;
}
}
// -------------------------------------------------------------------------
/**
*
*/
public static class PrimitiveArrayEltValueHolder<T> extends ValueHolderAST {
private PrimitiveArrayValueHolder<T> parent;
private int index;
private T value;
public PrimitiveArrayEltValueHolder(PrimitiveArrayValueHolder<T> parent, int index) {
super();
this.parent = parent;
this.index = index;
}
public void visit(ValueHolderVisitor v) {
v.casePrimitiveArrayElt(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.casePrimitiveArrayElt(this, a);
}
public PrimitiveArrayValueHolder<T> getParent() {
return parent;
}
public int getIndex() {
return index;
}
public T getValue() {
return value;
}
public void setValue(T value) {
if (value != null && value.getClass() != parent.componentWrapperType) {
throw new IllegalArgumentException();
}
this.value = value;
}
}
/**
*
*/
public static class PrimitiveArrayValueHolder<T> extends AbstractObjectValueHolder {
private Class<?> componentWrapperType;
private PrimitiveArrayEltValueHolder<T>[] holderArray;
@SuppressWarnings("unchecked")
public PrimitiveArrayValueHolder(Class<?> arrayObjType, int len) {
super(arrayObjType);
componentWrapperType = wrapperTypeFor(arrayObjType.getComponentType());
holderArray = new PrimitiveArrayEltValueHolder[len];
for (int i = 0; i < len; i++) {
holderArray[i] = new PrimitiveArrayEltValueHolder<T>(this, i);
}
}
public void visit(ValueHolderVisitor v) {
v.casePrimitiveArray(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.casePrimitiveArray(this, a);
}
public PrimitiveArrayEltValueHolder<T>[] getHolderArray() {
return holderArray;
}
public PrimitiveArrayEltValueHolder<T> getHolderArrayAt(int index) {
return holderArray[index];
}
public void setValueAt(int index, T value) {
PrimitiveArrayEltValueHolder<T> h = getHolderArrayAt(index);
h.setValue(value);
}
public T getValueAt(int index) {
PrimitiveArrayEltValueHolder<T> h = getHolderArrayAt(index);
return h.getValue();
}
}
// -------------------------------------------------------------------------
/**
*
*/
public static class ArrayEltRefValueHolder extends RefObjectValueHolder {
// cf super: ObjectArrayValueHolder from
private int index;
public ArrayEltRefValueHolder(RefArrayValueHolder from, int index) {
super(from);
this.index = index;
}
public void visit(ValueHolderVisitor v) {
v.caseRefArrayElt(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.caseRefArrayElt(this, a);
}
public RefArrayValueHolder getFromArray() {
return (RefArrayValueHolder) super.getFrom();
}
public int getIndex() {
return index;
}
}
/**
*
*/
public static class RefArrayValueHolder extends AbstractObjectValueHolder {
private ArrayEltRefValueHolder[] elts;
public RefArrayValueHolder(Class<?> arrayType, int len) {
super(arrayType);
elts = new ArrayEltRefValueHolder[len];
for (int i = 0; i < len; i++) {
elts[i] = new ArrayEltRefValueHolder(this, i);
}
}
@Override
public void visit(ValueHolderVisitor v) {
v.caseRefArray(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.caseRefArray(this, a);
}
public ArrayEltRefValueHolder[] getEltRefs() {
return elts;
}
public AbstractObjectValueHolder[] getElts() {
int len = elts.length;
AbstractObjectValueHolder[] res = new AbstractObjectValueHolder[len];
for (int i = 0; i < len; i++) {
res[i] = elts[i].getTo();
}
return res;
}
public ArrayEltRefValueHolder getHolderArrayEltAt(int index) {
return elts[index];
}
public void setValueAt(int index, AbstractObjectValueHolder value) {
ArrayEltRefValueHolder h = getHolderArrayEltAt(index);
h.setTo(value);
}
public AbstractObjectValueHolder getValueAt(int index) {
ArrayEltRefValueHolder h = getHolderArrayEltAt(index);
return h.getTo();
}
}
// -------------------------------------------------------------------------
/**
*
*/
public static class CollectionValueHolder extends ObjectValueHolder {
private Collection<CollectionEltRefValueHolder> elts;
public CollectionValueHolder() {
this(ArrayList.class, new ArrayList<CollectionEltRefValueHolder>());
}
public CollectionValueHolder(Class<?> type, Collection<CollectionEltRefValueHolder> value) {
super(type);
this.elts = value;
}
@Override
public void visit(ValueHolderVisitor v) {
v.caseCollection(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.caseCollection(this, a);
}
public Collection<CollectionEltRefValueHolder> getEltRefs() {
return elts;
}
public Collection<AbstractObjectValueHolder> getElts() {
Collection<AbstractObjectValueHolder> res = new ArrayList<AbstractObjectValueHolder>(elts.size());
for(CollectionEltRefValueHolder elt : elts) {
res.add(elt.getTo());
}
return res;
}
// public void setElts(Collection<RefObjectValueHolder> p) {
// this.elts = p;
// }
public void addRefElt(AbstractObjectValueHolder p) {
CollectionEltRefValueHolder refElt = new CollectionEltRefValueHolder(this, p);
elts.add(refElt);
}
}
/**
* ValuHolder for elements of CollectionValueHolder
*/
public static class CollectionEltRefValueHolder extends RefObjectValueHolder {
// cf super: CollectionValueHolder from
//
public CollectionEltRefValueHolder(CollectionValueHolder from) {
super(from);
}
public CollectionEltRefValueHolder(CollectionValueHolder from, AbstractObjectValueHolder to) {
this(from);
setTo(to);
}
@Override
public void visit(ValueHolderVisitor v) {
v.caseCollectionElt(this);
}
@Override
public <R, A> R visit(ValueHolderVisitor2<R, A> v, A arg) {
return v.caseCollectionElt(this, arg);
}
public String toString() {
return "EltRefVH[" + super.toString() + "]";
}
}
// -------------------------------------------------------------------------
/**
*
*/
public static class MapValueHolder extends ObjectValueHolder {
private Collection<MapEntryValueHolder> entries;
public MapValueHolder() {
this(HashMap.class);
}
public MapValueHolder(Class<?> type) {
super(type);
this.entries = new ArrayList<MapEntryValueHolder>();
}
public void visit(ValueHolderVisitor v) {
v.caseMap(this);
}
@Override
public <R,A> R visit(ValueHolderVisitor2<R,A> v, A a) {
return v.caseMap(this, a);
}
public Collection<MapEntryValueHolder> getEntries() {
return entries;
}
// public void setEntries(Collection<MapEntryValueHolder<K,T>> p) {
// this.entries = p;
// }
public void putEntry(AbstractObjectValueHolder/*<K>*/ key, AbstractObjectValueHolder/*<T>*/ value) {
MapEntryValueHolder e = new MapEntryValueHolder(this, key, value);
this.entries.add(e);
}
}
/**
*
*/
public static class MapEntryValueHolder extends AbstractObjectValueHolder {
final Map2MapEntryRefValueHolder map2MapEntryRef;
final MapEntryKeyRefValueHolder key = new MapEntryKeyRefValueHolder(this);
final MapEntryValueRefValueHolder value = new MapEntryValueRefValueHolder(this);
public MapEntryValueHolder(MapValueHolder from,
AbstractObjectValueHolder keyTo,
AbstractObjectValueHolder valueTo) {
super(Map.Entry.class);
this.map2MapEntryRef = new Map2MapEntryRefValueHolder(from, this);
this.key.setTo(keyTo);
this.value.setTo(valueTo);
}
@Override
public void visit(ValueHolderVisitor v) {
v.caseMapEntry(this);
}
@Override
public <R, A> R visit(ValueHolderVisitor2<R, A> v, A arg) {
return v.caseMapEntry(this, arg);
}
public MapValueHolder getFromMap() {
return map2MapEntryRef.getFromMap();
}
public MapEntryKeyRefValueHolder getKeyRef() {
return key;
}
public MapEntryValueRefValueHolder getValueRef() {
return value;
}
public AbstractObjectValueHolder getValue() {
return value.getTo();
}
public AbstractObjectValueHolder getKey() {
return key.getTo();
}
public void setValueTo(AbstractObjectValueHolder valueTo) {
this.value.setTo(valueTo);
}
}
/**
*
*/
public static class Map2MapEntryRefValueHolder extends RefObjectValueHolder {
public Map2MapEntryRefValueHolder(MapValueHolder from, MapEntryValueHolder to) {
super(from);
}
@Override
public void visit(ValueHolderVisitor v) {
// internal... do nothing! v.caseMap2MapEntry(this);
}
@Override
public <R, A> R visit(ValueHolderVisitor2<R, A> v, A arg) {
// internal... do nothing! return v.caseMap2MapEntry(this, arg);
return null;
}
public MapValueHolder getFromMap() {
return (MapValueHolder) getFrom();
}
public MapEntryValueHolder getToMapEntry() {
return (MapEntryValueHolder) getTo();
}
}
/**
*
*/
public static class MapEntryKeyRefValueHolder extends RefObjectValueHolder {
public MapEntryKeyRefValueHolder(MapEntryValueHolder from) {
super(from);
}
@Override
public void visit(ValueHolderVisitor v) {
v.caseMapEntryKey(this);
}
@Override
public <R, A> R visit(ValueHolderVisitor2<R, A> v, A arg) {
return v.caseMapEntryKey(this, arg);
}
public MapValueHolder getFromMap() {
return getFromMapEntry().getFromMap();
}
public MapEntryValueHolder getFromMapEntry() {
return (MapEntryValueHolder) getFrom();
}
}
/**
*
*/
public static class MapEntryValueRefValueHolder extends RefObjectValueHolder {
public MapEntryValueRefValueHolder(AbstractObjectValueHolder from) {
super(from);
}
@Override
public void visit(ValueHolderVisitor v) {
v.caseMapEntryValue(this);
}
@Override
public <R, A> R visit(ValueHolderVisitor2<R, A> v, A arg) {
return v.caseMapEntryValue(this, arg);
}
public MapValueHolder getFromMap() {
return getFromMapEntry().getFromMap();
}
public MapEntryValueHolder getFromMapEntry() {
return (MapEntryValueHolder) getFrom();
}
}
}