diff --git a/.gitignore b/.gitignore
index f68c122..d3692fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
bin/
dist/
nbproject/
-*.exe
\ No newline at end of file
+*.exe
+/src/padkey
\ No newline at end of file
diff --git a/src/Ubuntu-R info b/src/Ubuntu-R info
deleted file mode 100644
index 800c150..0000000
--- a/src/Ubuntu-R info
+++ /dev/null
@@ -1,2 +0,0 @@
-The ubuntu.ttf font file was originally Ubuntu-R.ttf.
-It was changed for several petty reasons.
\ No newline at end of file
diff --git a/src/ubuntu.ttf b/src/Ubuntu-R.ttf
similarity index 100%
rename from src/ubuntu.ttf
rename to src/Ubuntu-R.ttf
diff --git a/src/net/apocalypselabs/symat/CodeEditor.form b/src/net/apocalypselabs/symat/CodeEditor.form
index c70c93c..77633d3 100644
--- a/src/net/apocalypselabs/symat/CodeEditor.form
+++ b/src/net/apocalypselabs/symat/CodeEditor.form
@@ -101,6 +101,22 @@
Symja (parser), log4j, Java-Prettify:
+Symja (parser), log4j, Java-Prettify, json-simple, java-etherpad-lite:
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
diff --git a/src/net/apocalypselabs/symat/images/pads.png b/src/net/apocalypselabs/symat/images/pads.png
new file mode 100644
index 0000000..d392b3a
Binary files /dev/null and b/src/net/apocalypselabs/symat/images/pads.png differ
diff --git a/src/net/apocalypselabs/symat/images/shell.png b/src/net/apocalypselabs/symat/images/shell.png
index 5b67b1a..db0fe07 100644
Binary files a/src/net/apocalypselabs/symat/images/shell.png and b/src/net/apocalypselabs/symat/images/shell.png differ
diff --git a/src/org/etherpad_lite_client/EPLiteClient.java b/src/org/etherpad_lite_client/EPLiteClient.java
new file mode 100644
index 0000000..e941f1f
--- /dev/null
+++ b/src/org/etherpad_lite_client/EPLiteClient.java
@@ -0,0 +1,639 @@
+package org.etherpad_lite_client;
+
+import java.util.Date;
+import java.util.HashMap;
+
+/**
+ * A client for talking to Etherpad Lite's HTTP JSON API.
+ *
+ * Example:
+ *
+ *
+ * EPLiteClient api = new EPLiteClient("http://etherpad.mysite.com", "FJ7jksalksdfj83jsdflkj");
+ */
+public class EPLiteClient {
+ /**
+ * The Etherpad Lite API version this client targets by default
+ */
+ public static final String DEFAULT_API_VERSION = "1.2.11";
+
+ /**
+ * The connection object
+ */
+ public EPLiteConnection connection;
+
+ /**
+ * Initializes a new org.etherpad_lite_client.EPLiteClient object.
+ * The default Etherpad Lite API version (in DEFAULT_API_VERSION) will be used.
+ *
+ * @param url an absolute url, including protocol, to the EPL api
+ * @param apiKey the API Key
+ */
+ public EPLiteClient(String url, String apiKey) {
+ this.connection = new EPLiteConnection(url, apiKey, DEFAULT_API_VERSION);
+ }
+
+ /**
+ * Initializes a new org.etherpad_lite_client.EPLiteClient object.
+ * The specified Etherpad Lite API version will be used.
+ *
+ * @param url an absolute url, including protocol, to the EPL api
+ * @param apiKey the API Key
+ * @param apiVersion the API version
+ */
+ public EPLiteClient(String url, String apiKey, String apiVersion) {
+ this.connection = new EPLiteConnection(url, apiKey, apiVersion);
+ }
+
+ // Groups
+ // Pads may belong to a group. These pads are not considered "public", and won't be available through the Web UI without a session.
+
+ /**
+ * Creates a new Group. The group id is returned in "groupID" in the HashMap.
+ *
+ * @return HashMap
+ */
+ public HashMap createGroup() {
+ return this.connection.post("createGroup");
+ }
+
+ /**
+ * Creates a new Group for groupMapper if one doesn't already exist. Helps you map your application's groups to Etherpad Lite's groups.
+ * The group id is returned in "groupID" in the HashMap.
+ *
+ * @param groupMapper your group mapper string
+ * @return HashMap
+ */
+ public HashMap createGroupIfNotExistsFor(String groupMapper) {
+ HashMap args = new HashMap();
+ args.put("groupMapper", groupMapper);
+ return this.connection.post("createGroupIfNotExistsFor", args);
+ }
+
+ /**
+ * Delete group.
+ *
+ * @param groupID string
+ */
+ public void deleteGroup(String groupID) {
+ HashMap args = new HashMap();
+ args.put("groupID", groupID);
+ this.connection.post("deleteGroup", args);
+ }
+
+ /**
+ * List all the padIDs in a group. They will be in an array inside "padIDs".
+ *
+ * @param groupID string
+ * @return HashMap
+ */
+ public HashMap listPads(String groupID) {
+ HashMap args = new HashMap();
+ args.put("groupID", groupID);
+ return this.connection.get("listPads", args);
+ }
+
+ /**
+ * Create a pad in this group.
+ *
+ * @param groupID string
+ * @param padName string
+ */
+ public HashMap createGroupPad(String groupID, String padName) {
+ HashMap args = new HashMap();
+ args.put("groupID", groupID);
+ args.put("padName", padName);
+ return this.connection.post("createGroupPad", args);
+ }
+
+ /**
+ * Create a pad in this group.
+ *
+ * @param groupID string
+ * @param padName string
+ * @param text string
+ */
+ public void createGroupPad(String groupID, String padName, String text) {
+ HashMap args = new HashMap();
+ args.put("groupID", groupID);
+ args.put("padName", padName);
+ args.put("text", text);
+ this.connection.post("createGroupPad", args);
+ }
+
+ /**
+ * Lists all existing groups. The group ids are returned in "groupIDs".
+ *
+ * @return HashMap
+ */
+ public HashMap listAllGroups() {
+ return this.connection.get("listAllGroups");
+ }
+
+ // Authors
+ // These authors are bound to the attributes the users choose (color and name). The author id is returned in "authorID".
+
+ /**
+ * Create a new author.
+ *
+ * @return HashMap
+ */
+ public HashMap createAuthor() {
+ return this.connection.post("createAuthor");
+ }
+
+ /**
+ * Create a new author with the given name. The author id is returned in "authorID".
+ *
+ * @param name string
+ * @return HashMap
+ */
+ public HashMap createAuthor(String name) {
+ HashMap args = new HashMap();
+ args.put("name", name);
+ return this.connection.post("createAuthor", args);
+ }
+
+ /**
+ * Creates a new Author for authorMapper if one doesn't already exist. Helps you map your application's authors to Etherpad Lite's authors.
+ * The author id is returned in "authorID".
+ *
+ * @param authorMapper string
+ * @return HashMap
+ */
+ public HashMap createAuthorIfNotExistsFor(String authorMapper) {
+ HashMap args = new HashMap();
+ args.put("authorMapper", authorMapper);
+ return this.connection.post("createAuthorIfNotExistsFor", args);
+ }
+
+ /**
+ * Creates a new Author for authorMapper if one doesn't already exist. Helps you map your application's authors to Etherpad Lite's authors.
+ * The author id is returned in "authorID".
+ *
+ * @param authorMapper string
+ * @param name string
+ * @return HashMap
+ */
+ public HashMap createAuthorIfNotExistsFor(String authorMapper, String name) {
+ HashMap args = new HashMap();
+ args.put("authorMapper", authorMapper);
+ args.put("name", name);
+ return this.connection.post("createAuthorIfNotExistsFor", args);
+ }
+
+ /**
+ * List the ids of pads the author has edited. They will be in an array inside "padIDs".
+ *
+ * @param authorId the authors's id string
+ * @return HashMap
+ */
+ public HashMap listPadsOfAuthor(String authorId) {
+ HashMap args = new HashMap();
+ args.put("authorID", authorId);
+ return this.connection.get("listPadsOfAuthor", args);
+ }
+
+ /**
+ * Returns the Author Name of the author.
+ *
+ * @param authorId the author's id string
+ * @return String
+ */
+ public String getAuthorName(String authorId) {
+ HashMap args = new HashMap();
+ args.put("authorID", authorId);
+ return this.connection.get("getAuthorName", args).toString();
+ }
+
+ // Sessions
+ // Sessions can be created between a group and an author. This allows an author to access more than one group. The sessionID will be set as a
+ // cookie to the client and is valid until a certain date. Only users with a valid session for this group, can access group pads. You can create a
+ // session after you authenticated the user at your web application, to give them access to the pads. You should save the sessionID of this session
+ // and delete it after the user logged out.
+
+ /**
+ * Create a new session for the given author in the given group, valid until the given UNIX time.
+ * The session id will be returned in "sessionID".
+ * HashMap pad = api.getText("my_pad");
+ * String pad = pad.get("text").toString();
+ *
+ *
+ * Example:
+ *
+ *
+ * import java.util.Date;
+ *
+ * @param groupID string
+ * @param authorID string
+ * @param validUntil long UNIX timestamp in seconds
+ * @return HashMap
+ */
+ public HashMap createSession(String groupID, String authorID, long validUntil) {
+ HashMap args = new HashMap();
+ args.put("groupID", groupID);
+ args.put("authorID", authorID);
+ args.put("validUntil", String.valueOf(validUntil));
+ return this.connection.post("createSession", args);
+ }
+
+ /**
+ * Create a new session for the given author in the given group valid for the given number of hours.
+ * The session id will be returned in "sessionID".
+ * ...
+ * Date now = new Date();
+ * long in1Hour = (now.getTime() + (60L * 60L * 1000L) / 1000L);
+ * String sessID1 = api.createSession(groupID, authorID, in1Hour).get("sessionID").toString();
+ *
+ *
+ * Example:
+ *
+ *
+ * // in 2 hours
+ *
+ * @param groupID string
+ * @param authorID string
+ * @param validUntil int length of session in hours
+ * @return HashMap
+ */
+ public HashMap createSession(String groupID, String authorID, int length) {
+ long inNHours = ((new Date()).getTime() + ((long)length * 60L * 60L * 1000L)) / 1000L;
+ return this.createSession(groupID, authorID, inNHours);
+ }
+
+ /**
+ * Create a new session for the given author in the given group, valid until the given datetime.
+ * The session id will be returned in "sessionID".
+ * String sessID1 = api.createSession(groupID, authorID, 2).get("sessionID").toString();
+ *
+ *
+ * Example:
+ *
+ *
+ * import java.util.Date;
+ *
+ * @param groupID string
+ * @param authorID string
+ * @param validUntil Date
+ * @return HashMap
+ */
+ public HashMap createSession(String groupID, String authorID, Date validUntil) {
+ long seconds = validUntil.getTime() / 1000L;
+ return this.createSession(groupID, authorID, seconds);
+ }
+
+ /**
+ * Delete a session.
+ *
+ * @param sessionID string
+ */
+ public void deleteSession(String sessionID) {
+ HashMap args = new HashMap();
+ args.put("sessionID", sessionID);
+ this.connection.post("deleteSession", args);
+ }
+
+ /**
+ * Returns information about a session: authorID, groupID and validUntil.
+ *
+ * @param sessionID string
+ * @return HashMap
+ */
+ public HashMap getSessionInfo(String sessionID) {
+ HashMap args = new HashMap();
+ args.put("sessionID", sessionID);
+ return this.connection.get("getSessionInfo", args);
+ }
+
+ /**
+ * List all the sessions IDs in a group. Returned as a HashMap of sessionIDs keys, with values of HashMaps containing
+ * groupID, authorID, and validUntil.
+ *
+ * @param groupID string
+ * @return HashMap
+ */
+ public HashMap listSessionsOfGroup(String groupID) {
+ HashMap args = new HashMap();
+ args.put("groupID", groupID);
+ return this.connection.get("listSessionsOfGroup", args);
+ }
+
+ /**
+ * List all the sessions IDs belonging to an author. Returned as a HashMap of sessionIDs keys, with values of HashMaps containing
+ * groupID, authorID, and validUntil.
+ *
+ * @param authorID string
+ * @return HashMap
+ */
+ public HashMap listSessionsOfAuthor(String authorID) {
+ HashMap args = new HashMap();
+ args.put("authorID", authorID);
+ return this.connection.get("listSessionsOfAuthor", args);
+ }
+
+ // Pad content
+
+ /**
+ * Returns a list of all pads.
+ *
+ * @return HashMap
+ */
+ public HashMap listAllPads() {
+ return this.connection.get("listAllPads");
+ }
+
+ /**
+ * Returns a HashMap containing the latest revision of the pad's text.
+ * The text is stored under "text".
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap getText(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("getText", args);
+ }
+
+ /**
+ * Returns a HashMap containing the a specific revision of the pad's text.
+ * The text is stored under "text".
+ *
+ * @param padId the pad's id string
+ * @param rev the revision number
+ * @return HashMap
+ */
+ public HashMap getText(String padId, int rev) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("rev", new Integer(rev));
+ return this.connection.get("getText", args);
+ }
+
+ /**
+ * Creates a new revision with the given text (or creates a new pad).
+ *
+ * @param padId the pad's id string
+ * @param text the pad's new text
+ */
+ public void setText(String padId, String text) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("text", text);
+ this.connection.post("setText", args);
+ }
+
+ /**
+ * Returns a HashMap containing the current revision of the pad's text as HTML.
+ * The html is stored under "html".
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap getHTML(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("getHTML", args);
+ }
+
+ /**
+ * Returns a HashMap containing the a specific revision of the pad's text as HTML.
+ * The html is stored under "html".
+ *
+ * @param padId the pad's id string
+ * @param rev the revision number
+ * @return HashMap
+ */
+ public HashMap getHTML(String padId, int rev) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("rev", new Integer(rev));
+ return this.connection.get("getHTML", args);
+ }
+
+ /**
+ * Creates a new revision with the given html (or creates a new pad).
+ *
+ * @param padId the pad's id string
+ * @param html the pad's new html text
+ */
+ public void setHTML(String padId, String html) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("html", html);
+ this.connection.post("setHTML", args);
+ }
+
+ // Pads
+ // Group pads are normal pads, but with the name schema GROUPID$PADNAME. A security manager controls access of them and its
+ // forbidden for normal pads to include a $ in the name.
+
+ /**
+ * Create a new pad.
+ *
+ * @param padId the pad's id string
+ */
+ public void createPad(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ this.connection.post("createPad", args);
+ }
+
+ /**
+ * Create a new pad with the given initial text.
+ *
+ * @param padId the pad's id string
+ * @param text the initial text string
+ */
+ public void createPad(String padId, String text) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("text", text);
+ this.connection.post("createPad", args);
+ }
+
+ /**
+ * Returns the number of revisions of this pad. The number is in "revisions".
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap getRevisionsCount(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("getRevisionsCount", args);
+ }
+
+ /**
+ * List the ids of authors who have edited a pad. They will be in an array inside "authorIDs".
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap listAuthorsOfPad(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("listAuthorsOfPad", args);
+ }
+
+ /**
+ * Deletes a pad.
+ *
+ * @param padId the pad's id string
+ */
+ public void deletePad(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ this.connection.post("deletePad", args);
+ }
+
+ /**
+ * Get the pad's read-only id. The id will be in "readOnlyID".
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap getReadOnlyID(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("getReadOnlyID", args);
+ }
+
+ /**
+ * Get the pad's last edit date as a Unix timestamp. The timestamp will be in "lastEdited".
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap getLastEdited(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("getLastEdited", args);
+ }
+
+ /**
+ * Get the number of users currently editing a pad.
+ *
+ * @param padId the pad's id string
+ * @return Long
+ */
+ public Long padUsersCount(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ Long userCount = (Long) this.connection.get("padUsersCount", args).get("padUsersCount");
+ return userCount;
+ }
+
+ /**
+ * Returns the list of users that are currently editing this pad.
+ * A padUser has the values: "colorId", "name" and "timestamp".
+ *
+ * @param padId
+ * @return HashMap
+ */
+ public HashMap padUsers(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("padUsers", args);
+ }
+
+ /**
+ * Sets the pad's public status.
+ * This is only applicable to group pads.
+ *
+ * @param padId the pad's id string
+ * @param publicStatus boolean
+ */
+ public void setPublicStatus(String padId, Boolean publicStatus) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("publicStatus", publicStatus);
+ this.connection.post("setPublicStatus", args);
+ }
+
+ /**
+ * Gets the pad's public status. The boolean is in "publicStatus".
+ * This is only applicable to group pads.
+ * import java.text.DateFormat;
+ * import java.text.SimpleDateFormat;
+ * import java.util.TimeZone;
+ * ...
+ * DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ * dfm.setTimeZone(TimeZone.getTimeZone("GMT-5"));
+ * Date longTime = dfm.parse("2056-01-15 20:15:00");
+ * String sessID = api.createSession(groupID, authorID, longTime).get("sessionID").toString();
+ *
+ *
+ * Example:
+ *
+ *
+ * Boolean is_public = (Boolean)api.getPublicStatus("g.kjsdfj7ask$foo").get("publicStatus");
+ *
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap getPublicStatus(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("getPublicStatus", args);
+ }
+
+ /**
+ * Sets the pad's password. This is only applicable to group pads.
+ *
+ * @param padId the pad's id string
+ * @param password string
+ */
+ public void setPassword(String padId, String password) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("password", password);
+ this.connection.post("setPassword", args);
+ }
+
+ /**
+ * Checks whether the pad is password-protected or not. The boolean is in "isPasswordProtected".
+ * This is only applicable to group pads.
+ *
+ * Example:
+ *
+ *
+ * Boolean pass = (Boolean)api.isPasswordProtected("g.kjsdfj7ask$foo").get("isPasswordProtected");
+ *
+ *
+ * @param padId the pad's id string
+ * @return HashMap
+ */
+ public HashMap isPasswordProtected(String padId) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ return this.connection.get("isPasswordProtected", args);
+ }
+
+ /**
+ * Sends a custom message of type msg to the pad.
+ *
+ * @param padId
+ * @param msg
+ */
+ public void sendClientsMessage(String padId, String msg) {
+ HashMap args = new HashMap();
+ args.put("padID", padId);
+ args.put("msg", msg);
+ this.connection.post("sendClientsMessage", args);
+ }
+
+ /**
+ * Returns true if the connection is using SSL/TLS, false if not.
+ *
+ * @return boolean
+ */
+ public boolean isSecure() {
+ if (this.connection.uri.getPort() == 443) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/org/etherpad_lite_client/EPLiteConnection.java b/src/org/etherpad_lite_client/EPLiteConnection.java
new file mode 100644
index 0000000..857202c
--- /dev/null
+++ b/src/org/etherpad_lite_client/EPLiteConnection.java
@@ -0,0 +1,258 @@
+package org.etherpad_lite_client;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import net.apocalypselabs.symat.Debug;
+
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+/**
+ * Connection object for talking to and parsing responses from the Etherpad Lite Server.
+ */
+public class EPLiteConnection {
+ public static final int CODE_OK = 0;
+ public static final int CODE_INVALID_PARAMETERS = 1;
+ public static final int CODE_INTERNAL_ERROR = 2;
+ public static final int CODE_INVALID_METHOD = 3;
+ public static final int CODE_INVALID_API_KEY = 4;
+
+ /**
+ * The url of the API
+ */
+ public URI uri;
+
+ /**
+ * The API key
+ */
+ public String apiKey;
+
+ /**
+ * The Etherpad Lite API version
+ */
+ public String apiVersion;
+
+ /**
+ * Initializes a new org.etherpad_lite_client.EPLiteConnection object.
+ *
+ * @param url an absolute url, including protocol, to the EPL api
+ * @param apiKey the API Key
+ * @param apiVersion the API version
+ */
+ public EPLiteConnection(String url, String apiKey, String apiVersion) {
+ this.uri = URI.create(url);
+ this.apiKey = apiKey;
+ this.apiVersion = apiVersion;
+ }
+
+ /**
+ * GETs from the HTTP JSON API.
+ *
+ * @param apiMethod the name of the API method to call
+ * @return HashMap
+ */
+ public HashMap get(String apiMethod) {
+ return this.get(apiMethod, new HashMap());
+ }
+
+ /**
+ * GETs from the HTTP JSON API.
+ *
+ * @param apiMethod the name of the API method to call
+ * @param apiArgs a HashMap of url/form parameters. apikey will be set automatically
+ * @return HashMap
+ */
+ public HashMap get(String apiMethod, HashMap apiArgs) {
+ String path = this.apiPath(apiMethod);
+ String query = this.queryString(apiArgs);
+ URL url = apiUrl(path, query);
+ Request request = new GETRequest(url);
+ return this.call(request);
+ }
+
+ /**
+ * POSTs to the HTTP JSON API.
+ *
+ * @param apiMethod the name of the API method to call
+ * @return HashMap
+ */
+ public HashMap post(String apiMethod) {
+ return this.post(apiMethod, new HashMap());
+ }
+
+ /**
+ * POSTs to the HTTP JSON API.
+ *
+ * @param apiMethod the name of the API method to call
+ * @param apiArgs a HashMap of url/form parameters. apikey will be set automatically
+ * @return HashMap
+ */
+ public HashMap post(String apiMethod, HashMap apiArgs) {
+ String path = this.apiPath(apiMethod);
+ String query = this.queryString(apiArgs);
+ URL url = apiUrl(path, null);
+ Request request = new POSTRequest(url, query);
+ return this.call(request);
+ }
+
+ /**
+ * Calls the HTTP JSON API.
+ *
+ * @param request the request object to send
+ * @return HashMap
+ */
+ private HashMap call(Request request) {
+ trustServerAndCertificate();
+
+ try {
+ String response = request.send();
+ return this.handleResponse(response);
+ }
+ catch (EPLiteException e) {
+ throw new EPLiteException(e.getMessage());
+ }
+ catch (Exception e) {
+ throw new EPLiteException("Unable to connect to SyMAT: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Converts the API resonse's JSON string into a HashMap.
+ *
+ * @param jsonString a valid JSON string
+ * @return HashMap
+ */
+ private HashMap handleResponse(String jsonString) {
+ try {
+ JSONParser parser = new JSONParser();
+ Map response = (Map) parser.parse(jsonString);
+ // Act on the response code
+ if (!response.get("code").equals(null)) {
+ int code = ((Long) response.get("code")).intValue();
+ switch ( code ) {
+ // Valid code, parse the response
+ case CODE_OK:
+ HashMap data = (HashMap) response.get("data");
+ return data != null ? data: new HashMap();
+ // Invalid code, throw an exception with the message
+ case CODE_INVALID_PARAMETERS:
+ case CODE_INVALID_API_KEY:
+ case CODE_INVALID_METHOD:
+ throw new EPLiteException((String)response.get("message"));
+ default:
+ throw new EPLiteException("An unknown error has occurred while handling the response: " + jsonString);
+ }
+ // No response code, something's really wrong
+ } else {
+ throw new EPLiteException("An unknown error has occurred while handling the response: " + jsonString);
+ }
+ } catch (ParseException e) {
+ System.err.println("Unable to parse JSON response (" + jsonString + "): " + e.getMessage());
+ return new HashMap();
+ }
+ }
+
+ /**
+ * Returns the URL for the api path and query.
+ *
+ * @param path the api path
+ * @param query the query string (may be null)
+ * @return URL
+ */
+ private URL apiUrl(String path, String query) {
+ try {
+ URL url = new URL(new URI(this.uri.getScheme(), null, this.uri.getHost(), this.uri.getPort(), path, query, null).toString());
+ return url;
+ } catch (Exception e) {
+ throw new EPLiteException("Unable to connect to SyMAT: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a URI path for the API method
+ *
+ * @param apiMethod the api method
+ * @return String
+ */
+ private String apiPath(String apiMethod) {
+ return this.uri.getPath() + "/api/" + this.apiVersion + "/" + apiMethod;
+ }
+
+ /**
+ * Returns a query string made from HashMap keys and values
+ *
+ * @param apiArgs the api arguments in a HashMap
+ * @return String
+ */
+ private String queryString(HashMap apiArgs) {
+ String strArgs = "";
+ apiArgs.put("apikey", this.apiKey);
+ Iterator i = apiArgs.entrySet().iterator();
+ while (i.hasNext()) {
+ Map.Entry e = (Map.Entry)i.next();
+ Object value = e.getValue();
+ if (value != null) {
+ try {
+ strArgs += e.getKey() + "=" + URLEncoder.encode(value.toString(), "utf-8");
+ } catch (UnsupportedEncodingException ex) {
+ Debug.stacktrace(ex);
+ }
+ if (i.hasNext()) {
+ strArgs += "&";
+ }
+ }
+ }
+ return strArgs;
+ }
+
+ /**
+ * Creates a trust manager to trust all certificates if you open a ssl connection
+ */
+ private void trustServerAndCertificate() {
+ // Create a trust manager that does not validate certificate chains
+ TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ public void checkClientTrusted(
+ java.security.cert.X509Certificate[] certs, String authType) {
+ }
+
+ public void checkServerTrusted(
+ java.security.cert.X509Certificate[] certs, String authType) {
+ }
+ }
+ };
+
+ // Install the all-trusting trust manager
+ try {
+ SSLContext sc = SSLContext.getInstance("SSL");
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ } catch (Exception e) {
+ }
+
+ HostnameVerifier hv = new HostnameVerifier() {
+ //@Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ };
+ HttpsURLConnection.setDefaultHostnameVerifier(hv);
+ }
+}
diff --git a/src/org/etherpad_lite_client/EPLiteException.java b/src/org/etherpad_lite_client/EPLiteException.java
new file mode 100644
index 0000000..773af32
--- /dev/null
+++ b/src/org/etherpad_lite_client/EPLiteException.java
@@ -0,0 +1,7 @@
+package org.etherpad_lite_client;
+
+public class EPLiteException extends RuntimeException {
+ public EPLiteException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/org/etherpad_lite_client/GETRequest.java b/src/org/etherpad_lite_client/GETRequest.java
new file mode 100644
index 0000000..c9186d3
--- /dev/null
+++ b/src/org/etherpad_lite_client/GETRequest.java
@@ -0,0 +1,47 @@
+package org.etherpad_lite_client;
+
+import java.net.URL;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/**
+ * A class for easily executing an HTTP GET request.
+ *
+ * Example:
+ *
+ *
+ * Request req = new GETRequest(url_object);
+ */
+public class GETRequest implements Request {
+ /**
+ * The URL object.
+ */
+ private URL url;
+
+ /**
+ * Instantiates a new GETRequest.
+ *
+ * @param url the URL object
+ */
+ public GETRequest(URL url) {
+ this.url = url;
+ }
+
+ /**
+ * Sends the request and returns the response.
+ *
+ * @return String
+ */
+ public String send() throws Exception {
+ BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
+ String response = "";
+ String buffer;
+ while ((buffer = in.readLine()) != null) {
+ response += buffer;
+ }
+ in.close();
+ return response;
+ }
+}
diff --git a/src/org/etherpad_lite_client/POSTRequest.java b/src/org/etherpad_lite_client/POSTRequest.java
new file mode 100644
index 0000000..bf8d619
--- /dev/null
+++ b/src/org/etherpad_lite_client/POSTRequest.java
@@ -0,0 +1,59 @@
+package org.etherpad_lite_client;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+/**
+ * A class for easily executing an HTTP POST request.
+ * String resp = req.send();
+ *
+ *
+ * Example:
+ *
+ *
+ * Request req = new POSTRequest(url_object);
+ */
+public class POSTRequest implements Request {
+ /**
+ * The URL object.
+ */
+ private URL url;
+
+ /**
+ * Instantiates a new POSTRequest.
+ *
+ * @param url the URL object
+ */
+ private String args;
+
+ public POSTRequest(URL url, String args) {
+ this.url = url;
+ this.args = args;
+ }
+
+ /**
+ * Sends the request and returns the response.
+ *
+ * @return String
+ */
+ public String send() throws Exception {
+ URLConnection con = this.url.openConnection();
+ con.setDoOutput(true);
+
+ OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
+ out.write(this.args);
+ out.close();
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
+ String response = "";
+ String buffer;
+ while ((buffer = in.readLine()) != null) {
+ response += buffer;
+ }
+ in.close();
+ return response;
+ }
+}
diff --git a/src/org/etherpad_lite_client/Request.java b/src/org/etherpad_lite_client/Request.java
new file mode 100644
index 0000000..add1941
--- /dev/null
+++ b/src/org/etherpad_lite_client/Request.java
@@ -0,0 +1,9 @@
+package org.etherpad_lite_client;
+
+import java.net.URL;
+
+public interface Request {
+ URL url = null;
+
+ public abstract String send() throws Exception;
+}
+ * String resp = req.send();
+ *