package org.jboss.windup.graph;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.jboss.windup.graph.model.WindupVertexFrame;
import org.jboss.windup.util.Logging;
import org.jboss.windup.util.exception.WindupException;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.frames.FramedGraph;
import com.tinkerpop.frames.modules.MethodHandler;
/**
* Handles @MapInProperties Map<String,String>.
*
* @author <a href="mailto:ozizka@redhat.com">Ondrej Zizka</a>
*/
public class MapInPropertiesHandler implements MethodHandler<MapInProperties>
{
private static final Logger log = Logging.get(MapInPropertiesHandler.class);
@Override
public Class<MapInProperties> getAnnotationType()
{
return MapInProperties.class;
}
@Override
public Object processElement(Object frame, Method method, Object[] args, MapInProperties ann,
FramedGraph<?> framedGraph, Element elm)
{
String methodName = method.getName();
if (methodName.startsWith("get"))
return handleGetter((Vertex) elm, method, args, ann, framedGraph);
if (methodName.startsWith("set"))
return handleSetter((Vertex) elm, method, args, ann, framedGraph);
if (methodName.startsWith("put"))
return handleAdder((Vertex) elm, method, args, ann, framedGraph);
if (methodName.startsWith("putAll"))
return handleAdder((Vertex) elm, method, args, ann, framedGraph);
throw new WindupException("Only get*, set*, and put* method names are supported for @"
+ MapInProperties.class.getSimpleName() + ", found at: " + method.getName());
}
/**
* Getter
*/
private Map<String, Object> handleGetter(Vertex vertex, Method method, Object[] args, MapInProperties ann, FramedGraph<?> framedGraph)
{
if (args != null && args.length != 0)
throw new WindupException("Method must take zero arguments");
Map<String, Object> map = new HashMap<>();
String prefix = preparePrefix(ann);
Set<String> keys = vertex.getPropertyKeys();
for (String key : keys)
{
if (!key.startsWith(prefix))
continue;
final Object val = vertex.getProperty(key);
if (!ann.propertyType().isAssignableFrom(val.getClass()))
{
log.warning("@InProperties is meant for Map<String,"+ann.propertyType().getName()+">, but the value was: " + val.getClass());
}
map.put(key.substring(prefix.length()), val);
}
return map;
}
/**
* Setter
*/
private WindupVertexFrame handleSetter(Vertex vertex, Method method, Object[] args, MapInProperties 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, Object> map = (Map<String, Object>) args[0];
String prefix = preparePrefix(ann);
// For all keys in the old map...
Set<String> keys = vertex.getPropertyKeys();
Set<String> mapKeys = map.keySet();
for (String key : keys)
{
if (!key.startsWith(prefix))
continue;
if (WindupVertexFrame.TYPE_PROP.equals(key)) // Leave the "type" property.
continue;
if (key.startsWith("w:")) // Leave windup internal properties. TODO: Get the prefix from somewhere.
continue;
final Object val = vertex.getProperty(key);
if (!ann.propertyType().isAssignableFrom(val.getClass()))
{
log.warning("@InProperties is meant for Map<String,"+ann.propertyType().getName()+">, but the value was: " + val.getClass());
}
String subKey = key.substring(prefix.length());
// ...either change to new value,
if (map.containsKey(subKey))
{
vertex.setProperty(key, map.get(subKey));
mapKeys.remove(subKey);
}
// or remove the old.
else
vertex.removeProperty(key);
}
// Add the new entries.
for (String key : mapKeys)
{
vertex.setProperty(prefix + key, map.get(key));
}
return null;
}
/**
* Adder
*/
private WindupVertexFrame handleAdder(Vertex vertex, Method method, Object[] args, MapInProperties ann, FramedGraph<?> framedGraph)
{
if (args == null || args.length != 1)
throw new WindupException("Method must take one argument: " + method.getName());
String prefix = preparePrefix(ann);
// Argument.
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) args[0];
// Store all map entries in vertex'es properties.
for (Map.Entry<String, Object> entry : map.entrySet())
{
vertex.setProperty(prefix + entry.getKey(), entry.getValue());
}
return null;
}
/**
* Returns "<ann.propertyPrefix()><SEPAR>", for example, "map:".
*/
private String preparePrefix(MapInProperties ann)
{
return "".equals(ann.propertyPrefix()) ? "" : (ann.propertyPrefix() + MapInProperties.SEPAR);
}
}