package ecologylab.serialization;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import ecologylab.collections.MultiMap;
import ecologylab.generic.Debug;
import ecologylab.net.ParsedURL;
import ecologylab.serialization.SimplTypesScope.GRAPH_SWITCH;
/**
*
* @author nabeelshahzad
*
*/
public class TranslationContext extends Debug implements ScalarUnmarshallingContext, FieldTypes
{
public static final String SIMPL_NAMESPACE = " xmlns:simpl=\"http://ecologylab.net/research/simplGuide/serialization/index.html\"";
public static final String SIMPL = "simpl";
public static final String REF = "ref";
public static final String ID = "id";
public static final String SIMPL_ID = "simpl:id";
public static final String SIMPL_REF = "simpl:ref";
public static final String JSON_SIMPL_ID = "simpl.id";
public static final String JSON_SIMPL_REF = "simpl.ref";
private MultiMap<Integer, Object> marshalledObjects;
private MultiMap<Integer, Object> visitedElements;
private MultiMap<Integer, Object> needsAttributeHashCode;
private HashMap<String, Object> unmarshalledObjects;
protected ParsedURL baseDirPurl;
protected File baseDirFile;
protected String delimiter = ",";
/**
*
*/
public TranslationContext()
{
}
/**
*
* @param fileDirContext
*/
public TranslationContext(File fileDirContext)
{
if (fileDirContext != null)
setBaseDirFile(fileDirContext);
}
/**
*
* @param purlContext
*/
public TranslationContext(ParsedURL purlContext)
{
this.baseDirPurl = purlContext;
if (purlContext.isFile())
this.baseDirFile = purlContext.file();
}
/**
*
* @param fileDirContext
*/
public void setBaseDirFile(File fileDirContext)
{
this.baseDirFile = fileDirContext;
this.baseDirPurl = new ParsedURL(fileDirContext);
}
public void initializeMultiMaps()
{
marshalledObjects = new MultiMap<Integer, Object>();
visitedElements = new MultiMap<Integer, Object>();
needsAttributeHashCode = new MultiMap<Integer, Object>();
unmarshalledObjects = new HashMap<String, Object>();
}
/**
*
* @param value
* @param elementState
*/
public void markAsUnmarshalled(String value, Object elementState)
{
if (unmarshalledObjects == null)
initializeMultiMaps();
this.unmarshalledObjects.put(value, elementState);
}
public void resolveGraph(Object object)
{
if (visitedElements == null)
initializeMultiMaps();
resolveGraphRecursvie(object);
}
/**
*
* @param elementState
*/
public void resolveGraphRecursvie(Object elementState)
{
if (SimplTypesScope.graphSwitch == GRAPH_SWITCH.ON)
{
// this.visitedElements.put(System.identityHashCode(elementState), elementState);
this.visitedElements.put(elementState.hashCode(), elementState);
ClassDescriptor.getClassDescriptor(elementState);
ArrayList<? extends FieldDescriptor> elementFieldDescriptors = ClassDescriptor
.getClassDescriptor(elementState).elementFieldDescriptors();
for (FieldDescriptor elementFieldDescriptor : elementFieldDescriptors)
{
Object thatReferenceObject = null;
Field childField = elementFieldDescriptor.getField();
try
{
thatReferenceObject = childField.get(elementState);
}
catch (IllegalAccessException e)
{
debugA("WARNING re-trying access! " + e.getStackTrace()[0]);
childField.setAccessible(true);
try
{
thatReferenceObject = childField.get(elementState);
}
catch (IllegalAccessException e1)
{
error("Can't access " + childField.getName());
e1.printStackTrace();
}
}
catch (Exception e)
{
System.out.println(e);
}
// ignore null reference objects
if (thatReferenceObject == null)
continue;
FieldType childFdType = elementFieldDescriptor.getType();
Collection thatCollection;
switch (childFdType)
{
case COLLECTION_ELEMENT:
case COLLECTION_SCALAR:
case MAP_ELEMENT:
case MAP_SCALAR:
thatCollection = XMLTools.getCollection(thatReferenceObject);
break;
default:
thatCollection = null;
break;
}
if (thatCollection != null && (thatCollection.size() > 0))
{
for (Object next : thatCollection)
{
if (next instanceof Object)
{
Object compositeElement = next;
if (this.alreadyVisited(compositeElement))
{
// this.needsAttributeHashCode.put(System.identityHashCode(compositeElement),
// compositeElement);
this.needsAttributeHashCode.put(compositeElement.hashCode(), compositeElement);
}
else
{
this.resolveGraph(compositeElement);
}
}
}
}
else if (thatReferenceObject instanceof Object)
{
Object compositeElement = thatReferenceObject;
if (this.alreadyVisited(compositeElement))
{
// this.needsAttributeHashCode.put(System.identityHashCode(compositeElement),
// compositeElement);
this.needsAttributeHashCode.put(compositeElement.hashCode(), compositeElement);
}
else
{
resolveGraph(compositeElement);
}
}
}
}
}
/**
*
* @param elementState
* @return
*/
public boolean alreadyVisited(Object elementState)
{
if (unmarshalledObjects == null)
initializeMultiMaps();
return this.visitedElements.contains(elementState.hashCode(), elementState) != -1;
}
/**
*
* @param object
*/
public void mapObject(Object object)
{
if (SimplTypesScope.graphSwitch == GRAPH_SWITCH.ON)
{
if (object != null)
this.marshalledObjects.put(object.hashCode(), object);
}
}
/**
*
* @param compositeObject
* @return
*/
public boolean alreadyMarshalled(Object compositeObject)
{
if (compositeObject == null)
return false;
return this.marshalledObjects.contains(compositeObject.hashCode(), compositeObject) != -1;
}
/**
*
* @param elementState
* @return
*/
public boolean needsHashCode(Object elementState)
{
return this.needsAttributeHashCode.contains(elementState.hashCode(), elementState) != -1;
}
/**
*
* @return
*/
public boolean isGraph()
{
return this.needsAttributeHashCode.size() > 0;
}
/**
*
* @param value
* @return
*/
public Object getFromMap(String value)
{
return this.unmarshalledObjects.get(value);
}
/**
*
*/
@Override
public ParsedURL purlContext()
{
return (baseDirPurl != null) ? baseDirPurl : (baseDirFile != null) ? new ParsedURL(baseDirFile)
: null;
}
public String getSimplId(Object object)
{
Integer objectHashCode = object.hashCode();
Integer orderedIndex = marshalledObjects.contains(objectHashCode, object);
if (orderedIndex > 0)
return objectHashCode.toString() + "," + orderedIndex.toString();
else
return objectHashCode.toString();
}
/**
*
*/
@Override
public File fileContext()
{
return (baseDirFile != null) ? baseDirFile : (baseDirPurl != null) ? baseDirPurl.file() : null;
}
/**
*
* @return
*/
public String getDelimiter()
{
return delimiter;
}
void clean()
{
if (marshalledObjects != null)
marshalledObjects.clear();
if (visitedElements != null)
visitedElements.clear();
if (needsAttributeHashCode != null)
needsAttributeHashCode.clear();
if (needsAttributeHashCode != null)
unmarshalledObjects.clear();
baseDirPurl = null;
baseDirFile = null;
delimiter = ",";
}
}