package org.overture.codegen.runtime.traces;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.overture.codegen.runtime.ValueType;
import org.overture.codegen.runtime.copying.DeepCopy;
public class ModuleCopy
{
private static final String MODIFIERS_FIELD = "modifiers";
private static final String JAVA_LANG = "java.lang";
protected Map<Field, Object> staticFields;
public ModuleCopy(Class<?> clazz)
{
super();
if (!isJavaLangClass(clazz))
{
copyStaticFields(clazz);
}
}
private boolean isJavaLangClass(Class<?> clazz)
{
return clazz.getName().startsWith(JAVA_LANG);
}
public void reset()
{
resetStaticFields();
}
public static List<Field> getAllFields(Class<?> type)
{
return getAllFields(new LinkedList<Field>(), type);
}
public void resetStaticFields()
{
if (staticFields == null)
{
return;
}
for (Field f : staticFields.keySet())
{
f.setAccessible(true);
Object v = deepCopy(staticFields.get(f));
try
{
f.set(null, v);
} catch (IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
}
}
}
public void copyStaticFields(Class<?> clazz)
{
this.staticFields = new HashMap<>();
for (Field f : getAllFields(clazz))
{
try
{
/**
* The field may be 'private'. Make it accessible so we can set it later
*/
f.setAccessible(true);
if (isFinal(f))
{
/**
* Remove the 'final' modifier so we can set it later
*/
unfinal(f);
/**
* The Java code generator also makes 'final' fields 'static'
*/
staticFields.put(f, deepCopy(f.get(null)));
} else if (isStatic(f))
{
staticFields.put(f, deepCopy(f.get(null)));
}
} catch (NoSuchFieldException | SecurityException
| IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
}
}
}
private static void unfinal(Field f)
throws NoSuchFieldException, IllegalAccessException
{
f.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField(MODIFIERS_FIELD);
modifiersField.setAccessible(true);
modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
}
public static boolean isFinal(Field f)
{
return Modifier.isFinal(f.getModifiers());
}
public static boolean isStatic(Field f)
{
return Modifier.isStatic(f.getModifiers());
}
public static List<Field> getAllFields(List<Field> fields, Class<?> type)
{
fields.addAll(Arrays.asList(type.getDeclaredFields()));
if (type.getSuperclass() != null)
{
fields = getAllFields(fields, type.getSuperclass());
}
return fields;
}
public static Object deepCopy(Object orig)
{
if (orig == null)
{
return null;
} else if (orig instanceof ValueType)
{
ValueType vt = (ValueType) orig;
return vt.copy();
} else if (orig instanceof Number || orig instanceof Character
|| orig instanceof Boolean)
{
return orig;
} else
{
return DeepCopy.copy(orig);
}
}
public Object getValue()
{
// A module cannot be instantiated so it has no value
return null;
}
}