From: Bill Erickson Date: Fri, 21 Feb 2014 21:56:09 +0000 (-0500) Subject: initial import X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=7ca1454f309f5cacc8af2e23f1c6ecec5c531ed5;p=working%2Frandom.git initial import * jetty servlet * simple file IO handler * really dumb sample print driver * dependency fetcher, compiler script Signed-off-by: Bill Erickson --- diff --git a/WEB-INF/web.xml b/WEB-INF/web.xml new file mode 100644 index 000000000..6fb7917eb --- /dev/null +++ b/WEB-INF/web.xml @@ -0,0 +1,40 @@ + + + + + Hatch + org.evergreen_ils.hatch.HatchServlet + + + Hatch + /* + + + + + Comma-separated list of Origin domains + allowed to make requests of this service. + + trusted-domains + + * + + + + + + diff --git a/hatch-test.html b/hatch-test.html new file mode 100644 index 000000000..584047009 --- /dev/null +++ b/hatch-test.html @@ -0,0 +1,64 @@ + + + + + + +
+ + diff --git a/jetty_control.sh b/jetty_control.sh new file mode 100755 index 000000000..3842337ad --- /dev/null +++ b/jetty_control.sh @@ -0,0 +1,75 @@ +#!/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 + +# 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 WEB-INF/lib; + mkdir -p WEB-INF/classes; + + 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; + cp $JETTY_DIR/lib/jetty-util-$JETTY_VERSION.jar WEB-INF/lib/; + fi; + + if [ ! -f $JETTY_UTIL_AJAX ]; then + echo "Fetching $JETTY_UTIL_AJAX..." + wget "http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-util-ajax/$JETTY_VERSION/$JETTY_UTIL_AJAX"; + cp $JETTY_UTIL_AJAX $JETTY_DIR/lib/; + cp $JETTY_UTIL_AJAX WEB-INF/lib/; + fi; + + if [ ! -d $JETTY_DIR/webapps/hatch ]; then + echo "Setting up webapp links..."; + mkdir $JETTY_DIR/webapps/hatch; + ln -s $BASE_DIR/WEB-INF $JETTY_DIR/webapps/hatch/WEB-INF; + fi; +fi; + +if [ $OPT_COMPILE -eq 1 ]; then + echo "Compiling..." + cd $BASE_DIR/src; + javac -Xlint:unchecked -d ../WEB-INF/classes/ -cp "../$JETTY_DIR/lib/*" org/evergreen_ils/hatch/*.java; +fi; + +if [ $OPT_RUN -eq 1 ]; then + echo "Running..." + cd $BASE_DIR/$JETTY_DIR; + java -jar start.jar +fi; + diff --git a/src/org/evergreen_ils/hatch/FileIO.java b/src/org/evergreen_ils/hatch/FileIO.java new file mode 100644 index 000000000..95fc012c1 --- /dev/null +++ b/src/org/evergreen_ils/hatch/FileIO.java @@ -0,0 +1,145 @@ +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 nameList = new LinkedList(); + 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/src/org/evergreen_ils/hatch/HatchServlet.java b/src/org/evergreen_ils/hatch/HatchServlet.java new file mode 100644 index 000000000..da0d83807 --- /dev/null +++ b/src/org/evergreen_ils/hatch/HatchServlet.java @@ -0,0 +1,227 @@ +package org.evergreen_ils.hatch; + +import java.io.*; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +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; + +public class HatchServlet extends HttpServlet { + + static final String contentType = "application/json"; + static boolean trustAllDomains = false; + static String trustedDomainsString; + static String[] trustedDomains; + static String profileDirectory; + private static final Logger logger = Log.getLogger("HatchetServlet"); + + @Override + public void init(ServletConfig config) throws ServletException { + + trustedDomainsString = + config.getServletContext().getInitParameter("trusted-domains"); + + profileDirectory = + config.getServletContext().getInitParameter("profile-directory"); + + // 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"); + } + } + + if (trustedDomainsString == null) { + logger.info("No trusted domains configured"); + + } else { + + if (trustedDomainsString.equals("*")) { + trustAllDomains = true; + logger.info("All domains trusted"); + + } else { + + trustedDomains = trustedDomainsString.split(","); + for(String domain : trustedDomains) { + logger.info("Trusted domain: " + domain); + } + } + } + } + + protected boolean verifyOriginDomain( + HttpServletRequest request, HttpServletResponse response) { + String origin = request.getHeader("Origin"); + + if (trustAllDomains) { + if (origin == null) origin = request.getRemoteHost(); + response.addHeader("Access-Control-Allow-Origin", origin); + return true; + } + + if (origin == null) { + logger.warn("No Origin header in request; Dropping"); + return false; + } + + logger.info("Receive request from " + origin); + + if (java.util.Arrays.asList(trustedDomains).indexOf(origin) < 0) { + logger.warn("Request from un-trusted domain: " + origin); + return false; + } + + response.addHeader("Access-Control-Allow-Origin", trustedDomainsString); + return true; + } + + + /** + * Honor POST and GET the same. + */ + protected void doPostGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + + response.setContentType(contentType); + + // ensure the caller is allowed to access this resource + if (!verifyOriginDomain(request, response)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + return; + } + + FileIO io; + String action = request.getParameter("action"); + String key = request.getParameter("key"); + String value = request.getParameter("value"); + + // all requests require an action + if (action == null || action.equals("")) { + String err = JSON.toString("No action specified in request"); + response.getWriter().println(err); + logger.info(err); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + if (action.equals("keys")) { + io = new FileIO(profileDirectory); + String[] keys = io.keys(key); // OK for key to be null + + if (keys != null) { + String json = JSON.toString(keys); + response.getWriter().println(json); + } else { + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + return; + } + + // all remaining requests require a key + if (key == null || key.equals("")) { + String err = JSON.toString("No key specified in request"); + response.getWriter().println(err); + logger.info(err); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + if (action.equals("get")) { + io = new FileIO(profileDirectory); + BufferedReader reader = io.get(key); + if (reader != null) { + String line; + response.setStatus(HttpServletResponse.SC_OK); + 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. + response.getWriter().println(line); + } + } else { + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + return; + } + + if (action.equals("delete")) { + io = new FileIO(profileDirectory); + if (io.delete(key)) { + response.setStatus(HttpServletResponse.SC_OK); + } else { + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + return; + } + + // all remaining actions require value + if (value == null) { + String err = JSON.toString("No value specified in request"); + response.getWriter().println(err); + logger.info(err); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + switch(action) { + + case "print" : + boolean ok = new PrintDriver().printWithDialog(value); + if (ok) { + response.setStatus(HttpServletResponse.SC_OK); + } else { + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + break; + + case "set" : + io = new FileIO(profileDirectory); + if (io.set(key, value)) { + response.setStatus(HttpServletResponse.SC_OK); + } else { + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + break; + + case "append" : + io = new FileIO(profileDirectory); + if (io.append(key, value)) { + response.setStatus(HttpServletResponse.SC_OK); + } else { + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + break; + + default: + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().println(JSON.toString( + "\"No Such Action: " + action + "\"")); + logger.info("No such action: " + action); + } + } + + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + doPostGet(request, response); + } + + protected void doPost(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + doPostGet(request, response); + } +} diff --git a/src/org/evergreen_ils/hatch/PrintDriver.java b/src/org/evergreen_ils/hatch/PrintDriver.java new file mode 100644 index 000000000..f245c0a96 --- /dev/null +++ b/src/org/evergreen_ils/hatch/PrintDriver.java @@ -0,0 +1,88 @@ +package org.evergreen_ils.hatch; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.awt.print.*; + +public class PrintDriver implements Printable { + + private String printText; + + 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()); + + 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 text) { + printText = text; + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(this); + if (!job.printDialog()) return true; // print canceled by user + try { + job.print(); + } catch (PrinterException ex) { + // TODO + return false; + } + return true; + } + + // 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 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; + JButton printButton = new JButton("Print '" + msg + "'"); + printButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + printWithDialog(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); + } +} + +