org.neo4j.ogm.session.response.JsonResponse.java Source code

Java tutorial

Introduction

Here is the source code for org.neo4j.ogm.session.response.JsonResponse.java

Source

/*
 * Copyright (c) 2002-2015 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This product is licensed to you under the Apache License, Version 2.0 (the "License").
 * You may not use this product except in compliance with the License.
 *
 * This product may include a number of subcomponents with
 * separate copyright notices and license terms. Your use of the source
 * code for these subcomponents is subject to the terms and
 * conditions of the subcomponent's license, as noted in the LICENSE file.
 *
 */

package org.neo4j.ogm.session.response;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.neo4j.ogm.session.result.ResultProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.NoSuchElementException;
import java.util.Scanner;

/**
 * @author Vince Bickers
 */
public class JsonResponse implements Neo4jResponse<String> {

    private static final String COMMA = ",";
    private static final String START_RECORD_TOKEN = "{";
    private static final String NEXT_RECORD_TOKEN = COMMA + START_RECORD_TOKEN;

    private static final String ERRORS_TOKEN = "],\"errors";
    private static final String COMMIT_ERRORS_TOKEN = "},\"errors";
    private static final String COLUMNS_TOKEN = "{\"columns";

    private static final String GRAPH_TOKEN = "\"graph";
    private static final String ROW_TOKEN = "\"row";
    private static final String RESULTS_TOKEN = "\"results";
    private static final String STATS_TOKEN = "\"stats";

    private static final Logger LOGGER = LoggerFactory.getLogger(JsonResponse.class);

    private final InputStream results;
    private final Scanner scanner;
    private final CloseableHttpResponse response;
    private String scanToken = null;
    private String[] columns;
    private int currentRow = -1;

    public JsonResponse(CloseableHttpResponse response) {
        try {
            this.response = response;
            this.results = response.getEntity().getContent();
            this.scanner = new Scanner(results, "UTF-8");
        } catch (IOException ioException) {
            throw new RuntimeException(ioException);
        }
    }

    public JsonResponse(InputStream inputStream) {
        this.response = null;
        this.results = inputStream;
        this.scanner = new Scanner(results, "UTF-8");
    }

    public void initialiseScan(ResponseRecord record) {
        this.scanToken = extractToken(record);
        this.scanner.useDelimiter(scanToken);
        // TODO: this currently assumes only ONE data[] element in the response stream.
        parseColumns();
    }

    public String next() {
        try {
            String json = scanner.next();

            while (!json.endsWith(NEXT_RECORD_TOKEN)) {
                // the scan token may be embedded in the current response record, we need to keep parsing...
                try {
                    String rest = scanner.next();
                    json = json + scanToken + rest;
                } catch (Exception e) {
                    break;
                }
            }

            // will match all records except last in response
            if (json.endsWith(NEXT_RECORD_TOKEN)) {
                json = json.substring(0, json.length() - NEXT_RECORD_TOKEN.length());
            } else if (json.contains(ERRORS_TOKEN)) {

                int errorsPosition = json.indexOf(ERRORS_TOKEN);
                if (json.substring(errorsPosition).contains("[]")) {
                    json = json.substring(0, errorsPosition);
                } else {
                    parseErrors(json);
                }
            }
            String record = START_RECORD_TOKEN + scanToken + json;
            currentRow++;
            return record;

        } catch (NoSuchElementException e) {
            return null;
        }
    }

    public void close() {
        try {
            results.close();
            if (response != null) {
                LOGGER.debug("Closing HttpResponse");
                response.close();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String[] columns() {
        return this.columns;
    }

    @Override
    public int rowId() {
        return currentRow;
    }

    private void parseColumns() {
        String header = this.scanner.next(); // consume the header and return the columns array to the caller

        int cp = header.indexOf(COLUMNS_TOKEN);
        if (cp == -1) {
            parseErrors(header);
        } else {
            String colStart = header.substring(cp);
            this.columns = colStart.substring(colStart.indexOf("[") + 1, colStart.indexOf("]")).replace("\"", "")
                    .split(",");
        }
    }

    private void parseErrors(String header) {
        int cp = header.indexOf(ERRORS_TOKEN);
        if (cp == -1) {
            cp = header.indexOf(COMMIT_ERRORS_TOKEN);
        }
        if (cp == -1) {
            throw new RuntimeException("Unexpected problem! Cypher response starts: " + header + "...");
        }

        StringBuilder sb = new StringBuilder(header);
        String response;
        try {
            while ((response = scanner.next()) != null) {
                sb.append(response);
            }
        } catch (Exception e) {
            scanner.close();
        }

        throw new ResultProcessingException(sb.substring(cp + 2), null);
    }

    private String extractToken(ResponseRecord format) {

        switch (format) {
        case GRAPH:
            return GRAPH_TOKEN;
        case ROW:
            return ROW_TOKEN;
        case RESULTS:
            return RESULTS_TOKEN;
        case STATS:
            return STATS_TOKEN;
        default:
            throw new RuntimeException("Unhandled response format: " + format);
        }
    }
}