package org.jboss.windup.graph; import java.io.Serializable; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.jboss.windup.util.Logging; import org.jboss.windup.util.exception.WindupException; import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Element; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.frames.FramedGraph; import com.tinkerpop.frames.modules.MethodHandler; /** * Handles @MapInAdjacentProperties Map<String,String>. * * @author <a href="mailto:ozizka@redhat.com">Ondrej Zizka</a> */ public class MapInAdjacentPropertiesHandler implements MethodHandler<MapInAdjacentProperties> { private static final Logger log = Logging.get(MapInAdjacentPropertiesHandler.class); @Override public Class<MapInAdjacentProperties> getAnnotationType() { return MapInAdjacentProperties.class; } @Override public Map<String, Serializable> processElement(Object frame, Method method, Object[] arguments, MapInAdjacentProperties annotation, FramedGraph<?> framedGraph, Element elm) { if (!(elm instanceof Vertex)) throw new WindupException("@" + MapInAdjacentProperties.class.getSimpleName() + " is only supported on Vertex objects."); String methodName = method.getName(); if (methodName.startsWith("get")) return handleGetter((Vertex) elm, method, arguments, annotation, framedGraph); if (methodName.startsWith("set")) { handleSetter((Vertex) elm, method, arguments, annotation, framedGraph); return null; } throw new WindupException("Only get* and set* method names are supported for @" + MapInAdjacentProperties.class.getSimpleName()); } /** * Getter */ private Map<String, Serializable> handleGetter(Vertex vertex, Method method, Object[] args, MapInAdjacentProperties ann, FramedGraph<?> framedGraph) { if (args != null && args.length != 0) throw new WindupException("Method must take no arguments: " + method.getName()); // Find the map vertex. Map<String, Serializable> map = new HashMap<>(); Iterable<Vertex> verts = vertex.getVertices(Direction.OUT, ann.label()); Vertex mapVertex = null; final Iterator<Vertex> it = verts.iterator(); if (!it.hasNext()) { // No map yet. return map; } else { mapVertex = it.next(); if (it.hasNext()) { // Multiple vertices behind edges with given label. log.warning("Found multiple vertices for a map, using only first one; for: " + method.getName()); } } Set<String> keys = mapVertex.getPropertyKeys(); for (String key : keys) { final Object val = mapVertex.getProperty(key); if (!(val instanceof String)) log.warning("@InProperties is meant for Map<String,Serializable>, but the value was: " + val.getClass()); map.put(key, "" + val); } return map; } /** * Setter */ private void handleSetter(Vertex vertex, Method method, Object[] args, MapInAdjacentProperties ann, FramedGraph<?> framedGraph) { // Argument. if (args == null || args.length != 1) throw new WindupException("Method must take one argument: " + method.getName()); if (!(args[0] instanceof Map)) throw new WindupException("Argument of " + method.getName() + " must be a Map, but is: " + args[0].getClass()); @SuppressWarnings("unchecked") Map<String, Serializable> map = (Map<String, Serializable>) args[0]; // Find or create the map vertex. Iterable<Vertex> verts = vertex.getVertices(Direction.OUT, ann.label()); Vertex mapVertex = null; final Iterator<Vertex> it = verts.iterator(); if (!it.hasNext()) { // No map vertex yet. mapVertex = framedGraph.addVertex(null); vertex.addEdge(ann.label(), mapVertex); } else { mapVertex = it.next(); if (it.hasNext()) { // Multiple vertices behind edges with given label. log.warning("Found multiple vertices for a map, using only first one; for: " + method.getName()); } } // For all keys in the old map... Set<String> keys = mapVertex.getPropertyKeys(); Set<String> mapKeys = map.keySet(); for (String key : keys) { final Object val = mapVertex.getProperty(key); if (!(val instanceof String)) { log.warning("@InProperties is meant for Map<String,Serializable>, but the value was: " + val.getClass()); } // ...either change to new value, if (map.containsKey(key)) { mapVertex.setProperty(key, map.get(key)); mapKeys.remove(key); } // or remove the old. else mapVertex.removeProperty(key); } // Add the new entries. for (String key : mapKeys) { mapVertex.setProperty(key, map.get(key)); } } }