JAVA_HOME=jdk1.8
+JAVA=$JAVA_HOME/bin/java
CP=lib:lib/json-20160810.jar
+#LOGS="-Djava.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n'"
+#LOGS=-Djava.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n'
+LOGS=-Djava.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %5$s%6$s%n'
# compile
$JAVA_HOME/bin/javac -Xlint:unchecked -cp $CP -d lib src/org/evergreen_ils/hatch/*.java
[ -z "$1" ] && exit;
-# run
-$JAVA_HOME/bin/java -cp $CP org.evergreen_ils.hatch.Hatch
+if [ "$1" == "1" ]; then
+
+ # run
+ $JAVA "$LOGS" -cp $CP org.evergreen_ils.hatch.Hatch
+
+else
+
+ $JAVA "$LOGS" -cp $CP org.evergreen_ils.hatch.TestHatch \
+ | $JAVA "$LOGS" -cp $CP org.evergreen_ils.hatch.Hatch \
+ | $JAVA "$LOGS" -cp $CP org.evergreen_ils.hatch.TestHatch receive
+fi;
import java.io.*;
import java.util.LinkedList;
import java.util.Arrays;
+import java.util.logging.Logger;
public class FileIO {
// --------------------------------------------------
// logger
- //private static final Logger logger = Log.getLogger("FileIO");
+ private static final Logger logger = Hatch.getLogger();
/**
* Constructs a new FileIO with the provided base path.
return logger;
}
- /*
- public void onMessage(String message) {
- if (session == null || !session.isOpen()) return;
- logger.info("onMessage() " + message);
-
- HashMap<String,Object> params = null;
-
- try {
- params = (HashMap<String,Object>) JSON.parse(message);
- } catch (ClassCastException e) {
- reply("Invalid WebSockets JSON message " + message,
- new Long(-1), false);
- }
-
- Long msgid = (Long) params.get("msgid");
- String action = (String) params.get("action");
- String key = (String) params.get("key");
- String value = (String) params.get("value");
- String mime = (String) params.get("mime");
-
- logger.info("Received request for action " + action);
-
- // all requets require a message ID
- if (msgid == null) {
- reply("No msgid specified in request", msgid, false);
- return;
- }
-
- // all requests require an action
- if (action == null || action.equals("")) {
- reply("No action specified in request", msgid, false);
- return;
- }
-
- Object response = null;
- boolean error = false;
- FileIO io = new FileIO(profileDirectory, origin);
-
- switch (action) {
- case "keys":
- response = io.keys(key);
- break;
-
- case "printers":
- response = new PrintManager().getPrintersAsMaps();
- break;
-
- case "print":
- // pass ourselves off to the print handler so it can reply
- // for us after printing has completed.
- params.put("socket", this);
- Hatch.enqueueMessage(params);
-
- // we don't want to return a response below, since the
- // FX thread will handle that for us.
- return;
-
- case "print-config":
- try {
- response = new PrintManager().configurePrinter(params);
- } catch(IllegalArgumentException e) {
- response = e.toString();
- error = true;
- }
- break;
-
- case "get":
- String val = io.get(key);
- if (val != null) {
- // set() stores bare JSON. We must pass an
- // Object to reply so that it may be embedded into
- // a larger JSON response object, hence the JSON.parse().
- try {
- response = JSON.parse(val);
- } catch(java.lang.IllegalStateException e) {
- error = true;
- response = "Error JSON-parsing stored value " + val;
- }
- }
- break;
-
- case "remove":
- response = io.remove(key);
- break;
-
- case "set" :
- response = io.set(key, value);
- break;
-
- case "append" :
- response = io.append(key, value);
- break;
-
- default:
- response = "No such action: " + action;
- error = true;
- }
-
- reply(response, msgid, !error);
- }
- */
-
-
/**
* Hatch main.
*
*/
public static void main(String[] args) throws Exception {
- new RequestHandler().start();
+ new RequestHandler().start(); // start the STDIO handlers.
launch(args); // launch the FX Application thread
}
}
public void print(WebEngine engine, JSONObject request) {
JSONObject response = new JSONObject();
+ response.put("msgid", request.get("msgid"));
+ response.put("status", "200");
+ response.put("message", "OK");
try {
long msgid = request.getLong("msgid");
if (showDialog) {
if (!job.showPrintDialog(null)) {
job.endJob(); // canceled by user
- response.put("error", "Print job canceled by user");
+ response.put("status", "200");
+ response.put("message", "Print job canceled by user");
RequestHandler.reply(response);
return;
}
+ je.toString() + " : " + request.toString();
logger.warning(error);
- response.put("error", error);
+ response.put("status", "400");
+ response.put("message", error);
} catch(IllegalArgumentException iae) {
+ iae.toString() + " : " + request.toString();
logger.warning(error);
- response.put("error", error);
+ response.put("status", "400");
+ response.put("message", error);
}
RequestHandler.reply(response);
package org.evergreen_ils.hatch;
import org.json.*;
+import java.io.File;
import java.util.logging.*;
/**
static final Logger logger = Hatch.getLogger();
+ /** Root directory for all FileIO operations */
+ private static String profileDirectory = null;
+
+ /** Origin host/domain used for segregating files by browser host */
+ private static String origin = null;
+
+ void configure() {
+
+ // Find the profile directory.
+ // The profile directory + origin string represent the base
+ // directory for all file I/O for this session.
+ if (profileDirectory == null) { // TODO: make configurable
+ String home = System.getProperty("user.home");
+ profileDirectory = new File(home, ".evergreen").getPath();
+ if (profileDirectory == null) {
+ logger.warning("Unable to set profile directory");
+ }
+ }
+ }
+
/**
* Unpack a JSON request and send it to the necessary Hatch handler.
+ *
+ * @return True if the calling code should avoid calling reply() with
+ * the response object.
*/
- void dispatchRequest(JSONObject request) throws JSONException {
-
+ boolean dispatchRequest(
+ JSONObject request, JSONObject response) throws JSONException {
+
long msgid = request.getLong("msgid");
String action = request.getString("action");
+ response.put("msgid", msgid);
+
logger.info("Received message id=" + msgid + " action=" + action);
- JSONObject response = new JSONObject();
+ // init must be called first to set the origin info
+ if (action.equals("init")) {
+ origin = request.getString("origin");
+ return false;
+ }
+
+ if (origin == null) {
+ response.put("status", 400);
+ response.put("message", "'init' action must be called first!");
+ return false;
+ }
+
+ String key = null;
+ String content = null;
+ FileIO fileIO = new FileIO(profileDirectory, origin);
switch (action) {
-
+
case "printers":
response.put("printers",
new PrintManager().getPrintersAsMaps());
case "print":
// Confirm a minimal data set to enqueue print requests.
- String content = request.getString("content");
+ content = request.getString("content");
String contentType = request.getString("contentType");
if (content == null || "".equals(content)) {
- response.put("error", "Empty print message");
+ response.put("status", 400);
+ response.put("message", "Empty print message");
} else {
-
Hatch.enqueuePrintRequest(request);
// Responses to print requests are generated asynchronously
// and delivered from the FX print thread via reply().
- return;
+ return true;
+ }
+
+ case "keys": // Return stored keys
+ String pfxKey = request.optString("key");
+ response.put("keys", fileIO.keys(pfxKey));
+ break;
+
+ case "get":
+ key = request.getString("key");
+ String val = fileIO.get(key);
+
+ if (val != null) {
+ // set() stores bare JSON strings, but the caller to
+ // get() expects a unified JSON object in return, not
+ // a JSON string inside a JSON object. Parse the
+ // JSON and add it to the response object.
+ Object jsonBlob = new JSONTokener(val).nextValue();
+ response.put("content", jsonBlob);
}
+ break;
+
+ case "remove":
+ key = request.getString("key");
+
+ if (!fileIO.remove(key)) {
+ response.put("status", 500);
+ response.put("message", "Unable to remove key: " + key);
+ }
+
+ break;
+
+ case "set" :
+ key = request.getString("key");
+ // content is a JSON string
+ content = request.getString("content");
+
+ if (!fileIO.set(key, content)) {
+ response.put("status", 500);
+ response.put("message", "Unable to set key: " + key);
+ }
+
+ break;
+
+ case "append" :
+ key = request.getString("key");
+ content = request.getString("content");
+
+ if (!fileIO.append(key, content)) {
+ response.put("status", 500);
+ response.put("message", "Unable to append to key: " + key);
+ }
+
+ break;
+
default:
- response.put("error", "Unknown action: " + action);
+ response.put("status", 404);
+ response.put("message", "Action not found: " + action);
}
- reply(response);
+ return false;
}
/**
public void run() {
+ configure();
io.listen(); // STDIN/STDOUT handler
while (true) {
+
+ boolean skipReply = false;
+ JSONObject response = new JSONObject();
+
+ // these values are overidden as needed by the dispatch handler.
+ response.put("status", 200);
+ response.put("message", "OK");
+
try {
- dispatchRequest(io.recvMessage());
+ skipReply = dispatchRequest(io.recvMessage(), response);
} catch (JSONException je) {
- logger.warning(
- "JSON request protocol error: " + je.toString());
+ response.put("status", 400);
+ response.put("message", "Bad Request: " + je.toString());
}
+
+ if (!skipReply) reply(response);
}
}
}
public static void doSends() {
int msgId = 1;
+ // initialize connection to set origin info
JSONObject obj = new JSONObject();
obj.put("msgid", msgId++);
+ obj.put("action", "init");
+ obj.put("origin", "https://test.hatch.evergreen-ils.org");
+ io.sendMessage(obj);
+
+ rest();
+
+ // get a list of stored keys
+ obj = new JSONObject();
+ obj.put("msgid", msgId++);
+ obj.put("action", "keys");
+ io.sendMessage(obj);
+
+ rest();
+
+ // store a value
+ obj = new JSONObject();
+ obj.put("msgid", msgId++);
+ obj.put("action", "set");
+ obj.put("key", "eg.hatch.test.key1");
+ // "set" expects a pre-JSON-ified string. TODO: reconsider.
+ obj.put("content", "\"Rando content, now with cheese\"");
+ io.sendMessage(obj);
+
+ rest();
+
+ // store a value
+ obj = new JSONObject();
+ obj.put("msgid", msgId++);
+ obj.put("action", "get");
+ obj.put("key", "eg.hatch.test.key1");
+ io.sendMessage(obj);
+
+ rest();
+
+
+ obj = new JSONObject();
+ obj.put("msgid", msgId++);
+ obj.put("action", "keys");
+ io.sendMessage(obj);
+
+ rest();
+
+ // get a list of printers
+ obj = new JSONObject();
+ obj.put("msgid", msgId++);
obj.put("action", "printers");
io.sendMessage(obj);
rest();
/*
+ // Printing tests
+
obj = new JSONObject();
obj.put("msgid", msgId++);
obj.put("action", "print");
obj.put("contentType", "text/plain");
obj.put("content", "Hello, World!");
- obj.put("showDialog", true);
+ obj.put("showDialog", true); // avoid auto-print while testing
io.sendMessage(obj);
rest();
- */
obj = new JSONObject();
obj.put("msgid", msgId++);
obj.put("content", "<html><body><b>HELLO WORLD</b><img src='" +
"http://evergreen-ils.org/wp-content/uploads/2013/09/copy-Evergreen_Logo_sm072.jpg"
+ "'/></body></html>");
- obj.put("showDialog", true);
+ obj.put("showDialog", true); // avoid auto-print while testing
+
+ JSONObject settings = new JSONObject();
+ settings.put("copies", 2);
+ obj.put("settings", settings);
io.sendMessage(obj);
rest();
+
+ */
}
/**