/************************************************************************ * Copyright (c) 2014-2016 IoT-Solutions e.U. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ package iot.jcypher.query.writer; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.json.Json; import javax.json.stream.JsonGenerator; import javax.json.stream.JsonGeneratorFactory; import iot.jcypher.query.JcQuery; import iot.jcypher.query.writer.PreparedQuery.PQContext; public class JSONWriter { private static JsonGeneratorFactory prettyGeneratorFactory; public static void toJSON(List<JcQuery> queries, WriterContext context) { List<Statement> statements = new ArrayList<Statement>(queries.size()); PreparedQueries prepQs = new PreparedQueries(); context.preparedQuery = prepQs; Format cf = context.cypherFormat; context.cypherFormat = Format.NONE; boolean useTxEndpoint = ContextAccess.useTransationalEndpoint(context); // needed for multiple statements ContextAccess.setUseTransactionalEndpoint(true, context); boolean extract = QueryParam.isExtractParams(context); for (JcQuery query : queries) { PreparedQuery prepQ = new PreparedQuery(); prepQs.add(prepQ); PQContext pqContext = prepQ.getContext(); pqContext.cypherFormat = cf; pqContext.extractParams = query.isExtractParams(); pqContext.useTransationalEndpoint = ContextAccess.useTransationalEndpoint(context); pqContext.resultDataContents = ContextAccess.getResultDataContents(context); WriterContext ctxt = ContextAccess.cloneContext(context); ctxt.preparedQuery = prepQs; // needed to mark if there are dynamic parameters QueryParam.setExtractParams(query.isExtractParams(), ctxt); CypherWriter.toCypherExpression(query, ctxt); String cypher = ctxt.buffer.toString(); prepQ.setCypher(cypher); pqContext.queryParams = QueryParamSet.getQueryParams(ctxt); reInitContext(ctxt); statements.add(new Statement(ctxt, cypher)); } context.cypherFormat = cf; StringWriter sw = new StringWriter(); JsonGenerator generator; if (context.cypherFormat != Format.NONE) { JsonGeneratorFactory gf = getPrettyGeneratorFactory(); generator = gf.createGenerator(sw); } else generator = Json.createGenerator(sw); generator.writeStartObject(); Statement[] statementsArray = statements.toArray(new Statement[statements.size()]); writeStatements(statementsArray, generator); generator.writeEnd(); generator.flush(); context.buffer.append(sw.getBuffer()); // reset to original QueryParam.setExtractParams(extract, context); ContextAccess.setUseTransactionalEndpoint(useTxEndpoint, context); prepQs.setJson(context.buffer.toString()); } public static void toJSON(JcQuery query, WriterContext context) { PreparedQuery prepQ = new PreparedQuery(); context.preparedQuery = prepQ; PQContext pqContext = prepQ.getContext(); pqContext.cypherFormat = context.cypherFormat; context.cypherFormat = Format.NONE; boolean extract = QueryParam.isExtractParams(context); pqContext.extractParams = query.isExtractParams(); QueryParam.setExtractParams(query.isExtractParams(), context); CypherWriter.toCypherExpression(query, context); context.cypherFormat = pqContext.cypherFormat; String cypher = context.buffer.toString(); reInitContext(context); prepQ.setCypher(cypher); StringWriter sw = new StringWriter(); JsonGenerator generator; if (context.cypherFormat != Format.NONE) { JsonGeneratorFactory gf = getPrettyGeneratorFactory(); generator = gf.createGenerator(sw); } else generator = Json.createGenerator(sw); pqContext.useTransationalEndpoint = ContextAccess.useTransationalEndpoint(context); pqContext.resultDataContents = ContextAccess.getResultDataContents(context); pqContext.queryParams = QueryParamSet.getQueryParams(context); generator.writeStartObject(); if (ContextAccess.useTransationalEndpoint(context)) writeStatements(new Statement[] {new Statement(context, cypher)}, generator); else writeQuery("query", cypher, context, generator); generator.writeEnd(); generator.flush(); context.buffer.append(sw.getBuffer()); // reset to original QueryParam.setExtractParams(extract, context); prepQ.setJson(context.buffer.toString()); } public static PreparedQuery toPreparedQuery(JcQuery query, WriterContext context) { toJSON(query, context); return (PreparedQuery) context.preparedQuery; } public static PreparedQueries toPreparedQueries(List<JcQuery> queries, WriterContext context) { toJSON(queries, context); return (PreparedQueries) context.preparedQuery; } public static String toJSON(PreparedQuery preparedQuery) { if (preparedQuery.hasdSLParams()) { // parameters part of json must be recreated WriterContext context = new WriterContext(); PQContext pqContext = preparedQuery.getContext(); QueryParam.setExtractParams(pqContext.extractParams, context); context.cypherFormat = pqContext.cypherFormat; String cypher = preparedQuery.getCypher(); StringWriter sw = new StringWriter(); JsonGenerator generator; if (context.cypherFormat != Format.NONE) { JsonGeneratorFactory gf = getPrettyGeneratorFactory(); generator = gf.createGenerator(sw); } else generator = Json.createGenerator(sw); ContextAccess.setUseTransactionalEndpoint(pqContext.useTransationalEndpoint, context); ContextAccess.setResultDataContents(context, pqContext.resultDataContents); context.queryParams = pqContext.queryParams; generator.writeStartObject(); if (pqContext.useTransationalEndpoint) writeStatements(new Statement[] {new Statement(context, cypher)}, generator); else writeQuery("query", cypher, context, generator); generator.writeEnd(); generator.flush(); context.buffer.append(sw.getBuffer()); return context.buffer.toString(); } else return preparedQuery.getJson(); } public static String toJSON(PreparedQueries preparedQueries) { if (preparedQueries.hasdSLParams()) { // parameters part of json must be recreated WriterContext context = new WriterContext(); List<PreparedQuery> prepQs = preparedQueries.getPreparedQueries(); if (prepQs.isEmpty()) return new String(); PreparedQuery prepQ = prepQs.get(0); PQContext pqContext = prepQ.getContext(); List<Statement> statements = new ArrayList<Statement>(prepQs.size()); Format cf = pqContext.cypherFormat; pqContext.fillContext(context); context.cypherFormat = Format.NONE; // needed for multiple statements ContextAccess.setUseTransactionalEndpoint(true, context); for (PreparedQuery pq : prepQs) { WriterContext ctxt = new WriterContext(); PQContext pqCtxt = pq.getContext(); pqCtxt.fillContext(ctxt); String cypher = pq.getCypher(); statements.add(new Statement(ctxt, cypher)); } context.cypherFormat = cf; StringWriter sw = new StringWriter(); JsonGenerator generator; if (context.cypherFormat != Format.NONE) { JsonGeneratorFactory gf = getPrettyGeneratorFactory(); generator = gf.createGenerator(sw); } else generator = Json.createGenerator(sw); generator.writeStartObject(); Statement[] statementsArray = statements.toArray(new Statement[statements.size()]); writeStatements(statementsArray, generator); generator.writeEnd(); generator.flush(); context.buffer.append(sw.getBuffer()); preparedQueries.setJson(context.buffer.toString()); return preparedQueries.getJson(); } else return preparedQueries.getJson(); } private static void writeStatements(Statement[] statements, JsonGenerator generator) { generator.writeStartArray("statements"); for (Statement statement : statements) { generator.writeStartObject(); writeQuery("statement", statement.cypher, statement.context, generator); if (ContextAccess.getResultDataContents( statement.context).size() > 0) { generator.writeStartArray("resultDataContents"); for (String contentDescription : ContextAccess.getResultDataContents( statement.context)) { generator.write(contentDescription); } generator.writeEnd(); } generator.writeEnd(); } generator.writeEnd(); } private static void writeQuery(String queryKey, String cypher, WriterContext context, JsonGenerator generator) { generator.write(queryKey, cypher); writeQueryParams(context, generator); } private static void writeQueryParams(WriterContext context, JsonGenerator generator) { if (QueryParam.isExtractParams(context)) { List<IQueryParam> params = QueryParamSet.getQueryParams(context); if (params != null) { String paramsKey = "params"; if (ContextAccess.useTransationalEndpoint(context)) paramsKey = "parameters"; generator.writeStartObject(paramsKey); for (IQueryParam iparam : params) { if (iparam instanceof QueryParamSet) { QueryParamSet paramSet = (QueryParamSet)iparam; if (paramSet.canUseSet() && paramSet.getQueryParams().size() > 1) writeAsSet(paramSet, generator); else writeAsParams(paramSet, generator); } else if (iparam instanceof QueryParam) { writeParam((QueryParam)iparam, generator); } } generator.writeEnd(); } } } private static void writeAsParams(QueryParamSet paramSet, JsonGenerator generator) { for (QueryParam param : paramSet.getQueryParams()) { String key = param.getKey(); Object val = param.getValue(); writeLiteral(key, val, generator); } } private static void writeAsSet(QueryParamSet paramSet, JsonGenerator generator) { generator.writeStartObject(paramSet.getKey()); for (QueryParam param : paramSet.getQueryParams()) { String key = param.getOrgName(); Object val = param.getValue(); writeLiteral(key, val, generator); } generator.writeEnd(); } private static void writeParam(QueryParam param, JsonGenerator generator) { String key = param.getKey(); Object val = param.getValue(); writeLiteral(key, val, generator); } private static void writeLiteral(String key, Object val, JsonGenerator generator) { if (val instanceof String) generator.write(key, val.toString()); else if (val instanceof Number) { if (val instanceof Long) generator.write(key, (Long)val); else if (val instanceof Integer) generator.write(key, (Integer)val); else if (val instanceof Double) generator.write(key, (Double)val); else if (val instanceof Float) generator.write(key, (Float)val); } else if (val instanceof Boolean) generator.write(key, (Boolean)val); else if (val instanceof List<?>) { generator.writeStartArray(key); for (Object v : (List<?>)val) { writeLiteral(v, generator); } generator.writeEnd(); } else if (val != null) // handle everything else as a string generator.write(key, val.toString()); } private static void writeLiteral(Object val, JsonGenerator generator) { if (val instanceof String) generator.write(val.toString()); else if (val instanceof Number) { if (val instanceof Long) generator.write((Long)val); else if (val instanceof Integer) generator.write((Integer)val); else if (val instanceof Double) generator.write((Double)val); else if (val instanceof Float) generator.write((Float)val); } else if (val instanceof Boolean) generator.write((Boolean)val); else if (val != null) // handle everything else as a string generator.write(val.toString()); } private static void reInitContext(WriterContext context) { context.buffer = new StringBuilder(); context.inFunction = false; context.currentClause = null; context.previousClause = null; context.resetLevel(); } public static JsonGeneratorFactory getPrettyGeneratorFactory() { if (prettyGeneratorFactory == null) { HashMap<String, Object> prettyConfigMap = new HashMap<String, Object>(); prettyConfigMap.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE); prettyGeneratorFactory = Json.createGeneratorFactory(prettyConfigMap); } return prettyGeneratorFactory; } /*******************************************/ private static class Statement { private WriterContext context; private String cypher; private Statement(WriterContext context, String cypher) { super(); this.context = context; this.cypher = cypher; } } }