/*
* RDataUtil.java
*
* Copyright (C) 2010-2016, Microsoft Corporation
*
* This program is licensed to you under the terms of Version 2.0 of the
* Apache License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0) for more details.
*
*/
package com.revo.deployr.client.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.revo.deployr.client.RDataException;
import com.revo.deployr.client.data.*;
import com.revo.deployr.client.data.impl.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
// import org.codehaus.jackson.map.ObjectMapper;
/**
* RDataUtil provides support for the following:
* <p/>
* <br/><br/>
* 1. Builds RData from JSON.
* <br/>
* 2. Builds JSON from RData.
* <br/>
* 3. Builds JSON from List<RData>.
*/
public class RDataUtil {
private static Log log = LogFactory.getLog(RDataUtil.class);
public static RData fromJSON(String name, Map json) {
RData rData = null;
String type = (json.get("type") != null) ? (String) json.get("type") : "primitive";
log.debug("fromJSON: name=" + name + " type=" + type + " json=" + json);
if (type.equalsIgnoreCase("primitive")) {
rData = buildPrimitiveFromJSON(name, json);
} else if (type.equalsIgnoreCase("vector")) {
rData = buildVectorFromJSON(name, json);
} else if (type.equalsIgnoreCase("matrix")) {
rData = buildMatrixFromJSON(name, json);
} else if (type.equalsIgnoreCase("list")) {
rData = buildListFromJSON(name, json);
} else if (type.equalsIgnoreCase("dataframe")) {
rData = buildDataFrameFromJSON(name, json);
} else if (type.equalsIgnoreCase("factor")) {
rData = buildFactorFromJSON(name, json);
} else if (type.equalsIgnoreCase("date")) {
rData = buildDateFromJSON(name, json);
} else {
// Support RData without a corresponding
// Phoenix encoding as can be
// returned on a RSession listObjects call.
rData = buildSummaryFromJSON(name, json);
}
return rData;
}
public static String toJSON(RData rData) throws RDataException {
Map<String, Object> pMap = new HashMap<String, Object>();
Map<String, Object> pValues = new HashMap<String, Object>();
pValues.put("type", rData.getType());
pValues.put("rclass", rData.getRclass());
pValues.put("value", getValueForJSON(rData));
/*
* RData special cases needs additional properties in markup.
*/
if (rData instanceof RDate) {
RDate rDate = (RDate) rData;
pValues.put("format", rDate.getFormat());
} else if (rData instanceof RDateVector) {
RDateVector rDateVector = (RDateVector) rData;
pValues.put("format", rDateVector.getFormat());
} else if (rData instanceof RFactor) {
RFactor pFactor = (RFactor) rData;
if (pFactor.getLevels() != null)
pValues.put("levels", pFactor.getLevels());
if (pFactor.getLabels() != null)
pValues.put("labels", pFactor.getLabels());
pValues.put("ordered", pFactor.isOrdered());
}
pMap.put(rData.getName(), pValues);
ObjectMapper mapper = new ObjectMapper();
StringWriter writer = new StringWriter();
String json = null;
try {
mapper.writeValue(writer, pMap);
json = writer.toString();
} catch (Exception ex) {
log.warn("toJSON: exception writing RData, name=" + rData.getName() + " type=" + rData.getType() + " to JSON.", ex);
throw new RDataException("RData can be not be parsed into JSON, ex=" + ex.getMessage());
}
log.debug("toJSON: returning=" + json);
return json;
}
public static String toJSON(List<RData> data) throws RDataException {
Map<String, Object> pMap = new HashMap<String, Object>();
for (RData rData : data) {
Map<String, Object> pValues = new HashMap<String, Object>();
pValues.put("type", rData.getType());
pValues.put("rclass", rData.getRclass());
pValues.put("value", getValueForJSON(rData));
/*
* RData special cases needs additional properties in markup.
*/
if (rData instanceof RDate) {
RDate rDate = (RDate) rData;
pValues.put("format", rDate.getFormat());
} else if (rData instanceof RDateVector) {
RDateVector rDateVector = (RDateVector) rData;
pValues.put("format", rDateVector.getFormat());
} else if (rData instanceof RFactor) {
RFactor pFactor = (RFactor) rData;
if (pFactor.getLevels() != null)
pValues.put("levels", pFactor.getLevels());
if (pFactor.getLabels() != null)
pValues.put("labels", pFactor.getLabels());
pValues.put("ordered", pFactor.isOrdered());
}
pMap.put(rData.getName(), pValues);
}
ObjectMapper mapper = new ObjectMapper();
StringWriter writer = new StringWriter();
String json = null;
try {
mapper.writeValue(writer, pMap);
json = writer.toString();
} catch (Exception ex) {
log.warn("toJSON: exception writing List<RData> to JSON.", ex);
throw new RDataException("RData list can be not be parsed into JSON, ex=" + ex.getMessage());
}
log.debug("toJSON: List<RData> returning=" + json);
return json;
}
private static RData buildPrimitiveFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
log.debug("buildPrimitiveFromJSON: name=" + name + " type=" + type + " rclass=" + rclass + " json=" + json);
if (json.containsKey("value")) {
Object value = json.get("value");
log.debug("buildPrimitiveFromJSON: name=" + name + " has value=" + value);
if("character".equalsIgnoreCase(rclass)){
rData = new RStringImpl(name, value == null ? null : (String) value);
}else if("numeric".equalsIgnoreCase(rclass)){
rData = new RNumericImpl(name, value == null ? null : (Double) value);
}else if("logical".equalsIgnoreCase(rclass)){
rData = new RBooleanImpl(name, value == null ? null :(Boolean) value);
}
if(rData == null){
if (value instanceof Integer) {
rData = new RNumericImpl(name, ((Integer) value).doubleValue());
} else if (value instanceof Double) {
rData = new RNumericImpl(name, (Double) value);
} else if (value instanceof String) {
rData = new RStringImpl(name, (String) value);
} else if (value instanceof Boolean) {
rData = new RBooleanImpl(name, (Boolean) value);
} else {
// Indeterminate type, skip here to treat as RDataNA.
}
}
} else {
rData = new RDataImpl(name, type, rclass);
}
if (rData == null) {
rData = new RDataNAImpl(name, "vector");
}
log.debug("buildPrimitiveFromJSON: name=" + name + " returning=" + rData);
return rData;
}
private static RData buildVectorFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
String format = (String) json.get("format");
log.debug("buildVectorFromJSON: name=" + name + " type=" + type + " rclass=" + rclass + " format=" + format + " json=" + json);
if (format != null) {
if (json.containsKey("value")) {
List value = (List) json.get("value");
log.debug("buildVectorFromJSON: name=" + name + " format=" + format + " has value=" + value);
Iterator iter = value.iterator();
List<Date> dates = new ArrayList<Date>();
SimpleDateFormat sdf = new SimpleDateFormat(format);
while (iter.hasNext()) {
Object found = iter.next();
if (found instanceof String) {
try {
Date date = sdf.parse((String) found);
dates.add(date);
} catch (Exception ex) {
log.debug("buildVectorFromJSON: date sdf.parse format=${format} adding NULL because ex=${ex}");
ex.printStackTrace();
dates.add(null);
}
}else{
dates.add(null);
}
}
rData = new RDateVectorImpl(name, dates, format, rclass);
}
} else if (json.containsKey("value")) {
List value = (List) json.get("value");
log.debug("buildVectorFromJSON: name=" + name + " has value=" + value);
if("character".equalsIgnoreCase(rclass)){
rData = new RStringVectorImpl(name, value);
}else if("numeric".equalsIgnoreCase(rclass)){
rData = new RNumericVectorImpl(name, value);
}else if("logical".equalsIgnoreCase(rclass)){
rData = new RBooleanVectorImpl(name, value);
}
if(rData == null){
Iterator iter = value.iterator();
// Loop to determine the "type" of context in the JSON vector.
while (iter.hasNext()) {
Object found = iter.next();
if (found instanceof Integer) {
rData = new RNumericVectorImpl(name, value);
} else if (found instanceof Double) {
rData = new RNumericVectorImpl(name, value);
} else if (found instanceof String) {
rData = new RStringVectorImpl(name, value);
} else if (found instanceof Boolean) {
rData = new RBooleanVectorImpl(name, value);
} else {
// Indeterminate type, skip here allowing other value in vector to determine type.
}
if (rData != null)
break;
}
}
} else {
rData = new RDataImpl(name, type, rclass);
}
if (rData == null) {
rData = new RDataNAImpl(name, "vector");
}
log.debug("buildVectorFromJSON: name=" + name + " returning=" + rData);
return rData;
}
private static RData buildMatrixFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
log.debug("buildMatrixFromJSON: name=" + name + " type=" + type + " rclass=" + rclass + " json=" + json);
if (json.containsKey("value")) {
List value = (List) json.get("value");
log.debug("buildMatrixFromJSON: name=" + name + " value=" + value);
Iterator rows = value.iterator();
// Loop to determine the "type" of context in the JSON matrix.
while (rows.hasNext()) {
List rowList = (List) rows.next();
Iterator rowIterator = rowList.iterator();
while (rowIterator.hasNext()) {
Object entry = rowIterator.next();
if (entry instanceof Integer) {
rData = new RNumericMatrixImpl(name, value);
} else if (entry instanceof Double) {
rData = new RNumericMatrixImpl(name, value);
} else if (entry instanceof String) {
rData = new RStringMatrixImpl(name, value);
} else if (entry instanceof Boolean) {
rData = new RBooleanMatrixImpl(name, value);
} else {
// Indeterminate type, skip here allowing other value in matrix to determine type.
}
if (rData != null)
break;
}
if (rData != null)
break;
}
} else {
rData = new RDataImpl(name, type, rclass);
}
if (rData == null) {
rData = new RDataNAImpl(name, "matrix");
}
log.debug("buildMatrixFromJSON: name=" + name + " returning=" + rData);
return rData;
}
private static RData buildListFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
log.debug("buildListFromJSON: name=" + name + " type=" + type + " rclass=" + rclass + " json=" + json);
if (json.containsKey("value")) {
List<Map> values = (List<Map>) json.get("value");
List<RData> listData = new ArrayList();
for (Map entry : values) {
// Recursively build RList from JSON.
String entryName = (String) entry.get("name");
RData dataItem = fromJSON(entryName, entry);
listData.add(dataItem);
}
rData = new RListImpl(name, listData);
} else {
rData = new RDataImpl(name, type, rclass);
}
log.debug("buildListFromJSON: name=" + name + " returning=" + rData);
return rData;
}
private static RData buildDataFrameFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
log.debug("buildDataFrameFromJSON: name=" + name + " type=" + type + " rclass=" + rclass + " json=" + json);
if (json.containsKey("value")) {
List<Map> values = (List<Map>) json.get("value");
List<RData> frameData = new ArrayList();
for (Map entry : values) {
// Recursively build RDataFrame from JSON.
String entryName = (String) entry.get("name");
RData dataItem = fromJSON(entryName, entry);
frameData.add(dataItem);
}
rData = new RDataFrameImpl(name, frameData);
} else {
rData = new RDataImpl(name, type, rclass);
}
log.debug("buildDataFrameFromJSON: name=" + name + " returning=" + rData);
return rData;
}
private static RData buildFactorFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
log.debug("buildFactorFromJSON: name=" + name + " type=" + type + " rclass=" + rclass + " json=" + json);
if (json.containsKey("value")) {
List value = (List) json.get("value");
List levels = (List) json.get("levels");
List labels = (List) json.get("labels");
boolean ordered = (Boolean) json.get("ordered");
rData = new RFactorImpl(name, value, levels, labels, ordered, rclass);
} else {
rData = new RDataImpl(name, type, rclass);
}
log.debug("buildFactorFromJSON: name=" + name + " returning=" + rData);
return rData;
}
private static RData buildDateFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
log.debug("buildDateFromJSON: name=" + name + " type=" + type + " rclass=" + rclass + " json=" + json);
if (json.containsKey("value")) {
String value = (String) json.get("value");
String format = (String) json.get("format");
if(value != null){
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date date = sdf.parse(value);
rData = new RDateImpl(name, date, format, rclass);
} catch (ParseException pex) {
rData = new RDataImpl(name, type, rclass);
log.warn("buildDateFromJSON: bad date results in NA, RDataImpl=" + rData);
}
}else{
rData = new RDateImpl(name, null, format, rclass);
}
} else {
rData = new RDataImpl(name, type, rclass);
}
log.debug("buildDateFromJSON: name=" + name + " returning=" + rData);
return rData;
}
private static RData buildSummaryFromJSON(String name, Map json) {
RData rData = null;
String type = (String) json.get("type");
String rclass = (String) json.get("rclass");
rData = new RDataImpl(name, type, rclass);
log.debug("buildSummaryFromJSON: name=" + name + " returning=" + rData);
return rData;
}
/**
* Facilitate the building of valid Phoenix JSON.
*/
private static Object getValueForJSON(RData rData) {
if (rData instanceof RNumeric) {
return ((RNumeric) rData).getValue();
} else if (rData instanceof RString) {
return ((RString) rData).getValue();
} else if (rData instanceof RBoolean) {
return ((RBoolean) rData).getValue();
} else if (rData instanceof RNumericVector) {
return ((RNumericVector) rData).getValue();
} else if (rData instanceof RStringVector) {
return ((RStringVector) rData).getValue();
} else if (rData instanceof RDateVector) {
RDateVector rDateVector = (RDateVector) rData;
SimpleDateFormat sdf = new SimpleDateFormat(rDateVector.getFormat());
List<Date> dates = rDateVector.getValue();
List<String> dateValues = new ArrayList<String>();
Iterator iter = dates.iterator();
while (iter.hasNext()) {
Date date = (Date) iter.next();
String dateString = null;
try {
dateString = sdf.format(date);
} catch (Exception ex) {
}
dateValues.add(dateString);
}
return dateValues;
} else if (rData instanceof RBooleanVector) {
return ((RBooleanVector) rData).getValue();
} else if (rData instanceof RNumericMatrix) {
return ((RNumericMatrix) rData).getValue();
} else if (rData instanceof RStringMatrix) {
return ((RStringMatrix) rData).getValue();
} else if (rData instanceof RBooleanMatrix) {
return ((RBooleanMatrix) rData).getValue();
} else if (rData instanceof RList) {
RListImpl pList = (RListImpl) rData;
List<Map> pListItems = new ArrayList<Map>();
for (RData pChild : pList.getValue()) {
pListItems.add(mapPDataValues(pChild, true));
}
return pListItems;
} else if (rData instanceof RDataFrame) {
RDataFrame pFrame = (RDataFrame) rData;
List<Map> pFrameItems = new ArrayList<Map>();
for (RData pChild : pFrame.getValue()) {
pFrameItems.add(mapPDataValues(pChild, true));
}
return pFrameItems;
} else if (rData instanceof RFactor) {
return ((RFactor) rData).getValue();
} else if (rData instanceof RDate) {
RDate rDate = (RDate) rData;
String format = rDate.getFormat();
Date date = rDate.getValue();
SimpleDateFormat sdf = new SimpleDateFormat(rDate.getFormat());
String dateString = null;
try {
dateString = sdf.format(date);
} catch (Exception ex) {
}
return dateString;
} else
return null;
}
/**
* Facilitate the building of valid Phoenix JSON.
*/
private static Map mapPDataValues(RData rData) {
return mapPDataValues(rData, false);
}
private static Map mapPDataValues(RData rData, boolean mapForOrderedCollection) {
Map<String, Object> pValues = new HashMap<String, Object>();
if (mapForOrderedCollection)
pValues.put("name", rData.getName());
pValues.put("type", rData.getType());
pValues.put("rclass", rData.getRclass());
pValues.put("value", getValueForJSON(rData));
if (rData instanceof RDate) {
RDate rDate = (RDate) rData;
pValues.put("format", rDate.getFormat());
} else if (rData instanceof RDateVector) {
RDateVector rDateVector = (RDateVector) rData;
pValues.put("format", rDateVector.getFormat());
} else if (rData instanceof RFactor) {
RFactor pFactor = (RFactor) rData;
if (pFactor.getLevels() != null)
pValues.put("levels", pFactor.getLevels());
if (pFactor.getLabels() != null)
pValues.put("labels", pFactor.getLabels());
pValues.put("ordered", pFactor.isOrdered());
}
return pValues;
}
}