fi.iki.mtr.jot.Neo4jDao.java Source code

Java tutorial

Introduction

Here is the source code for fi.iki.mtr.jot.Neo4jDao.java

Source

/*
    
  Neo4jDao.java
    
  Copyright (c) 2016, Markku Rossi
  All rights reserved.
    
  BSD 2-Clause License:
    
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:
    
  1. Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
    
  2. Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
    
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE.
    
*/

package fi.iki.mtr.jot;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import fi.iki.mtr.util.ArrayParamsIterator;
import fi.iki.mtr.util.JSONBuilder;
import fi.iki.mtr.util.ListParamsIterator;
import fi.iki.mtr.util.ParamsIterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import org.apache.commons.codec.binary.Base64;

import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Neo4jDao {
    private static Logger log = LoggerFactory.getLogger(Neo4jDao.class);

    private String serverUri;
    private String username;
    private String password;
    private CloseableHttpClient httpClient;

    public static class Statement {
        private CharSequence statement;

        public Statement(CharSequence stmt, ParamsIterator params) {
            statement = JSONBuilder.expand(stmt, params);
        }

        public JSONObject toJSON() {
            JSONObject json = new JSONObject();

            json.put("statement", statement);

            return json;
        }

        @Override
        public String toString() {
            return statement.toString();
        }
    }

    public static class Result {

        /** Result row. */
        public class Row {
            public List<Column> columns;

            public Row() {
                columns = new ArrayList<>();
            }

            public int size() {
                return columns.size();
            }
        }

        /** Result row column. */
        public class Column {
            public String name;
            public Map<String, Object> properties;

            public Column(String name) {
                this.name = name;
                properties = new HashMap<>();
            }

            public void addProperty(String key, Object value) {
                properties.put(key, value);
            }

            public JSONObject toJSON() {
                try {
                    JSONObject json = new JSONObject();

                    for (String key : properties.keySet()) {
                        json.put(key, properties.get(key));
                    }

                    return json;
                } catch (JSONException e) {
                    throw new AssertionError(e);
                }
            }
        }

        /** Result rows. */
        public List<Row> rows;

        public Result(JSONObject json) throws JSONException, IOException {
            JSONArray errors = json.getJSONArray("errors");
            if (errors.length() != 0) {
                String errorMessage = null;

                log.debug("Operation failed:");
                for (int i = 0; i < errors.length(); i++) {
                    JSONObject o = errors.getJSONObject(i);
                    String msg = o.getString("message");

                    log.error("Operation failed: " + o.getString("code") + ": " + msg);

                    if (errorMessage == null) {
                        errorMessage = msg;
                    }
                }
                if (errorMessage == null) {
                    errorMessage = "Storage error";
                }
                throw new IOException("Operation failed: " + errorMessage);
            }

            JSONArray results = json.getJSONArray("results");

            log.debug("results: " + results.toString(2));

            rows = new ArrayList<>();

            for (int i = 0; i < results.length(); i++) {
                JSONObject result = results.getJSONObject(i);
                JSONArray columns = result.getJSONArray("columns");
                JSONArray data = result.getJSONArray("data");

                for (int r = 0; r < data.length(); r++) {
                    Row row = new Row();
                    JSONObject dObj = data.getJSONObject(r);
                    JSONArray rArr = dObj.getJSONArray("row");

                    for (int c = 0; c < rArr.length(); c++) {
                        Column column = new Column(columns.getString(c));
                        Object val = rArr.get(c);
                        if (val instanceof JSONObject) {
                            JSONObject col = (JSONObject) val;

                            Iterator<String> iter = col.keys();
                            while (iter.hasNext()) {
                                String key = iter.next();
                                column.addProperty(key, col.get(key));
                            }
                        } else if (val instanceof Integer) {
                            column.addProperty("{value}", val);
                        } else {
                            throw new AssertionError("Unexpected value: " + val);
                        }

                        row.columns.add(column);
                    }

                    rows.add(row);
                }
            }
        }

        public int size() {
            return rows.size();
        }
    }

    public Neo4jDao(String serverUri, String username, String password) {
        this.serverUri = serverUri;
        this.username = username;
        this.password = password;

        httpClient = HttpClients.createDefault();
    }

    public Result execute(CharSequence stmt, Object[] params) throws IOException {
        return execute(new Statement(stmt, new ArrayParamsIterator(params)));
    }

    public Result execute(CharSequence stmt, List<Object> params) throws IOException {
        return execute(new Statement(stmt, new ListParamsIterator(params)));
    }

    public Result execute(Statement stmt) throws IOException {
        return execute(new Statement[] { stmt });
    }

    public Result execute(Statement[] statements) throws IOException {
        JSONObject json = new JSONObject();
        JSONArray arr = new JSONArray();

        for (Statement stmt : statements) {
            arr.put(stmt.toJSON());
        }

        json.put("statements", arr);

        String url = String.format("%s%s", serverUri, "/db/data/transaction/commit");

        HttpPost m = new HttpPost(url);
        m.setEntity(new StringEntity(json.toString(), ContentType.APPLICATION_JSON));
        sign(m);

        CloseableHttpResponse response = httpClient.execute(m);
        try {
            StatusLine line = response.getStatusLine();
            int code = line.getStatusCode();
            if (code < 200 || code >= 300) {
                throw new IOException("Failed to create task: " + line.getReasonPhrase());
            }
            JSONObject data = new JSONObject(EntityUtils.toString(response.getEntity()));

            return new Result(data);

        } catch (JSONException e) {
            log.error("Failed to parse response JSON", e);
            throw new IOException("Invalid server response");
        } finally {
            response.close();
        }
    }

    private void sign(HttpRequestBase req) {
        try {
            String credentials = username + ":" + password;

            req.addHeader("Authorization", "Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            throw new AssertionError(e);
        }
    }

    public void close() {
        if (httpClient != null) {
            try {
                httpClient.close();
            } catch (IOException e) {
            }
            httpClient = null;
        }
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            close();
        } finally {
            super.finalize();
        }
    }
}