added initial opensrf stack layer objects. more tuning/testing of the jabber layer
authorerickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Thu, 10 May 2007 02:51:51 +0000 (02:51 +0000)
committererickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Thu, 10 May 2007 02:51:51 +0000 (02:51 +0000)
git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@880 9efc2488-bf62-4759-914b-345cdb29e865

src/java/org/opensrf/Message.java [new file with mode: 0644]
src/java/org/opensrf/Method.java [new file with mode: 0644]
src/java/org/opensrf/MethodException.java [new file with mode: 0644]
src/java/org/opensrf/Result.java [new file with mode: 0644]
src/java/org/opensrf/Session.java [new file with mode: 0644]
src/java/org/opensrf/net/xmpp/XMPPException.java
src/java/org/opensrf/net/xmpp/XMPPReader.java
src/java/org/opensrf/net/xmpp/XMPPSession.java
src/java/org/opensrf/test/TestJSON.java [new file with mode: 0644]
src/java/org/opensrf/util/JSON.java [new file with mode: 0644]
src/java/org/opensrf/util/Utils.java [new file with mode: 0644]

diff --git a/src/java/org/opensrf/Message.java b/src/java/org/opensrf/Message.java
new file mode 100644 (file)
index 0000000..798839a
--- /dev/null
@@ -0,0 +1,50 @@
+package org.opensrf;
+
+
+public class Message {
+
+    /** Message types */
+    public enum Type {
+        REQUEST,
+        STATUS,
+        RESULT,
+        CONNECT,
+        DISCONNECT,
+    };
+
+    /** Message ID.  This number is used to relate requests to responses */
+    private int id;
+    /** Type of message. */
+    private Type type;
+    /** message payload */
+    private Object payload;
+
+    /**
+     * @param id This message's ID
+     * @param type The type of message
+     */
+    public Message(int id, Type type) {
+        setId(id);
+        setType(type);
+    }
+    public int getId() {
+        return id;
+    }   
+    public Type getType() {
+        return type;
+    }
+    public Object getPayload() {
+        return payload;
+    }
+    public void setId(int id) {
+        this.id = id;
+    }
+    public void setType(Type type) {
+        this.type = type;
+    }
+    public void setPayload(Object p) {
+        payload = p;
+    }
+}
+
+
diff --git a/src/java/org/opensrf/Method.java b/src/java/org/opensrf/Method.java
new file mode 100644 (file)
index 0000000..97a5ba3
--- /dev/null
@@ -0,0 +1,36 @@
+package org.opensrf;
+import java.util.List;
+import java.util.ArrayList;
+
+
+public class Method {
+
+    private String name;
+    private List<Object> params;
+
+    public Method(String name) {
+        this.name = name;
+        this.params = new ArrayList<Object>(8);
+    }
+
+    public Method(String name, List<Object> params) {
+        this.name = name;
+        this.params = params;
+    }
+
+    public String getName() {
+        return name;
+    }
+    public List<Object> getParams() {
+       return params; 
+    }
+
+    /**
+     * Pushes a new param object onto the set of params 
+     * @param p The new param to add to the method.
+     */
+    public void pushParam(Object p) {
+        this.params.add(p);
+    }
+}
+
diff --git a/src/java/org/opensrf/MethodException.java b/src/java/org/opensrf/MethodException.java
new file mode 100644 (file)
index 0000000..bf47313
--- /dev/null
@@ -0,0 +1,11 @@
+package org.opensrf;
+
+/**
+ * Thrown when the server responds with a method exception.
+ */
+public class MethodException extends Exception {
+    public MethodException(String info) {
+        super(info);
+    }
+}
+
diff --git a/src/java/org/opensrf/Result.java b/src/java/org/opensrf/Result.java
new file mode 100644 (file)
index 0000000..f295a1a
--- /dev/null
@@ -0,0 +1,70 @@
+package org.opensrf;
+
+
+/**
+ * Models a single result from a method request.
+ */
+public class Result {
+
+    /** Method result content */
+    private Object content;
+    /** Name of the status */
+    private String status;
+    /** Status code number */
+    private int statusCode;
+
+    public Result(String status, int statusCode, Object content) {
+        this.status = status;
+        this.statusCode = statusCode;
+        this.content = content;
+    }
+    
+    /**
+     * Get status.
+     * @return status as String.
+     */
+    public String getStatus() {
+        return status;
+    }
+    
+    /**
+     * Set status.
+     * @param status the value to set.
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+    
+    /**
+     * Get statusCode.
+     * @return statusCode as int.
+     */
+    public int getStatusCode() {
+        return statusCode;
+    }
+    
+    /**
+     * Set statusCode.
+     * @param statusCode the value to set.
+     */
+    public void setStatusCode(int statusCode) {
+        this.statusCode = statusCode;
+    }
+    
+    /**
+     * Get content.
+     * @return content as Object.
+     */
+    public Object getContent() {
+        return content;
+    }
+    
+    /**
+     * Set content.
+     * @param content the value to set.
+     */
+    public void setContent(Object content) {
+        this.content = content;
+    }
+}
+
diff --git a/src/java/org/opensrf/Session.java b/src/java/org/opensrf/Session.java
new file mode 100644 (file)
index 0000000..59eef49
--- /dev/null
@@ -0,0 +1,50 @@
+package org.opensrf;
+import org.opensrf.util.JSON;
+import org.opensrf.net.xmpp.*;
+
+public abstract class Session {
+
+    /** Represents the different connection states for a session */
+    public enum ConnectState {
+        DISCONNECTED,
+        CONNECTING,
+        CONNECTED
+    };
+
+    /** the current connection state */
+    private ConnectState connectState;
+
+    /** The (jabber) address of the remote party we are communicating with */
+    private String remoteNode;
+
+    /** 
+     * The thread is used to link messages to a given session. 
+     * In other words, each session has a unique thread, and all messages 
+     * in that session will carry this thread around as an indicator.
+     */
+    private String thread;
+
+    public Session() {
+        connectState = ConnectState.DISCONNECTED;
+    }
+    
+    /**
+     * Sends a Message to our remoteNode.
+     */
+    public void send(Message omsg) throws XMPPException {
+
+        /** construct the XMPP message */
+        XMPPMessage xmsg = new XMPPMessage();
+        xmsg.setTo(remoteNode);
+        xmsg.setThread(thread);
+        xmsg.setBody(JSON.toJSON(omsg));
+        XMPPSession ses = XMPPSession.getGlobalSession();
+
+        try {
+            XMPPSession.getGlobalSession().send(xmsg);
+        } catch(XMPPException e) {
+            /* XXX log */
+            connectState = ConnectState.DISCONNECTED;
+        }
+    }
+}
index 29ee0e7..8c20ab7 100644 (file)
@@ -4,15 +4,7 @@ package org.opensrf.net.xmpp;
  * Used for XMPP stream/authentication errors
  */
 public class XMPPException extends Exception {
-    private String info;
-
-    /**
-     * @param info Runtime exception information.
-     */
     public XMPPException(String info) {
-        this.info = info;
-    }
-    public String toString() {
-        return this.info;
+        super(info);
     }
 }
