00001
00005 package edu.mit.csail.sdg.squander.serializer;
00006
00007 import java.lang.reflect.Array;
00008 import java.lang.reflect.Field;
00009 import java.util.ArrayList;
00010 import java.util.Collection;
00011 import java.util.HashMap;
00012 import java.util.LinkedList;
00013 import java.util.List;
00014 import java.util.Map;
00015 import java.util.SortedSet;
00016 import java.util.Map.Entry;
00017
00018 import edu.mit.csail.sdg.squander.utils.Predicate;
00019 import edu.mit.csail.sdg.squander.utils.Utils;
00020 import edu.mit.csail.sdg.util.reflection.FieldPredicates;
00021
00022 public class Serializer {
00023
00024 private final Map<Integer, Object> serializedObjects = new HashMap<Integer, Object>();
00025
00026 private static enum Phase { Serialization, Mutation, Disposed }
00027 private Phase phase = Phase.Serialization;
00028
00033 public List<Object> serializedObjects() {
00034 return new ArrayList<Object>(serializedObjects.values());
00035 }
00036
00037
00038
00039
00040
00051 public void serialize(Object obj, HeapListener listener, Predicate<Field> fieldPred) {
00052 if (phase != Phase.Serialization) {
00053 throw new IllegalStateException("already moved on to phase " + phase);
00054 }
00055
00056 if (obj == null) {
00057 return;
00058 }
00059
00060 if (Utils.isPrimitive(obj.getClass())) {
00061 listener.visitPrimitive(obj);
00062 return;
00063 }
00064
00065
00066
00067 final int id = System.identityHashCode(obj);
00068
00069
00070 if (serializedObjects.put(id, obj) != null)
00071 return;
00072
00073
00074 listener.newObject(obj);
00075
00076 if (obj.getClass().isArray()) {
00077 serializeArray(obj, listener, fieldPred);
00078 } else {
00079 serializeClass(obj, listener, fieldPred);
00080 }
00081 }
00082
00083
00092 private void serializeArray(Object obj, HeapListener listener, Predicate<Field> fieldPred) {
00093 Class<?> cls = obj.getClass();
00094 Class<?> arrCls = cls.getComponentType();
00095 if (arrCls.isPrimitive()) {
00096 if (arrCls != int.class) {
00097 throw new RuntimeException("UNSUPPORTED PRIMITIVE TYPE: " + arrCls.getName());
00098 } else {
00099 traverseIntArray(obj, listener);
00100 }
00101 } else {
00102 traverseObjArray(obj, listener, fieldPred);
00103 }
00104 }
00105
00111 private void traverseIntArray(Object obj, HeapListener listener) {
00112 int len = Array.getLength(obj);
00113 listener.visitArrayLength(obj, len);
00114 for (int i = 0; i < len; i++) {
00115 listener.visitArrayIntField(obj, i, Array.getInt(obj, i));
00116 }
00117 }
00118
00125 private void traverseObjArray(Object obj, HeapListener listener, Predicate<Field> fieldPred) {
00126 List<Object> arrElems = new LinkedList<Object>();
00127 int len = Array.getLength(obj);
00128 listener.visitArrayLength(obj, len);
00129 for (int i = 0; i < len; i++) {
00130 Object value = Array.get(obj, i);
00131 listener.visitArrayRefField(obj, i, value);
00132 arrElems.add(value);
00133 }
00134 for (Object arrElem : arrElems) {
00135 serialize(arrElem, listener, fieldPred);
00136 }
00137 }
00138
00139
00140 private void serializeClass(Object obj, HeapListener listener, Predicate<Field> fieldPred) {
00141 if (obj.getClass() == String.class)
00142 return;
00143 if (obj instanceof Collection<?>) {
00144 for (Object o : (Collection<?>) obj)
00145 serialize(o, listener, fieldPred);
00146 return;
00147 }
00148
00149 if (obj instanceof Map<?, ?>) {
00150 for (Entry<?, ?> e : ((Map<?, ?>) obj).entrySet()) {
00151 serialize(e.getKey(), listener, fieldPred);
00152 serialize(e.getValue(), listener, fieldPred);
00153 }
00154 return;
00155 }
00156
00157 final SortedSet<Field> fields = FieldPredicates.satisfyingFields(
00158 FieldPredicates.AllNonTransientInstanceFields, obj.getClass(), Object.class);
00159
00160 for (final Field field : fields) {
00161 try {
00162 if (!fieldPred.exe(field))
00163 continue;
00164 field.setAccessible(true);
00165 if (field.getType().isPrimitive()) {
00166
00167 if (field.getType().equals(int.class)) {
00168 final int value = field.getInt(obj);
00169 listener.visitIntField(field, obj, value);
00170 } else if (field.getType().equals(boolean.class)) {
00171 final boolean value = field.getBoolean(obj);
00172 listener.visitBooleanField(field, obj, value);
00173 } else {
00174
00175 System.err.println("UNSUPPORTED PRIMITIVE TYPE: " + field);
00176 }
00177 } else {
00178
00179 final Object value = field.get(obj);
00180 listener.visitRefField(field, obj, value);
00181 serialize(value, listener, fieldPred);
00182 }
00183 } catch (final IllegalArgumentException e) {
00184 throw new RuntimeException(e);
00185 } catch (final IllegalAccessException e) {
00186 throw new RuntimeException(e);
00187 }
00188 }
00189 }
00190
00191 public void mutate(final Field field, final int sourceId, final int targetId) {
00192 if (phase.compareTo(Phase.Mutation) > 0) {
00193 throw new IllegalStateException("already moved on to phase " + phase);
00194 }
00195 phase = Phase.Mutation;
00196
00197 final Object source = serializedObjects.get(sourceId);
00198 final Object target = serializedObjects.get(targetId);
00199 field.setAccessible(true);
00200 try {
00201 field.set(source, target);
00202 } catch (final IllegalArgumentException e) {
00203 throw new RuntimeException(e);
00204 } catch (final IllegalAccessException e) {
00205 throw new RuntimeException(e);
00206 }
00207 }
00208
00209 public void dispose() {
00210 phase = Phase.Disposed;
00211 serializedObjects.clear();
00212 }
00213
00214 }