All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.jkschneider.pappus.MapToVertexMapper Maven / Gradle / Ivy
Go to download
Pappus projects any Java object model onto a Tinkerpop compatible graph.
package com.github.jkschneider.pappus;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;
import org.jibx.schema.codegen.extend.DefaultNameConverter;
import org.jibx.schema.codegen.extend.NameConverter;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.TransactionalGraph;
import com.tinkerpop.blueprints.Vertex;
public class MapToVertexMapper {
String typeProperty = "_type";
String indexProperty = "_index";
String hashProperty = "_hash";
String keyProperty = "_key";
Cache hashToVertexId = CacheBuilder.newBuilder().maximumSize(8192).build();
NameConverter nameTools = new DefaultNameConverter();
RecursiveMapDecorator hasher = new RecursiveMapDecorator();
Graph g;
public MapToVertexMapper(Graph g) {
this.g = g;
}
@SuppressWarnings("unchecked")
public Vertex toGraph(Map map, Class> c) {
Long hash = hasher.hash(map, c);
Vertex v;
Object id = hashToVertexId.getIfPresent(hash);
if(id != null)
return g.getVertex(id);
Iterator vIter = g.query().has(hashProperty, map.get(hashProperty)).vertices().iterator();
if(vIter.hasNext()) {
v = vIter.next();
hashToVertexId.put(hash, v.getId());
commitIfNecessary();
return v;
}
v = g.addVertex(null);
v.setProperty(typeProperty, c.getName());
for(Entry e : ((Map) map).entrySet()) {
String fieldName = e.getKey().toString();
if(typeProperty.equals(fieldName)) {
v.setProperty(fieldName, ((Class>) e.getValue()).getName());
}
else if(Map.class.isAssignableFrom(e.getValue().getClass())) {
// this field is a complex type, which will be mapped to a subgraph
Map e2 = (Map) e.getValue();
Class> fieldType = (Class>) e2.get("_type");
if(fieldType == null) {
// the field type itself is a map
if(e2.isEmpty())
continue;
Class> mapValueType = e2.values().iterator().next().getClass();
if(Map.class.isAssignableFrom(mapValueType)) {
for(Entry entry : e2.entrySet()) {
Vertex v2 = toGraph((Map) entry.getValue(), mapValueType);
Edge edge = v.addEdge(nameTools.depluralize(fieldName), v2);
edge.setProperty(keyProperty, entry.getKey().toString());
}
}
else
v.setProperty(fieldName, e.getValue());
}
else {
// the field is a complex type
Vertex v2 = toGraph(e2, fieldType);
v.addEdge(fieldName, v2);
}
}
else if(Collection.class.isAssignableFrom(e.getValue().getClass())) {
// this field represents a collection of objects
Collection e2 = (Collection) e.getValue();
if(e2.isEmpty())
continue;
Class> collType = e2.iterator().next().getClass();
if(Map.class.isAssignableFrom(collType)) {
// the collection contains complex types that will be mapped to individual subgraphs
int i = 0;
for(Object e3 : e2) {
Map e4 = (Map) e3;
Vertex v2 = toGraph(e4, (Class>) e4.get("_type"));
Edge edge = v.addEdge(nameTools.depluralize(fieldName), v2);
edge.setProperty(indexProperty, i++);
}
}
else {
// the collection contains primitive types... we will store the whole collection on a single property
v.setProperty(fieldName, e.getValue());
}
}
else
v.setProperty(fieldName, e.getValue());
}
commitIfNecessary();
return v;
}
private void commitIfNecessary() {
if(TransactionalGraph.class.isAssignableFrom(g.getClass()))
((TransactionalGraph) g).commit();
}
public Map fromGraph(Vertex v) {
Map map = new HashMap<>();
fromGraph(v, map);
return map;
}
Comparator edgeSorter = new Comparator() {
@Override
public int compare(Edge edge1, Edge edge2) {
if(edge1.getLabel().equals(edge2.getLabel())) {
if(edge2.getProperty(indexProperty) != null) {
// descending order by indexProperty
return (int) edge2.getProperty(indexProperty) - (int) edge1.getProperty(indexProperty);
}
if(edge2.getProperty(keyProperty) != null) {
// descending order by keyProperty
String key2 = edge2.getProperty(keyProperty), key1 = edge1.getProperty(keyProperty);
return key2.compareTo(key1);
}
}
return edge1.getLabel().compareTo(edge2.getLabel());
}
};
protected void fromGraph(Vertex v, Map map) {
for(String key : v.getPropertyKeys())
if(!hashProperty.equals(key) && !typeProperty.equals(key)) map.put(key, v.getProperty(key));
PriorityQueue edgeQueue = new PriorityQueue(10, edgeSorter);
for(Iterator edgeIter = v.query().direction(Direction.OUT).edges().iterator(); edgeIter.hasNext();)
edgeQueue.add(edgeIter.next());
String collectionLabel = null;
String mapLabel = null;
List> collection = null;
Map> mapField = null;
Edge e;
while((e = edgeQueue.poll()) != null) {
if(e.getProperty(indexProperty) != null) {
if(!e.getLabel().equals(collectionLabel)) {
// this edge represents the first element in a collection
collection = new ArrayList<>((int) e.getProperty(indexProperty));
// TODO don't assume that the field name is going to need to be pluralized
map.put(nameTools.pluralize(e.getLabel()), collection);
}
Map child = new HashMap<>();
fromGraph(e.getVertex(Direction.IN), child);
collection.add(0, child); // edges are sorted last index first
collectionLabel = e.getLabel();
}
else if(e.getProperty(keyProperty) != null) {
if(!e.getLabel().equals(mapLabel)) {
// this edge represents the first element in a map
mapField = new HashMap<>();
map.put(e.getLabel(), mapField);
}
Map child = new HashMap();
fromGraph(e.getVertex(Direction.IN), child);
mapField.put(e.getProperty(keyProperty), child);
mapLabel = e.getLabel();
}
else {
Map child = new HashMap<>();
fromGraph(e.getVertex(Direction.IN), child);
map.put(e.getLabel(), child);
}
}
commitIfNecessary();
}
}