/*******************************************************************************
* Copyright 2014 Virginia Polytechnic Institute and State University
*
* 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 org.theseed.serverConnections;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.theseed.json.JSONArray;
import org.theseed.json.JSONException;
import org.theseed.json.JSONObject;
import org.theseed.json.JSONStringer;
import org.theseed.json.JSONTokener;
/**
* @author Rob Edwards
* @version 0.1 The SeverConnectJson class uses JSON, the <a href="http://www.json.org">Javascript Object Notation</a> to transmit data to and from
* the server. This is another lightweight markup language similar to YAML (used by the original ServerConnect class). However, JSON is tightly
* integrated into Javascript, and so is receiving wide support.
*
* To use this class, you will also need to download the JSON classes from <a href="http://www.json.org/java/">JSON Java</a>
*/
public class ServerConnectJson extends SEEDServer implements ServerConnection {
// private JSONObject json;
private JSONStringer jStringer;
// default constructor
public ServerConnectJson(String s) throws MalformedURLException {
super(s);
encoding = "json";
}
/**
* Encode a String[] array into a yaml object. You can then add this to data
* @param array a string array to encode
* @return the string representation of the array
*/
public String encode(String[] array) {
jStringer = new JSONStringer();
try {
jStringer.array();
for (String s : array)
jStringer.value(s);
jStringer.endArray();
}
catch (JSONException e) {
System.err.println("There was a JSON exception. Sorry:");
e.printStackTrace();
}
return jStringer.toString();
}
/**
* Encode a HashMap<String, Object> into a yaml object. You can then add this to the args
* @param hashmap a HashMap to encode
* @return the string representation of the array
*/
public String encode(HashMap<String, Object> hashmap) {
jStringer = new JSONStringer();
try {
jStringer.object();
for (String key : hashmap.keySet()) {
jStringer.key(key);
jStringer.value(hashmap.get(key));
}
jStringer.endObject();
}
catch (JSONException e) {
System.err.println("There was a JSON exception. Sorry:");
e.printStackTrace();
}
return jStringer.toString();
}
/**
* This method is provided as a convenience. If you have a call that simply returns an array, then use this and it will return the items as an
* array of strings.
*
* @return the results as a simple String[] array
*/
public String[] resultsAsArray() {
ArrayList<Object> results = this.resultsAsArrayList();
// convert the arrayList to a new array of strings and return that.
return results.toArray(new String[0]);
}
/**
* Return the results as a HashMap<String, Object>. This will allow you to retrieve the objects at will.
*
* @return the results from the server.
*/
public HashMap<Object, Object> resultsAsHashMapObject() {
HashMap<Object, Object> results = new HashMap<Object, Object>();
try {
JSONObject jsonO = new JSONObject(new JSONTokener(new InputStreamReader(this.query())));
if (debug)
System.err.println("JSON object returned from server: " + jsonO.toString());
Iterator<?> iter = jsonO.keys();
while (iter.hasNext()) {
String key = (String) iter.next();
results.put(key, jsonO.get(key));
}
}
catch (JSONException e) {
System.err.println("There was an error loading the JSON stream");
e.printStackTrace();
}
catch (NoSuchElementException e) {
System.err.println("We ran out of elements!");
e.printStackTrace();
}
catch (Exception e) {
System.err.println("There was an error getting the results stream");
e.printStackTrace();
}
return results;
}
/**
* Return the results as a HashMap<String, String>. A convenience to accomodate the casting.
*
* @return the results from the server.
*/
public HashMap<String, String> resultsAsHashMapString() {
HashMap<Object, Object> results = this.resultsAsHashMapObject();
if (results == null)
return null;
HashMap<String, String> toReturn = new HashMap<String, String>();
for (Object o : results.keySet()) {
String s = o.toString();
String a = (String) results.get(o);
toReturn.put(s, a);
}
return toReturn;
}
/**
* Return the results as a HashMap<String, ArrayList<String>>. This is probably the most common method for getting the results back from the
* server
*
* @return the results from the server.
*/
public HashMap<String, ArrayList<String>> resultsAsHashMap() {
HashMap<Object, Object> results = this.resultsAsHashMapObject();
HashMap<String, ArrayList<String>> toReturn = new HashMap<String, ArrayList<String>>();
try {
for (Object o : results.keySet()) {
String s = (String) o;
JSONArray jsonA = (JSONArray) results.get(o);
ArrayList<String> a = new ArrayList<String>();
for (int i = 0; i < jsonA.length(); i++)
a.add(jsonA.getString(i));
toReturn.put(s, a);
}
}
catch (JSONException e) {
System.err.println("Sorry, we got an error parsing the JSON stream");
e.printStackTrace();
}
return toReturn;
}
/**
* Return the results as a HashMap<String, ArrayList<HashMap<String, Object>>>.
*
* @return the results from the server.
*/
public HashMap<String, ArrayList<HashMap<String, Object>>> resultsAsHashMapArrayHashMap() {
HashMap<String, ArrayList<HashMap<String, Object>>> toReturn = new HashMap<String, ArrayList<HashMap<String, Object>>>();
try {
HashMap<Object, Object> results = this.resultsAsHashMapObject();
for (Object o : results.keySet()) {
String s = (String) o;
JSONArray jsonA = (JSONArray) results.get(o);
ArrayList<HashMap<String, Object>> a = new ArrayList<HashMap<String, Object>>();
for (int i = 0; i < jsonA.length(); i++) {
HashMap<String, Object> hm = new HashMap<String, Object>();
JSONObject jo = jsonA.getJSONObject(i);
Iterator<?> iter = jo.keys();
while (iter.hasNext()) {
String key = (String) iter.next();
hm.put(key, jo.get(key));
}
a.add(hm);
}
toReturn.put(s, a);
}
}
catch (JSONException e) {
System.err.println("Sorry, we got an error parsing the JSON stream");
e.printStackTrace();
}
return toReturn;
}
/**
* Get an array of results. This is not often used, since most results are returned as hashes.
*/
public ArrayList<Object> resultsAsArrayList() {
// we use an array list here since we don't know how large it is.
ArrayList<Object> results = null;
try {
InputStream res = this.query();
JSONTokener tok = new JSONTokener(new InputStreamReader(res));
JSONObject jsonO = new JSONObject(tok);
// if (debug)
// System.err.println("Result is" +res;)
JSONArray jsonA = new JSONArray(jsonO);
if (debug)
System.err.println("JSON Array is " + jsonA.toString());
results = new ArrayList<Object>(jsonA.length());
for (int i = 0; i < jsonA.length(); i++)
results.add(jsonA.get(i));
}
catch (JSONException e) {
System.err.println("There was an error loading the JSON stream");
e.printStackTrace();
}
catch (Exception e) {
System.err.println("There was an error parsing stream");
e.printStackTrace();
}
return results;
}
}