package com.orbitz.monitoring.lib.decomposer;
import com.orbitz.monitoring.api.Decomposer;
import com.orbitz.monitoring.api.monitor.AttributeHolder;
import com.orbitz.monitoring.api.monitor.CompositeAttributeHolder;
import com.orbitz.monitoring.lib.decomposer.AttributeDecomposer.Step;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A class that takes any Object and turns it into a Serializable implementation that can be a
* drop-in replacement for the original Object.
*
* @author Doug Barth
*/
public class AttributeDecomposer implements Decomposer {
public Serializable decompose(final Object object) {
return new BaseAttributeDecomposer().decompose(object,
new IdentityHashMap<Object, Serializable>());
}
interface Step {
Serializable decompose(Object object, IdentityHashMap<Object, Serializable> alreadyDecomposed);
}
}
class BaseAttributeDecomposer implements AttributeDecomposer.Step {
private Map<Class<?>, Step> _classToDecomposer;
public BaseAttributeDecomposer() {
_classToDecomposer = new HashMap<Class<?>, Step>();
final IdentityDecomposer identityDecomposer = new IdentityDecomposer();
_classToDecomposer.put(Character.class, identityDecomposer);
_classToDecomposer.put(String.class, identityDecomposer);
_classToDecomposer.put(Byte.class, identityDecomposer);
_classToDecomposer.put(Short.class, identityDecomposer);
_classToDecomposer.put(Integer.class, identityDecomposer);
_classToDecomposer.put(Long.class, identityDecomposer);
_classToDecomposer.put(Float.class, identityDecomposer);
_classToDecomposer.put(Double.class, identityDecomposer);
_classToDecomposer.put(Boolean.class, identityDecomposer);
_classToDecomposer.put(Date.class, identityDecomposer);
_classToDecomposer.put(StringBuffer.class, new ToStringDecomposer());
_classToDecomposer.put(Class.class, new ClassDecomposer());
_classToDecomposer.put(Map.class, new MapDecomposer(this));
_classToDecomposer.put(List.class, new ListDecomposer(this));
_classToDecomposer.put(Set.class, new SetDecomposer(this));
_classToDecomposer.put(CompositeAttributeHolder.class, new AttributeHolderDecomposer(this));
_classToDecomposer.put(AttributeHolder.class, new AttributeHolderDecomposer(this));
_classToDecomposer.put(Object[].class, new ArrayDecomposer(this));
_classToDecomposer.put(Object.class, new ReflectiveDecomposer(this));
}
public Map<Class<?>, Step> getClassDecomposerMap() {
return new HashMap<Class<?>, Step>(_classToDecomposer);
}
public Serializable decompose(final Object object,
final IdentityHashMap<Object, Serializable> alreadyDecomposed) {
if (object == null) {
return null;
}
Class<?> klass = object.getClass();
AttributeDecomposer.Step decomposer = null;
CLASS_LOOP:
while (klass != null) {
decomposer = _classToDecomposer.get(klass);
if (decomposer != null) {
break;
}
if (Object[].class.isAssignableFrom(klass)) {
decomposer = _classToDecomposer.get(Object[].class);
if (decomposer != null) {
break;
}
}
final Class<?>[] interfaces = klass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
final Class<?> anInterface = interfaces[i];
decomposer = _classToDecomposer.get(anInterface);
if (decomposer != null) {
break CLASS_LOOP;
}
}
klass = klass.getSuperclass();
}
if (decomposer == null) {
// Not using Preconditions for verification so that this message is only generated when needed
throw new NullPointerException("Could not find an AttributeDecomposer.Step for "
+ klass.getCanonicalName());
}
return decomposer.decompose(object, alreadyDecomposed);
}
}