index 9f5bdb4..9a9c332 100644 (file)
@@ -217,7 +217,10 @@ public class XMPPReader implements Runnable {
             }
 
         } catch(javax.xml.stream.XMLStreamException se) {
-            /* XXX log an error, set a state, and notify */
+            /* XXX log an error */
+            xmlState = XMLState.IN_NOTHING;
+            streamState = XMPPStreamState.DISCONNECTED;
+            notifyCoreEvent();
         }
     }
 
index 98b555f..ccc85d2 100644 (file)
@@ -37,6 +37,9 @@ public class XMPPSession {
     /** Raw socket output stream */
     OutputStream outStream;
 
+    /** The process-wide session.  All communication occurs
+     * accross this single connection */
+    private static XMPPSession globalSession;
 
 
     /**
@@ -49,12 +52,21 @@ public class XMPPSession {
         this.port = port;
     }
 
+    public static XMPPSession getGlobalSession() {
+        return globalSession;
+    }
+
+    public static void setGlobalSession(XMPPSession ses) {
+        globalSession = ses;
+    }
+
 
     /** true if this session is connected to the server */
     public boolean connected() {
         return (
             reader != null && 
-            reader.getXMPPStreamState() == XMPPReader.XMPPStreamState.CONNECTED);
+            reader.getXMPPStreamState() == 
+                XMPPReader.XMPPStreamState.CONNECTED);
     }
 
 
