package org.myrobotlab.memory; import java.io.Serializable; import java.util.HashMap; import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.Logging; import org.myrobotlab.logging.LoggingFactory; import org.slf4j.Logger; /** * @author GroG a "very" generalized memory node - potentially used to grow * associations with other nodes uses the concept of attributes and * free-form associations * */ public class Node implements Serializable { /** * NodeContext is used with messaging to publish updates of nodes. A location * parentPath is needed since the node is not aware of its location. */ public static class NodeContext { public String parentPath; public Node node; public NodeContext(String parentPath, Node node) { this.parentPath = parentPath; this.node = node; } } private static final long serialVersionUID = 1L; public final static Logger log = LoggerFactory.getLogger(Node.class.getCanonicalName()); private String name; public double feelingIndex = 0; public double timestamp = System.currentTimeMillis(); private HashMap<String, Object> data = new HashMap<String, Object>(); public static void main(String[] args) { try { LoggingFactory.init(Level.INFO); Node root = new Node("root"); root.put("key1", "value1"); root.put("key2", "value2"); Node node2 = new Node("node2"); root.put("node2", node2); node2.put("subkey1", "subValue"); node2.put("subIntKey", 5); Node node3 = new Node("node3"); node3.put("subkey1", "value3"); node2.put("node3", node3); Node node4 = root.getNode("root/node2/node3"); log.info("{}", node4.get("subkey1")); // Node node5 = root.getNode("root/node2/node5"); // SerializableImage img = new SerializableImage(ImageIO.read(new // File("opencv.4084.jpg")), "myImage"); // node2.put("img", img); CodecUtils.toJsonFile(root, "node.json"); log.info("here"); } catch (Exception e) { Logging.logError(e); } } public Node(String name) { this.name = name; } /** * the most important method get is the effective "search" method of memory. * It has an XPath like syntax the "/" means "data of" a node, so when the * path is /k1/k2/ - would mean get the hashmap of k2 /k1/k2 - means get the * key value of k2 in the hashmap of k1 * * other examples /background /background/position/x /background/position/y * /foreground /known/ball/red /known/ball/yellow /known/cup /unknown/object1 * /positions/x/ <map> /positions/y/ <map> /positions/time/ <map> /tracking * * @param path * @return */ public Object get(String path) { if (path == "") { return this; } if (path == "/") { return this.data; } int pos0 = path.indexOf('/'); if (pos0 != -1) { int pos1 = path.indexOf('/', pos0 + 1); String subpath; String remaining; if (pos1 != -1) { subpath = path.substring(pos0 + 1, pos1); remaining = path.substring(pos0 + 1); } else { subpath = path.substring(pos0 + 1); remaining = subpath; } if (data.containsKey(subpath)) { Object o = data.get(subpath); Class<?> c = o.getClass(); if (c == Node.class) { return ((Node) o).get(remaining); } else { return o; } } } else if (data.containsKey(path)) { return data.get(path); } if (path.equals(name)) { return this; } return null; } public String getName() { return name; } /** * a convienent cast method to get a node * * @param path * @return */ public Node getNode(String path) { return (Node) get(path); } public HashMap<String, Object> getNodes() { return data; } public Node put(Node node) { return (Node) data.put(node.getName(), node); } public Object put(String key, Object value) { return data.put(key, value); } public int size() { return data.size(); } }