hatch websocket cont.; mostly working now
authorBill Erickson <berick@esilibrary.com>
Tue, 8 Apr 2014 18:03:02 +0000 (14:03 -0400)
committerBill Erickson <berick@esilibrary.com>
Tue, 8 Apr 2014 18:03:02 +0000 (14:03 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
jetty_control.sh
src/org/evergreen_ils/hatch/HatchSocket.java
src/org/evergreen_ils/hatch/PrintDriver.java
websocket/fetch_comp_run.sh [deleted file]
websocket/org/evergreen_ils/hatch/EventClient.java [deleted file]
websocket/org/evergreen_ils/hatch/EventServer.java [deleted file]
websocket/org/evergreen_ils/hatch/EventSocket.java [deleted file]
websocket/org/evergreen_ils/hatch/FileIO.java [deleted file]
websocket/org/evergreen_ils/hatch/PrintDriver.java [deleted file]

index 4240491..7271220 100755 (executable)
@@ -6,6 +6,11 @@ JETTY_VERSION=9.1.2.v20140210
 JETTY_DIR="jetty-distribution-$JETTY_VERSION"
 JETTY_PACKAGE="$JETTY_DIR.tar.gz"
 JETTY_UTIL_AJAX=jetty-util-ajax-$JETTY_VERSION.jar
+export JAVA_HOME=$BASE_DIR/jdk1.8.0
+
+# NOTE:
+# http://stackoverflow.com/questions/22806946/getting-error-scanning-file-when-running-jetty-9-on-java-8-using-the-maven-jetty
+# http://forge.ow2.org/project/showfiles.php?group_id=23&release_id=5424
 
 OPT_FETCH=0;
 OPT_COMPILE=0
@@ -64,12 +69,12 @@ fi;
 if [ $OPT_COMPILE -eq 1 ]; then
     echo "Compiling..."
     cd $BASE_DIR/src;
-    javac -Xlint:unchecked -d ../WEB-INF/classes/ -cp "../$JETTY_DIR/lib/*:../$JETTY_DIR/lib/websocket/*" org/evergreen_ils/hatch/*.java;
+    $JAVA_HOME/bin/javac -Xlint:unchecked -d ../WEB-INF/classes/ -cp "../$JETTY_DIR/lib/*:../$JETTY_DIR/lib/websocket/*" org/evergreen_ils/hatch/*.java;
 fi;
 
 if [ $OPT_RUN -eq 1 ]; then
     echo "Running..."
     cd $BASE_DIR/$JETTY_DIR;
-    java -jar start.jar 
+    $JAVA_HOME/bin/java -jar start.jar 
 fi;
 
index bfcb772..e8a7ce3 100644 (file)
@@ -16,6 +16,7 @@ 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;
 
 @WebSocket
 public class HatchSocket {
@@ -104,69 +105,74 @@ public class HatchSocket {
         this.session = null;
     }
 
-    private void sendJSONMessage(Object json) {
+    private void reply(Object json) {
+        reply(json, true);
+    }
+
+    private void reply(Object json, boolean success) {
+
+        HashMap<String, Object> response = new HashMap<String, Object>();
+        if (success) {
+            response.put("success", json);
+        } else {
+            response.put("error", json);
+        }
+
         try {
-            session.getRemote().sendString(JSON.toString(json));
+            String jsonString = JSON.toString(response);
+            if (!success) logger.warn(jsonString);
+            session.getRemote().sendString(jsonString);
         } catch (IOException e) {
             logger.warn(e);
         }
     }
 
     @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,String> params = null;
+
+        try {
+            params = (HashMap<String,String>) JSON.parse(message);
+        } catch (ClassCastException e) {
+            reply("Invalid WebSockets JSON message " + message, false);
+        }
+
         FileIO io;
-        /*
-         * TODO: inbound message should be a JSON blob
-        String action = request.getParameter("action");
-        String key = request.getParameter("key");
-        String value = request.getParameter("value");
-        */
-        String action = "keys";
-        String key = "";
-        String value = "";
+        String action = params.get("action");
+        String key = params.get("key");
+        String value = params.get("value");
+        String mime = params.get("mime");
 
         // all requests require an action
-        /*
         if (action == null || action.equals("")) {
-            String err = JSON.toString("No action specified in request");
-            sendJSONMessage(err);
-            logger.info(err);
-            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+            reply("No action specified in request", false);
             return;
         }
-        */
 
         if (action.equals("keys")) {
             io = new FileIO(profileDirectory);
             String[] keys = io.keys(key); // OK for key to be null
-
             if (keys != null) {
-                sendJSONMessage(keys);
+                reply(keys);
             } else {
-                /*
-                response.setStatus(
-                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-                    */
+                reply("key lookup error", false);
             }
             return;
         }
 
         if (action.equals("printers")) {
             List printers = new PrintDriver().getPrinters();
-            //response.setStatus(HttpServletResponse.SC_OK);
-            sendJSONMessage(printers);
+            reply(printers);
             return;
         }
 
         // all remaining requests require a key
         if (key == null || key.equals("")) {
-            String err = "No key specified in request";
-            sendJSONMessage(err);
-            logger.info(err);
-            //response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+            reply("No key specified in request", false);
             return;
         }
 
@@ -175,22 +181,18 @@ public class HatchSocket {
             BufferedReader reader = io.get(key);
             if (reader != null) {
                 String line;
-                //response.setStatus(HttpServletResponse.SC_OK);
                 try {
                     while ( (line = reader.readLine()) != null) {
                         // relay lines of text to the caller as we read them
                         // assume the text content is JSON and return it
                         // un-JSON-ified.
-                        sendJSONMessage(line);
+                        reply(line);
                     }
                 } catch (IOException e) {
                     logger.warn(e);
                 }
             } else {
-                /*
-                response.setStatus(
-                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-                */
+                reply("Error accessing property " + key, false);
             }
             return;
         }
@@ -198,61 +200,50 @@ public class HatchSocket {
         if (action.equals("delete")) {
             io = new FileIO(profileDirectory);
             if (io.delete(key)) {
-                //response.setStatus(HttpServletResponse.SC_OK);
+                reply("Delete of " + key + " successful");
             } else {
-                //response.setStatus(
-                    //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                reply("Delete of " + key + " failed", false);
             }
             return;
         }
 
         // all remaining actions require value
         if (value == null) {
-            String err = "No value specified in request";
-            sendJSONMessage(err);
-            logger.info(err);
-            //response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+            reply("No value specified in request", false);
             return;
         }
 
-        switch(action) {
+        switch (action) {
 
             case "print" : 
-                boolean ok = new PrintDriver().printWithDialog(key, value);
+                boolean ok = new PrintDriver().printWithDialog(mime, value);
                 if (ok) {
-                    //response.setStatus(HttpServletResponse.SC_OK);
+                    reply("print succeeded");
                 } else {
-                    //response.setStatus(
-                        //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                    reply("print failed", false);
                 }
                 break;
 
             case "set" :
                 io = new FileIO(profileDirectory);
                 if (io.set(key, value)) {
-                    //response.setStatus(HttpServletResponse.SC_OK);
+                    reply("setting value for " + key + " succeeded");
                 } else {
-                    //response.setStatus(
-                        //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                    reply("setting value for " + key + " succeeded", false);
                 }
                 break;
 
             case "append" :
                 io = new FileIO(profileDirectory);
                 if (io.append(key, value)) {
-                    //response.setStatus(HttpServletResponse.SC_OK);
+                    reply("appending value for " + key + " succeeded");
                 } else {
-                    //response.setStatus(
-                        //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                    reply("appending value for " + key + " succeeded", false);
                 }
                 break;
 
             default:
-                //response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
-                sendJSONMessage(
-                    "\"No Such Action: " + action + "\"");
-                logger.info("No such action: " + action);
+                reply("No such action: " + action, false);
         }
-
     }
 }
index 5247e38..89fc691 100644 (file)
@@ -29,12 +29,29 @@ import java.util.LinkedList;
 public class PrintDriver implements Printable {
 
     private String printText;
+    private String mimeType;
     private static final Logger logger = Log.getLogger("PrintDriver");
 
     private final static int POINTS_PER_INCH = 72;
 
-    public int print(Graphics g, PageFormat pf, int page) 
-        throws PrinterException {
+    public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
+
+        switch (mimeType) {
+            case "text/csv"   : return printTextCSV(g, pf, page);
+            case "text/plain" : return printTextPlain(g, pf, page);
+            case "text/html"  : return printTextHTML(g, pf, page);
+            default :
+                logger.warn("Print MIME type not supported: " + mimeType);
+        }
+
+        return NO_SUCH_PAGE;
+    }
+
+    private int printTextHTML(Graphics g, PageFormat pf, int page) {
+        return PAGE_EXISTS;
+    }
+
+    private int printTextPlain(Graphics g, PageFormat pf, int page) {
 
         // for now, assume we only have one page
         if (page > 0) return NO_SUCH_PAGE;
@@ -43,8 +60,8 @@ public class PrintDriver implements Printable {
         Graphics2D g2d = (Graphics2D)g;
         g2d.translate(pf.getImageableX(), pf.getImageableY());
 
-        /* --------------------------------------------- */
-        /* -- rendering the print text as paragraph ---  */
+        // --------------------------------------------- 
+        // -- rendering the print text as paragraph --- 
         Point2D.Double pen = new Point2D.Double(
             0.25 * POINTS_PER_INCH, 0.25 * POINTS_PER_INCH);
         double width = 7.5 * POINTS_PER_INCH;
@@ -70,14 +87,22 @@ public class PrintDriver implements Printable {
             //--- the leading of the font
             pen.y += layout.getDescent() + layout.getLeading();
         }
-        /* -------------------------------------------- */
+        // -------------------------------------------- 
+
+        return PAGE_EXISTS;
+    }
+
+    private int printTextCSV(Graphics g, PageFormat pf, int page) {
+        // for now, assume we only have one page
+        if (page > 0) return NO_SUCH_PAGE;
 
-        /*
+        // find the imageable area
+        Graphics2D g2d = (Graphics2D)g;
+        g2d.translate(pf.getImageableX(), pf.getImageableY());
         int x = 5;
         int y = 5;
         for (String line : printText.split("\n"))
             g.drawString(line, x, y += g.getFontMetrics().getHeight());
-        */
 
         return PAGE_EXISTS;
     }
@@ -85,16 +110,17 @@ public class PrintDriver implements Printable {
     /**
      * Spawns standard JAVA-driven print dialog and prints text
      */
-    public boolean printWithDialog(String key, String text) {
+    public boolean printWithDialog(String mime, String text) {
         debugPrintService(null); // testing
         printText = text;
+        mimeType = mime;
         PrinterJob job = PrinterJob.getPrinterJob();
         job.setPrintable(this);
         if (!job.printDialog()) return true; // print canceled by user
         try {
             job.print();
         } catch (PrinterException ex) {
-            logger.warn("Error printing document for key " + key);
+            logger.warn("Error printing document for mime " + mime);
             logger.warn(ex);
             return false;
         }
diff --git a/websocket/fetch_comp_run.sh b/websocket/fetch_comp_run.sh
deleted file mode 100755 (executable)
index 4c0b4f3..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash
-set -e
-
-BASE_DIR=$PWD
-JETTY_VERSION=9.1.2.v20140210
-JETTY_DIR="jetty-distribution-$JETTY_VERSION"
-JETTY_PACKAGE="$JETTY_DIR.tar.gz"
-JETTY_UTIL_AJAX=jetty-util-ajax-$JETTY_VERSION.jar
-
-OPT_FETCH=0;
-OPT_COMPILE=0
-OPT_RUN=0
-
-DEPENDS="javax.websocket-api-1.0.jar javax-websocket-client-impl-$JETTY_VERSION.jar javax-websocket-server-impl-$JETTY_VERSION.jar jetty-http-$JETTY_VERSION.jar jetty-io-$JETTY_VERSION.jar jetty-security-$JETTY_VERSION.jar jetty-server-$JETTY_VERSION.jar jetty-servlet-$JETTY_VERSION.jar jetty-util-$JETTY_VERSION.jar servlet-api-3.1.jar websocket-api-$JETTY_VERSION.jar websocket-client-$JETTY_VERSION.jar websocket-common-$JETTY_VERSION.jar websocket-server-$JETTY_VERSION.jar websocket-servlet-$JETTY_VERSION.jar"
-
-# return here on exit
-trap "{ cd $BASE_DIR; }" EXIT
-
-function usage() {
-    echo ""
-    echo "Fetch dependencies, compile, and run Hatch:";
-    echo ""
-    echo "$0 -fcr";
-    echo ""
-}
-
-while getopts  "fcrh" flag; do                                         
-    case $flag in                                                              
-        "f")   OPT_FETCH=1;;
-        "c")   OPT_COMPILE=1;;
-        "r")   OPT_RUN=1;;
-        "h"|*)  usage;;                                                        
-    esac;                                                                      
-done 
-
-if [ $OPT_FETCH -eq 1 ]; then
-
-    mkdir -p lib;
-
-    if [ ! -f $JETTY_PACKAGE ]; then
-        echo "Fetching Jetty package...";
-        wget "http://carroll.aset.psu.edu/pub/eclipse/jetty/$JETTY_VERSION/dist/$JETTY_PACKAGE";
-    fi;
-
-    if [ ! -d $JETTY_DIR ]; then
-        echo "Unpacking Jetty...";
-        tar xf $JETTY_PACKAGE;
-        for jar in $DEPENDS; do
-            find $JETTY_DIR -name "$jar" -exec cp -v {} lib/ \; 
-        done;
-    fi;
-fi;
-
-if [ $OPT_COMPILE -eq 1 ]; then
-    echo "Compiling..."
-    javac -Xlint:unchecked -cp "lib/*" org/evergreen_ils/hatch/*.java
-fi;
-
-if [ $OPT_RUN -eq 1 ]; then
-    echo "Running..."
-    java -cp ".:lib/*" org.evergreen_ils.hatch.EventServer
-fi;
diff --git a/websocket/org/evergreen_ils/hatch/EventClient.java b/websocket/org/evergreen_ils/hatch/EventClient.java
deleted file mode 100644 (file)
index 25a903d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.evergreen_ils.hatch;
-
-import java.net.URI;
-import javax.websocket.ContainerProvider;
-import javax.websocket.Session;
-import javax.websocket.WebSocketContainer;
-
-import org.eclipse.jetty.util.component.LifeCycle;
-
-public class EventClient
-{
-    public static void main(String[] args)
-    {
-        URI uri = URI.create("ws://localhost:8080/hatch/");
-
-        try
-        {
-            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
-
-            try
-            {
-                // Attempt Connect
-                Session session = container.connectToServer(EventSocket.class,uri);
-                // Send a message
-                session.getBasicRemote().sendText("Hello");
-                // Close session
-                session.close();
-            }
-            finally
-            {
-                // Force lifecycle stop when done with container.
-                // This is to free up threads and resources that the
-                // JSR-356 container allocates. But unfortunately
-                // the JSR-356 spec does not handle lifecycles (yet)
-                if (container instanceof LifeCycle)
-                {
-                    ((LifeCycle)container).stop();
-                }
-            }
-        }
-        catch (Throwable t)
-        {
-            t.printStackTrace(System.err);
-        }
-    }
-}
diff --git a/websocket/org/evergreen_ils/hatch/EventServer.java b/websocket/org/evergreen_ils/hatch/EventServer.java
deleted file mode 100644 (file)
index 7966725..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.evergreen_ils.hatch;
-
-// Code derived from 
-// https://github.com/jetty-project/embedded-jetty-websocket-examples/tree/master/javax.websocket-example
-
-import javax.websocket.server.ServerContainer;
-
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
-
-public class EventServer
-{
-    public static void main(String[] args)
-    {
-        Server server = new Server();
-        ServerConnector connector = new ServerConnector(server);
-        connector.setPort(8080);
-        server.addConnector(connector);
-
-        // Setup the basic application "context" for this application at "/"
-        // This is also known as the handler tree (in jetty speak)
-        ServletContextHandler context = 
-            new ServletContextHandler(ServletContextHandler.SESSIONS);
-        context.setContextPath("/");
-        server.setHandler(context);
-
-        try {
-            // Initialize javax.websocket layer
-            ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
-
-            // Add WebSocket endpoint to javax.websocket layer
-            wscontainer.addEndpoint(EventSocket.class);
-
-            server.start();
-            server.dump(System.err);
-            server.join();
-
-        } catch (Throwable t) {
-            t.printStackTrace(System.err);
-        }
-    }
-}
diff --git a/websocket/org/evergreen_ils/hatch/EventSocket.java b/websocket/org/evergreen_ils/hatch/EventSocket.java
deleted file mode 100644 (file)
index 26b3986..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.evergreen_ils.hatch;
-
-import javax.websocket.ClientEndpoint;
-import javax.websocket.CloseReason;
-import javax.websocket.OnClose;
-import javax.websocket.OnError;
-import javax.websocket.OnMessage;
-import javax.websocket.OnOpen;
-import javax.websocket.Session;
-import javax.websocket.server.ServerEndpoint;
-
-@ClientEndpoint
-@ServerEndpoint(value="/hatch/")
-public class EventSocket
-{
-    @OnOpen
-    public void onWebSocketConnect(Session sess)
-    {
-        System.out.println("Socket Connected: " + sess);
-    }
-    
-    @OnMessage
-    public void onWebSocketText(String message)
-    {
-        System.out.println("Received TEXT message: " + message);
-    }
-    
-    @OnClose
-    public void onWebSocketClose(CloseReason reason)
-    {
-        System.out.println("Socket Closed: " + reason);
-    }
-    
-    @OnError
-    public void onWebSocketError(Throwable cause)
-    {
-        cause.printStackTrace(System.err);
-    }
-}
diff --git a/websocket/org/evergreen_ils/hatch/FileIO.java b/websocket/org/evergreen_ils/hatch/FileIO.java
deleted file mode 100644 (file)
index 95fc012..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-package org.evergreen_ils.hatch;
-import java.io.*;
-import java.util.LinkedList;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class FileIO {
-
-    String basePath;
-    private static final Logger logger = Log.getLogger("FileIO");
-
-    public FileIO(String directory) {
-        basePath = directory;
-    }
-
-    protected File getFile(String key) {
-        File dir = new File(basePath);
-        if (!dir.exists()) {
-            if (!dir.mkdir()) {
-                logger.info("Unable to create director: " + basePath);
-                return null;
-            }
-        }
-        return new File(dir, key);
-    }
-
-    public boolean set(String key, String text) {
-        logger.info("set => " + key);
-        File file = getFile(key);
-
-        try {
-
-            // delete the file if it exists
-            if (!file.exists() && !file.createNewFile()) {
-                logger.info(
-                    "Unable to create file: " + file.getCanonicalPath());
-                return false;
-            }
-
-            // destructive write (replace existing text)
-            Writer outStream = new BufferedWriter(
-                new FileWriter(file.getAbsoluteFile()));
-
-            outStream.write(text);
-            outStream.close();
-
-        } catch(IOException e) {
-            logger.warn("Error calling set() with key " + key);
-            logger.warn(e);
-            return false;
-        }
-
-        return true;
-    }
-
-    public boolean append(String key, String text) {
-        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());
-                return false;
-            }
-
-            // non-destructive write (append)
-            Writer outStream = new BufferedWriter(
-                new FileWriter(file.getAbsoluteFile(), true));
-            outStream.write(text);
-            outStream.close();
-
-        } catch(IOException e) {
-            logger.warn("Error in append() with key " + key);
-            logger.warn(e);
-            return false;
-        }
-
-        return true;
-    }
-
-    public BufferedReader get(String key) {
-        logger.info("get => " + key);
-        File file = getFile(key);
-        if (!file.exists()) return null;
-
-        StringBuffer sbuf = new StringBuffer();
-        try {
-            return new BufferedReader(
-                new FileReader(file.getAbsoluteFile()));
-        } catch (IOException e) {
-            logger.warn("Error reading key: " + key);
-            logger.warn(e);
-            return null;
-        }
-    }
-
-    public boolean delete(String key) {
-        logger.info("delete => " + key);
-        File file = getFile(key);
-        try {
-            if (file.exists() && !file.delete()) {
-                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;
-        }
-    }
-
-    public String[] keys() {
-        return keys(null);
-    }
-
-    public String[] keys(String prefix) {
-        logger.info("keys => " + prefix);
-        File dir = new File(basePath);
-        if (!dir.exists()) return new String[0];
-
-        LinkedList<String> nameList = new LinkedList<String>();
-        File[] files = dir.listFiles();
-
-        for (File file : files) {
-            if (file.isFile()) {
-                String name = file.getName();
-                if (prefix == null) {
-                    nameList.add(name);
-                } else {
-                    if (name.startsWith(prefix)) {
-                        nameList.add(name);
-                    }
-                }
-            }
-        }
-
-        return (String[]) nameList.toArray(new String[0]);
-    }
-}
diff --git a/websocket/org/evergreen_ils/hatch/PrintDriver.java b/websocket/org/evergreen_ils/hatch/PrintDriver.java
deleted file mode 100644 (file)
index 5247e38..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-package org.evergreen_ils.hatch;
-
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import java.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import java.awt.print.*;
-
-import javax.print.PrintService;
-import javax.print.PrintServiceLookup;
-import javax.print.attribute.Attribute;
-import javax.print.attribute.AttributeSet;
-
-import java.awt.font.FontRenderContext;
-import java.awt.font.LineBreakMeasurer;
-import java.awt.font.TextAttribute;
-import java.awt.font.TextLayout;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.text.AttributedString;
-
-import java.util.Map;
-import java.util.List;
-import java.util.HashMap;
-import java.util.LinkedList;
-
-public class PrintDriver implements Printable {
-
-    private String printText;
-    private static final Logger logger = Log.getLogger("PrintDriver");
-
-    private final static int POINTS_PER_INCH = 72;
-
-    public int print(Graphics g, PageFormat pf, int page) 
-        throws PrinterException {
-
-        // for now, assume we only have one page
-        if (page > 0) return NO_SUCH_PAGE;
-
-        // find the imageable area
-        Graphics2D g2d = (Graphics2D)g;
-        g2d.translate(pf.getImageableX(), pf.getImageableY());
-
-        /* --------------------------------------------- */
-        /* -- rendering the print text as paragraph ---  */
-        Point2D.Double pen = new Point2D.Double(
-            0.25 * POINTS_PER_INCH, 0.25 * POINTS_PER_INCH);
-        double width = 7.5 * POINTS_PER_INCH;
-        AttributedString paragraphText = new AttributedString(printText);
-
-        LineBreakMeasurer lineBreaker = new LineBreakMeasurer(
-             paragraphText.getIterator(), new FontRenderContext(null, true, true));
-
-        //--- Create the TextLayout object
-        TextLayout layout;
-
-        //--- LineBreakMeasurer will wrap each line to correct length and
-        //--- return it as a TextLayout object
-        while ((layout = lineBreaker.nextLayout((float) width)) != null) {
-            //--- Align the Y pen to the ascend of the font, remember that
-            //--- the ascend is origin (0, 0) of a font. Refer to figure 1
-            pen.y += layout.getAscent();
-
-            //--- Draw the line of text
-            layout.draw(g2d, (float) pen.x, (float) pen.y);
-
-            //--- Move the pen to the next position adding the descent and
-            //--- the leading of the font
-            pen.y += layout.getDescent() + layout.getLeading();
-        }
-        /* -------------------------------------------- */
-
-        /*
-        int x = 5;
-        int y = 5;
-        for (String line : printText.split("\n"))
-            g.drawString(line, x, y += g.getFontMetrics().getHeight());
-        */
-
-        return PAGE_EXISTS;
-    }
-
-    /**
-     * Spawns standard JAVA-driven print dialog and prints text
-     */
-    public boolean printWithDialog(String key, String text) {
-        debugPrintService(null); // testing
-        printText = text;
-        PrinterJob job = PrinterJob.getPrinterJob();
-        job.setPrintable(this);
-        if (!job.printDialog()) return true; // print canceled by user
-        try {
-            job.print();
-        } catch (PrinterException ex) {
-            logger.warn("Error printing document for key " + key);
-            logger.warn(ex);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Print using defaults
-     *
-     * Sends the print job to the configured printer based on the key
-     * and user settings.
-     */
-    public boolean printWithoutDialog(String key, String text) {
-        printText = text;
-        PrinterJob job = PrinterJob.getPrinterJob();
-        job.setPrintable(this);
-
-        // TODO: load user settings, find the right printer, send the
-        // correct attributes, etc.
-
-        try {
-            job.print();
-        } catch (PrinterException ex) {
-            logger.warn("Error printing document for key " + key);
-            logger.warn(ex);
-            return false;
-        }
-        return true;
-    }
-
-    private void debugPrintService(PrintService printer) {
-
-        PrintService[] printServices;
-        String defaultPrinter = "";
-
-        if (printer != null) {
-            printServices = new PrintService[] {printer};
-        } else {
-            printServices = PrintServiceLookup.lookupPrintServices(null, null);
-            PrintService def = PrintServiceLookup.lookupDefaultPrintService();
-            if (def != null) defaultPrinter = def.getName();
-        }
-
-        for (PrintService service : printServices) {
-            logger.info("Printer Debug: found printer " + service.getName());
-            if (service.getName().equals(defaultPrinter)) {
-                logger.info("    Printer Debug: Is Default");
-            }
-
-            AttributeSet attributes = service.getAttributes();
-            for (Attribute a : attributes.toArray()) {
-                String name = a.getName();
-                String value = attributes.get(a.getClass()).toString();
-                logger.info("    Printer Debug: " + name + " => " + value);
-            }
-        }
-    }
-
-    public List<HashMap> getPrinters() {
-
-        List<HashMap> printers = new LinkedList<HashMap>();
-        PrintService[] printServices = 
-            PrintServiceLookup.lookupPrintServices(null, null);
-
-        String defaultPrinter = "";
-        PrintService def = PrintServiceLookup.lookupDefaultPrintService();
-        if (def != null) defaultPrinter = def.getName();
-
-        for (PrintService service : printServices) {
-            HashMap<String, Object> printer = new HashMap<String, Object>();
-            printers.add(printer);
-
-            if (service.getName().equals(defaultPrinter)) 
-                printer.put("is-default", new Boolean(true));
-
-            AttributeSet attributes = service.getAttributes();
-            for (Attribute a : attributes.toArray()) {
-                String name = a.getName();
-                String value = attributes.get(a.getClass()).toString();
-                printer.put(name, value);
-            }
-        }
-
-        return printers;
-    }
-
-    // experiment
-    // show our own print dialog before the real print action takes over
-    // currently just shows Print and Cancel.
-    // Not sure if there is a need for such a thing..
-    public void printWithCustomDialog(String key, String msg) {
-        UIManager.put("swing.boldMetal", Boolean.FALSE);
-        JFrame f = new JFrame("Hello World Printer");
-
-        // close the frame when Cancel / X are clicked
-        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-
-        final String printMsg = msg;
-        final String printKey = key;
-        JButton printButton = new JButton("Print '" + msg + "'");
-        printButton.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                printWithDialog(printKey, printMsg);
-            }
-        });
-
-        JButton cancelButton = new JButton("Cancel");
-        cancelButton.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                Component component = (Component) e.getSource();
-                JFrame frame = (JFrame) SwingUtilities.getRoot(component);
-                WindowEvent windowClosing = 
-                    new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
-                frame.dispatchEvent(windowClosing);
-            }
-        });
-
-        JPanel grid = new JPanel(new FlowLayout(FlowLayout.LEFT,3,3));
-        f.add(grid);
-        grid.add(cancelButton);
-        grid.add(printButton);
-        f.pack();
-        f.setVisible(true);
-   }
-}
-
-