diff --git a/pom.xml b/pom.xml index 92ba534..f755963 100644 --- a/pom.xml +++ b/pom.xml @@ -85,6 +85,22 @@ + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + + org.apache.maven.plugins maven-compiler-plugin @@ -155,13 +171,28 @@ junit junit - 3.8.1 + 4.7 test - - com.google.code.gson - gson - 2.2.4 - - + + com.google.code.gson + gson + 2.2.4 + + + org.bouncycastle + bcprov-jdk16 + 1.46 + + + org.eclipse.jetty.orbit + javax.servlet + 3.0.0.v201112011016 + + + com.liferay.org.apache.commons.fileupload + com.liferay.org.apache.commons.fileupload + 6.2.0.1 + + diff --git a/src/main/java/gov/adlnet/xapi/App.java b/src/main/java/gov/adlnet/xapi/App.java deleted file mode 100644 index 34fe734..0000000 --- a/src/main/java/gov/adlnet/xapi/App.java +++ /dev/null @@ -1,17 +0,0 @@ -package gov.adlnet.xapi; - -import java.io.IOException; -import java.net.MalformedURLException; - -import gov.adlnet.xapi.client.StatementClient; -import gov.adlnet.xapi.model.Statement; - -public class App { - private static final String LRS_URI = "https://lrs.adlnet.gov/xAPI/"; - private static final String USERNAME = "jXAPI"; - private static final String PASSWORD = "password"; - public static void main(String[] args) throws IOException { - StatementClient client = new StatementClient(LRS_URI, USERNAME, - PASSWORD); - } -} diff --git a/src/main/java/gov/adlnet/xapi/client/AboutClient.java b/src/main/java/gov/adlnet/xapi/client/AboutClient.java new file mode 100644 index 0000000..9bae0c1 --- /dev/null +++ b/src/main/java/gov/adlnet/xapi/client/AboutClient.java @@ -0,0 +1,30 @@ +package gov.adlnet.xapi.client; + +import gov.adlnet.xapi.model.About; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Created by lou on 6/18/15. + */ +public class AboutClient extends BaseClient { + + public AboutClient(String uri, String username, String password) + throws MalformedURLException { + super(uri, username, password); + } + + public AboutClient(URL uri, String username, String password) + throws MalformedURLException { + super(uri, username, password); + } + + public About getAbout() + throws IOException { + String path = "/xAPI/about"; + String result = issueGet(path); + return getDecoder().fromJson(result, About.class); + } +} diff --git a/src/main/java/gov/adlnet/xapi/client/ActivityClient.java b/src/main/java/gov/adlnet/xapi/client/ActivityClient.java index 565ce5d..e0d5670 100644 --- a/src/main/java/gov/adlnet/xapi/client/ActivityClient.java +++ b/src/main/java/gov/adlnet/xapi/client/ActivityClient.java @@ -1,18 +1,139 @@ package gov.adlnet.xapi.client; import gov.adlnet.xapi.model.Activity; +import gov.adlnet.xapi.model.ActivityProfile; +import gov.adlnet.xapi.model.ActivityState; import gov.adlnet.xapi.model.Agent; -import java.io.IOException; +import java.io.*; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.util.HashMap; +import java.util.UUID; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; public class ActivityClient extends BaseClient { + protected String issueProfilePost(String path, String data, HashMap etag) + throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + HttpURLConnection conn = initializePOSTConnection(url); + + // Agent Profile requires either of these headers being sent + // If neither are sent it will set If-None-Match to null and exception + // will be caught during request + if (etag.containsKey("If-Match")){ + conn.addRequestProperty("If-Match", etag.get("If-Match")); + } + else{ + conn.addRequestProperty("If-None-Match", etag.get("If-None-Match")); + } + conn.setRequestMethod("POST"); + OutputStreamWriter writer = new OutputStreamWriter( + conn.getOutputStream()); + try { + writer.write(data); + } catch (IOException ex) { + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + } finally { + writer.close(); + } + try { + return readFromConnection(conn); + } finally { + conn.disconnect(); + } + } + + protected String issueProfilePut(String path, String data, HashMap etag) + throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + HttpURLConnection conn = initializePOSTConnection(url); + + // Agent Profile requires either of these headers being sent + // If neither are sent it will set If-None-Match to null and exception + // will be caught during request + if (etag.containsKey("If-Match")){ + conn.addRequestProperty("If-Match", etag.get("If-Match")); + } + else{ + conn.addRequestProperty("If-None-Match", etag.get("If-None-Match")); + } + + conn.setRequestMethod("PUT"); + OutputStreamWriter writer = new OutputStreamWriter( + conn.getOutputStream()); + try { + writer.write(data); + } catch (IOException ex) { + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + } finally { + writer.close(); + } + try { + return readFromConnection(conn); + } finally { + conn.disconnect(); + } + } + + protected String issueProfileDelete(String path, String ifMatchEtagValue) + throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + HttpURLConnection conn = initializeConnection(url); + //Agent profile requires If-Match header - exception will get caught when making + conn.addRequestProperty("If-Match", ifMatchEtagValue); + conn.setRequestMethod("DELETE"); + try{ + return readFromConnection(conn); + } + catch (IOException ex){ + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + } + finally{ + conn.disconnect(); + } + } + public ActivityClient(String uri, String username, String password) throws MalformedURLException { super(uri, username, password); @@ -24,96 +145,99 @@ public ActivityClient(URL uri, String username, String password) } public Activity getActivity(String activityId) - throws MalformedURLException, IOException { + throws IOException { String path = "/xapi/activities?activityId=" + activityId; String result = issueGet(path); return getDecoder().fromJson(result, Activity.class); } - private String createProfilePath(String activityId, String profileId){ + private String createProfilePath(ActivityProfile activityProfile){ StringBuilder sb = new StringBuilder(); sb.append("/xAPI/activities/profile?activityId="); - sb.append(activityId); + sb.append(activityProfile.getActivityId()); sb.append("&profileId="); - sb.append(profileId); + sb.append(activityProfile.getProfileId()); return sb.toString(); } - public JsonObject getActivityProfile(String activityId, String profileId) - throws MalformedURLException, IOException{ - String result = issueGet(createProfilePath(activityId, profileId)); + public JsonObject getActivityProfile(ActivityProfile activityProfile) + throws IOException{ + String result = issueGet(createProfilePath(activityProfile)); return getDecoder().fromJson(result, JsonObject.class); } - public JsonArray getActivityProfiles(String activityId, String since) throws MalformedURLException, IOException { - String path = "/xapi/activities/profile?activityId=" + activityId; - if (since != null && since.length() > 0){ - path += ("&since=" + since); - } - String result = issueGet(path); - return getDecoder().fromJson(result, JsonArray.class); - } - - public boolean postActivityProfile(String activityId, String profileId, - JsonElement profile) throws IOException { - String json = getDecoder().toJson(profile); - String response = issuePost(createProfilePath(activityId, profileId), - json); + public boolean postActivityProfile(ActivityProfile activityProfile, HashMap etag) + throws IOException { + String json = getDecoder().toJson(activityProfile.getProfile()); + String response = issueProfilePost(createProfilePath(activityProfile), json, etag); return response.isEmpty(); } - public boolean putActivityProfile(String activityId, String profileId, - JsonElement profile) throws IOException { - String json = getDecoder().toJson(profile); - String response = issuePut(createProfilePath(activityId, profileId), - json); + public boolean putActivityProfile(ActivityProfile activityProfile, HashMap etag) + throws IOException { + String json = getDecoder().toJson(activityProfile.getProfile()); + String response = issueProfilePut(createProfilePath(activityProfile), json, etag); return response.isEmpty(); } - public boolean deleteActivityProfile(String activityId, String profileId) throws IOException { - String response = issueDelete(createProfilePath(activityId, profileId)); + public boolean deleteActivityProfile(ActivityProfile activityProfile, String ifMatchEtagValue) + throws IOException { + String response = issueProfileDelete(createProfilePath(activityProfile), ifMatchEtagValue); return response.isEmpty(); } - private String createStatePath(String activityId, Agent agent, String registration, String stateId){ - String path = String.format("/xapi/activities/state?activityId=%s&agent=%s&stateId=%s", activityId, - getDecoder().toJson(agent.serialize()), stateId); - if (registration != null && registration.length() > 0){ - path += ("®istration=" + registration); + public JsonArray getActivityProfiles(String activityId, String since) throws IOException { + String path = "/xapi/activities/profile?activityId=" + activityId; + if (since != null && since.length() > 0){ + path += ("&since=" + since); + } + String result = issueGet(path); + return getDecoder().fromJson(result, JsonArray.class); + } + + private String createStatePath(ActivityState activityState){ + StringBuilder sb = new StringBuilder(); + sb.append("/xAPI/activities/state?activityId="); + sb.append(activityState.getActivityId()); + sb.append("&stateId="); + sb.append(activityState.getStateId()); + sb.append("&agent="); + sb.append(getDecoder().toJson(activityState.getAgent())); + UUID reg = activityState.getRegistration(); + if (reg != null){ + sb.append("®istration=" + reg.toString()); } - return path; + return sb.toString(); } - public JsonObject getActivityState(String activityId, Agent agent, String registration, String stateId) - throws MalformedURLException, IOException{ - String result = issueGet(createStatePath(activityId, agent, registration, stateId)); + public JsonObject getActivityState(ActivityState activityState) + throws IOException{ + String result = issueGet(createStatePath(activityState)); return getDecoder().fromJson(result, JsonObject.class); } - public boolean postActivityState(String activityId, Agent agent, String registration, String stateId, - JsonElement state) - throws MalformedURLException, IOException{ - String json = getDecoder().toJson((state)); - String result = issuePost(createStatePath(activityId, agent, registration, stateId), json); + public boolean postActivityState(ActivityState activityState) + throws IOException{ + String json = getDecoder().toJson(activityState.getState()); + String result = issuePost(createStatePath(activityState), json); return result.isEmpty(); } - public boolean putActivityState(String activityId, Agent agent, String registration, String stateId, - JsonElement state) - throws MalformedURLException, IOException{ - String json = getDecoder().toJson((state)); - String result = issuePut(createStatePath(activityId, agent, registration, stateId), json); + public boolean putActivityState(ActivityState activityState) + throws IOException{ + String json = getDecoder().toJson(activityState.getState()); + String result = issuePut(createStatePath(activityState), json); return result.isEmpty(); } - public boolean deleteActivityState(String activityId, Agent agent, String registration, String stateId) - throws MalformedURLException, IOException{ - String result = issueDelete(createStatePath(activityId, agent, registration, stateId)); + public boolean deleteActivityState(ActivityState activityState) + throws IOException{ + String result = issueDelete(createStatePath(activityState)); return result.isEmpty(); } public JsonArray getActivityStates(String activityId, Agent agent, String registration, String since) - throws MalformedURLException, IOException{ + throws IOException{ String path = String.format("/xapi/activities/state?activityId=%s&agent=%s", activityId, getDecoder().toJson(agent.serialize())); if (registration != null && registration.length() > 0){ @@ -127,7 +251,7 @@ public JsonArray getActivityStates(String activityId, Agent agent, String regist } public boolean deleteActivityStates(String activityId, Agent agent, String registration) - throws MalformedURLException, IOException{ + throws IOException{ String path = String.format("/xapi/activities/state?activityId=%s&agent=%s", activityId, getDecoder().toJson(agent.serialize())); if (registration != null && registration.length() > 0){ diff --git a/src/main/java/gov/adlnet/xapi/client/AgentClient.java b/src/main/java/gov/adlnet/xapi/client/AgentClient.java index 83eea06..aa8adc6 100644 --- a/src/main/java/gov/adlnet/xapi/client/AgentClient.java +++ b/src/main/java/gov/adlnet/xapi/client/AgentClient.java @@ -1,17 +1,141 @@ package gov.adlnet.xapi.client; import gov.adlnet.xapi.model.Agent; +import gov.adlnet.xapi.model.AgentProfile; import gov.adlnet.xapi.model.Person; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.util.HashMap; import com.google.gson.JsonArray; import com.google.gson.JsonElement; public class AgentClient extends BaseClient { + protected String issueProfilePost(String path, String data, HashMap etag) + throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + HttpURLConnection conn = initializePOSTConnection(url); + + // Agent Profile requires either of these headers being sent + // If neither are sent it will set If-None-Match to null and exception + // will be caught during request + if (etag.containsKey("If-Match")){ + conn.addRequestProperty("If-Match", etag.get("If-Match")); + } + else{ + conn.addRequestProperty("If-None-Match", etag.get("If-None-Match")); + } + conn.setRequestMethod("POST"); + OutputStreamWriter writer = new OutputStreamWriter( + conn.getOutputStream()); + try { + writer.write(data); + } catch (IOException ex) { + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + } finally { + writer.close(); + } + try { + return readFromConnection(conn); + } finally { + conn.disconnect(); + } + } + + protected String issueProfilePut(String path, String data, HashMap etag) + throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + HttpURLConnection conn = initializePOSTConnection(url); + + // Agent Profile requires either of these headers being sent + // If neither are sent it will set If-None-Match to null and exception + // will be caught during request + if (etag.containsKey("If-Match")){ + conn.addRequestProperty("If-Match", etag.get("If-Match")); + } + else{ + conn.addRequestProperty("If-None-Match", etag.get("If-None-Match")); + } + + conn.setRequestMethod("PUT"); + OutputStreamWriter writer = new OutputStreamWriter( + conn.getOutputStream()); + try { + writer.write(data); + } catch (IOException ex) { + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + } finally { + writer.close(); + } + try { + return readFromConnection(conn); + } finally { + conn.disconnect(); + } + } + + protected String issueProfileDelete(String path, String ifMatchEtagValue) + throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + HttpURLConnection conn = initializeConnection(url); + //Agent profile requires If-Match header - exception will get caught when making + conn.addRequestProperty("If-Match", ifMatchEtagValue); + conn.setRequestMethod("DELETE"); + try{ + return readFromConnection(conn); + } + catch (IOException ex){ + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + } + finally{ + conn.disconnect(); + } + } + public AgentClient(String uri, String username, String password) throws MalformedURLException { super(uri, username, password); @@ -23,51 +147,54 @@ public AgentClient(URL uri, String username, String password) } public Person getPerson(Agent a) - throws MalformedURLException, IOException { + throws IOException { String path = "/xapi/agents?agent=" + getDecoder().toJson(a.serialize()); String result = issueGet(path); return getDecoder().fromJson(result, Person.class); } - private String formatProfilePath(Agent a, String profileId) { - String agentJson = getDecoder().toJson(a.serialize()); - String path = "/xAPI/agents/profile?agent=" + agentJson + "&profileId=" - + profileId; - return path; + private String formatProfilePath(AgentProfile agentProfile) { + String agentJson = getDecoder().toJson(agentProfile.getAgent().serialize()); + StringBuilder sb = new StringBuilder(); + sb.append("/xAPI/agents/profile?agent="); + sb.append(agentJson); + sb.append("&profileId="); + sb.append(agentProfile.getProfileId()); + return sb.toString(); } - public JsonElement getAgentProfile(Agent a, String profileId) - throws MalformedURLException, IOException { - String path = formatProfilePath(a, profileId); + public JsonElement getAgentProfile(AgentProfile agentProfile) + throws IOException { + String path = formatProfilePath(agentProfile); String result = issueGet(path); return getDecoder().fromJson(result, JsonElement.class); } - public boolean putAgentProfile(Agent a, String profileId, JsonElement profile) - throws MalformedURLException, IOException { - String path = formatProfilePath(a, profileId); - String json = getDecoder().toJson((profile)); - String result = issuePut(path, json); + public boolean putAgentProfile(AgentProfile agentProfile, HashMap etag) + throws IOException { + String path = formatProfilePath(agentProfile); + String json = getDecoder().toJson(agentProfile.getProfile()); + String result = issueProfilePut(path, json, etag); return result.isEmpty(); } - public boolean postAgentProfile(Agent a, String profileId, JsonElement profile) - throws MalformedURLException, IOException { - String path = formatProfilePath(a, profileId); - String json = getDecoder().toJson((profile)); - String result = issuePost(path, json); + public boolean postAgentProfile(AgentProfile agentProfile, HashMap etag) + throws IOException { + String path = formatProfilePath(agentProfile); + String json = getDecoder().toJson(agentProfile.getProfile()); + String result = issueProfilePost(path, json, etag); return result.isEmpty(); } - public boolean deleteAgentProfile(Agent a, String profileId) - throws MalformedURLException, IOException { - String path = formatProfilePath(a, profileId); - String result = issueDelete(path); + public boolean deleteAgentProfile(AgentProfile agentProfile, String ifMatchEtagValue) + throws IOException { + String path = formatProfilePath(agentProfile); + String result = issueProfileDelete(path, ifMatchEtagValue); return result.isEmpty(); } public JsonArray getAgentProfiles(Agent a, String since) - throws MalformedURLException, IOException { + throws IOException { String agentJson = getDecoder().toJson(a.serialize()); String path = "/xAPI/agents/profile?agent=" + agentJson; if (since != null && since.length() > 0){ @@ -76,5 +203,4 @@ public JsonArray getAgentProfiles(Agent a, String since) String result = issueGet(path); return getDecoder().fromJson(result, JsonArray.class); } - } diff --git a/src/main/java/gov/adlnet/xapi/client/BaseClient.java b/src/main/java/gov/adlnet/xapi/client/BaseClient.java index 914e214..f001cff 100644 --- a/src/main/java/gov/adlnet/xapi/client/BaseClient.java +++ b/src/main/java/gov/adlnet/xapi/client/BaseClient.java @@ -6,12 +6,7 @@ import gov.adlnet.xapi.model.adapters.StatementObjectAdapter; import gov.adlnet.xapi.util.Base64; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; +import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; @@ -19,6 +14,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import javax.servlet.http.HttpServletResponse; + public class BaseClient { protected URL _host; protected Gson gson; @@ -49,34 +46,52 @@ protected void init(URL uri, String user, String password) { this._host = uri; this.username = user; this.password = password; -// this.authString = "Basic " + DatatypeConverter.printBase64Binary((this.username + ":" + this.password).getBytes()); - this.authString = "Basic " + Base64.encodeToString((this.username + ":" + this.password).getBytes(), Base64.URL_SAFE);//.DEFAULT); - this.authString = this.authString.replaceAll("\n", "").replaceAll("\r", ""); + this.authString = "Basic " + Base64.encodeToString((this.username + ":" + this.password).getBytes(), Base64.NO_WRAP); } protected String readFromConnection(HttpURLConnection conn) throws java.io.IOException { - InputStream in = new BufferedInputStream(conn.getInputStream()); - StringBuilder sb = new StringBuilder(); - InputStreamReader reader = new InputStreamReader(in); - BufferedReader br = new BufferedReader(reader); - try { - String line = ""; - while ((line = br.readLine()) != null) { - sb.append(line); - } - return sb.toString(); - } finally { - br.close(); - reader.close(); - } + InputStream in; + if(conn.getResponseCode() >= 400){ + in = new BufferedInputStream(conn.getErrorStream()); + StringBuilder sb = new StringBuilder(); + InputStreamReader reader = new InputStreamReader(in); + BufferedReader br = new BufferedReader(reader); + try { + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + } finally { + br.close(); + reader.close(); + } + throw new IOException(String.format("Server Responded with %d: %s", + conn.getResponseCode(), sb.toString())); + } + else { + in = new BufferedInputStream(conn.getInputStream()); + StringBuilder sb = new StringBuilder(); + InputStreamReader reader = new InputStreamReader(in); + BufferedReader br = new BufferedReader(reader); + try { + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + return sb.toString(); + } finally { + br.close(); + reader.close(); + } + } } protected HttpURLConnection initializeConnection(URL url) throws IOException { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true); - conn.addRequestProperty("X-Experience-API-Version", "1.0"); + conn.addRequestProperty("X-Experience-API-Version", "1.0.0"); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Authorization", this.authString); return conn; @@ -91,7 +106,7 @@ protected HttpURLConnection initializePOSTConnection(URL url) protected String issuePost(String path, String data) throws java.io.IOException { - URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + URL url = new URL(this._host.getProtocol(), this._host.getHost(),this._host.getPort() ,path); HttpURLConnection conn = initializePOSTConnection(url); conn.setRequestMethod("POST"); OutputStreamWriter writer = new OutputStreamWriter( @@ -103,7 +118,7 @@ protected String issuePost(String path, String data) InputStreamReader isr = new InputStreamReader(s); BufferedReader br = new BufferedReader(isr); try { - String line = ""; + String line; while((line = br.readLine()) != null){ System.out.print(line); } @@ -124,7 +139,7 @@ protected String issuePost(String path, String data) protected String issuePut(String path, String data) throws java.io.IOException { - URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + URL url = new URL(this._host.getProtocol(), this._host.getHost(),this._host.getPort() ,path); HttpURLConnection conn = initializePOSTConnection(url); conn.setRequestMethod("PUT"); OutputStreamWriter writer = new OutputStreamWriter( @@ -136,7 +151,7 @@ protected String issuePut(String path, String data) InputStreamReader isr = new InputStreamReader(s); BufferedReader br = new BufferedReader(isr); try { - String line = ""; + String line; while((line = br.readLine()) != null){ System.out.print(line); } @@ -157,7 +172,7 @@ protected String issuePut(String path, String data) protected String issueDelete(String path) throws java.io.IOException { - URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); + URL url = new URL(this._host.getProtocol(), this._host.getHost(),this._host.getPort() ,path); HttpURLConnection conn = initializeConnection(url); conn.setRequestMethod("DELETE"); try{ @@ -168,7 +183,7 @@ protected String issueDelete(String path) InputStreamReader isr = new InputStreamReader(s); BufferedReader br = new BufferedReader(isr); try { - String line = ""; + String line; while((line = br.readLine()) != null){ System.out.print(line); } @@ -183,18 +198,17 @@ protected String issueDelete(String path) } } - protected String issueGet(String path) throws java.io.IOException, - java.net.MalformedURLException { - URL url = new URL(this._host.getProtocol(), this._host.getHost(), path); - HttpURLConnection conn = initializeConnection(url); - try { + protected String issueGet(String path) throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(),this._host.getPort() ,path); + HttpURLConnection conn = initializeConnection(url); + try { return readFromConnection(conn); } catch (IOException ex) { InputStream s = conn.getErrorStream(); InputStreamReader isr = new InputStreamReader(s); BufferedReader br = new BufferedReader(isr); try { - String line = ""; + String line; while((line = br.readLine()) != null){ System.out.print(line); } @@ -207,4 +221,28 @@ protected String issueGet(String path) throws java.io.IOException, conn.disconnect(); } } + + protected HttpServletResponse issueGetWithAttachments(String path) throws java.io.IOException { + URL url = new URL(this._host.getProtocol(), this._host.getHost(),this._host.getPort() ,path); + HttpURLConnection conn = initializeConnection(url); + try { + return (HttpServletResponse)conn.getInputStream(); + } catch (IOException ex) { + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + }finally { + conn.disconnect(); + } + } } diff --git a/src/main/java/gov/adlnet/xapi/client/StatementClient.java b/src/main/java/gov/adlnet/xapi/client/StatementClient.java index b5dd8a3..817e423 100644 --- a/src/main/java/gov/adlnet/xapi/client/StatementClient.java +++ b/src/main/java/gov/adlnet/xapi/client/StatementClient.java @@ -5,18 +5,30 @@ import gov.adlnet.xapi.model.StatementResult; import gov.adlnet.xapi.model.Verb; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Map.Entry; import java.util.TreeMap; import com.google.gson.Gson; import com.google.gson.JsonArray; +import org.bouncycastle.util.encoders.Hex; + public class StatementClient extends BaseClient { private TreeMap filters; + private static final String LINE_FEED = "\r\n"; public StatementClient(String uri, String user, String password) throws java.net.MalformedURLException { @@ -28,8 +40,74 @@ public StatementClient(URL uri, String user, String password) super(uri, user, password); } - public String publishStatement(Statement statement) - throws java.io.UnsupportedEncodingException, java.io.IOException { + protected HttpURLConnection initializeConnectionForAttachments(URL url, String boundary) + throws IOException { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoInput(true); + conn.addRequestProperty("X-Experience-API-Version", "1.0.0"); + conn.setRequestProperty("Content-Type", "multipart/mixed; boundary=" + boundary); + conn.setRequestProperty("Authorization", this.authString); + conn.setUseCaches(false); + return conn; + } + + protected HttpURLConnection initializePOSTConnectionForAttachments(URL url, String boundary) + throws IOException { + HttpURLConnection conn = initializeConnectionForAttachments(url, boundary); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + return conn; + } + + protected String issuePostWithFileAttachment(String path, String data, String contentType, ArrayList attachmentData) + throws java.io.IOException, NoSuchAlgorithmException { + String boundary = "===" + System.currentTimeMillis() + "==="; + URL url = new URL(this._host.getProtocol(), this._host.getHost(),this._host.getPort() ,path); + HttpURLConnection conn = initializePOSTConnectionForAttachments(url, boundary); + OutputStreamWriter writer = new OutputStreamWriter( + conn.getOutputStream()); + try { + writer.append("--" + boundary).append(LINE_FEED); + writer.append("Content-Type:application/json").append(LINE_FEED).append(LINE_FEED); + writer.append(data).append(LINE_FEED); + writer.append("--" + boundary).append(LINE_FEED); + for(byte[] ba: attachmentData){ + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(ba); + String sha256String = new String(Hex.encode(md.digest())); + writer.append("Content-Type:" + contentType).append(LINE_FEED); + writer.append("Content-Transfer-Encoding:binary").append(LINE_FEED); + writer.append("X-Experience-API-Hash:" + sha256String).append(LINE_FEED).append(LINE_FEED); + writer.append(ba.toString()).append(LINE_FEED); + writer.append("--" + boundary + "--"); + } + writer.flush(); + } catch (IOException ex) { + InputStream s = conn.getErrorStream(); + InputStreamReader isr = new InputStreamReader(s); + BufferedReader br = new BufferedReader(isr); + try { + String line; + while((line = br.readLine()) != null){ + System.out.print(line); + } + System.out.println(); + } finally { + s.close(); + } + throw ex; + } finally { + writer.close(); + } + try { + return readFromConnection(conn); + } finally { + conn.disconnect(); + } + } + + public String postStatement(Statement statement) + throws java.io.IOException { Gson gson = getDecoder(); String json = gson.toJson(statement); String result = issuePost("/xapi/statements", json); @@ -37,6 +115,24 @@ public String publishStatement(Statement statement) return jsonResult.get(0).getAsString(); } + public Boolean putStatement(Statement statement, String stmtId) + throws java.io.IOException { + Gson gson = getDecoder(); + String json = gson.toJson(statement); + String result = issuePut("/xapi/statements?statementId=" + stmtId, json); + return result.isEmpty(); + } + + public String postStatementWithAttachment(Statement statement, String contentType, ArrayList attachmentData) + throws IOException, NoSuchAlgorithmException{ + Gson gson = getDecoder(); + String json = gson.toJson(statement); + String result = issuePostWithFileAttachment("/xapi/statements", json, contentType, attachmentData); + JsonArray jsonResult = gson.fromJson(result, JsonArray.class); + return jsonResult.get(0).getAsString(); + } + + public StatementResult getStatements(String more) throws java.io.IOException { String result = this.issueGet(more); @@ -61,7 +157,30 @@ public StatementResult getStatements() throws java.io.IOException { return this.getDecoder().fromJson(result, StatementResult.class); } - public Statement get(String statementId) throws java.io.IOException { + public String getStatementsWithAttachments() throws java.io.IOException { + StringBuilder query = new StringBuilder(); + query.append("/xapi/statements"); + if (this.filters != null && !this.filters.isEmpty()) { + query.append("?"); + for (Entry item : this.filters.entrySet()) { + query.append(item.getKey()); + query.append("="); + query.append(item.getValue()); + query.append("&"); + } + query.deleteCharAt(query.length() - 1); + this.filters.clear(); + } + if (query.toString().contains("?")){ + query.append("&attachments=true"); + } + else{ + query.append("?attachments=true"); + } + return this.issueGet(query.toString()); + } + + public Statement get(String statementId) throws java.io.IOException { String result = this.issueGet("/xapi/statements?statementId=" + statementId); return this.getDecoder().fromJson(result, Statement.class); @@ -126,17 +245,14 @@ public StatementClient includeRelatedAgents(boolean include) { return addFilter("related_agents", "false"); } - public StatementClient includeAttachments(boolean include) { - if (include) - return addFilter("attachments", "true"); - else - return addFilter("attachments", "false"); - } - public StatementClient filterBySince(String timestamp) { return addFilter("since", timestamp); } + public StatementClient limitResults(int limit){ + return addFilter("limit", Integer.toString(limit)); + } + public StatementClient filterByUntil(String timestamp) { return addFilter("until", timestamp); } diff --git a/src/main/java/gov/adlnet/xapi/model/About.java b/src/main/java/gov/adlnet/xapi/model/About.java new file mode 100644 index 0000000..3a1b0e2 --- /dev/null +++ b/src/main/java/gov/adlnet/xapi/model/About.java @@ -0,0 +1,20 @@ +package gov.adlnet.xapi.model; + +import com.google.gson.JsonObject; + +import java.util.ArrayList; + +/** + * Created by lou on 2/6/15. + */ +public class About { + private ArrayList version; + private JsonObject extensions; + + public ArrayList getVersion() { + return version; + } + public JsonObject getExtensions() { + return extensions; + } +} diff --git a/src/main/java/gov/adlnet/xapi/model/Activity.java b/src/main/java/gov/adlnet/xapi/model/Activity.java index 33ce602..0e27515 100644 --- a/src/main/java/gov/adlnet/xapi/model/Activity.java +++ b/src/main/java/gov/adlnet/xapi/model/Activity.java @@ -7,7 +7,6 @@ public class Activity implements IStatementObject { public static final String ACTIVITY = "Activity"; private String id; - private ActivityDefinition definition; public Activity() {} @@ -55,7 +54,11 @@ public JsonElement serialize() { public String toString() { return String.format( "%s", (definition == null || - definition.toString() == null || - definition.toString().isEmpty()) ? id : definition.toString()); + definition.getName() == null) ? id : definition.toString()); } + public String toString(String langMap) { + return String.format( + "%s", (definition == null || + definition.getName().get(langMap) == null) ? id : definition.toString(langMap)); + } } diff --git a/src/main/java/gov/adlnet/xapi/model/ActivityDefinition.java b/src/main/java/gov/adlnet/xapi/model/ActivityDefinition.java index 9d37124..0d8b946 100644 --- a/src/main/java/gov/adlnet/xapi/model/ActivityDefinition.java +++ b/src/main/java/gov/adlnet/xapi/model/ActivityDefinition.java @@ -202,4 +202,7 @@ public String toString() { return name.get("en-US"); return ""; } + public String toString(String langMap) { + return name.get(langMap); + } } diff --git a/src/main/java/gov/adlnet/xapi/model/ActivityProfile.java b/src/main/java/gov/adlnet/xapi/model/ActivityProfile.java new file mode 100644 index 0000000..dbcb802 --- /dev/null +++ b/src/main/java/gov/adlnet/xapi/model/ActivityProfile.java @@ -0,0 +1,34 @@ +package gov.adlnet.xapi.model; + +import com.google.gson.JsonObject; + +/** + * Created by lou on 2/6/15. + */ +public class ActivityProfile { + private String activityId; + private String profileId; + private JsonObject profile; + + public ActivityProfile(){}; + + public ActivityProfile(String activityId, String profileId){ + this.activityId = activityId; + this.profileId = profileId; + } + + public String getActivityId() { + return activityId; + } + public void setActivityId(String activityId) { + this.activityId = activityId; + } + public String getProfileId(){ + return this.profileId; + } + public void setProfileId(String profileId){ + this.profileId = profileId; + } + public JsonObject getProfile(){return this.profile;} + public void setProfile(JsonObject p){ this.profile = p; } +} diff --git a/src/main/java/gov/adlnet/xapi/model/ActivityState.java b/src/main/java/gov/adlnet/xapi/model/ActivityState.java new file mode 100644 index 0000000..714bfd6 --- /dev/null +++ b/src/main/java/gov/adlnet/xapi/model/ActivityState.java @@ -0,0 +1,48 @@ +package gov.adlnet.xapi.model; + +import com.google.gson.JsonObject; + +import java.util.UUID; + +public class ActivityState { + private String activityId; + private String stateId; + private Agent agent; + private UUID registration; + private JsonObject state; + + public ActivityState(){} + + public ActivityState(String activityId, String stateId, Agent agent){ + this.activityId = activityId; + this.stateId = stateId; + this.agent = agent; + } + + public String getActivityId() { + return activityId; + } + public void setActivityId(String activityId) { + this.activityId = activityId; + } + public String getStateId() { + return stateId; + } + public void setStateId(String stateId) { + this.stateId = stateId; + } + public void setAgent(Agent a){ + this.agent = a; + } + public Agent getAgent(){ + return this.agent; + } + public UUID getRegistration() { + return registration; + } + public void setRegistration(UUID registration) { + this.registration = registration; + } + public JsonObject getState(){return this.state;} + public void setState(JsonObject s){ this.state = s; } +} diff --git a/src/main/java/gov/adlnet/xapi/model/Actor.java b/src/main/java/gov/adlnet/xapi/model/Actor.java index 7891806..24e64cc 100644 --- a/src/main/java/gov/adlnet/xapi/model/Actor.java +++ b/src/main/java/gov/adlnet/xapi/model/Actor.java @@ -10,7 +10,7 @@ public abstract class Actor { private String mbox_sha1sum; private URI openid; private Account account; - private boolean inverseFunctionalPropertySet = false; + private transient boolean inverseFunctionalPropertySet = false; public String getMbox() { return mbox; @@ -108,7 +108,7 @@ public JsonElement serialize() { obj.add("account", this.account.serialize()); } obj.addProperty("objectType", this.getObjectType()); - return obj; + return obj; } public String toString() { diff --git a/src/main/java/gov/adlnet/xapi/model/AgentProfile.java b/src/main/java/gov/adlnet/xapi/model/AgentProfile.java new file mode 100644 index 0000000..bb7e372 --- /dev/null +++ b/src/main/java/gov/adlnet/xapi/model/AgentProfile.java @@ -0,0 +1,32 @@ +package gov.adlnet.xapi.model; + +import com.google.gson.JsonObject; + +/** + * Created by lou on 2/6/15. + */ +public class AgentProfile { + private Agent agent; + private String profileId; + private JsonObject profile; + + public AgentProfile(){} + + public AgentProfile(Agent agent, String profileId){ + this.agent = agent; + this.profileId = profileId; + } + + public Agent getAgent() { + return agent; + } + public void setAgent(Agent a) { this.agent = a; } + public String getProfileId(){ + return this.profileId; + } + public void setProfileId(String profileId){ + this.profileId = profileId; + } + public JsonObject getProfile(){return this.profile;} + public void setProfile(JsonObject p){ this.profile = p; } +} diff --git a/src/main/java/gov/adlnet/xapi/model/Attachment.java b/src/main/java/gov/adlnet/xapi/model/Attachment.java index 8b12313..7bbc9bd 100644 --- a/src/main/java/gov/adlnet/xapi/model/Attachment.java +++ b/src/main/java/gov/adlnet/xapi/model/Attachment.java @@ -15,24 +15,6 @@ public class Attachment { private String sha2; private URI fileUrl; - private JsonElement serializeHash(HashMap map) { - JsonObject obj = new JsonObject(); - for (Entry item : map.entrySet()) { - obj.addProperty(item.getKey(), item.getValue()); - } - return obj; - } - public JsonElement serialize(){ - JsonObject obj = new JsonObject(); - obj.addProperty("usageType", this.usageType.toString()); - obj.add("display", this.serializeHash(this.display)); - obj.add("description", this.serializeHash(this.description)); - obj.addProperty("contentType", this.contentType); - obj.addProperty("length", this.length); - obj.addProperty("sha2", this.sha2); - obj.addProperty("fileUrl", this.fileUrl.toString()); - return obj; - } public URI getUsageType() { return usageType; } @@ -88,4 +70,23 @@ public URI getFileUrl() { public void setFileUrl(URI fileUrl) { this.fileUrl = fileUrl; } + + private JsonElement serializeHash(HashMap map) { + JsonObject obj = new JsonObject(); + for (Entry item : map.entrySet()) { + obj.addProperty(item.getKey(), item.getValue()); + } + return obj; + } + public JsonElement serialize(){ + JsonObject obj = new JsonObject(); + obj.addProperty("usageType", this.usageType.toString()); + obj.add("display", this.serializeHash(this.display)); + obj.add("description", this.serializeHash(this.description)); + obj.addProperty("contentType", this.contentType); + obj.addProperty("length", this.length); + obj.addProperty("sha2", this.sha2); + obj.addProperty("fileUrl", this.fileUrl.toString()); + return obj; + } } diff --git a/src/main/java/gov/adlnet/xapi/model/Context.java b/src/main/java/gov/adlnet/xapi/model/Context.java index 44a5909..de0f694 100644 --- a/src/main/java/gov/adlnet/xapi/model/Context.java +++ b/src/main/java/gov/adlnet/xapi/model/Context.java @@ -10,54 +10,19 @@ public class Context { private String revision; private String platform; private String language; - private Actor instructor; private Group team; private StatementReference statement; private ContextActivities contextActivities; - private HashMap extensions; - public void setContextActivities(ContextActivities ca){ + + public void setContextActivities(ContextActivities ca){ this.contextActivities = ca; } + public ContextActivities getContextActivities(){ return this.contextActivities; } - public JsonElement serialize() { - JsonObject obj = new JsonObject(); - if (this.registration != null) { - obj.addProperty("registration", this.registration); - } - if (this.revision != null) { - obj.addProperty("revision", this.revision); - } - if (this.platform != null) { - obj.addProperty("platform", this.platform); - } - if (this.language != null) { - obj.addProperty("language", this.language); - } - if (this.instructor != null) { - obj.add("instructor", instructor.serialize()); - } - if (this.team != null) { - obj.add("team", this.team.serialize()); - } - if (this.extensions != null) { - JsonObject extensionsObj = new JsonObject(); - obj.add("extensions", extensionsObj); - for (Entry item : extensions.entrySet()) { - extensionsObj.add(item.getKey(), item.getValue()); - } - } - if (this.statement != null) { - obj.add("statement", statement.serialize()); - } - if (this.contextActivities != null) { - obj.add("contextActivities", contextActivities.serialize()); - } - return obj; - } public String getRegistration() { return registration; @@ -122,4 +87,40 @@ public HashMap getExtensions() { public void setExtensions(HashMap extensions) { this.extensions = extensions; } + + public JsonElement serialize() { + JsonObject obj = new JsonObject(); + if (this.registration != null) { + obj.addProperty("registration", this.registration); + } + if (this.revision != null) { + obj.addProperty("revision", this.revision); + } + if (this.platform != null) { + obj.addProperty("platform", this.platform); + } + if (this.language != null) { + obj.addProperty("language", this.language); + } + if (this.instructor != null) { + obj.add("instructor", instructor.serialize()); + } + if (this.team != null) { + obj.add("team", this.team.serialize()); + } + if (this.extensions != null) { + JsonObject extensionsObj = new JsonObject(); + obj.add("extensions", extensionsObj); + for (Entry item : extensions.entrySet()) { + extensionsObj.add(item.getKey(), item.getValue()); + } + } + if (this.statement != null) { + obj.add("statement", statement.serialize()); + } + if (this.contextActivities != null) { + obj.add("contextActivities", contextActivities.serialize()); + } + return obj; + } } diff --git a/src/main/java/gov/adlnet/xapi/model/ContextActivities.java b/src/main/java/gov/adlnet/xapi/model/ContextActivities.java index 2628cf4..aa5f893 100644 --- a/src/main/java/gov/adlnet/xapi/model/ContextActivities.java +++ b/src/main/java/gov/adlnet/xapi/model/ContextActivities.java @@ -8,7 +8,8 @@ public class ContextActivities { private ArrayList grouping; private ArrayList category; private ArrayList other; - public ArrayList getParent() { + + public ArrayList getParent() { return parent; } @@ -24,6 +25,22 @@ public void setGrouping(ArrayList grouping) { this.grouping = grouping; } + public ArrayList getCategory() { + return category; + } + + public void setCategory(ArrayList category) { + this.category = category; + } + + public ArrayList getOther() { + return other; + } + + public void setOther(ArrayList other) { + this.other = other; + } + public JsonElement serialize() { JsonObject obj = new JsonObject(); if (this.parent != null) { @@ -56,20 +73,4 @@ public JsonElement serialize() { } return obj; } - - public ArrayList getCategory() { - return category; - } - - public void setCategory(ArrayList category) { - this.category = category; - } - - public ArrayList getOther() { - return other; - } - - public void setOther(ArrayList other) { - this.other = other; - } } diff --git a/src/main/java/gov/adlnet/xapi/model/Definition.java b/src/main/java/gov/adlnet/xapi/model/Definition.java deleted file mode 100644 index 5a3f459..0000000 --- a/src/main/java/gov/adlnet/xapi/model/Definition.java +++ /dev/null @@ -1,19 +0,0 @@ -package gov.adlnet.xapi.model; - -import com.google.gson.*; -public class Definition { - private JsonObject extensions; - public JsonElement serialize(){ - - JsonObject self = new JsonObject(); - self.add("extensions", extensions); - return self; - } - public JsonObject getExtensions() { - return extensions; - } - - public void setExtensions(JsonObject extensions) { - this.extensions = extensions; - } -} diff --git a/src/main/java/gov/adlnet/xapi/model/IStatementObject.java b/src/main/java/gov/adlnet/xapi/model/IStatementObject.java index 86996cc..0c46f3a 100644 --- a/src/main/java/gov/adlnet/xapi/model/IStatementObject.java +++ b/src/main/java/gov/adlnet/xapi/model/IStatementObject.java @@ -1,5 +1,6 @@ package gov.adlnet.xapi.model; import com.google.gson.*; + public interface IStatementObject { public String getObjectType(); public JsonElement serialize(); diff --git a/src/main/java/gov/adlnet/xapi/model/InteractionComponent.java b/src/main/java/gov/adlnet/xapi/model/InteractionComponent.java index b06c5b5..776abb6 100644 --- a/src/main/java/gov/adlnet/xapi/model/InteractionComponent.java +++ b/src/main/java/gov/adlnet/xapi/model/InteractionComponent.java @@ -5,7 +5,9 @@ import java.util.Map.Entry; public class InteractionComponent { - public String getId() { + private String id; + private HashMap description; + public String getId() { return id; } @@ -39,7 +41,4 @@ public JsonElement serialize() { } return obj; } - - private String id; - private HashMap description; } \ No newline at end of file diff --git a/src/main/java/gov/adlnet/xapi/model/Person.java b/src/main/java/gov/adlnet/xapi/model/Person.java index b6be5e0..822d9bc 100644 --- a/src/main/java/gov/adlnet/xapi/model/Person.java +++ b/src/main/java/gov/adlnet/xapi/model/Person.java @@ -15,6 +15,22 @@ public String getObjectType() { return OBJECTTYPE; } + public String[] getName(){ + return this.name; + } + public String[] getMbox(){ + return this.mbox; + } + public String[] getMbox_sha1sum(){ + return this.mbox_sha1sum; + } + public String[] getOpenid(){ + return this.openid; + } + public Account[] getAccount(){ + return this.account; + } + public String toString() { String ret = getObjectType() + " ; "; if (name != null && name.length != 0){ diff --git a/src/main/java/gov/adlnet/xapi/model/Result.java b/src/main/java/gov/adlnet/xapi/model/Result.java index 37d324c..ff68ac9 100644 --- a/src/main/java/gov/adlnet/xapi/model/Result.java +++ b/src/main/java/gov/adlnet/xapi/model/Result.java @@ -4,6 +4,13 @@ import com.google.gson.JsonObject; public class Result { + private Score score; + private Boolean success; + private Boolean completion; + private String response; + private String duration; + private JsonObject extensions; + public Score getScore() { return score; } @@ -74,11 +81,4 @@ public JsonElement serialize() { } return obj; } - - private Score score; - private Boolean success; - private Boolean completion; - private String response; - private String duration; - private JsonObject extensions; } diff --git a/src/main/java/gov/adlnet/xapi/model/Score.java b/src/main/java/gov/adlnet/xapi/model/Score.java index 835b71b..3624179 100644 --- a/src/main/java/gov/adlnet/xapi/model/Score.java +++ b/src/main/java/gov/adlnet/xapi/model/Score.java @@ -2,7 +2,38 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; + public class Score { + private float scaled; + private float raw; + private float min; + private float max; + + public float getScaled() { + return scaled; + } + public void setScaled(float scaled) { + this.scaled = scaled; + } + public float getRaw() { + return raw; + } + public void setRaw(float raw) { + this.raw = raw; + } + public float getMin() { + return min; + } + public void setMin(float min) { + this.min = min; + } + public float getMax() { + return max; + } + public void setMax(float max) { + this.max = max; + } + public JsonElement serialize() { JsonObject obj = new JsonObject(); obj.addProperty("scaled", this.scaled); @@ -11,32 +42,5 @@ public JsonElement serialize() { obj.addProperty("max", this.max); return obj; } - public float getScaled() { - return scaled; - } - public void setScaled(float scaled) { - this.scaled = scaled; - } - public float getRaw() { - return raw; - } - public void setRaw(float raw) { - this.raw = raw; - } - public float getMin() { - return min; - } - public void setMin(float min) { - this.min = min; - } - public float getMax() { - return max; - } - public void setMax(float max) { - this.max = max; - } - private float scaled; - private float raw; - private float min; - private float max; + } diff --git a/src/main/java/gov/adlnet/xapi/model/State.java b/src/main/java/gov/adlnet/xapi/model/State.java deleted file mode 100644 index ac09f63..0000000 --- a/src/main/java/gov/adlnet/xapi/model/State.java +++ /dev/null @@ -1,30 +0,0 @@ -package gov.adlnet.xapi.model; - -import java.util.UUID; - -public class State { - private String activityId; - private Agent agent; - private UUID registration; - public String getActivityId() { - return activityId; - } - - public void setActivityId(String activityId) { - this.activityId = activityId; - } - public void setAgent(Agent a){ - this.agent = a; - } - public Agent getAgent(){ - return this.agent; - } - - public UUID getRegistration() { - return registration; - } - - public void setRegistration(UUID registration) { - this.registration = registration; - } -} diff --git a/src/main/java/gov/adlnet/xapi/model/Statement.java b/src/main/java/gov/adlnet/xapi/model/Statement.java index f5060d3..63d95e0 100644 --- a/src/main/java/gov/adlnet/xapi/model/Statement.java +++ b/src/main/java/gov/adlnet/xapi/model/Statement.java @@ -1,5 +1,9 @@ package gov.adlnet.xapi.model; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + import java.util.ArrayList; import java.util.UUID; @@ -8,7 +12,6 @@ public class Statement { private String timestamp; private String stored; private String version; - private Verb verb; private Actor actor; private IStatementObject object; @@ -32,7 +35,7 @@ public String getTimestamp() { public void setTimestamp(String timestamp) { this.timestamp = timestamp; } - public String getStored() { + public String getStored() { return stored; } public void setStored(String stored) { @@ -92,8 +95,48 @@ public Result getResult() { public void setResult(Result result) { this.result = result; } - - public String toString() { - return String.format("%s: %s %s %s", id, actor, verb, object); - } + + public String toString(){ + return String.format("%s %s %s", actor.toString(), verb.toString(), object.toString()); + } + + public JsonElement serialize() { + JsonObject obj = new JsonObject(); + if (this.id!= null) { + obj.addProperty("id", this.id); + } + if (this.actor != null) { + obj.add("actor", this.actor.serialize()); + } + if (this.verb != null) { + obj.add("verb", verb.serialize()); + } + if (this.object != null) { + obj.add("object", object.serialize()); + } + if (this.result != null) { + obj.add("result", result.serialize()); + } + if (this.context != null) { + obj.add("context", this.context.serialize()); + } + if (this.timestamp != null) { + obj.addProperty("timestamp", this.timestamp); + } + if (this.stored != null) { + obj.addProperty("stored", this.stored); + } + if (this.version != null) { + obj.addProperty("version", this.version); + } + if (this.authority != null) { + obj.add("authority", this.authority.serialize()); + } + JsonArray jsonAttachments = new JsonArray(); + obj.add("attachments", jsonAttachments); + for (Attachment a : this.attachments) { + jsonAttachments.add(a.serialize()); + } + return obj; + } } diff --git a/src/main/java/gov/adlnet/xapi/model/StatementReference.java b/src/main/java/gov/adlnet/xapi/model/StatementReference.java index 43fdc7e..f4105d7 100644 --- a/src/main/java/gov/adlnet/xapi/model/StatementReference.java +++ b/src/main/java/gov/adlnet/xapi/model/StatementReference.java @@ -7,6 +7,12 @@ public class StatementReference implements IStatementObject { public static final String STATEMENT_REFERENCE = "StatementRef"; private String id; + public StatementReference(){} + + public StatementReference(String id){ + this.id = id; + } + public JsonElement serialize() { JsonObject obj = new JsonObject(); obj.addProperty("objectType", this.getObjectType()); diff --git a/src/main/java/gov/adlnet/xapi/model/StatementResult.java b/src/main/java/gov/adlnet/xapi/model/StatementResult.java index 5b50c0d..d8d361b 100644 --- a/src/main/java/gov/adlnet/xapi/model/StatementResult.java +++ b/src/main/java/gov/adlnet/xapi/model/StatementResult.java @@ -3,6 +3,9 @@ import java.util.ArrayList; public class StatementResult { + private ArrayList statements; + private String more; + public ArrayList getStatements() { return statements; } @@ -18,7 +21,4 @@ public void setMore(String more) { public boolean hasMore() { return this.more != null && this.more.length() > 0; } - private ArrayList statements; - private String more; - } diff --git a/src/main/java/gov/adlnet/xapi/model/SubStatement.java b/src/main/java/gov/adlnet/xapi/model/SubStatement.java index 8125cf0..eb53cc9 100644 --- a/src/main/java/gov/adlnet/xapi/model/SubStatement.java +++ b/src/main/java/gov/adlnet/xapi/model/SubStatement.java @@ -13,35 +13,6 @@ public class SubStatement implements IStatementObject { private Context context; private ArrayList attachments; - public JsonElement serialize() { - JsonObject obj = new JsonObject(); - if (this.timestamp != null) { - obj.addProperty("timestamp", this.timestamp); - } - if (this.actor != null) { - obj.add("actor", this.actor.serialize()); - } - if (this.verb != null) { - obj.add("verb", verb.serialize()); - } - if (this.object != null) { - obj.add("object", object.serialize()); - } - if (this.result != null) { - obj.add("result", result.serialize()); - } - if (this.context != null) { - obj.add("context", this.context.serialize()); - } - obj.addProperty("objectType", this.getObjectType()); - JsonArray jsonAttachments = new JsonArray(); - obj.add("attachments", jsonAttachments); - for (Attachment a : this.attachments) { - jsonAttachments.add(a.serialize()); - } - return obj; - } - public String getTimestamp() { return timestamp; } @@ -105,4 +76,33 @@ public void setResult(Result result) { public String getObjectType() { return SUB_STATEMENT; } + + public JsonElement serialize() { + JsonObject obj = new JsonObject(); + if (this.timestamp != null) { + obj.addProperty("timestamp", this.timestamp); + } + if (this.actor != null) { + obj.add("actor", this.actor.serialize()); + } + if (this.verb != null) { + obj.add("verb", verb.serialize()); + } + if (this.object != null) { + obj.add("object", object.serialize()); + } + if (this.result != null) { + obj.add("result", result.serialize()); + } + if (this.context != null) { + obj.add("context", this.context.serialize()); + } + obj.addProperty("objectType", this.getObjectType()); + JsonArray jsonAttachments = new JsonArray(); + obj.add("attachments", jsonAttachments); + for (Attachment a : this.attachments) { + jsonAttachments.add(a.serialize()); + } + return obj; + } } diff --git a/src/main/java/gov/adlnet/xapi/model/Verb.java b/src/main/java/gov/adlnet/xapi/model/Verb.java index f1eee3e..cc6f5b8 100644 --- a/src/main/java/gov/adlnet/xapi/model/Verb.java +++ b/src/main/java/gov/adlnet/xapi/model/Verb.java @@ -5,7 +5,9 @@ import com.google.gson.*; public class Verb { - + private String id; + private HashMap display; + public Verb() {} public Verb(String id) { @@ -56,6 +58,11 @@ public String toString() { return ret; } - private String id; - private HashMap display; + public String toString(String langKey) { + String ret = id; + if (display != null && + display.get(langKey) != null && + ! display.get(langKey).isEmpty()) ret = display.get(langKey); + return ret; + } } diff --git a/src/test/java/gov/adlnet/xapi/ActivityTest.java b/src/test/java/gov/adlnet/xapi/ActivityTest.java index 96dc6bf..35e74d6 100644 --- a/src/test/java/gov/adlnet/xapi/ActivityTest.java +++ b/src/test/java/gov/adlnet/xapi/ActivityTest.java @@ -3,11 +3,15 @@ import gov.adlnet.xapi.client.ActivityClient; import gov.adlnet.xapi.client.StatementClient; import gov.adlnet.xapi.model.Activity; +import gov.adlnet.xapi.model.ActivityProfile; +import gov.adlnet.xapi.model.ActivityState; import gov.adlnet.xapi.model.Agent; import gov.adlnet.xapi.model.Statement; import gov.adlnet.xapi.model.Verb; import java.io.IOException; +import java.net.URL; +import java.util.HashMap; import java.util.UUID; import junit.framework.Test; @@ -28,6 +32,7 @@ public class ActivityTest extends TestCase { private static final String USERNAME = "jXAPI"; private static final String PASSWORD = "password"; private static final String MBOX = "mailto:test@example.com"; + private static final UUID REGISTRATION = UUID.randomUUID(); /** * Create the test case @@ -61,28 +66,41 @@ public void setUp() throws IOException{ ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); JsonObject puobj = new JsonObject(); puobj.addProperty("putproftest", "putproftest"); - assertTrue(_client.putActivityProfile(ACTIVITY_ID, PUT_PROFILE_ID, puobj)); + ActivityProfile puap = new ActivityProfile(ACTIVITY_ID, PUT_PROFILE_ID); + puap.setProfile(puobj); + HashMap putEtag = new HashMap(); + putEtag.put("If-Match", "*"); + assertTrue(_client.putActivityProfile(puap, putEtag)); JsonObject pobj = new JsonObject(); pobj.addProperty("postproftest", "postproftest"); - assertTrue(_client.postActivityProfile(ACTIVITY_ID, POST_PROFILE_ID, pobj)); + ActivityProfile pap = new ActivityProfile(ACTIVITY_ID, POST_PROFILE_ID); + pap.setProfile(pobj); + HashMap postEtag = new HashMap(); + postEtag.put("If-Match", "*"); + assertTrue(_client.postActivityProfile(pap, postEtag)); JsonObject pusobj = new JsonObject(); pusobj.addProperty("putstatetest", "putstatetest"); - assertTrue(_client.putActivityState(ACTIVITY_ID, a, null, PUT_STATE_ID, pusobj)); + ActivityState pus = new ActivityState(ACTIVITY_ID, PUT_STATE_ID, a); + pus.setRegistration(REGISTRATION); + pus.setState(pusobj); + assertTrue(_client.putActivityState(pus)); JsonObject posbj = new JsonObject(); posbj.addProperty("poststatetest", "poststatetest"); - assertTrue(_client.postActivityState(ACTIVITY_ID, a, null, POST_STATE_ID, posbj)); + ActivityState pos = new ActivityState(ACTIVITY_ID, POST_STATE_ID, a); + pos.setState(posbj); + assertTrue(_client.postActivityState(pos)); } public void tearDown() throws IOException{ ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); Agent a = new Agent(); a.setMbox(MBOX); - assertTrue(_client.deleteActivityProfile(ACTIVITY_ID, PUT_PROFILE_ID)); - assertTrue(_client.deleteActivityProfile(ACTIVITY_ID, POST_PROFILE_ID)); - assertTrue(_client.deleteActivityState(ACTIVITY_ID, a, null, PUT_STATE_ID)); + assertTrue(_client.deleteActivityProfile(new ActivityProfile(ACTIVITY_ID, PUT_PROFILE_ID), "*")); + assertTrue(_client.deleteActivityProfile(new ActivityProfile(ACTIVITY_ID, POST_PROFILE_ID), "*")); + assertTrue(_client.deleteActivityState(new ActivityState(ACTIVITY_ID, PUT_STATE_ID, a))); assertTrue(_client.deleteActivityStates(ACTIVITY_ID, a, null)); } @@ -93,7 +111,6 @@ public void testGetActivity() throws IOException { Verb v = new Verb("http://example.com/tested"); Activity act = new Activity(ACTIVITY_ID); Statement st = new Statement(a, v, act); - String stID = sc.publishStatement(st); ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); Activity returnAct = _client.getActivity(ACTIVITY_ID); @@ -103,21 +120,33 @@ public void testGetActivity() throws IOException { public void testGetActivityProfile() throws IOException{ ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); - JsonElement putProfile = _client.getActivityProfile(ACTIVITY_ID, PUT_PROFILE_ID); + JsonElement putProfile = _client.getActivityProfile(new ActivityProfile(ACTIVITY_ID, PUT_PROFILE_ID)); assertNotNull(putProfile); assertTrue(putProfile.isJsonObject()); JsonObject obj = (JsonObject)putProfile; assertEquals(obj.getAsJsonPrimitive("putproftest").getAsString(), "putproftest"); - JsonElement postProfile = _client.getActivityProfile(ACTIVITY_ID, POST_PROFILE_ID); + ActivityProfile ap = new ActivityProfile(); + ap.setActivityId(ACTIVITY_ID); + ap.setProfileId(POST_PROFILE_ID); + JsonElement postProfile = _client.getActivityProfile(ap); assertNotNull(postProfile); assertTrue(postProfile.isJsonObject()); JsonObject pobj = (JsonObject)postProfile; assertEquals(pobj.getAsJsonPrimitive("postproftest").getAsString(), "postproftest"); } + public void testPutProfileIfNoneMatch() throws IOException{} + + public void testPostProfileIfNoneMatch() throws IOException{} + + public void testPutProfileBadEtag() throws IOException{} + + public void testPostProfileBadEtag() throws IOException{} + public void testGetActivityProfiles() throws IOException{ - ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); + URL url = new URL("https", "lrs.adlnet.gov", "/xAPI/"); + ActivityClient _client = new ActivityClient(url, USERNAME, PASSWORD); JsonArray a = _client.getActivityProfiles(ACTIVITY_ID, null); assertNotNull(a); assertTrue(a.size() >= 2); @@ -129,23 +158,41 @@ public void testGetActivityProfilesWithSince() throws IOException { assertNotNull(a); assertTrue(a.size() >= 2); } + public void testGetActivityState() throws IOException{ ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); Agent a = new Agent(); a.setMbox(MBOX); - JsonElement putState = _client.getActivityState(ACTIVITY_ID, a, null, PUT_STATE_ID); + JsonElement putState = _client.getActivityState(new ActivityState(ACTIVITY_ID, PUT_STATE_ID, a)); assertNotNull(putState); assertTrue(putState.isJsonObject()); JsonObject obj = (JsonObject)putState; assertEquals(obj.getAsJsonPrimitive("putstatetest").getAsString(), "putstatetest"); - JsonElement postState = _client.getActivityState(ACTIVITY_ID, a, null, POST_STATE_ID); + ActivityState pas = new ActivityState(); + pas.setActivityId(ACTIVITY_ID); + pas.setStateId(POST_STATE_ID); + pas.setAgent(a); + JsonElement postState = _client.getActivityState(pas); assertNotNull(postState); assertTrue(postState.isJsonObject()); JsonObject pobj = (JsonObject)postState; assertEquals(pobj.getAsJsonPrimitive("poststatetest").getAsString(), "poststatetest"); } + public void testGetActivityStateWithRegistration() throws IOException{ + ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); + Agent a = new Agent(); + a.setMbox(MBOX); + ActivityState as = new ActivityState(ACTIVITY_ID, PUT_STATE_ID, a); + as.setRegistration(REGISTRATION); + JsonElement putState = _client.getActivityState(new ActivityState(ACTIVITY_ID, PUT_STATE_ID, a)); + assertNotNull(putState); + assertTrue(putState.isJsonObject()); + JsonObject obj = (JsonObject)putState; + assertEquals(obj.getAsJsonPrimitive("putstatetest").getAsString(), "putstatetest"); + } + public void testGetActivityStates() throws IOException{ ActivityClient _client = new ActivityClient(LRS_URI, USERNAME, PASSWORD); Agent a = new Agent(); diff --git a/src/test/java/gov/adlnet/xapi/AgentTest.java b/src/test/java/gov/adlnet/xapi/AgentTest.java index a6c0c3e..c2b6ff9 100644 --- a/src/test/java/gov/adlnet/xapi/AgentTest.java +++ b/src/test/java/gov/adlnet/xapi/AgentTest.java @@ -1,12 +1,17 @@ package gov.adlnet.xapi; import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.util.HashMap; import java.util.UUID; import com.google.gson.*; import gov.adlnet.xapi.client.AgentClient; +import gov.adlnet.xapi.model.Account; import gov.adlnet.xapi.model.Agent; +import gov.adlnet.xapi.model.AgentProfile; import gov.adlnet.xapi.model.Person; import junit.framework.TestCase; @@ -28,33 +33,45 @@ public void setUp() throws IOException{ a.setMbox(MBOX); JsonObject puobj = new JsonObject(); puobj.addProperty("puttest", "puttest"); - assertTrue(client.putAgentProfile(a, PUT_PROFILE_ID, puobj)); + AgentProfile ap = new AgentProfile(a, PUT_PROFILE_ID); + ap.setProfile(puobj); + HashMap putEtag = new HashMap(); + putEtag.put("If-Match", "*"); + assertTrue(client.putAgentProfile(ap, putEtag)); JsonObject pobj = new JsonObject(); pobj.addProperty("posttest", "posttest"); - assertTrue(client.postAgentProfile(a, POST_PROFILE_ID, pobj)); + AgentProfile poap = new AgentProfile(a, POST_PROFILE_ID); + poap.setProfile(pobj); + HashMap postEtag = new HashMap(); + postEtag.put("If-Match", "*"); + assertTrue(client.postAgentProfile(poap, postEtag)); } public void tearDown() throws IOException{ AgentClient client = new AgentClient(LRS_URI, USERNAME, PASSWORD); Agent a = new Agent(); a.setMbox(MBOX); - boolean putResp = client.deleteAgentProfile(a, PUT_PROFILE_ID); + boolean putResp = client.deleteAgentProfile(new AgentProfile(a, PUT_PROFILE_ID), "*"); assertTrue(putResp); - boolean postResp = client.deleteAgentProfile(a, POST_PROFILE_ID); + boolean postResp = client.deleteAgentProfile(new AgentProfile(a, POST_PROFILE_ID), "*"); assertTrue(postResp); } public void testGetProfile() throws IOException { - AgentClient client = new AgentClient(LRS_URI, USERNAME, PASSWORD); + URL url = new URL("https", "lrs.adlnet.gov", "/xAPI/"); + AgentClient client = new AgentClient(url, USERNAME, PASSWORD); Agent a = new Agent(); a.setMbox(MBOX); - JsonElement putProfile = client.getAgentProfile(a, PUT_PROFILE_ID); + JsonElement putProfile = client.getAgentProfile(new AgentProfile(a, PUT_PROFILE_ID)); assertNotNull(putProfile); assertTrue(putProfile.isJsonObject()); JsonObject obj = (JsonObject)putProfile; assertEquals(obj.getAsJsonPrimitive("puttest").getAsString(), "puttest"); - JsonElement postProfile = client.getAgentProfile(a, POST_PROFILE_ID); + AgentProfile ap = new AgentProfile(); + ap.setAgent(a); + ap.setProfileId(POST_PROFILE_ID); + JsonElement postProfile = client.getAgentProfile(ap); assertNotNull(postProfile); assertTrue(postProfile.isJsonObject()); JsonObject pobj = (JsonObject)postProfile; @@ -70,6 +87,14 @@ public void testGetProfiles() throws IOException{ assertTrue(profiles.size() >= 2); } + public void testPutProfileIfNoneMatch() throws IOException{} + + public void testPostProfileIfNoneMatch() throws IOException{} + + public void testPutProfileBadEtag() throws IOException{} + + public void testPostProfileBadEtag() throws IOException{} + public void testGetProfilesWithSince() throws IOException{ AgentClient client = new AgentClient(LRS_URI, USERNAME, PASSWORD); Agent a = new Agent(); @@ -85,5 +110,6 @@ public void testGetPerson() throws IOException{ a.setMbox(MBOX); Person p = client.getPerson(a); assertNotNull(p); + assertEquals(p.getMbox()[0], MBOX); } } diff --git a/src/test/java/gov/adlnet/xapi/AppTest.java b/src/test/java/gov/adlnet/xapi/AppTest.java index b8baf4a..7ee0311 100644 --- a/src/test/java/gov/adlnet/xapi/AppTest.java +++ b/src/test/java/gov/adlnet/xapi/AppTest.java @@ -1,29 +1,32 @@ package gov.adlnet.xapi; +import gov.adlnet.xapi.client.AboutClient; import gov.adlnet.xapi.client.StatementClient; -import gov.adlnet.xapi.model.Activity; -import gov.adlnet.xapi.model.ActivityDefinition; -import gov.adlnet.xapi.model.Actor; -import gov.adlnet.xapi.model.Agent; -import gov.adlnet.xapi.model.InteractionComponent; -import gov.adlnet.xapi.model.Statement; -import gov.adlnet.xapi.model.StatementResult; -import gov.adlnet.xapi.model.Verb; -import gov.adlnet.xapi.model.Verbs; +import gov.adlnet.xapi.model.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.UUID; +import java.util.*; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; + /** * Unit test for simple App. */ @@ -47,20 +50,24 @@ public static String now() { public static Calendar toCalendar(final String iso8601string) throws ParseException { Calendar calendar = GregorianCalendar.getInstance(); - String s = iso8601string.replace("Z", "+00:00"); - try { - s = s.substring(0, 22) + s.substring(23); // to get rid of the - // ":" - } catch (IndexOutOfBoundsException e) { - throw new ParseException("Invalid length", 0); - } + + String s = ""; + if (iso8601string.contains("'Z'")){ + s = iso8601string.replace("Z", "+00:00"); + } + else if (!iso8601string.contains("+")){ + s = iso8601string + "+00:00"; + } + else{ + s = iso8601string; + } + Date date = new SimpleDateFormat(dateFormat).parse(s); calendar.setTime(date); return calendar; } } - - private static final String LRS_URI = "https://lrs.adlnet.gov/xAPI/"; + private static final String LRS_URI = "https://lrs.adlnet.gov/XAPI/"; private static final String USERNAME = "jXAPI"; private static final String PASSWORD = "password"; @@ -88,25 +95,66 @@ public static Test suite() { * Rigourous Test ;-) */ public void testGetStatements() throws java.net.URISyntaxException, - java.io.UnsupportedEncodingException, java.io.IOException { + java.io.IOException { StatementClient _client = new StatementClient(LRS_URI, USERNAME, PASSWORD); StatementResult collection = _client.getStatements(); assert !collection.getStatements().isEmpty(); } -// public void testGetSingleStatement() throws java.net.URISyntaxException, -// java.io.UnsupportedEncodingException, java.io.IOException { -// String statementId = "23d0a261-fede-4548-9431-314389bc1ebd"; -// StatementClient _client = new StatementClient(LRS_URI, USERNAME, -// PASSWORD); -// Statement collection = _client.get(statementId); -// assert collection.getId().equals(statementId); -// } + public void testGetMoreStatements() throws URISyntaxException, + IOException{ + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + StatementResult collection = _client.getStatements(); + assert !collection.getStatements().isEmpty(); + + String more = collection.getMore(); + + if (!more.isEmpty()){ + StatementResult moreCollection = _client.getStatements(more); + assert !moreCollection.getStatements().isEmpty(); + } + } + + public void testPutGetSingleStatement() throws java.net.URISyntaxException, + java.io.IOException { + String statementId = UUID.randomUUID().toString(); + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + + Statement stmt = new Statement(new Agent("test name", "mailto:testname@testname.com"), + Verbs.experienced(), new Activity("http://testactivity.testactivity.com")); + stmt.setId(statementId); + Boolean put = _client.putStatement(stmt, statementId); + assertTrue(put); + Statement collection = _client.get(statementId); + assert collection.getId().equals(statementId); + } + + public void testVoidStatement() throws java.net.URISyntaxException, + java.io.IOException { + String voidedId = UUID.randomUUID().toString(); + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + + Statement stmt = new Statement(new Agent("test name", "mailto:testname@testname.com"), + Verbs.experienced(), new Activity("http://testactivity.testactivity.com")); + stmt.setId(voidedId); + Boolean put = _client.putStatement(stmt, voidedId); + assertTrue(put); + + Statement stmt2 = new Statement(new Agent("test name", "mailto:testname@testname.com"), + Verbs.voided(), new StatementReference(voidedId)); + String postedId = _client.postStatement(stmt2); + assert postedId.length() > 0; + + Statement collection = _client.getVoided(voidedId); + assert collection.getId().equals(voidedId); + } public void testPublishStatementWithAgent() - throws java.net.URISyntaxException, - java.io.UnsupportedEncodingException, java.io.IOException { + throws java.net.URISyntaxException, java.io.IOException { StatementClient _client = new StatementClient(LRS_URI, USERNAME, PASSWORD); Statement statement = new Statement(); @@ -128,16 +176,18 @@ public void testPublishStatementWithAgent() ic.setDescription(new HashMap()); ic.getDescription().put("en-US", "test"); ad.getChoices().add(ic); + ArrayList crp = new ArrayList(); + crp.add("http://example.com"); + ad.setCorrectResponsesPattern(crp); ad.setInteractionType("choice"); ad.setMoreInfo("http://example.com"); a.setDefinition(ad); - String publishedId = _client.publishStatement(statement); + String publishedId = _client.postStatement(statement); assert publishedId.length() > 0; } public void testSettingMultipeInverseFunctionProperties() - throws java.net.URISyntaxException, - java.io.UnsupportedEncodingException, java.io.IOException { + throws java.net.URISyntaxException, java.io.IOException { Agent agent = new Agent(); agent.setMbox("mailto:test@example.com"); try { @@ -148,12 +198,150 @@ public void testSettingMultipeInverseFunctionProperties() } } + public void testPublishStatementWithAttachmentFileURL() + throws URISyntaxException, IOException{ + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + Statement statement = new Statement(); + Agent agent = new Agent(); + Verb verb = new Verb(); + verb.setId("http://adlnet.gov/expapi/verbs/experienced"); + agent.setMbox("mailto:test@example.com"); + agent.setName("Tester McTesterson"); + statement.setActor(agent); + statement.setId(UUID.randomUUID().toString()); + statement.setVerb(verb); + Activity a = new Activity(); + a.setId("http://attachmentexample.com"); + statement.setObject(a); + ActivityDefinition ad = new ActivityDefinition(); + ad.setChoices(new ArrayList()); + InteractionComponent ic = new InteractionComponent(); + ic.setId("http://example.com"); + ic.setDescription(new HashMap()); + ic.getDescription().put("en-US", "test"); + ad.getChoices().add(ic); + ad.setInteractionType("choice"); + ArrayList crp = new ArrayList(); + crp.add("http://example.com"); + ad.setCorrectResponsesPattern(crp); + ad.setMoreInfo("http://example.com"); + a.setDefinition(ad); + + Attachment att = new Attachment(); + HashMap attDis = new HashMap(); + attDis.put("en-US", "jxapi Test Attachment From FileURL"); + att.setDisplay(attDis); + URI usageType = new URI("http://example.com/test/usage"); + att.setUsageType(usageType); + att.setContentType("application/json"); + att.setLength(45); + att.setFileUrl(new URI("http://test/attachment/url")); + + ArrayList attList = new ArrayList(); + attList.add(att); + statement.setAttachments(attList); + + String publishedId = _client.postStatement(statement); + assert publishedId.length() > 0; + } + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @org.junit.Test + public void testPublishStatementWithAttachmentFile() + throws URISyntaxException, IOException, NoSuchAlgorithmException{ + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + Statement statement = new Statement(); + Agent agent = new Agent(); + Verb verb = new Verb(); + verb.setId("http://adlnet.gov/expapi/verbs/experienced"); + agent.setMbox("mailto:test@example.com"); + agent.setName("Tester McTesterson"); + statement.setActor(agent); + statement.setId(UUID.randomUUID().toString()); + statement.setVerb(verb); + Activity a = new Activity(); + a.setId("http://attachmentexample.com"); + statement.setObject(a); + ActivityDefinition ad = new ActivityDefinition(); + ad.setChoices(new ArrayList()); + InteractionComponent ic = new InteractionComponent(); + ic.setId("http://example.com"); + ic.setDescription(new HashMap()); + ic.getDescription().put("en-US", "test"); + ad.getChoices().add(ic); + ad.setInteractionType("choice"); + ArrayList crp = new ArrayList(); + crp.add("http://example.com"); + ad.setCorrectResponsesPattern(crp); + ad.setMoreInfo("http://example.com"); + a.setDefinition(ad); + + Attachment att = new Attachment(); + HashMap attDis = new HashMap(); + attDis.put("en-US", "jxapi Test Attachment From File"); + att.setDisplay(attDis); + URI usageType = new URI("http://example.com/test/usage"); + att.setUsageType(usageType); + + File testfile = folder.newFile("testatt.txt"); + BufferedWriter out = new BufferedWriter(new FileWriter(testfile)); + out.write("This is the first line\n"); + out.write("This is the second line!!!\n"); + out.write(UUID.randomUUID().toString()); + out.close(); + + String contentType = "text/plain"; + att.setContentType(contentType); + att.setLength((int)testfile.length()); + byte[] arr = fileToByteArray(testfile); + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(arr); + att.setSha2(new String(Hex.encode(md.digest()))); + + ArrayList attList = new ArrayList(); + attList.add(att); + statement.setAttachments(attList); + + ArrayList realAtts = new ArrayList(); + realAtts.add(arr); + + String publishedId = _client.postStatementWithAttachment(statement, contentType, realAtts); + assert publishedId.length() > 0; + + String res = _client.getStatementsWithAttachments(); + assertNotNull(res); + } + + private byte[] fileToByteArray(File file) throws IOException { + byte []buffer = new byte[(int) file.length()]; + InputStream ios = null; + try { + ios = new FileInputStream(file); + if ( ios.read(buffer) == -1 ) { + throw new IOException("EOF reached while trying to read the whole file"); + } + } finally { + try { + if ( ios != null ) + ios.close(); + } catch ( IOException e) { + } + } + + return buffer; + } + public void testQueryByVerb() throws java.net.URISyntaxException, - java.io.UnsupportedEncodingException, java.io.IOException { + java.io.IOException { StatementClient _client = new StatementClient(LRS_URI, USERNAME, PASSWORD); Verb v = Verbs.experienced(); - StatementResult result = _client.filterByVerb(v).getStatements(); + StatementResult result = _client.filterByVerb(v).limitResults(10) + .getStatements(); assertFalse(result.getStatements().isEmpty()); for (Statement s : result.getStatements()) { assertNotNull(s.getVerb()); @@ -162,12 +350,13 @@ public void testQueryByVerb() throws java.net.URISyntaxException, } public void testQueryByAgent() throws java.net.URISyntaxException, - java.io.UnsupportedEncodingException, java.io.IOException { + java.io.IOException { StatementClient _client = new StatementClient(LRS_URI, USERNAME, PASSWORD); Actor a = new Agent(); a.setMbox("mailto:test@example.com"); - StatementResult result = _client.filterByActor(a).getStatements(); + StatementResult result = _client.filterByActor(a).limitResults(10) + .getStatements(); assertFalse(result.getStatements().isEmpty()); for (Statement s : result.getStatements()) { assertNotNull(s.getActor()); @@ -175,57 +364,165 @@ public void testQueryByAgent() throws java.net.URISyntaxException, } } + public void testQueryByActivity() throws java.net.URISyntaxException, + java.io.IOException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + StatementResult result = _client.filterByActivity("http://example.com") + .limitResults(10).getStatements(); + assertFalse(result.getStatements().isEmpty()); + for (Statement s : result.getStatements()) { + assertNotNull(s.getObject()); + assertEquals("http://example.com", ((Activity)s.getObject()).getId()); + } + } + + public void testQueryByRelatedAgent() throws java.net.URISyntaxException, + java.io.IOException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + Agent a = new Agent(); + a.setMbox("mailto:test@example.com"); + Agent oa = new Agent(); + oa.setMbox("mailto:tester2@example.com"); + Statement stmt = new Statement(a, Verbs.asked(), oa); + String publishedId = _client.postStatement(stmt); + assert publishedId.length() > 0; + + StatementResult result = _client.filterByActor(oa).includeRelatedAgents(true) + .limitResults(10).canonical().getStatements(); + assertFalse(result.getStatements().isEmpty()); + } + + public void testQueryByRelatedActivity() throws java.net.URISyntaxException, + java.io.IOException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + Agent a = new Agent(); + a.setMbox("mailto:test@example.com"); + ArrayList arr = new ArrayList(); + arr.add(new Activity("http://caexample.com")); + Context c = new Context(); + ContextActivities ca = new ContextActivities(); + ca.setCategory(arr); + c.setContextActivities(ca); + Statement stmt = new Statement(a, Verbs.asked(), new Activity("http://example.com")); + stmt.setContext(c); + String publishedId = _client.postStatement(stmt); + assert publishedId.length() > 0; + + StatementResult result = _client.filterByActivity("http://caexample.com") + .includeRelatedActivities(true) + .limitResults(10).exact().getStatements(); + assertFalse(result.getStatements().isEmpty()); + } + + public void testQueryByRegistration() throws java.net.URISyntaxException, + java.io.IOException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + String reg = UUID.randomUUID().toString(); + Agent a = new Agent(); + a.setMbox("mailto:test@example.com"); + Statement stmt = new Statement(a, Verbs.experienced(), + new Activity("http://example.com")); + Context c = new Context(); + c.setRegistration(reg); + stmt.setContext(c); + String publishedId = _client.postStatement(stmt); + assert publishedId.length() > 0; + + StatementResult result = _client.filterByRegistration(reg) + .limitResults(10).getStatements(); + assertFalse(result.getStatements().isEmpty()); + + } + + public void testQueryByLimit() throws java.net.URISyntaxException, + java.io.IOException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + + StatementResult result = _client.limitResults(1).getStatements(); + assertFalse(result.getStatements().isEmpty()); + assertEquals(result.getStatements().size(), 1); + } + public void testQueryByAgentAndVerb() throws java.net.URISyntaxException, - java.io.UnsupportedEncodingException, java.io.IOException { + java.io.IOException { StatementClient _client = new StatementClient(LRS_URI, USERNAME, PASSWORD); Actor a = new Agent(); a.setMbox("mailto:test@example.com"); - Verb v = Verbs.experienced(); - StatementResult result = _client.filterByVerb(v).filterByActor(a).ids() + StatementResult result = _client.filterByVerb("http://adlnet.gov/expapi/verbs/experienced") + .limitResults(10).filterByActor(a).ids() .getStatements(); assertFalse(result.getStatements().isEmpty()); for (Statement s : result.getStatements()) { assertNotNull(s.getActor()); assertEquals(a.getMbox(), s.getActor().getMbox()); assertNotNull(s.getVerb()); - assertEquals(v.getId(), s.getVerb().getId()); + assertEquals("http://adlnet.gov/expapi/verbs/experienced", s.getVerb().getId()); } } -// public void testQueryBySince() throws java.net.URISyntaxException, -// java.io.UnsupportedEncodingException, java.io.IOException, -// ParseException { -// StatementClient _client = new StatementClient(LRS_URI, USERNAME, -// PASSWORD); -// String dateQuery = "2014-05-02T17:28:47.000000+00:00"; -// Calendar date = ISO8601.toCalendar(dateQuery); -// StatementResult result = _client.filterBySince(dateQuery) -// .getStatements(); -// assertFalse(result.getStatements().isEmpty()); -// for (Statement s : result.getStatements()) { -// Calendar statementTimestampe = ISO8601.toCalendar(s.getTimestamp()); -// // the since date should be less than (denoted by a compareTo value -// // being less than 0 -// assert date.compareTo(statementTimestampe) < 0; -// } -// } - -// public void testQueryByUntil() throws java.net.URISyntaxException, -// java.io.UnsupportedEncodingException, java.io.IOException, -// ParseException { -// StatementClient _client = new StatementClient(LRS_URI, USERNAME, -// PASSWORD); -// String dateQuery = "2014-05-02T17:28:47.000000+00:00"; -// Calendar date = ISO8601.toCalendar(dateQuery); -// StatementResult result = _client.filterByUntil(dateQuery) -// .getStatements(); -// assertFalse(result.getStatements().isEmpty()); -// for (Statement s : result.getStatements()) { -// Calendar statementTimestampe = ISO8601.toCalendar(s.getTimestamp()); -// // the until date should be greater than (denoted by a compareTo value -// // being greater than 0 -// assert date.compareTo(statementTimestampe) >= 0; -// } -// } + public void testQueryBySince() throws java.net.URISyntaxException, + java.io.IOException, ParseException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + String dateQuery = "2014-05-02T00:00:00Z"; + Calendar date = javax.xml.bind.DatatypeConverter.parseDateTime(dateQuery); + StatementResult result = _client.filterBySince(dateQuery).limitResults(10) + .getStatements(); + assertFalse(result.getStatements().isEmpty()); + for (Statement s : result.getStatements()) { + Calendar statementTimestamp = javax.xml.bind.DatatypeConverter.parseDateTime(s.getTimestamp()); + // the since date should be less than (denoted by a compareTo value + // being less than 0 + assert date.compareTo(statementTimestamp) < 0; + } + } + + public void testQueryByUntil() throws java.net.URISyntaxException, + java.io.IOException, ParseException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + df.setTimeZone(tz); + String dateQuery = df.format(new Date()); + Calendar date = javax.xml.bind.DatatypeConverter.parseDateTime(dateQuery); + StatementResult result = _client.filterByUntil(dateQuery).limitResults(10) + .getStatements(); + assertFalse(result.getStatements().isEmpty()); + for (Statement s : result.getStatements()) { + Calendar statementTimestamp = javax.xml.bind.DatatypeConverter.parseDateTime(s.getTimestamp()); + // the until date should be greater than (denoted by a compareTo value + // being greater than 0 + assert date.compareTo(statementTimestamp) >= 0; + } + } + + public void testQueryByAscending() throws java.net.URISyntaxException, + java.io.IOException, ParseException { + StatementClient _client = new StatementClient(LRS_URI, USERNAME, + PASSWORD); + + StatementResult result = _client.limitResults(10).ascending(true) + .getStatements(); + assertFalse(result.getStatements().isEmpty()); + for (int i=0; i