/**
* Copyright 2014 Global Crop Diversity Trust
*
* 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.genesys2.client.oauth;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.SocketException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.scribe.exceptions.OAuthConnectionException;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
/**
* Command line interface to Genesys
*
* @author matijaobreza
*
*/
public class CLI {
private static final Logger _log = LogManager.getLogger(CLI.class);
private File propertiesFile;
private Properties properties;
private Scanner in = new Scanner(System.in);
private static ObjectMapper mapper = new ObjectMapper();
private GenesysClient genesysClient = new GenesysClient();
private static Set<String> ignoredFields;
static {
ignoredFields = new HashSet<String>();
ignoredFields.add("id");
ignoredFields.add("createdBy");
ignoredFields.add("createdDate");
ignoredFields.add("lastModifiedBy");
ignoredFields.add("lastModifiedDate");
ignoredFields.add("version");
}
public static void main(String[] args) {
_log.info("Hello World!");
CLI cli = new CLI();
cli.loadProperties("client.properties");
cli.run();
}
private void run() {
checkPreconditions();
try {
System.out.println("/me: " + genesysClient.query("/me"));
Token accessToken = genesysClient.getAccessToken();
this.properties.put("access.token", accessToken.getToken());
saveProperties();
} catch (OAuthAuthenticationException e) {
_log.error("Failed to fetch /me", e);
authenticate();
} catch (OAuthConnectionException e) {
if (e.getCause() != null && e.getCause() instanceof SocketException) {
_log.error("Could not connect to host");
return;
} else {
_log.error(e.getMessage(), e);
}
} catch (Throwable e) {
_log.error(e.getMessage(), e);
return;
}
try {
doWork();
} catch (Throwable e) {
_log.error(e.getMessage(), e);
}
}
private void doWork() throws GenesysApiException, PleaseRetryException, IOException {
String line = null;
do {
System.out.println("1 Datasets");
System.out.println("2 Traits");
System.out.println("3 Crops");
System.out.println("0 Custom");
System.out.println("Q QUIT");
line = in.nextLine();
if ("1".equals(line))
doDatasets();
else if ("2".equals(line))
doTraits();
else if ("3".equals(line))
doCrops();
else if ("0".equals(line))
doCustom();
} while (!"Q".equalsIgnoreCase(line));
}
private void updateJsonData(String label, JsonNode n) {
if (n.isArray()) {
updateJsonArray(label, (ArrayNode) n);
} else if (n.isObject()) {
updateJsonObject(label, n);
}
}
private void updateJsonObject(String label, JsonNode n) {
Iterator<Entry<String, JsonNode>> f = n.fields();
while (f.hasNext()) {
Entry<String, JsonNode> field = f.next();
System.out.print(label + "." + StringUtils.capitalize(field.getKey()) + ":");
System.out.println(field.getValue());
if (ignoredFields.contains(field.getKey())) {
continue;
}
if (field.getValue().isObject() || field.getValue().isArray()) {
System.out.println("Edit subobject ?");
if (StringUtils.equalsIgnoreCase("y", in.nextLine())) {
updateJsonData(label + "." + field.getKey(), field.getValue());
}
continue;
}
String val = in.nextLine();
if (!field.getValue().isNull() && val.length() == 0) {
continue;
}
if (val.startsWith("i ")) {
field.setValue(new IntNode(Integer.parseInt(val.substring(2))));
} else if (val.startsWith("d ")) {
field.setValue(new DoubleNode(Double.parseDouble(val.substring(2))));
} else if (StringUtils.isBlank(val)) {
field.setValue(NullNode.getInstance());
} else {
field.setValue(new TextNode(val.trim()));
}
}
System.out.println("Done editing " + label);
}
private void updateJsonArray(String label, ArrayNode n) {
System.out.println("Array: " + n);
ArrayNode na = n.arrayNode();
String val;
do {
val = in.nextLine().trim();
if (val.startsWith("i ")) {
na.add(Integer.parseInt(val.substring(2)));
} else if (val.startsWith("d ")) {
na.add(Double.parseDouble(val.substring(2)));
} else if (val.startsWith("o ")) {
try {
Object o = Class.forName("org.genesys2.client.rest.model." + val.substring(2)).newInstance();
JsonNode newNode = mapper.readTree(mapper.writeValueAsString(o));
System.out.println(newNode);
updateJsonObject(label + "." + val.substring(2), newNode);
na.add(newNode);
} catch (ClassNotFoundException e) {
System.err.println(e.getMessage());
} catch (JsonProcessingException e) {
System.err.println(e.getMessage());
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (InstantiationException e) {
System.err.println(e.getMessage());
} catch (IllegalAccessException e) {
System.err.println(e.getMessage());
}
} else if (StringUtils.isBlank(val)) {
break;
} else {
na.add(val);
}
} while (StringUtils.isNotBlank(val));
n.removeAll();
n.addAll(na);
System.out.println("Done editing array " + label);
}
private void doCustom() throws GenesysApiException {
System.out.print("URL: ");
String url = in.nextLine();
System.out.print("Method [GET]: ");
String method = StringUtils.defaultIfBlank(in.nextLine(), "GET");
System.out.println("JSON: ");
String data = StringUtils.defaultIfBlank(in.nextLine(), null);
// Exec
System.out.println(genesysClient.query(Verb.valueOf(method), url, null, data));
}
private void doCrops() throws GenesysApiException {
String line = null;
do {
System.out.println("1 List crops");
System.out.println("2 Update crop");
System.out.println("3 Update crop rules");
System.out.println("0 Back");
line = in.nextLine();
if ("1".equals(line))
System.out.println("/crops: " + genesysClient.query("/crops"));
else if ("2".equals(line))
updateCrop();
else if ("3".equals(line))
updateCropRules();
else if ("9".equals(line))
System.out.println("/methods: " + genesysClient.query("/methods"));
else if ("0".equalsIgnoreCase(line))
return;
} while (!("0".equalsIgnoreCase(line)));
}
private void updateCropRules() throws GenesysApiException {
System.out.println("Crop shortName: ");
String shortName = in.nextLine().trim();
String rules = genesysClient.query("/crops/" + shortName + "/rules");
System.out.println("Crop rules: " + rules);
String newRules = StringUtils.defaultIfBlank(in.nextLine().trim(), rules);
if (StringUtils.equals(newRules, rules)) {
System.out.println("No change.");
return;
}
ArrayNode arr;
try {
arr = (ArrayNode) mapper.readTree(newRules);
} catch (Throwable e) {
System.err.println(e.getMessage());
return;
}
System.out.println(arr.toString());
// make a crop
System.out.println("New rules: " + genesysClient.query(Verb.POST, "/crops/" + shortName + "/rules", null, arr.toString()));
}
private void updateCrop() throws GenesysApiException {
System.out.println("Crop shortName: ");
String shortName = in.nextLine().trim();
ObjectNode cropJson = null;
try {
cropJson = (ObjectNode) mapper.readTree(genesysClient.getCrop(shortName));
cropJson.remove("rules");
} catch (IOException e) {
System.err.println(e.getMessage());
}
if (cropJson == null) {
cropJson = mapper.createObjectNode();
cropJson.put("shortName", shortName);
cropJson.put("name", "");
cropJson.put("i18n", "{}");
}
System.out.println(">> " + cropJson.toString());
System.out.println("Name [" + cropJson.get("name").textValue() + "]: ");
cropJson.put("name", StringUtils.defaultIfBlank(in.nextLine().trim(), cropJson.get("name").textValue()));
System.out.println("i18n [" + cropJson.get("i18n").textValue() + "]: ");
cropJson.put("i18n", StringUtils.defaultIfBlank(in.nextLine().trim(), cropJson.get("i18n").textValue()));
System.out.println(cropJson.toString());
// make a crop
System.out.println("Put method: " + genesysClient.query(Verb.PUT, "/crops", null, cropJson.toString()));
}
private void doTraits() throws GenesysApiException {
String line = null;
do {
System.out.println("1 List parameters");
System.out.println("2 List my methods");
System.out.println("9 List all methods");
System.out.println("3 Add method");
System.out.println("0 Back");
line = in.nextLine();
if ("1".equals(line))
System.out.println("/parameters: " + genesysClient.query("/descriptors"));
else if ("2".equals(line))
System.out.println("/mymethods: " + genesysClient.query("/mymethods"));
else if ("3".equals(line))
addMethod();
else if ("9".equals(line))
System.out.println("/methods: " + genesysClient.query("/methods"));
else if ("0".equalsIgnoreCase(line))
return;
} while (!("0".equalsIgnoreCase(line)));
}
private void doDatasets() throws GenesysApiException {
String line = null;
do {
System.out.println("1 List");
System.out.println("2 Add");
System.out.println("3 Add data");
System.out.println("4 Add RAW");
System.out.println("0 Back");
line = in.nextLine();
if ("1".equals(line))
System.out.println("/datasets: " + genesysClient.query("/datasets"));
else if ("2".equals(line))
addDataset();
else if ("3".equals(line))
addDatasetData();
else if ("4".equals(line))
addDatasetRaw();
else if ("0".equalsIgnoreCase(line))
return;
} while (!("0".equalsIgnoreCase(line)));
}
private void addMethod() throws GenesysApiException {
ObjectNode datasetJson = mapper.createObjectNode();
System.out.println("Method description: ");
datasetJson.put("description", in.nextLine());
System.out.println("UOM: ");
datasetJson.put("unit", StringUtils.defaultIfBlank(in.nextLine(), null));
System.out.println("Field name: ");
datasetJson.put("fieldName", StringUtils.defaultIfBlank(in.nextLine(), null));
System.out.println("Field type: (0=String, 1=Double, 2=Long)");
int fieldType = Integer.parseInt(in.nextLine());
datasetJson.put("fieldType", fieldType);
if (fieldType == 0) {
System.out.println("Field size: ");
datasetJson.put("fieldSize", Integer.parseInt(in.nextLine()));
}
System.out.println("Options: ");
datasetJson.put("options", StringUtils.defaultIfBlank(in.nextLine(), null));
System.out.println("Range: ");
datasetJson.put("range", StringUtils.defaultIfBlank(in.nextLine(), null));
System.err.println(datasetJson.toString());
// make a dataset
System.out.println("Put method: " + genesysClient.query(Verb.PUT, "/methods", null, datasetJson.toString()));
}
private void addDataset() throws GenesysApiException {
ObjectNode datasetJson = mapper.createObjectNode();
System.out.println("WIEWS Code: ");
datasetJson.put("institute", in.nextLine());
System.out.println("Dataset title: ");
datasetJson.put("title", in.nextLine());
System.out.println("Dataset description: ");
datasetJson.put("description", in.nextLine());
System.err.println(datasetJson.toString());
// make a dataset
System.out.println("Put dataset: " + genesysClient.query(Verb.PUT, "/datasets", null, datasetJson.toString()));
}
private void addDatasetData() throws GenesysApiException {
ObjectNode datasetJson = mapper.createObjectNode();
System.out.println("Dataset ID: ");
long datasetId = Long.parseLong(in.nextLine());
System.out.println("WIEWS Code: ");
datasetJson.put("instCode", in.nextLine());
System.out.println("Data data: ");
datasetJson.put("data", in.nextLine());
System.err.println(datasetJson.toString());
// make a dataset
System.out.println("Put dataset: " + genesysClient.query(Verb.PUT, "/datasets/" + datasetId + "/data", null, datasetJson.toString()));
}
private void addDatasetRaw() throws GenesysApiException {
System.out.println("Dataset ID: ");
long datasetId = Long.parseLong(in.nextLine());
System.out.println("JSON: ");
String json = in.nextLine();
System.err.println(json);
// make a dataset
System.out.println("Put dataset: " + genesysClient.query(Verb.PUT, "/datasets/" + datasetId + "/data", null, json));
}
private void checkPreconditions() {
boolean restart = false;
if (StringUtils.isBlank(properties.getProperty("client.key"))) {
System.out.print("Provide client key: ");
properties.put("client.key", in.nextLine());
restart = true;
}
if (StringUtils.isBlank(properties.getProperty("client.secret"))) {
System.out.print("Provide client secret: ");
properties.put("client.secret", in.nextLine());
restart = true;
}
if (StringUtils.isBlank(properties.getProperty("api.url"))) {
System.out.print("Provide API url: ");
properties.put("api.url", in.nextLine());
restart = true;
}
if (restart) {
saveProperties();
_log.warn("Properties udpated, please restart CLI application");
System.exit(-1);
}
}
private void authenticate() {
String authorizationUrl = genesysClient.getAuthorizationUrl(GenesysClient.EMPTY_TOKEN);
System.out.println("Authorization URL: \n" + authorizationUrl);
System.out.print("\nVerifier: ");
String verifierCode = in.nextLine();
System.out.println();
// Trade the Request Token and Verifier for the Access Token
genesysClient.authenticate(verifierCode);
Token accessToken = genesysClient.getAccessToken();
this.properties.put("access.token", accessToken.getToken());
// Get refresh token ()
Token refreshToken = genesysClient.getRefreshToken();
if (refreshToken != null) {
this.properties.put("refresh.token", refreshToken.getToken());
} else {
this.properties.remove("refresh.token");
}
saveProperties();
}
private void saveProperties() {
FileOutputStream fis = null;
try {
fis = new FileOutputStream(propertiesFile);
this.properties.store(fis, "OAuth client properties");
} catch (IOException e) {
_log.error(e);
} finally {
IOUtils.closeQuietly(fis);
}
}
private void loadProperties(String propertiesFileName) {
// .properties file location
propertiesFile = new File(propertiesFileName);
Properties properties = new Properties();
FileInputStream fis = null;
try {
_log.info("Loading " + propertiesFile.getAbsolutePath());
fis = new FileInputStream(propertiesFile);
properties.load(fis);
// Keep properties
this.properties = properties;
} catch (FileNotFoundException e) {
_log.warn(e, e);
} catch (IOException e) {
_log.error(e, e);
} finally {
IOUtils.closeQuietly(fis);
}
genesysClient.loadProperties(properties);
}
}