jxapi - Experience API Java library

Build Status

Note: To build jxapi jar with all included dependencies simply run mvn package

If you're just interested in using the library, the jar can be found here. We will be discontinuing the releases here on GitHub.

Installation

Either clone:

git clone https://github.com/adlnet/jxapi

run mvn package

or

Download directly from the Central Repository

Use

StatementClient

import gov.adlnet.xapi.client.StatementClient;

To instantiate a new StatementClient you need the URL to an LRS, and a username/password combo that works for HTTP BasicAuth

StatementClient client = new StatementClient(url, username, password);
//URL example: https://lrs.adlnet.gov/xAPI

This has the possiblitiy of throwing a MalformedURLException if an invalid URL is passed it.

Creating a Statement

import gov.adlnet.xapi.model.*;

This library has some overloaded model constructors to simplify building common parts of a statement.

// create an activity with just an id
Activity activity = new Activity("http://activity.com");
System.out.println("Activity");
System.out.println( "\t" +  activity  );

// prints...
// Activity
//  http://activity.com

// create an agent with name and mbox
Agent agent = new Agent("tommy", "mailto:[email protected]");
System.out.println("Agent - name & mbox");
System.out.println("\t" + agent);

// prints...
// Agent - name & mbox
//  tommy

// create an agent with just an mbox
Agent agent = new Agent(null, "mailto:[email protected]")
System.out.println("Agent - mbox");
System.out.println("\t" + agent);

// prints...
// Agent - mbox
//  mailto:[email protected]

// create an agent with openid
Agent agent = new Agent(null, new URI("http://tom-is-me")));
System.out.println("Agent - openid");
System.out.println("\t" + agent);

// prints...
// Agent - openid
//  http://tom-is-me

// create an agent with an account
Agent agent = new Agent("", new Account("joe", "http://joe.com"));
System.out.println("Agent - account");
System.out.println("\t" + agent);

// prints...
// Agent - account
//  joe (http://joe.com)

// use an ADL verb
System.out.println("ADL verb");
System.out.println("\t" + Verbs.answered());

// prints...
// ADL verb
//  answered

// create a verb
Verb verb = new Verb("http://my.verb/didsomething");
System.out.println("my verb");
System.out.println("\t" + verb);

// prints...
// my verb
//  http://my.verb/didsomething

// create a verb with display 
HashMap<String, String> disp = new HashMap<String, String>();
disp.put("fr", "le ran");
disp.put("en-US", "ran");
Verb verb = new Verb("http://my.verb/ran", disp);
System.out.println("my ran verb");
System.out.println("\t" + verb);

// prints...
// my ran verb
//  ran

// create a basic statement
System.out.println("Statement ");
System.out.println("\t" + new Statement(new Agent("tom", "mailto:[email protected]"), 
                                        new Verb("http://verb.com/did", getVerbDisp()),
                                        new Activity("act:id")));

// prints...
// Statement 
//  7fdbc0cc-aef8-47d6-97ad-b1929afc34b5: tom did act:id

Publishing a Statement

To publish a statement you'll need a Verb (There is a predefined list of ADL verbs available in gov.adlnet.xapi.model.Verbs class), an Actor who completed the activity the statement describes, and the Statement object, which can be an Activity, a SubStatement, or a StatementRef

StatementClient client = new StatementClient(LRS_URI, USERNAME,
PASSWORD);
Statement statement = new Statement();
Agent agent = new Agent();
Verb verb = Verbs.experienced();
agent.setMbox("mailto:[email protected]");
agent.setName("Tester McTesterson");
statement.setActor(agent);
statement.setId(UUID.randomUUID().toString());
statement.setVerb(verb);
Activity a = new Activity();
a.setId("http://example.com");
statement.setObject(a);
ActivityDefinition ad = new ActivityDefinition();
ad.setChoices(new ArrayList<InteractionComponent>());
InteractionComponent ic = new InteractionComponent();
ic.setId("http://example.com");
ic.setDescription(new HashMap<String, String>());
ic.getDescription().put("en-US", "test");
ad.getChoices().add(ic);
ad.setInteractionType("choice");
ad.setMoreInfo("http://example.com");
a.setDefinition(ad);
String publishedId = client.postStatement(statement);

Publishing a Statement with an Attachment

Publishing a statement with an attachment follows the steps for publishing a statement seen above with the addition of adding an attachment. An attachment require a content type, URI usage type, and display. A file URL and a description can optionally be added.

