net.praqma.tracey.tracey_rabbitmq_neo4j_bridge.Tracey2Neo.java Source code

Java tutorial

Introduction

Here is the source code for net.praqma.tracey.tracey_rabbitmq_neo4j_bridge.Tracey2Neo.java

Source

package net.praqma.tracey.tracey_rabbitmq_neo4j_bridge;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.session.result.Result;

/**
 *
 * @author sofus
 */
public class Tracey2Neo {

    private final static SessionFactory sessionFactory = new SessionFactory();
    private Properties prop;

    public Tracey2Neo(Properties neoprop) {
        prop = neoprop;
        if (neoprop.size() == 0)
            System.err.println("no props");
        System.out.println(neoprop.getProperty("server_url"));
    }

    private Session getSession() {
        if (prop.getProperty("use_password").equals("no")) {
            return sessionFactory.openSession(prop.getProperty("server_url"));
        } else {
            return sessionFactory.openSession(prop.getProperty("server_url"), prop.getProperty("username"),
                    prop.getProperty("password"));
        }
    }

    /**
     * Use the {@link persistEntity} instead
     * 
     * @param jsonString
     */
    @Deprecated
    public void persist(String jsonString) {
        JsonObject json = new JsonParser().parse(jsonString).getAsJsonObject();
        Set<Entry<String, JsonElement>> paramSet = json.entrySet();
        int id = persistJsonObject(json, "Event");
        for (Entry<String, JsonElement> ent : paramSet) {
            JsonElement el = ent.getValue();
            if (el.isJsonObject()) {
                parseJson(el.getAsJsonObject(), id, ent.getKey());
            } else if (el.isJsonArray()) {
                JsonArray list = el.getAsJsonArray();
                for (JsonElement list1 : list) {
                    parseJson(list1.getAsJsonObject(), id, ent.getKey());
                }
            }
        }
    }

    /**
     * Could be used recursive
     *
     * @param json
     * @param parentId
     * @param relationType
     */
    private void parseJson(JsonObject json, int parentId, String relationType) {
        if (json.entrySet().size() == 0)
            System.out.println(json.toString());
        int childId = persistJsonObject(json, relationType);
        makeRelation(parentId, childId, relationType);

        Set<Entry<String, JsonElement>> paramSet = json.entrySet();
        for (Entry<String, JsonElement> ent : paramSet) {
            JsonElement el = ent.getValue();
            if (el.isJsonObject()) {
                parseJson(el.getAsJsonObject(), childId, ent.getKey());
            } else if (el.isJsonArray()) {
                JsonArray list = el.getAsJsonArray();
                for (JsonElement list1 : list) {
                    // TODO: What about array with primitives?!?
                    if (list1.isJsonObject()) {
                        parseJson(list1.getAsJsonObject(), childId, ent.getKey());
                    }
                }
            }
        }

    }

    private Integer[] getNeoId(String id) {
        List<Integer> outs = new ArrayList<>();
        Session s = getSession();

        Map<String, Object> cypherParams = new HashMap<>();
        cypherParams.put("id", id);
        // MATCH(n:Event{id:"59a5a70bce877dfef8d3d9b3de74d87e9b26161f"}) return
        // n
        String query = "MATCH(n:Event{id:{id}}) return id(n)";
        s.beginTransaction();
        Result res = s.query(query, cypherParams);
        Iterable<Map<String, Object>> tmp = res.queryResults();

        for (Map<String, Object> row : tmp) {
            outs.add((Integer) row.get("id(n)"));
        }
        s.getTransaction().commit();
        if (outs.isEmpty())
            outs.add(createShadowNode(id));
        System.out.println(id + " gets translated to: ");
        System.out.println(outs);
        return outs.toArray(new Integer[outs.size()]);
    }

    private void makeRelation(int from, Integer[] to, String relationType) {
        for (int i = 0; i < to.length; i++) {
            makeRelation(from, to[i], relationType);
        }
    }

    /**
     * Make relation between two nodes.
     *
     * @param from
     * @param to
     * @param relationType
     */
    private void makeRelation(int from, int to, String relationType) {
        if (from == to)
            return;
        // System.out.println("Make relation" + from + to + relationType);
        Session s = getSession();
        Map<String, Object> cypherParams = new HashMap<>();
        cypherParams.put("from", from);
        cypherParams.put("to", to);
        String query = "MATCH (lft),(rgt)\n" + "WHERE id(rgt)={to} AND id(lft)={from}\n" + "CREATE UNIQUE (lft)-[r:"
                + satisfyNoe4CrapNodeType(relationType) + "]->(rgt)\n" + "RETURN r";
        s.beginTransaction();
        s.query(query, cypherParams);
        s.getTransaction().commit();
    }

    private int persistJsonObject(JsonObject jo, String type) {
        int id = -1;
        Set<Entry<String, JsonElement>> paramSet = jo.entrySet();
        if (paramSet.isEmpty()) {
            return id;
        }
        Session s = getSession();
        StringBuilder sb = new StringBuilder(100);
        Map<String, Object> cypherParams = new HashMap<>();

        for (Entry<String, JsonElement> paramSet1 : paramSet) {
            if (paramSet1.getValue().isJsonPrimitive()) {
                String key = satisfyNeo4CrapParamValue(paramSet1.getKey());
                // Construct the key
                sb.append(key).append(":").append("{" + key + "},");
                cypherParams.put(key, getPrimitiveType(paramSet1.getValue()));
            }
        }
        if (sb.lastIndexOf(",") != -1)
            sb.deleteCharAt(sb.lastIndexOf(","));
        String query = "MERGE (n:" + satisfyNoe4CrapNodeType(type) + " {" + sb.toString() + "}) RETURN id(n)";
        System.out.println("\t" + query);
        s.beginTransaction();
        Result res = s.query(query, cypherParams);
        Iterable<Map<String, Object>> tmp = res.queryResults();
        for (Map<String, Object> row : tmp) {
            id = (Integer) row.get("id(n)");
        }
        s.getTransaction().commit();
        return id;
    }

