** ROUGH SETUP NOTES **
-Install Hatch on your desktop -- Linux edition:
-
-% wget http://download.eclipse.org/jetty/stable-9/dist/jetty-distribution-9.2.5.v20141112.tar.gz
-% tar -zxf jetty-distribution-9.2.5.v20141112.tar.gz
-% ln -s jetty-distribution-9.2.5.v20141112 jetty
-
# download jdk1.8 (requires license agreement) -- haven't tested on openjdk yet.
# http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
# and extract in the same directory
% ln -s jdk1.8.0_25 jdk1.8
% mkdir lib
-% wget -O lib/jetty-util-ajax-9.2.5.v20141112.jar \
- 'http://central.maven.org/maven2/org/eclipse/jetty/jetty-util-ajax/9.2.5.v20141112/jetty-util-ajax-9.2.5.v20141112.jar'
-
-# create an SSL certificat for jetty
-# if you use a password other than "password", modify references to
-# "password" in hath.xml (in the top directory).
-% cd jetty/etc/
-% ../../jdk1.8/bin/keytool -keystore keystore -alias jetty -genkey -keyalg RSA
+Download javax.json-api jar file from
+http://search.maven.org/remotecontent?filepath=javax/json/javax.json-api/1.0/javax.json-api-1.0.jar
# compile
% ./run.sh
# compile + run
% ./run.sh 1
-# open https://localhost:8443/ in Chrome and click through the security warning.
-# Then open the browser client.
-# Set "This workstation uses a remote print / storage service ("Hatch")?" under Admin -> Workstation
-# optionally configure / test printing
JAVA_HOME=jdk1.8
-JETTY_HOME=jetty
+CP=lib:lib/javax.json-api-1.0.jar
# compile
-$JAVA_HOME/bin/javac \
- -cp "$JETTY_HOME/lib/*:$JETTY_HOME/lib/websocket/*:lib/*" \
- -Xdiags:verbose -d lib \
- src/org/evergreen_ils/hatch/*.java
+$JAVA_HOME/bin/javac -cp $CP -d lib src/org/evergreen_ils/hatch/*.java
[ -z "$1" ] && exit;
# run
-$JAVA_HOME/bin/java \
- -cp "$JETTY_HOME/lib/*:$JETTY_HOME/lib/websocket/*:lib/*:lib" \
- org.evergreen_ils.hatch.Hatch
+$JAVA_HOME/bin/java -cp $CP org.evergreen_ils.hatch.Hatch
import java.io.*;
import java.util.LinkedList;
import java.util.Arrays;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
public class FileIO {
// --------------------------------------------------
// logger
- private static final Logger logger = Log.getLogger("FileIO");
+ //private static final Logger logger = Log.getLogger("FileIO");
/**
* Constructs a new FileIO with the provided base path.
File dir = new File(basePath);
if (!dir.exists()) {
if (!dir.mkdir()) {
- logger.info("Unable to create directory: " + dir.getName());
+ //logger.info("Unable to create directory: " + dir.getName());
return null;
}
}
File subDir = new File(basePath, originDomain);
if (!subDir.exists()) {
if (!subDir.mkdir()) {
- logger.info("Unable to create directory: " + subDir.getName());
+ //logger.info("Unable to create directory: " + subDir.getName());
return null;
}
}
- logger.info("baseDir: " + subDir.getName());
+ //logger.info("baseDir: " + subDir.getName());
return subDir;
}
* @return success or failure
*/
public boolean set(String key, String text) {
- logger.info("set => " + key);
+ //logger.info("set => " + key);
File file = getFile(key);
if (text == null) return false;
// delete the file if it exists
if (!file.exists() && !file.createNewFile()) {
- logger.info(
- "Unable to create file: " + file.getCanonicalPath());
+ //logger.info(
+ //"Unable to create file: " + file.getCanonicalPath());
return false;
}
outStream.close();
} catch(IOException e) {
- logger.warn("Error calling set() with key " + key);
- logger.warn(e);
+ //logger.warn("Error calling set() with key " + key);
+ //logger.warn(e);
return false;
}
* @return success or failure
*/
public boolean append(String key, String text) {
- logger.info("append => " + key);
+ //logger.info("append => " + key);
File file = getFile(key);
try {
// create the file if it doesn's already exist
if (!file.exists() && !file.createNewFile()) {
- logger.info(
- "Unable to create file: " + file.getCanonicalPath());
+ //logger.info(
+ //"Unable to create file: " + file.getCanonicalPath());
return false;
}
outStream.close();
} catch(IOException e) {
- logger.warn("Error in append() with key " + key);
- logger.warn(e);
+ //logger.warn("Error in append() with key " + key);
+ //logger.warn(e);
return false;
}
* @return The text content of the file
*/
public String get(String key) {
- logger.info("get => " + key);
+ //logger.info("get => " + key);
File file = getFile(key);
if (!file.exists()) return null;
buf.append(line);
}
} catch (IOException e) {
- logger.warn("Error reading key: " + key);
- logger.warn(e);
+ //logger.warn("Error reading key: " + key);
+ //logger.warn(e);
return null;
}
* @return success or failure
*/
public boolean remove(String key) {
- logger.info("remove => " + key);
+ //logger.info("remove => " + key);
File file = getFile(key);
- try {
+ //try {
if (file.exists() && !file.delete()) {
- logger.info(
- "Unable to delete file: " + file.getCanonicalPath());
+ //logger.info(
+ //"Unable to delete file: " + file.getCanonicalPath());
return false;
}
return true;
- } catch (IOException e) {
- logger.warn("Error deleting key: " + key);
- logger.warn(e);
- return false;
- }
+ //} catch (IOException e) {
+ //logger.warn("Error deleting key: " + key);
+ //logger.warn(e);
+ //return false;
+ //}
}
/**
* @return Array of keys
*/
public String[] keys(String prefix) {
- logger.info("keys => " + prefix);
+ //logger.info("keys => " + prefix);
File dir = baseDir();
if (dir == null || !dir.exists())
*/
package org.evergreen_ils.hatch;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.handler.HandlerList;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.xml.XmlConfiguration;
-
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.event.EventHandler;
import javafx.concurrent.WorkerStateEvent;
import java.util.concurrent.LinkedBlockingQueue;
-
-import org.eclipse.jetty.util.ajax.JSON;
+import java.util.logging.*;
import java.util.Map;
private Stage primaryStage;
/** Our logger instance */
- static final Logger logger = Log.getLogger("Hatch");
-
- /** Message queue for passing messages from the Jetty thread into
- * the JavaFX Application thread */
- private static LinkedBlockingQueue<Map> requestQueue =
- new LinkedBlockingQueue<Map>();
+ static Logger logger;
+
/**
- * Printable region containing a browser
+ * Printable region containing a browser.
*/
class BrowserView extends Region {
WebView webView = new WebView();
}
/**
- * Service task which listens for inbound messages from the
- * servlet.
- *
- * The code blocks on the concurrent queue, so it must be
- * run in a separate thread to avoid locking the main FX thread.
- */
- private static class MsgListenService extends Service<Map<String,Object>> {
- protected Task<Map<String,Object>> createTask() {
- return new Task<Map<String,Object>>() {
- protected Map<String,Object> call() {
- while (true) {
- logger.info("MsgListenService waiting for a message...");
- try {
- // take() blocks until a message is available
- return requestQueue.take();
- } catch (InterruptedException e) {
- // interrupted, go back and listen
- continue;
- }
- }
- }
- };
- }
- }
-
-
- /**
* JavaFX startup call
*/
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
- startMsgTask();
- }
-
- /**
- * Queues a message for processing by the queue processing thread.
- */
- public static void enqueueMessage(Map<String,Object> params) {
- logger.debug("queueing print message");
- requestQueue.offer(params);
}
/**
String contentType = (String) params.get("contentType");
if (content == null) {
- logger.warn("handlePrint() called with no content");
+ //logger.warn("handlePrint() called with no content");
return;
}
browser.webEngine.getLoadWorker()
.stateProperty()
.addListener( (ChangeListener) (obsValue, oldState, newState) -> {
- logger.info("browser load state " + newState);
+ //logger.info("browser load state " + newState);
if (newState == State.SUCCEEDED) {
- logger.info("Print browser page load completed");
+ //logger.info("Print browser page load completed");
// Avoid nested UI event loops -- runLater
Platform.runLater(new Runnable() {
}
});
- logger.info("printing " + content.length() + " bytes of " + contentType);
+ //logger.info("printing " + content.length() + " bytes of " + contentType);
browser.webEngine.loadContent(content, contentType);
-
- // After queueing up the HTML for printing, go back to listening
- // for new messages.
- startMsgTask();
}
- /**
- * Fire off the Service task, which checks for queued messages.
- *
- * When a queued message is found, it's sent off for printing.
- */
- public void startMsgTask() {
- MsgListenService service = new MsgListenService();
+ /*
+ public void onMessage(String message) {
+ if (session == null || !session.isOpen()) return;
+ //logger.info("onMessage() " + message);
+
+ HashMap<String,Object> params = null;
- logger.info("starting MsgTask");
+ try {
+ params = (HashMap<String,Object>) JSON.parse(message);
+ } catch (ClassCastException e) {
+ reply("Invalid WebSockets JSON message " + message,
+ new Long(-1), false);
+ }
- service.setOnSucceeded(
- new EventHandler<WorkerStateEvent>() {
+ 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");
- @Override
- public void handle(WorkerStateEvent t) {
- logger.info("MsgTask handling message.. ");
- Map<String,Object> message =
- (Map<String,Object>) t.getSource().getValue();
+ //logger.info("Received request for action " + action);
- // avoid nesting UI event loops by kicking off the print
- // operation from the main FX loop after this event handler
- // has exited.
- Platform.runLater(
- new Runnable() {
- @Override public void run() {
- handlePrint(message);
- }
+ // 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;
+ }
- service.start();
+ reply(response, msgid, !error);
}
+ */
+
+
+ /* TODO: make me configurable,
+ * see java.util.logging docs for xml config file
+ */
+ public static Logger getLogger() {
+ if (logger == null) {
+ logger = Logger.getLogger("Hatch");
+ logger.setLevel(Level.ALL);
+ ConsoleHandler handler = new ConsoleHandler();
+ handler.setLevel(Level.ALL);
+ handler.setFormatter(new SimpleFormatter());
+ logger.addHandler(handler);
+ logger.setUseParentHandlers(false);
+ }
+ return logger;
+ }
+
/**
* Hatch main.
*
- * Reads the Jetty configuration, starts the Jetty server thread,
- * then launches the JavaFX Application thread.
*/
public static void main(String[] args) throws Exception {
- // build a server from our hatch.xml configuration file
- XmlConfiguration configuration =
- new XmlConfiguration(new FileInputStream("hatch.xml"));
-
- Server server = (Server) configuration.configure();
-
- logger.info("Starting Jetty server");
-
- // start our server, but do not join(), since we want to server
- // to continue running in its own thread
- server.start();
-
- logger.info("Launching FX Application");
+ // start the messageIO reader/writer threads
+ new MessageIO().start();
// launch the FX Application thread
launch(args);
+
+ System.out.println("Here");
+
}
+
}
+++ /dev/null
-/* -----------------------------------------------------------------------
- * Copyright 2014 Equinox Software, Inc.
- * Bill Erickson <berick@esilibrary.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * -----------------------------------------------------------------------
- */
-package org.evergreen_ils.hatch;
-
-import java.io.IOException;
-import java.io.File;
-import java.io.BufferedReader;
-import org.eclipse.jetty.websocket.api.Session;
-import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
-import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
-import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
-import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
-import org.eclipse.jetty.websocket.api.annotations.WebSocket;
-import javax.servlet.ServletConfig;
-
-import org.eclipse.jetty.util.ajax.JSON;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import java.util.Arrays;
-import java.util.List;
-import java.util.HashMap;
-import java.util.Map;
-
-@WebSocket
-public class HatchWebSocketHandler {
-
- /** A single connection to a WebSockets client */
- private Session session;
-
- /** Current origin domain */
- private String origin;
-
- /** List of Origin domains from which we allow connections */
- private static String[] trustedDomains;
-
- /** True if we trust all Origin domains */
- private static boolean trustAllDomains = false;
-
- /** Root directory for all FileIO operations */
- private static String profileDirectory;
-
- /** Our logger instance */
- private static final Logger logger = Log.getLogger("WebSocketHandler");
-
- /**
- * Apply trusted domains.
- *
- * If the first domain in the list equals "*", that signifies that
- * all domains should be trusted.
- *
- * @param domains Array of domains to trust.
- */
- public static void setTrustedDomains(String[] domains) {
- trustedDomains = domains;
-
- if (domains.length > 0 ) {
-
- if ("*".equals(domains[0])) {
- logger.info("All domains trusted");
- trustAllDomains = true;
-
- } else {
-
- for(String domain : trustedDomains) {
- logger.info("Trusted domain: " + domain);
- }
- }
- } else {
- logger.warn("No domains are trusted. All requests will be denied");
- }
- }
-
- /**
- * Sets the profile directory
- *
- * @param directory Directory path as a String
- */
- public static void setProfileDirectory(String directory) {
- profileDirectory = directory;
- }
-
-
- /**
- * Runs the initial, global configuration for this handler.
- * TODO: move this into setProfileDirectory() (which will need to
- * be force-called regardless of config)?
- */
- public static void configure() {
- logger.info("WebSocketHandler.configure()");
-
- // default to ~/.evergreen
- if (profileDirectory == null) {
- String home = System.getProperty("user.home");
- profileDirectory = new File(home, ".evergreen").getPath();
- if (profileDirectory == null) {
- logger.info("Unable to set profile directory");
- }
- }
- }
-
- /**
- * Compares the Origin of the current WebSocket connection to the list
- * of allowed domains to determine if the current connection should
- * be allowed.
- *
- * @return True if the Origin domain is allowed, false otherwise.
- */
- protected boolean verifyOriginDomain() {
- logger.info("received connection from IP " +
- session.getRemoteAddress().getAddress());
-
- origin = session.getUpgradeRequest().getHeader("Origin");
-
- if (origin == null) {
- logger.warn("No Origin header in request; Dropping connection");
- return false;
- }
-
- logger.info("connection origin is " + origin);
-
- if (trustAllDomains) return true;
-
- if (java.util.Arrays.asList(trustedDomains).indexOf(origin) < 0) {
- logger.warn("Request from un-trusted domain: " + origin);
- return false;
- }
-
- return true;
- }
-
-
- /**
- * WebSocket onConnect handler.
- *
- * Verify the Origin domain before any communication may take place
- */
- @OnWebSocketConnect
- public void onConnect(Session session) {
- this.session = session;
- if (!verifyOriginDomain()) session.close();
- }
-
- /**
- * WebSocket onClose handler.
- *
- * Clears our current session.
- */
- @OnWebSocketClose
- public void onClose(int statusCode, String reason) {
- logger.info("onClose() statusCode=" + statusCode + ", reason=" + reason);
- this.session = null;
- }
-
- /**
- * Send a message to our connected client.
- *
- * @param json A JSON-encodable object to send to the caller.
- * @param msgid The message identifier
- */
- protected void reply(Object json, Long msgid) {
- reply(json, msgid, true);
- }
-
- /**
- * Send a message to our connected client.
- *
- * @param json A JSON-encodable object to send to the caller.
- * @param msgid The message identifier
- * @param success If false, the response will be packaged as an error
- * message.
- */
- protected void reply(Object json, Long msgid, boolean success) {
-
- Map<String, Object> response = new HashMap<String, Object>();
- response.put("msgid", msgid);
-
- if (success) {
- response.put("content", json);
- } else {
- response.put("error", json);
- }
-
- String jsonString = JSON.toString(response);
- logger.info("replying with : " + jsonString);
-
- try {
- if (!success) logger.warn(jsonString);
- session.getRemote().sendString(jsonString);
- } catch (IOException e) {
- logger.warn(e);
- }
- }
-
- /**
- * WebSocket onMessage handler.
- *
- * Processes the incoming message and passes the request off to the
- * necessary handler. Messages must be encoded as JSON strings.
- */
- @OnWebSocketMessage
- @SuppressWarnings("unchecked") // direct casting JSON-parsed objects
- 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);
- }
-}
+++ /dev/null
-/* -----------------------------------------------------------------------
- * Copyright 2014 Equinox Software, Inc.
- * Bill Erickson <berick@esilibrary.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * -----------------------------------------------------------------------
- */
-package org.evergreen_ils.hatch;
-
-import javax.servlet.annotation.WebServlet;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
-import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
-
-/**
- * Links HatchWebSocketHandler in as a Servlet handler.
- */
-public class HatchWebSocketServlet extends WebSocketServlet {
-
- @Override
- public void configure(WebSocketServletFactory factory) {
- factory.register(HatchWebSocketHandler.class);
- }
-
- @Override
- public void init(ServletConfig config) throws ServletException {
- super.init(config); // required for WS
- HatchWebSocketHandler.configure();
- }
-}
-
--- /dev/null
+package org.evergreen_ils.hatch;
+
+import java.util.logging.*;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.nio.ByteBuffer;
+import javax.json.*;
+import java.io.IOException;
+
+public class MessageIO {
+
+ private LinkedBlockingQueue<JsonValue> inQueue;
+ private LinkedBlockingQueue<JsonValue> outQueue;
+ //private static Logger logger = Logger.getLogger("org.evergreen_ils.hatch");
+ private static Logger logger = Hatch.getLogger();
+
+ private MessageReader reader;
+ private MessageWriter writer;
+
+ public MessageIO() {
+ inQueue = new LinkedBlockingQueue<JsonValue>();
+ outQueue = new LinkedBlockingQueue<JsonValue>();
+ reader = new MessageReader();
+ writer = new MessageWriter();
+ }
+
+ public void start() {
+ writer.start();
+ reader.start();
+ }
+
+ class MessageReader extends Thread {
+
+ private class EndOfStreamException extends IOException {
+ }
+
+ private int bytesToInt(byte[] bytes) {
+ return
+ (bytes[3] << 24) & 0xff000000
+ | (bytes[2] << 16) & 0x00ff0000
+ | (bytes[1] << 8) & 0x0000ff00
+ | (bytes[0] << 0) & 0x000000ff;
+ }
+
+ private String readOneMessage() throws EndOfStreamException, IOException {
+ byte[] lenBytes = new byte[4];
+ int bytesRead = System.in.read(lenBytes);
+
+ if (bytesRead == -1) {
+ throw new EndOfStreamException();
+ }
+
+ int msgLength = bytesToInt(lenBytes);
+
+ if (msgLength == 0) {
+ throw new IOException("Inbound message is 0 bytes. Interrupted?");
+ }
+
+ logger.info("MessageReader read message length: " + msgLength);
+
+ byte[] msgBytes = new byte[msgLength];
+
+ bytesRead = System.in.read(msgBytes);
+
+ if (bytesRead == -1) {
+ throw new EndOfStreamException();
+ }
+
+ String message = new String(msgBytes, "UTF-8");
+
+ logger.info("MessageReader read message " + message);
+
+ return message;
+ }
+
+ public void run() {
+
+ while (true) {
+
+ try {
+
+ String message = readOneMessage();
+
+ } catch (EndOfStreamException eose) {
+
+ logger.warning("STDIN closed. MessageReader thread exiting");
+ return;
+
+ } catch (IOException ioe) {
+ logger.warning(ioe);
+ }
+
+ // TODO: convert to JSON
+ // TODO: push onto inQueue
+ }
+
+ }
+ }
+
+ class MessageWriter extends Thread {
+
+ private byte[] intToBytes(int length) {
+ byte[] bytes = new byte[4];
+ bytes[0] = (byte) (length & 0xFF);
+ bytes[1] = (byte) ((length >> 8) & 0xFF);
+ bytes[2] = (byte) ((length >> 16) & 0xFF);
+ bytes[3] = (byte) ((length >> 24) & 0xFF);
+ return bytes;
+ }
+
+
+ public void writeOneMessage(String message) throws IOException {
+
+ System.out.write(intToBytes(message.length()));
+ System.out.write(message.getBytes("UTF-8"));
+ System.out.flush();
+ }
+
+ public void run() {
+
+ }
+ }
+
+}
*/
package org.evergreen_ils.hatch;
-// logging
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
// printing
import javafx.print.*;
public class PrintManager {
/** Our logger instance */
- static final Logger logger = Log.getLogger("PrintManager");
+ //static final Logger logger = Log.getLogger("PrintManager");
/**
* Shows the print dialog, allowing the user to modify settings,
Map<String,Object> settings =
(Map<String,Object>) params.get("config");
+ /*
HatchWebSocketHandler socket =
(HatchWebSocketHandler) params.get("socket");
+ */
PrinterJob job = null;
try {
job = buildPrinterJob(settings);
} catch(IllegalArgumentException e) {
- socket.reply(e.toString(), msgid, false);
+ //socket.reply(e.toString(), msgid, false);
return;
}
if (showDialog != null && showDialog.booleanValue()) {
- logger.info("Print dialog requested");
+ //logger.info("Print dialog requested");
if (!job.showPrintDialog(null)) {
// job canceled by user
- logger.info("after dialog");
+ //logger.info("after dialog");
job.endJob();
- socket.reply("Print job canceled", msgid);
+ //socket.reply("Print job canceled", msgid);
return;
}
} else {
- logger.info("No print dialog requested");
+ //logger.info("No print dialog requested");
}
Thread[] all = new Thread[100];
int count = Thread.currentThread().enumerate(all);
- logger.info(count + " active threads in print");
- logger.info("Thread " + Thread.currentThread().getId() + " printing...");
+ //logger.info(count + " active threads in print");
+ //logger.info("Thread " + Thread.currentThread().getId() + " printing...");
engine.print(job);
- logger.info("after print");
+ //logger.info("after print");
job.endJob();
- socket.reply("Print job succeeded", msgid);
+ //socket.reply("Print job succeeded", msgid);
}
/**
Set<Paper> papers = printerAttrs.getSupportedPapers();
for (Paper source : papers) {
if (source.getName().equals(paperName)) {
- logger.info("Found matching paper for " + paperName);
+ //logger.info("Found matching paper for " + paperName);
paper = source;
break;
}
// meaning no source.. meaning let the printer decide.
for (PaperSource source : paperSources) {
if (source.getName().equals(paperSource)) {
- logger.info("matched paper source for " + paperSource);
+ //logger.info("matched paper source for " + paperSource);
jobSettings.setPaperSource(source);
break;
}
if (pageRanges != null) {
- logger.info("pageRanges = " + pageRanges.toString());
+ //logger.info("pageRanges = " + pageRanges.toString());
List<PageRange> builtRanges = new LinkedList<PageRange>();
int i = 0, start = 0, end = 0;
do {
Map<String,Object> settings = new HashMap<String,Object>();
JobSettings jobSettings = job.getJobSettings();
- logger.info("Extracting print job settings from " + job);
+ //logger.info("Extracting print job settings from " + job);
settings.put(
jobSettings.collationProperty().getName(),
}
}
- logger.info("compiled printer properties: " + settings.toString());
+ //logger.info("compiled printer properties: " + settings.toString());
return settings;
}
printer.getName().equals(defaultPrinter.getName())) {
printerMap.put("is-default", new Boolean(true));
}
- logger.info("found printer " + printer.getName());
+ //logger.info("found printer " + printer.getName());
}
return printerMaps;