package com.tinkerpop.rexster.gremlin.converter; import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Edge; import com.tinkerpop.blueprints.Element; import com.tinkerpop.pipes.util.structures.Row; import com.tinkerpop.pipes.util.structures.Table; import com.tinkerpop.rexster.Tokens; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Converts graph results into a serializable format * * @author Blake Eggleston (bdeggleston.github.com) */ public class SerializedResultConverter { static Object serializeElementId(final Element element) { final Object id = element.getId(); if (id.getClass().isPrimitive()) { return id; } else { return id.toString(); } } public static Object convert(Object object) { if (object == null) { return null; } else if (object instanceof String || object instanceof Number || object instanceof Boolean) { return object; } else if (object instanceof Element) { try { final Element element = (Element) object; final Set<String> propertyKeys = element.getPropertyKeys(); final boolean isVertex = !(element instanceof Edge); HashMap<Object, Object> outMap = new HashMap<Object, Object>(); outMap.put(Tokens._ID, serializeElementId(element)); if (isVertex) { outMap.put(Tokens._TYPE, Tokens.VERTEX); } else { final Edge edge = (Edge) element; outMap.put(Tokens._TYPE, Tokens.EDGE); outMap.put(Tokens._IN_V, serializeElementId(edge.getVertex(Direction.IN))); outMap.put(Tokens._OUT_V, serializeElementId(edge.getVertex(Direction.OUT))); outMap.put(Tokens._LABEL, edge.getLabel()); } if (propertyKeys.size() > 0) { HashMap<Object, Object> propertyMap = new HashMap<Object, Object>(); final Iterator<String> itty = propertyKeys.iterator(); while (itty.hasNext()) { final String propertyKey = itty.next(); propertyMap.put(propertyKey, convert(element.getProperty(propertyKey))); } outMap.put(Tokens._PROPERTIES, propertyMap); } return outMap; } catch (Exception e) { // if a transaction gets closed and the element goes out of scope it may not serialize. in these // cases the vertex will just be written as null. this can happen during binding serialization. // specific case is doing this: // v = g.addVertex() // g.rollback() // in some graphs v will go out of scope, yet it is still on the bindings as a Vertex object. return null; } } else if (object instanceof Map) { final Map map = (Map) object; HashMap<Object, Object> outMap = new HashMap<Object, Object>(); for (Object key : map.keySet()) { if(key instanceof Element) { // restructure element -> x maps // this is typical in Tree and Map returns where the key is an object value instead of a // primitive. MsgPack can't process keys that way so the data needs to be restructured // so that it doesn't end up simply being toString'd final Element element = (Element) key; final HashMap<String, Object> m = new HashMap<String, Object>(); m.put(Tokens._KEY, element); m.put(Tokens._VALUE, map.get(key)); outMap.put(element.getId().toString(), convert(m)); } else { outMap.put(key, convert(map.get(key))); } } return outMap; } else if (object instanceof Table) { final Table table = (Table) object; final Iterator<Row> rows = table.iterator(); ArrayList<Object> outArray = new ArrayList<Object>(); while (rows.hasNext()) { outArray.add(convert(rows.next())); } return outArray; } else if (object instanceof Row) { final Row row = (Row) object; final List<String> columnNames = row.getColumnNames(); HashMap<Object, Object> outMap = new HashMap<Object, Object>(); for (String columnName : columnNames) { outMap.put(columnName, convert(row.getColumn(columnName))); } return outMap; } else if (object instanceof Iterable) { final ArrayList<Object> outArray = new ArrayList<Object>(); for (Object o : (Iterable) object) { outArray.add(convert(o)); } return outArray; } else if (object instanceof Iterator) { //we need to know the array size before beginning serialization final ArrayList<Object> outArray = new ArrayList<Object>(); Iterator itty = (Iterator) object; while (itty.hasNext()) { outArray.add(convert(itty.next())); } return outArray; } else { return object.toString(); } } }