Playr:ApiExamples

From QTITools Wiki

Jump to: navigation, search

Contents

[edit] Introduction

This page describes demonstrates how playr can be integrated into other projects/systems.

[edit] Support files

  • R2Q2 support files (Javascript & applets): R2Q2_support.zip (see comments at the bottom of index.jsp, below to see how this can be used)

[edit] Java/jsp integration

We have written a sample web-application that shows how to integrate playr using the web api into a java application. The Apache HttpComponents HttpClient library is used to provide the communication layer between the playr and custom webapp. The sample code can be used with the online playr (http://playr.qtitools.org), or with your own playr install. If you have your own install, you can create custom rendering templates to reduce the amount of string-replacement that needs to be done & also make the assessments render just as you would like.

Note: if you use this sample code with the 'default (xhtml)' template, the playr and JISC images that are part of the template will not load as they will point to your webapp, rather than the playr. This is why you should customise your own templates.

To get started, either browse the code below or download the war file, or maven project:

[edit] index.jsp

This is the code for the main page. It mediates content between your webapp and playr:

<%@page language="java"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.io.File"%>
<%@page import="java.io.IOException"%>
<%@page import="java.util.List"%>
<%@page import="java.util.Map"%>
<%@page import="org.apache.commons.httpclient.HttpClient"%>
<%@page import="org.apache.commons.httpclient.HttpException"%>
<%@page import="org.apache.commons.httpclient.HttpMethodBase"%>
<%@page import="org.apache.commons.httpclient.NameValuePair"%>
<%@page import="org.apache.commons.httpclient.methods.GetMethod"%>

<%@page import="org.apache.commons.httpclient.methods.PostMethod"%>
<%@page import="org.apache.commons.httpclient.methods.multipart.FilePart"%>
<%@page import="org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity"%>
<%@page import="org.apache.commons.httpclient.methods.multipart.Part"%>
<%@page import="org.apache.commons.httpclient.methods.multipart.StringPart"%>
<%
		/*
		 * This is the location of the playr webapp that we'll use
		 * i.e. it might be http://localhost:8080/playr on a default
		 * tomcat install
		 */
		String playr_server = "http://playr.qtitools.org";
		String playr_port = "80";
		String path_to_playr = "";
		//String playr_server = "http://localhost";
		//String playr_port = "8080";
		//String path_to_playr = "playr";

		String playr_url = playr_server+":"+playr_port+"/"+path_to_playr;
		
		//media.jsp will get the playr url from here...
		session.setAttribute("playr_url", playr_url);
		
		/*
		 * This is the location of the content package we'll use
		 */
		String content = application.getRealPath("Archive.zip");

		//Create a new HttpClient
		HttpClient client = new HttpClient();
		
		//get the session variable that contains our playr session id
		String playr_id = (String)session.getAttribute("playr_id");
		
		//the string we'll save the playr response to
		String xhtml = "";
		
		//if the playr session didn't exist then the assessment hasn't been started yet
		if (playr_id == null) {
			//create a new playr session and save the session id (GET /api/newSession)
			GetMethod get = new GetMethod(playr_url+"/api/newSession");
			client.executeMethod(get);
			playr_id = get.getResponseBodyAsString().trim();
	        session.setAttribute("playr_id", playr_id);
			get.releaseConnection();
	    	
			//initialise the session with the content package (POST [multpart] /api/init)
			File f = new File(content);
			PostMethod filePost = new PostMethod(playr_url+"/api/init;jsessionid="+playr_id);
			Part[] parts = {
				new StringPart("view", "candidate"),		//the qti view that the renderer should use
				new StringPart("renderer", "default (xhtml)"),//the name of the renderer to use
				new FilePart(f.getName(), f)
			};
			filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
			client.executeMethod(filePost); 
			
			xhtml = filePost.getResponseBodyAsString(); //the first rendered page is the response body
			filePost.releaseConnection();
		} else {
			//subsequent rendering-responding (POST /api/play)
			PostMethod post = new PostMethod(playr_url+"/api/play;jsessionid="+playr_id);
			//this code, below equates to response munging... we are basically copying all the values
			//posted to this page to a set of values to post to the playr page. If your application
			//adds any extra variables, it is important to remove them here...
			Map<String, Object> map = request.getParameterMap();
	        List<NameValuePair> data = new ArrayList<NameValuePair>();
			for (String o : map.keySet()) {
				for (String s : request.getParameterValues(o)) {
					NameValuePair nvp = new NameValuePair(o, s);
					data.add(nvp);
				}
			}
	        post.setRequestBody(data.toArray(new NameValuePair[data.size()]));
			client.executeMethod(post);
			
			//the next rendered page is the response...
			xhtml = post.getResponseBodyAsString();
			post.releaseConnection();
			
			//we might want to get the QTI report after each response, perhaps to save to a database
			//or log somewhere. You can get the report at ANY time, so long as the session has been
			//initialised and it hasn't expired...
			GetMethod get = new GetMethod(playr_url+"/api/report;jsessionid="+playr_id);
			client.executeMethod(get);
			String qti_report = get.getResponseBodyAsString();
			get.releaseConnection();
		}
		
		//it is a good idea to close the playr session if the test is complete
		//Note; once this is done, you wont be able to access the report, etc...
		GetMethod get = new GetMethod(playr_url+"/api/introspect/isCompleted;jsessionid="+playr_id);
		client.executeMethod(get);
		Boolean isCompleted = Boolean.valueOf(get.getResponseBodyAsString().trim());
		get.releaseConnection();
		if (isCompleted) {
			//calling GET /api/closeSession will delete all the server-side objects pertaining
			//to this candidates particular playr session
			get = new GetMethod(playr_url+"/api/closeSession;jsessionid="+playr_id);
			client.executeMethod(get);
			get.releaseConnection();
			session.removeAttribute("playr_id");
		}
		
		/*
		 * the pieces below correspond to the html-munging stage
		 */
		//the following changes the generated forms action to the this jsp page.
		//If you have access to your own playr server, you should create a new
		//new renderer template and set the correct action in that template rather
		//than doing this!!
		xhtml = xhtml.replaceAll("asdel.jsp", "index.jsp"); //this works for the default (xhtml) template, but not necessarily for others!!

		//You need to provide a proxy for hosting any media in the content package. In this case, we
		//have a local jsp page, called media.jsp which does this. Playr and r2q2 generate paths in the 
		//xhtml which need to be replaced as follows, to change any images/media to point to our media.jsp
		//rather than the playr one:
		xhtml = xhtml.replaceAll("../../*"+path_to_playr+"/media.jsp;jsessionid="+playr_id , request.getContextPath()+"/media.jsp");
		xhtml = xhtml.replaceAll("/*"+path_to_playr+"/media.jsp;jsessionid="+playr_id , request.getContextPath()+"/media.jsp");
		//(NOTE: in the future, we'll make playr do this for you...)

		//if you are running r2q2 on a different domain to this page, then none of the applets
		//will work correctly due to javascript security violations. In order to circumvent this,
		//you need to install the r2q2_support folder in the same place as this page (so that it
		//can be accessed relatively), and re-write the r2q2 generated applet codebase...
		xhtml = xhtml.replaceAll("codebase='.*/r2q2/content/'", "codebase='r2q2_support/'");
		//also, if you have access to the playr template, you should change the r2q2 javascript includes
		//to point at r2q2_support/Jscript rather than the javascript files on your r2q2 server. If you
		//can't or don't want to change the template, you can do something like this (works for the default (xhtml) template):
		xhtml = xhtml.replaceAll("/r2q2/Jscript/", "r2q2_support/Jscript/");

		//finally, print out the xhtml
		out.println(xhtml);
%>

[edit] media.jsp

This file proxies media between playr and your webapp. Security considerations mean that media has to be handled in this way...

<%@page language="java"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.io.File"%>
<%@page import="java.io.IOException"%>
<%@page import="java.util.List"%>
<%@page import="java.util.Map"%>
<%@page import="java.io.*"%>
<%@page import="org.apache.commons.httpclient.HttpClient"%>
<%@page import="org.apache.commons.httpclient.HttpException"%>
<%@page import="org.apache.commons.httpclient.HttpMethodBase"%>
<%@page import="org.apache.commons.httpclient.NameValuePair"%>
<%@page import="org.apache.commons.httpclient.methods.GetMethod"%>
<%@page import="org.apache.commons.httpclient.Header"%>
<%@page import="org.apache.commons.httpclient.HeaderElement"%>

<%@page import="java.net.*"%>
<%@page import="java.net.*"%>
<%
		/* This file proxies requests for the media to the playr application */
		//basically it just forwards the request to playr and echos back the response
		
		String playr_url = (String)session.getAttribute("playr_url");
		
		//Create a new HttpClient
		HttpClient client = new HttpClient();
		
		//get the session variable that contains our playr session id
		String playr_id = (String)session.getAttribute("playr_id");
		
		if (playr_id != null) {
			//just get the media from playr's media.jsp
			GetMethod get = new GetMethod(playr_url+"/media.jsp;jsessionid="+playr_id);
			get.setQueryString("m="+request.getParameter("m")); //the important parameter is "m"
			client.executeMethod(get);
			
			//it is important to set the correct mime-type!
			Header h = get.getResponseHeader("Content-type");
			HeaderElement [] he = h.getElements();
			response.setContentType(he[0].getName());
			
			//this just copies the input to output
			InputStream is = get.getResponseBodyAsStream();
			OutputStream os = response.getOutputStream();

			int chunkSize = 4096;
			int count;
			byte[] b = new byte[chunkSize];

			while( ( count = is.read( b, 0, chunkSize ) ) > 0 )
				os.write(b,0,count);

			is.close();
			os.close();
		}
%>


[edit] Related Links

get rid of cellulite

Personal tools