
prerna.engine.impl.json.JsonAPIEngine Maven / Gradle / Ivy
The newest version!
package prerna.engine.impl.json;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import org.apache.commons.io.FilenameUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
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.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import net.minidev.json.JSONArray;
import prerna.engine.impl.AbstractDatabaseEngine;
import prerna.engine.impl.SmssUtilities;
import prerna.query.interpreters.IQueryInterpreter;
import prerna.query.interpreters.JsonInterpreter;
import prerna.util.Constants;
import prerna.util.Utility;
public class JsonAPIEngine extends AbstractDatabaseEngine {
private static final Logger classLogger = LogManager.getLogger(JsonAPIEngine.class);
private static final String ARRAY = "ARRAY";
public static final String COUNT = "COUNT";
private static final String STRING = "String";
public static final String INPUT_TYPE = "input_type";
public static final String INPUT_METHOD = "input_method";
public static final String INPUT_URL = "input_url";
public static final String INPUT_PARAMS = "input_params";
public static final String MANDATORY_INPUT = "mandatory_input";
public static final String OUTPUT_TYPE = "output_type";
public static final String PATH_PATTERNS = "path_patterns";
public static final String CONCAT = "concat";
public static final String DELIM = "delim";
public static final String REPEATER = "repeater";
Object document = null;
String baseFolder = null;
@Override
public void open(Properties smssProp) throws Exception {
setSmssProp(smssProp);
baseFolder = Utility.getBaseFolder();
Hashtable paramHash = new Hashtable <>();
paramHash.put("BaseFolder", baseFolder);
if(getEngineId() != null)
paramHash.put("engine", getEngineId());
if(this.smssProp != null) {
// load the rdbms insights db
// nope nothing to load here
// load the rdf owl db
String owlFile = smssProp.getProperty(Constants.OWL);
if(owlFile != null) {
File owlF = new File(Utility.normalizePath(owlFile));
// need a check here to say if I am asking this to be remade or keep what it is
if(!owlF.exists() || owlFile.equalsIgnoreCase("REMAKE")) {
// the process of remake will start here
// see if the usefile is there
if(this.smssProp.containsKey(USE_FILE)) {
String owlFileName = null;
String dataFile = SmssUtilities.getDataFile(this.smssProp).getAbsolutePath();
if(owlFile.equals("REMAKE")) {
// we will make the name
File dF = new File(dataFile);
owlFileName = this.engineName + "_OWL.OWL";
owlFile = dF.getParentFile() + DIR_SEPARATOR + owlFileName;
} else {
owlFileName = FilenameUtils.getName(owlFile);
}
owlFile = generateOwlFromFlatFile(dataFile, owlFile, owlFileName);
} else {
owlFile = null;
}
}
// set the owl file
if(owlFile != null) {
owlFile = SmssUtilities.getOwlFile(this.smssProp).getAbsolutePath();
classLogger.info("Loading OWL: " + Utility.cleanLogString(owlFile));
setOwlFilePath(owlFile);
}
}
// load properties object for db
// not sure what this is doing
// I changed this to public
String genEngPropFile = smssProp.getProperty(Constants.ENGINE_PROPERTIES);
if (genEngPropFile != null) {
generalEngineProp = Utility.loadProperties(baseFolder + "/" + genEngPropFile);
}
}
loadDocument();
}
protected void loadDocument() {
try {
if(this.smssProp.containsKey(INPUT_TYPE) && ((String)this.smssProp.get(INPUT_TYPE)).equalsIgnoreCase("file")) {
this.document = Configuration.defaultConfiguration().jsonProvider().parse(
new FileInputStream(this.baseFolder + "/" + Utility.normalizePath(this.smssProp.getProperty(INPUT_URL))), "utf-8");
}
} catch (IOException ioe) {
classLogger.error(Constants.STACKTRACE, ioe);
}
}
// inputparams@@@alias patterns=alias or just alias@@@metadata - I will not worry about metadata for now
@Override
public Object execQuery(String query) {
// the exec query has to get a couple of different things
// parameters for the input
// selection for the output
// output metadata - may not be needed
// need to use a better delimiter
// need some way to identify how to segregate into one vs. many requests
String [] pathParts = query.split("@@@");
String [] inputParams = null;
String [] jsonPaths = null;
Hashtable retHash = new Hashtable();
Object curDoc = getDocument(null);
//JSONArray [] data = new JSONArray[jsonPaths.length];
if(pathParts.length == 2)
{
jsonPaths = pathParts[0].split(";");
inputParams = pathParts[1].split(";");
}
else
{
jsonPaths = pathParts[0].split(";");
}
// which of the params are list params
// hopefully there is only one
// I have no idea how to deal with many at htis point
// without it being a MESS of for loops
Hashtable listParams = new Hashtable();
// since I am hoping there is only one
// I am keeping it here
String listKey = null;
String listValue = null;
boolean array = false;
for(int paramIndex = 0;inputParams != null && paramIndex < inputParams.length;paramIndex++)
{
String [] keyValue = inputParams[paramIndex].split("=");
String key = keyValue[0];
String value = keyValue[1];
if(value.startsWith(ARRAY)) {
array = true;
listKey = key;
listValue = value.replace(ARRAY, "");
listParams.put(key, value.replace(ARRAY, ""));
}
}
// make the doc
// get the content
// if this is not a file based then we need to make the URL
if(curDoc == null)
{
String inputData = "";
// need to run the http to grab the URL etc. and then load the document
// need to make a check to see if this one vs. many
// Hashtable inputParamHash = Utility.getParams(smssProp.getProperty(input_url));
// Hashtable inputValHash = getParamHash(inputParams);
//
// // make the primary hash
// Hashtable finalValHash = fillParams(inputParamHash, inputValHash);
Hashtable inputHash = getMandatoryInputs();
Hashtable finalValHash = getParamHash(inputParams);
finalValHash = fillParams(inputHash, finalValHash);
// replace each value for the key and send it in
if(array && listValue != null) {
String [] multiValue = listValue.split("<>");
for(int valIndex = 0;valIndex < multiValue.length;valIndex++)
{
finalValHash.put(listKey, multiValue[valIndex]);
String url = constructURL(finalValHash);
if(smssProp.getProperty(INPUT_METHOD).equalsIgnoreCase("GET"))
{
inputData = doGet(url);
}
else
{
inputData = doPost(finalValHash);
}
curDoc = getDocument(inputData);
// send the data to add to it
retHash = getOutput(curDoc, jsonPaths, retHash, listKey, multiValue[valIndex]);
}
}
else // this is not a list.. one time pull call it a day
{
String url = constructURL(finalValHash);
if(smssProp.getProperty(INPUT_METHOD).equalsIgnoreCase("GET"))
inputData = doGet(url);
else
inputData = doPost(finalValHash);
curDoc = getDocument(inputData);
// send the data to add to it
retHash = getOutput(curDoc, jsonPaths, retHash, null, null);
}
}
else // it is a file
{
retHash = getOutput(curDoc, jsonPaths, retHash, null, null);
}
//return the data
return retHash;
}
protected Object getDocument(String json)
{
Object retNode = document;
if(json != null) {
try {
retNode = Configuration.defaultConfiguration().jsonProvider().parse(json);
} catch(Exception ex) {
classLogger.error(Constants.STACKTRACE, ex);
}
}
return retNode;
}
protected Hashtable getOutput(Object doc, String [] jsonPaths, Hashtable retHash, String repeaterHeader, String repeaterValue)
{
JSONArray [] data = null;
String [] headers = new String[jsonPaths.length];
if(repeaterHeader != null) {
data = new JSONArray[jsonPaths.length + 1];
headers = new String[jsonPaths.length + 1];
}
else {
data = new JSONArray[jsonPaths.length];
}
int numRows = 0;
int totalRows = 0;
JSONArray [] input = null;
if(retHash.containsKey("DATA"))
input = (JSONArray []) retHash.get("DATA");
if(retHash.containsKey(COUNT))
totalRows = (Integer) retHash.get(COUNT);
boolean foundData = true;
for(int pathIndex = 0;pathIndex < jsonPaths.length;pathIndex++)
{
String thisHeader = null;
String thisPath = null;
if(jsonPaths[pathIndex].contains("="))
{
String [] pathToks = jsonPaths[pathIndex].split("=");
thisHeader = pathToks[0];
thisPath = pathToks[1];
}
else
{
thisPath = smssProp.getProperty(jsonPaths[pathIndex]);
thisHeader = jsonPaths[pathIndex];
}
// need to track for classnot found
// and PathNotFound exception
try {
Object object = JsonPath.read(doc, thisPath);
if(object instanceof JSONArray)
data[pathIndex] = (JSONArray)object;
else // if it is a single item just add it to the list of things
{
if(data[pathIndex] == null)
data[pathIndex] = new JSONArray();
data[pathIndex].add(object);
}
// add it to the current input
if(input != null)
input[pathIndex].addAll(data[pathIndex]);
// set the headers
headers[pathIndex] = thisHeader;
// if we are starting at a new point
// add the number of rows to comparator
if(numRows == 0 || numRows > data[pathIndex].size())
numRows = data[pathIndex].size();
classLogger.info(" >> " + data[pathIndex].toString());
classLogger.info("Length >> " + data[pathIndex].size());
} catch(PathNotFoundException ex) {
classLogger.info("Path not found.. " + Utility.cleanLogString(thisPath));
foundData = false;
}
}
// add the repeater
if(repeaterHeader != null && foundData)
{
headers[jsonPaths.length] = repeaterHeader;
// fill it with the repeater value
JSONArray repeaterData = new JSONArray();
for(int rowIndex = 0;rowIndex < numRows;rowIndex++)
repeaterData.add(repeaterValue);
data[jsonPaths.length] = repeaterData;
if(input != null)
input[jsonPaths.length].addAll(data[jsonPaths.length]);
}
totalRows = totalRows + numRows;
if(!retHash.containsKey("TYPES"))
retHash.put("TYPES", getTypes(data));
retHash.put("HEADERS", headers);
if(input == null)
retHash.put("DATA", data);
else
retHash.put("DATA", input);
retHash.put(COUNT, totalRows);
classLogger.info("Output.. " + Utility.cleanLogString(Arrays.toString(data)));
return retHash;
}
protected String [] getTypes(Object data2)
{
JSONArray [] data = (JSONArray [])data2;
String [] types = new String[data.length];
for(int dataIndex = 0;data != null && dataIndex < data.length;dataIndex++)
{
if(!data[dataIndex].isEmpty()) {
Object firstOne = data[dataIndex].get(0);
if(firstOne == null)
types[dataIndex] = STRING;
else if(firstOne instanceof Integer)
types[dataIndex] = "int";
else if(firstOne instanceof JSONArray)
types[dataIndex] = STRING;
else if(firstOne instanceof Double)
types[dataIndex] = "Double";
else
types[dataIndex] = STRING;
}
}
return types;
}
@Override
public void insertData(String query) {
// TODO Auto-generated method stub
}
@Override
public DATABASE_TYPE getDatabaseType() {
return prerna.engine.api.IDatabaseEngine.DATABASE_TYPE.JSON;
}
@Override
public Vector
© 2015 - 2025 Weber Informatics LLC | Privacy Policy