    private JsonObject elementToObject(JsonElement el) {
        if (el.isJsonObject())
            return el.getAsJsonObject();

        JsonObject out = new JsonObject();
        out.add("data", el);
        return out;
    }

    // Ditched because NEO4J does not support nested maps. SIGHT!
    // public int createDataNode(JsonElement el, String type){
    // JsonObject obj= elementToObject(el);
    //
    // Session s = getSession();
    // int id = -1;
    // Map<String, Object> params = new HashMap<>();
    // params.put("props",JsonParserUtill.jsonToMap(obj));
    //
    // String query = "CREATE (n:Data) SET n={props}";
    // s.beginTransaction();
    // Result res = s.query(query, params);
    // Iterable<Map<String, Object>> tmp = res.queryResults();
    // for (Map<String, Object> row : tmp) {
    // id = (Integer) row.get("id(n)");
    // }
    // s.getTransaction().commit();
    //
    // return id;
    // }
    private int createShadowNode(String id) {
        // System.err.println("Creating Shadow node for: "+id);
        int out = -1;
        Session s = getSession();
        StringBuilder sb = new StringBuilder(100);
        Map<String, Object> cypherParams = new HashMap<>();

        sb.append("id : {id},");
        sb.append("type : {type}");

        cypherParams.put("id", id);
        cypherParams.put("type", "shadow_node");

        String query = "MERGE (n:Event {" + sb.toString() + "}) SET n:ShadowNode RETURN id(n)";
        s.beginTransaction();
        Result res = s.query(query, cypherParams);
        Iterable<Map<String, Object>> tmp = res.queryResults();
        for (Map<String, Object> row : tmp) {
            out = (Integer) row.get("id(n)");
        }
        s.getTransaction().commit();
        return out;
    }

    /**
     * Method that persists the Entity object, along with it's data JSON,
     * converted to nodes in NEO, with relations
     *
     * @param ent
     * @return
     */
    public int persistEvent(String ent) {
        int id = -1;
        Session s = getSession();
        StringBuilder sb = new StringBuilder(100);
        Map<String, Object> cypherParams = new HashMap<>();
        JsonParser parser = new JsonParser();
        JsonObject jsonEvent = parser.parse(ent).getAsJsonObject();
        DocumentContext dc;
        Configuration conf = Configuration.defaultConfiguration().addOptions(Option.SUPPRESS_EXCEPTIONS);
        dc = JsonPath.using(conf).parse(ent);

        sb.append("n.type = {type},");
        sb.append("n.timestamp = {timestamp},");
        sb.append("n:" + dc.read("$.meta.type", String.class));

        cypherParams.put("id", dc.read("$.meta.id", String.class));
        cypherParams.put("type", dc.read("$.meta.type", String.class));
        cypherParams.put("timestamp", dc.read("$.meta.time", String.class));

        String query = "MERGE (n:ShadowNode { id:{id},type:\"shadow_node\"}) SET " + sb.toString()
                + " REMOVE n:ShadowNode RETURN id(n)";
        s.beginTransaction();
        Result res = s.query(query, cypherParams);
        Iterable<Map<String, Object>> tmp = res.queryResults();
        for (Map<String, Object> row : tmp) {
            id = (Integer) row.get("id(n)");
        }
        s.getTransaction().commit();
        //      String[] prev = dc.read("$.links[?(@.type =~ /.*CAUSE/i)].id");

        List<Map<String, String>> prev = dc.read("$.links[*]");
        // Make relation to the last entities
        for (Map<String, String> map : prev) {
            makeRelation(id, getNeoId(map.get("id")), map.get("type"));
        }

        persistDataField(jsonEvent.get("meta"), id, "meta");

        persistDataField(jsonEvent.get("data"), id, "Data");

        return id;
    }

    private void persistDataField(JsonElement elm, int id, String relationType) {
        if (elm.isJsonObject()) {
            parseJson(elm.getAsJsonObject(), id, relationType);
        }
        // call this method again for all the elements in the array
        else if (elm.isJsonArray()) {
            JsonArray ja = elm.getAsJsonArray();
            for (JsonElement jsonElement : ja) {
                persistDataField(jsonElement, id, relationType);
            }
        }
        // make an object out of the primitive to make a node in Neo4j
        else if (elm.isJsonPrimitive()) {
            JsonObject jo = new JsonObject();
            jo.add("data", elm);
            persistDataField(jo, id, relationType);
        }
    }

    private Object getPrimitiveType(JsonElement jo) {
        if (!jo.isJsonPrimitive()) {
            return null;
        }
        JsonPrimitive jp = jo.getAsJsonPrimitive();
        if (jp.isBoolean()) {
            return jp.getAsBoolean();
        }
        if (jp.isNumber()) {
            return jp.getAsNumber();
        }
        if (jp.isString()) {
            return jp.getAsString();
        }
        return null;
    }

    /**
     * This is only due to the fact that a property key of a node cannot be a
     * number. Sight!
     *
     * @param key
     * @return
     */
    private String satisfyNeo4CrapParamValue(String key) {
        char c = key.charAt(0);
        if (c >= '0' && c <= '9') {
            key = "n" + key;
        }
        return key;
    }

    private String satisfyNoe4CrapNodeType(String type) {
        return type.replace("/", "_");

    }

}