Agent a = new Agent();
a.setMbox(mbox);
Verb v = new Verb("http://example.com/tested");
Activity act = new Activity(activity_id);
Statement statement = new Statement(a, v, act);

ActivityDefinition ad = new ActivityDefinition();
ad.setChoices(new ArrayList<InteractionComponent>());
InteractionComponent ic = new InteractionComponent();
ic.setId("http://example.com");
ic.setDescription(new HashMap<String, String>());
ic.getDescription().put("en-US", "test");
ad.getChoices().add(ic);
ad.setInteractionType("choice");
ArrayList<String> crp = new ArrayList<String>();
crp.add("http://example.com");
ad.setCorrectResponsesPattern(crp);
ad.setMoreInfo("http://example.com");
act.setDefinition(ad);

Attachment att = new Attachment();
HashMap<String, String> display = new HashMap<String, String>();
display.put("en-US", "Test Display.");
att.setDisplay(display);

HashMap<String, String> description = new HashMap<String, String>();
description.put("en-US", "Test Description.");
att.setDescription(description);

URI usageType = new URI("http://example.com/test/usage");
att.setUsageType(usageType);

String attachment = "This is a text/plain test.";
String contentType = "text/plain";
byte[] arr = att.addAttachment(attachment, contentType);

ArrayList<Attachment> attList = new ArrayList<Attachment>();
attList.add(att);
statement.setAttachments(attList);

ArrayList<byte[]> attachedData = new ArrayList<byte[]>();
attachedData.add(arr);
String publishedId = sc.postStatementWithAttachments(statement, contentType, attachedData);

A non text/plain example of an attachment.

Attachment att = new Attachment();
HashMap<String, String> display = new HashMap<String, String>();
display.put("en-US", "Test Display.");
att.setDisplay(display);

String attachment = "../jxapi/src/test/java/config/example.png";
String contentType = "image/png";
byte[] arr = att.addAttachment(attachment, contentType);

ArrayList<Attachment> attList = new ArrayList<Attachment>();
attList = new ArrayList<Attachment>();
attList.add(att);
statement.setAttachments(attList);

ArrayList<byte[]> attachedData = new ArrayList<byte[]>();
attachedData.add(arr);
String publishedId = sc.postStatementWithAttachments(statement, contentType, attachedData);

Querying an LRS

You can get all the statements from an LRS by calling the getStatements method on the client

This will return a StatementResult object, which will have a list of all returned statements along with a string needed to get the next page of results, the code below demonstrates how to get the first page of results.

StatementResult results = client.getStatements()

To get the next page of results call getStatements with the value returned from getMore

StatementResult nextPage = client.getStatements(previousPage.getMore());

To query an LRS by verb you add a call to filterByVerb to the above queries

StatementResult results = client.filterByVerb(Verbs.experienced()).getStatements();

Subsequent pages can then be queried as the above example.

There are a number of filters available that function similiarly to filterByVerb, they are

filterByVerb
filterByActor
filterByActivity
filterByRegistration
filterBySince
filterByUntil

In addition to these preset filters, you can add non-standard filters to the statements query by using addFilter. For example:

client.addFilter('context.extensions.yourExtension', 'customExtensionValue').getStatements();

These filters can be chained together to created more complex queries, such as

StatementResult results = client.filterByVerb(verb).filterByActivity(activity).getStatements();

You can also specify what data is brought back from the LRS, by calling the include* methods, the available methods are

includeRelatedActivities
includeRelatedAgents
includeAttachments

To bring back only statement ids from the LRS, include the ids method call when chaining filters/include methods

Getting statements with attachments.

AttachmentResult attachmntResult = sc.getStatementsWithAttachments();
Statement s = attachmntResult.getXapiStatements().getStatements().get(0);

//Get the attached file.
byte[] actualArray = attachmntResult.getAttachment().get(sha2).getAttachment().get(i);

Getting a statement with a statement ID.

AttachmentResult attachmntResult = sc.getStatementWithAttachments(statementId);

Note: Before testing, please change the config properties in test/config to your own endpoint and credentials.

Contributing to the project

We welcome contributions to this project. Fork this repository, make changes, and submit pull requests. If you're not comfortable with editing the code, please submit an issue and we'll be happy to address it.

License

Copyright ©2016 Advanced Distributed Learning

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

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.