/** Our logger instance */
static Logger logger;
+ /** Queue of incoming print requests */
+ private static LinkedBlockingQueue<JSONObject>
+ printRequestQueue = new LinkedBlockingQueue<JSONObject>();
/**
* Printable region containing a browser.
}
/**
+ * Shuffles print requests from the request queue into the
+ * FX Platform queue.
+ *
+ * This step allows the code to process print requests in order
+ * and without nesting UI event loops.
+ */
+ class PrintRequestShuffler extends Thread {
+ public void run() {
+ while (true) {
+ try {
+ JSONObject printRequest = printRequestQueue.take();
+ Platform.runLater(
+ new Runnable() {
+ @Override public void run() {
+ handlePrint(printRequest);
+ }
+ }
+ );
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ }
+
+ /** Add a print request object to the print queue. */
+ public static void enqueuePrintRequest(JSONObject request) {
+ printRequestQueue.offer(request);
+ }
+
+ /**
* JavaFX startup call
*/
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
+ new PrintRequestShuffler().start();
}
/**
* Build a browser view from the print content, tell the
* browser to print itself.
*/
- private void handlePrint(Map<String,Object> params) {
- String content = (String) params.get("content");
- String contentType = (String) params.get("contentType");
-
- if (content == null) {
- logger.warning("handlePrint() called with no content");
- return;
- }
+ private void handlePrint(JSONObject request) {
browser = new BrowserView();
Scene scene = new Scene(browser);
browser.webEngine.getLoadWorker()
.stateProperty()
.addListener( (ChangeListener<State>) (obsValue, oldState, newState) -> {
- logger.info("browser load state " + newState);
+ logger.finest("browser load state " + newState);
if (newState == State.SUCCEEDED) {
- logger.info("Print browser page load completed");
+ logger.finer("Print browser page load completed");
- // Avoid nested UI event loops -- runLater
+ // Avoid nested UI event loops
Platform.runLater(new Runnable() {
@Override public void run() {
- new PrintManager().print(browser.webEngine, params);
+ new PrintManager().print(browser.webEngine, request);
}
});
}
});
- logger.info("printing " + content.length() + " bytes of " + contentType);
- browser.webEngine.loadContent(content, contentType);
+ try {
+ String content = request.getString("content");
+ String contentType = request.getString("contentType");
+
+ logger.info("printing " +
+ content.length() + " bytes of " + contentType);
+
+ browser.webEngine.loadContent(content, contentType);
+
+ } catch (JSONException je) {
+ // RequestHandler already confirmed 'content' and 'contentType'
+ // values exist. No exceptions should occur here.
+ }
}
/* TODO: make me configurable via config file
*/
package org.evergreen_ils.hatch;
-
// printing
import javafx.print.*;
import javafx.scene.web.WebEngine;
import java.lang.IllegalArgumentException;
// data structures
+import java.util.Set;
import java.util.Map;
import java.util.List;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
-import java.util.Set;
-import java.util.LinkedHashSet;
+
+import java.util.logging.Logger;
+
+import org.json.*;
public class PrintManager {
/** Our logger instance */
- //static final Logger logger = Log.getLogger("PrintManager");
+ static final Logger logger = Hatch.getLogger();
/**
* Shows the print dialog, allowing the user to modify settings,
* @param engine The WebEngine instance to print
* @param params Print request parameters
*/
- public void print(WebEngine engine, Map<String,Object>params) {
+ public void print(WebEngine engine, JSONObject request) {
+
+ JSONObject response = new JSONObject();
+
+ try {
+ long msgid = request.getLong("msgid");
+ response.put("msgid", msgid);
+ /*
Long msgid = (Long) params.get("msgid");
Boolean showDialog = (Boolean) params.get("showDialog");
Map<String,Object> settings =
(Map<String,Object>) params.get("config");
- /*
- HatchWebSocketHandler socket =
- (HatchWebSocketHandler) params.get("socket");
- */
PrinterJob job = null;
//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...");
-
engine.print(job);
- //logger.info("after print");
job.endJob();
//socket.reply("Print job succeeded", msgid);
+
+ */
+
+ } catch (JSONException je) {
+ String error = "JSON request protocol error: "
+ + je.toString() + " : " + request.toString();
+
+ logger.warning(error);
+ response.put("error", error);
+ }
+
+ RequestHandler.reply(response);
}
/**
* via MessageIO.
*/
public class RequestHandler extends Thread {
- private MessageIO io;
+ private static MessageIO io = new MessageIO();
static final Logger logger = Hatch.getLogger();
- public RequestHandler() {
- io = new MessageIO();
- }
-
/**
* Unpack a JSON request and send it to the necessary Hatch handler.
*/
case "print":
String content = request.getString("content");
String contentType = request.getString("contentType");
-
+ Hatch.enqueuePrintRequest(request);
+ // print response is delivered from the FX print
+ // thread via reply().
+ return;
default:
response.put("error", "Unknown action: " + action);
}
- io.sendMessage(response);
+ reply(response);
}
+ /**
+ * Most replies are delivered from within dispatchRequest, but some
+ * like printing require the reply be delivered from another thread.
+ */
+ protected static void reply(JSONObject response) {
+ io.sendMessage(response);
+ }
public void run() {