@@ -123,7 +135,7 @@ public class XMPPSession {
      * Sends an XMPPMessage.
      * @param msg The message to send.
      */
-    public void send(XMPPMessage msg) throws XMPPException {
+    public synchronized void send(XMPPMessage msg) throws XMPPException {
         checkConnected();
         try {
             outStream.write(msg.toXML().getBytes()); 
diff --git a/src/java/org/opensrf/test/TestJSON.java b/src/java/org/opensrf/test/TestJSON.java
new file mode 100644 (file)
index 0000000..31a1550
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opensrf.test;
+
+import org.opensrf.util.JSON;
+import java.util.*;
+
+public class TestJSON {
+
+    public static void main(String args[]) {
+        
+        Map<String,Object> map = new HashMap<String,Object>();
+        map.put("key1", "value1");
+        map.put("key2", "value2");
+        map.put("key3", "value3");
+        map.put("key4", "athe\u0301s");
+        map.put("key5", null);
+
+        List<Object> list = new ArrayList<Object>(16);
+        list.add(new Integer(1));
+        list.add(new Boolean(true));
+        list.add("WATER");
+        list.add(null);
+        map.put("key6", list);
+
+        System.out.println(JSON.toJSON(map));
+    }
+}
diff --git a/src/java/org/opensrf/util/JSON.java b/src/java/org/opensrf/util/JSON.java
new file mode 100644 (file)
index 0000000..4ba7066
--- /dev/null
@@ -0,0 +1,117 @@
+package org.opensrf.util;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * JSON utilities.
+ */
+public class JSON {
+
+    public static final String JSON_CLASS_KEY = "__c";
+    public static final String JSON_PAYLOAD_KEY = "__p";
+
+
+    /**
+     * @see toJSON(Object, StringBuffer)
+     */
+    public static String toJSON(Object obj) {
+        StringBuffer sb = new StringBuffer();
+        toJSON(obj, sb);
+        return sb.toString();
+    }
+
+
+    /**
+     * Encodes a java object to JSON.
+     * Maps (HashMaps, etc.) are encoded as JSON objects.  
+     * Iterable's (Lists, etc.) are encoded as JSON arrays
+     */
+    public static void toJSON(Object obj, StringBuffer sb) {
+
+        /** JSON null */
+        if(obj == null) {
+            sb.append("null");
+            return;
+        }
+
+        /** JSON string */
+        if(obj instanceof String) {
+            sb.append('"');
+            Utils.escape((String) obj, sb);
+            sb.append('"');
+            return;
+        }
+
+        /** JSON number */
+        if(obj instanceof Number) {
+            sb.append(obj.toString());
+            return;
+        }
+
+        /** JSON array */
+        if(obj instanceof Iterable) {
+            encodeJSONArray((Iterable) obj, sb);
+            return;
+        }
+
+        /** JSON object */
+        if(obj instanceof Map) {
+            encodeJSONObject((Map) obj, sb);
+            return;
+        }
+
+        /** JSON boolean */
+        if(obj instanceof Boolean) {
+            sb.append((((Boolean) obj).booleanValue() ? "true" : "false"));
+            return;
+        }
+    }
+
+
+    /**
+     * Encodes a List as a JSON array
+     */
+    private static void encodeJSONArray(Iterable iterable, StringBuffer sb) {
+        Iterator itr = iterable.iterator();
+        sb.append("[");
+        boolean some = false;
+
+        while(itr.hasNext()) {
+            some = true;
+            toJSON(itr.next(), sb);
+            sb.append(',');
+        }
+
+        /* remove the trailing comma if the array has any items*/
+        if(some) 
+            sb.deleteCharAt(sb.length()-1); 
+        sb.append("]");
+    }
+
+
+    /**
+     * Encodes a Map to a JSON object
+     */
+    private static void encodeJSONObject(Map map, StringBuffer sb) {
+        Iterator itr = map.keySet().iterator();
+        sb.append("{");
+        Object key = null;
+
+        while(itr.hasNext()) {
+            key = itr.next();
+            toJSON(key, sb);
+            sb.append(':');
+            toJSON(map.get(key), sb);
+            sb.append(',');
+        }
+
+        /* remove the trailing comma if the object has any items*/
+        if(key != null) 
+            sb.deleteCharAt(sb.length()-1); 
+        sb.append("}");
+    }
+}
+
+
+
diff --git a/src/java/org/opensrf/util/Utils.java b/src/java/org/opensrf/util/Utils.java
new file mode 100644 (file)
index 0000000..60c476f
--- /dev/null
@@ -0,0 +1,86 @@
+package org.opensrf.util;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Collection of general, static utility methods
+ */
+public class Utils {
+
+    /**
+     * Returns the string representation of a given file.
+     * @param filename The file to turn into a string
+     */
+    public static String fileToString(String filename) 
+            throws FileNotFoundException, IOException {
+
+        StringBuffer sb = new StringBuffer();
+        BufferedReader in = new BufferedReader(new FileReader(filename));
+        String str;
+        while ((str = in.readLine()) != null) 
+            sb.append(str);
+        in.close();
+        return sb.toString();
+    }
+
+
+    /**
+     * @see escape(String, StringBuffer)
+     */
+    public static String escape(String string) {
+        StringBuffer sb = new StringBuffer();
+        escape(string, sb);
+        return sb.toString();
+    }
+
+    /**
+     * Escapes a string.  Turns bare newlines into \n, etc.
+     * Escapes \n, \r, \t, ", \f
+     * Encodes non-ascii characters as UTF-8: \u0000
+     * @param string The string to escape
+     * @param sb The string buffer to write the escaped string into
+     */
+    public static void escape(String string, StringBuffer sb) {
+        int len = string.length();
+        String utf;
+        char c;
+        for( int i = 0; i < len; i++ ) {
+            c = string.charAt(i);
+            switch (c) {
+                case '\\':
+                    sb.append("\\\\");
+                    break;
+                case '"':
+                    sb.append("\\\"");
+                    break;
+                case '\b':
+                    sb.append("\\b");
+                    break;
+                case '\t':
+                    sb.append("\\t");
+                    break;
+                case '\n':
+                    sb.append("\\n");
+                    break;
+                case '\f':
+                    sb.append("\\f");
+                    break;
+                case '\r':
+                    sb.append("\\r");
+                    break;
+                default:
+                    if (c < 32 || c > 126 ) { 
+                        /* escape all non-ascii or control characters as UTF-8 */
+                        utf = "000" + Integer.toHexString(c);
+                        sb.append("\\u" + utf.substring(utf.length() - 4));
+                    } else {
+                        sb.append(c);
+                    }
+            }
+        }
+    }
+}
+
+
+