/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.ims.lti.ui;
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import org.imsglobal.basiclti.XMLMap;
import org.imsglobal.pox.IMSPOXRequest;
import org.olat.basesecurity.BaseSecurity;
import org.olat.core.CoreSpringFactory;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.StringMediaResource;
import org.olat.core.id.Identity;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.SessionInfo;
import org.olat.core.util.UserSession;
import org.olat.core.util.session.UserSessionManager;
import org.olat.ims.lti.LTIManager;
import org.olat.resource.OLATResource;
/**
*
* Initial date: 13.05.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class OutcomeMapper implements Mapper, Serializable {
private static final long serialVersionUID = 7954337449619783210L;
private static final OLog log = Tracing.createLoggerFor(OutcomeMapper.class);
private static final String READ_RESULT_REQUEST = "readResultRequest";
private static final String DELETE_RESULT_REQUEST = "deleteResultRequest";
private static final String REPLACE_RESULT_REQUEST = "replaceResultRequest";
private String sourcedId;
private Identity identity;
private Long identityKey;
private OLATResource resource;
private String resSubPath;
private String oauth_consumer_key;
private String oauth_secret;
public OutcomeMapper() {
//
}
public OutcomeMapper(Identity identity, OLATResource resource, String resSubPath,
String oauth_consumer_key, String oauth_secret, String sourcedId) {
this.sourcedId = sourcedId;
this.oauth_consumer_key = oauth_consumer_key;
this.oauth_secret = oauth_secret;
this.identity = identity;
this.identityKey = identity.getKey();
this.resource = resource;
this.resSubPath = resSubPath;
}
@Override
public MediaResource handle(String relPath, HttpServletRequest request) {
reconnectUserSession(request);
String contentType = request.getContentType();
log.audit("LTI outcome for: " + identityKey);
// test on equals of content type, done the same way later on in IMSPOXRequest code
if (contentType != null && contentType.equals("application/xml") ) {
String xmlResponse = doPostXml(request);
return createMediaResource(xmlResponse, "application/xml");
}
return createMediaResource("Outcome service error: wrong content type. Must match 'application/xml' but was '" + (contentType == null ? "NULL" : contentType) + "'", "text/plain");
}
public Identity getIdentity() {
return identity;
}
public String getSourcedId() {
return sourcedId;
}
protected void reconnectUserSession(HttpServletRequest request) {
if(identity == null) {
identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityByKey(identityKey);
}
UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request);
if(usess == null) {
usess = new UserSession();
}
if(usess.getSessionInfo() == null) {
usess.setSessionInfo(new SessionInfo(identityKey, identity.getName(), request.getSession(true)));
}
if(usess.getIdentityEnvironment() == null || usess.getIdentity() == null) {
usess.setIdentity(identity);
}
}
private MediaResource createMediaResource(String body, String mimeType) {
StringMediaResource mediares = new StringMediaResource();
mediares.setData(body);
mediares.setContentType(mimeType);
mediares.setEncoding("UTF-8");
return mediares;
}
private String doPostXml(HttpServletRequest request) {
IMSPOXRequest pox = new IMSPOXRequest(oauth_consumer_key, oauth_secret, request);
if(!pox.valid) {
log.error("LTI outcome, OAuth verification failed: " + pox.errorMessage);
return pox.getResponseFailure("OAuth verification failed", null);
}
String lti_message_type = pox.getOperation();
Map<String,String> body = pox.getBodyMap();
String reqSourceId = body.get("/resultRecord/sourcedGUID/sourcedId");
if(!sourcedId.equals(reqSourceId)) {
log.error("LTI outcome sourcedId doesn't match: " + reqSourceId);
}
if(REPLACE_RESULT_REQUEST.equals(lti_message_type)) {
String scoreString = body.get("/resultRecord/result/resultScore/textString");
if(doUpdateResult(Float.parseFloat(scoreString))) {
Map<String,Object> theMap = new TreeMap<String,Object>();
theMap.put("/replaceResultRequest", "");
String theXml = XMLMap.getXMLFragment(theMap, true);
if (log.isDebug()) {
log.debug("replace-result message successfull with score::" + scoreString);
}
return pox.getResponseSuccess("Update result",theXml);
} else {
if (log.isDebug()) {
log.debug("replace-result message failed with score::" + scoreString);
}
return pox.getResponseFailure("Update result failed", null);
}
} else if(DELETE_RESULT_REQUEST.equals(lti_message_type)) {
if(doDeleteResult()) {
Map<String,Object> theMap = new TreeMap<String,Object>();
theMap.put("/deleteResultRequest", "");
String theXml = XMLMap.getXMLFragment(theMap, true);
if (log.isDebug()) {
log.debug("delete-result message successfull");
}
return pox.getResponseSuccess("Result deleted",theXml);
} else {
if (log.isDebug()) {
log.debug("delete-result message failed");
}
return pox.getResponseFailure("Delete result failed", null);
}
} else if (READ_RESULT_REQUEST.equals(lti_message_type)) {
return doReadResult(pox);
}
return pox.getResponseFailure("Not implemented", null);
}
protected String doReadResult(IMSPOXRequest pox) {
return pox.getResponseFailure("Not implemented", null);
}
protected boolean doUpdateResult(Float score) {
String outcomeValue = score == null ? null : score.toString();
saveOutcome(REPLACE_RESULT_REQUEST, "/resultRecord/result/resultScore/textString", outcomeValue);
return true;
}
protected boolean doDeleteResult() {
saveOutcome(DELETE_RESULT_REQUEST, "/resultRecord/result/resultScore/textString", null);
return true;
}
private void saveOutcome(String action, String outcomeKey, String outcomeValue) {
CoreSpringFactory.getImpl(LTIManager.class).createOutcome(identity, resource, resSubPath, action, outcomeKey, outcomeValue);
}
}