From bb3c44ff9efb8d0c56b11fb08e19e571e937b4fe Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Thu, 30 May 2013 13:56:37 -0400
Subject: [PATCH] Added TPS servlet.

A basic TPS servlet has been added to demonstrate sending and
receiving TPS messages using chunked encoding.
---
 base/tps/java/org/dogtagpki/tps/TPSConnection.java |  98 ++++++++++++++++++++
 base/tps/java/org/dogtagpki/tps/TPSMessage.java    | 101 +++++++++++++++++++++
 .../java/org/dogtagpki/tps/server/TPSServlet.java  |  61 +++++++++++++
 base/tps/shared/webapps/tps/WEB-INF/web.xml        |  10 ++
 4 files changed, 270 insertions(+)
 create mode 100644 base/tps/java/org/dogtagpki/tps/TPSConnection.java
 create mode 100644 base/tps/java/org/dogtagpki/tps/TPSMessage.java
 create mode 100644 base/tps/java/org/dogtagpki/tps/server/TPSServlet.java

diff --git a/base/tps/java/org/dogtagpki/tps/TPSConnection.java b/base/tps/java/org/dogtagpki/tps/TPSConnection.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd62ff530f7365befbb08e2bc162d1d021580a92
--- /dev/null
+++ b/base/tps/java/org/dogtagpki/tps/TPSConnection.java
@@ -0,0 +1,98 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// 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; version 2 of the License.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.tps;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * @author Endi S. Dewata <edewata@redhat.com>
+ */
+public class TPSConnection {
+
+    public InputStream in;
+    public PrintStream out;
+    public boolean chunked;
+
+    public TPSConnection(InputStream in, OutputStream out) {
+        this(in, out, false);
+    }
+
+    public TPSConnection(InputStream in, OutputStream out, boolean chunked) {
+        this.in = in;
+        this.out = new PrintStream(out);
+        this.chunked = chunked;
+    }
+
+    public TPSMessage read() throws IOException {
+
+        StringBuilder sb = new StringBuilder();
+        int b;
+
+        // read the first parameter
+        while ((b = in.read()) >= 0) {
+            char c = (char)b;
+            if (c == '&') break;
+            sb.append(c);
+        }
+
+        if (b < 0) throw new IOException("Unexpected end of stream");
+
+        // parse message size
+        String nvp = sb.toString();
+        String[] s = nvp.split("=");
+        int size = Integer.parseInt(s[1]);
+
+        sb.append('&');
+
+        // read the rest of message
+        for (int i=0; i<size; i++) {
+
+            b = in.read();
+            if (b < 0) throw new IOException("Unexpected end of stream");
+
+            char c = (char)b;
+            sb.append(c);
+        }
+
+        // parse the entire message
+        return new TPSMessage(sb.toString());
+    }
+
+    public void write(TPSMessage message) throws IOException {
+        String s = message.encode();
+
+        if (chunked) {
+            // send message length + EOL
+            out.print(Integer.toHexString(s.length()));
+            out.print("\r\n");
+        }
+
+        // send message
+        out.print(s);
+
+        if (chunked) {
+            // send EOL
+            out.print("\r\n");
+        }
+
+        out.flush();
+    }
+}
diff --git a/base/tps/java/org/dogtagpki/tps/TPSMessage.java b/base/tps/java/org/dogtagpki/tps/TPSMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..522a0f4086deb62ac77b058784ef5f519d12387a
--- /dev/null
+++ b/base/tps/java/org/dogtagpki/tps/TPSMessage.java
@@ -0,0 +1,101 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// 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; version 2 of the License.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.tps;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author Endi S. Dewata <edewata@redhat.com>
+ */
+public class TPSMessage {
+
+    Map<String, String> map = new LinkedHashMap<String, String>();
+
+    public TPSMessage() {
+    }
+
+    public TPSMessage(String message) {
+        decode(message);
+    }
+
+    public TPSMessage(Map<String, String> map) {
+        this.map.putAll(map);
+    }
+
+    public void put(String key, String value) {
+        map.put(key, value);
+    }
+
+    public void put(String key, Integer value) {
+        map.put(key, value.toString());
+    }
+
+    public void put(String key, byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+
+        for (byte b : bytes) {
+            sb.append("%");
+            sb.append(String.format("%02X", b));
+        }
+
+        map.put(key, sb.toString());
+    }
+
+    public void decode(String message) {
+
+        for (String nvp : message.split("&")) {
+            String[] s = nvp.split("=");
+
+            String key = s[0];
+            String value = s[1];
+
+            // skip message size
+            if (key.equals("s")) continue;
+
+            map.put(key, value);
+        }
+    }
+
+    public String encode() {
+
+        StringBuilder sb = new StringBuilder();
+
+        // encode message type
+        String type = map.get("msg_type");
+        sb.append("msg_type=" + type);
+
+        // encode other parameters
+        for (String key : map.keySet()) {
+
+            if (key.equals("msg_type")) continue;
+
+            String value = map.get(key);
+            sb.append("&" + key + "=" + value);
+        }
+
+        String message = sb.toString();
+
+        // encode message_size
+        return "s=" + message.length() + "&" + message;
+    }
+
+    public String toString() {
+        return map.toString();
+    }
+}
diff --git a/base/tps/java/org/dogtagpki/tps/server/TPSServlet.java b/base/tps/java/org/dogtagpki/tps/server/TPSServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..78e6df4f8b4a7de5a285183e83d4f9a584e66b00
--- /dev/null
+++ b/base/tps/java/org/dogtagpki/tps/server/TPSServlet.java
@@ -0,0 +1,61 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// 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; version 2 of the License.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.tps.server;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.dogtagpki.tps.TPSConnection;
+import org.dogtagpki.tps.TPSMessage;
+
+/**
+ * @author Endi S. Dewata <edewata@redhat.com>
+ */
+public class TPSServlet extends HttpServlet {
+
+    private static final long serialVersionUID = -1092227495262381074L;
+
+    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
+
+        response.setHeader("Transfer-Encoding", "chunked");
+
+        TPSConnection con = new TPSConnection(
+                request.getInputStream(), response.getOutputStream(), true);
+
+        TPSMessage message = con.read();
+        System.out.println("Receive: " + message);
+
+        message = new TPSMessage();
+        message.put("msg_type", 9);
+        message.put("pdu_size", 12);
+        message.put("pdu_data", new byte[] {
+                (byte)0x00, (byte)0xA4, (byte)0x04, (byte)0x00,
+                (byte)0x07, (byte)0xA0, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x00
+        });
+
+        System.out.println("Send: " + message);
+        con.write(message);
+
+        message = con.read();
+        System.out.println("Receive: " + message);
+    }
+}
diff --git a/base/tps/shared/webapps/tps/WEB-INF/web.xml b/base/tps/shared/webapps/tps/WEB-INF/web.xml
index 8b4b4826766557a51420d76b614ac0dc22b10273..9a6c87462cc536f02f9beb653a4a7654b87814a5 100644
--- a/base/tps/shared/webapps/tps/WEB-INF/web.xml
+++ b/base/tps/shared/webapps/tps/WEB-INF/web.xml
@@ -78,6 +78,11 @@
         </init-param>
     </servlet>
 
+    <servlet>
+        <servlet-name>tps</servlet-name>
+        <servlet-class>org.dogtagpki.tps.server.TPSServlet</servlet-class>
+    </servlet>
+
     <listener>
         <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
     </listener>
@@ -131,6 +136,11 @@
         <url-pattern>/admin/tps/getStatus</url-pattern>
     </servlet-mapping>
 
+    <servlet-mapping>
+        <servlet-name>tps</servlet-name>
+        <url-pattern>/tps</url-pattern>
+    </servlet-mapping>
+
     <!-- ==================== Default Session Configuration =============== -->
     <!-- You can set the default session timeout (in minutes) for all newly -->
     <!-- created sessions by modifying the value below.                     -->
-- 
1.8.1.4

