/**
* <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>
* BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de
* <p>
*/
package de.bps.onyx.plugin.wsserver;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.id.Identity;
import org.olat.core.id.IdentityEnvironment;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.FileUtils;
import org.olat.core.util.WebappHelper;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.course.assessment.AssessmentManager;
import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
import org.olat.course.nodes.AssessableCourseNode;
import org.olat.course.nodes.CourseNode;
import org.olat.course.run.scoring.ScoreEvaluation;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.course.run.userview.UserCourseEnvironmentImpl;
import org.olat.ims.qti.QTIResultManager;
import org.olat.ims.qti.QTIResultSet;
import org.olat.modules.assessment.model.AssessmentEntryStatus;
import de.bps.onyx.plugin.OnyxResultManager;
/**
* OLATCE-1322 Switched from AXIS2 based WebService to JAXWS / Annotations-based
* implementation for the ReturnWSService
*
* This WebService could be used by the web-onyx-player to save the results for
* qti2.1 tests in olat.
*
*
*/
@WebService(name = "RenderServices", serviceName = "ReturnWSService", targetNamespace = "http://test.plugin.bps.de/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class ReturnWSService {
private static final String NONEXISTING_RESULT = "The uniqueId does not reference a valid qti-result-set: ";
private static final String MSG_MISSING_RESULT = "Missing or empty result file-data";
private final static OLog log = Tracing.createLoggerFor(ReturnWSService.class);
private final static String FULLY_ASSESSED = "fullyassessed";
private final static String SUSPENDED = "attemptSuspended";
private static File errorFolder;
private static void init() {
try {
File tmp = new File(WebappHelper.getUserDataRoot());
tmp = new File(tmp, "resreportingErrorFiles");
if (!tmp.exists()) {
tmp.mkdir();
}
errorFolder = tmp;
} catch (NullPointerException npe) {
log.error("Unable to set errorFolder yet, try again later");
}
}
@WebMethod(operationName = "saveResult2")
public void saveResult(@WebParam(name = "uniqueId") String uniqueId, @WebParam(name = "resultFile") byte[] resultFile, @WebParam(name = "params") MapWrapper params)
throws Exception {
File temp = null;
try {
if (resultFile == null || resultFile.length < 1) {
log.error(MSG_MISSING_RESULT);
throw new IllegalArgumentException(MSG_MISSING_RESULT);
}
// file.createtempfile() is not correctly interpreted as an archive
// even if the isArchive() method says so
temp = new File(System.getProperty("java.io.tmpdir"), java.io.File.separatorChar + this.hashCode() + "_" + new Date().getTime() + ".zip");
FileOutputStream out = new FileOutputStream(temp);
out.write(resultFile);
out.flush();
out.close();
QTIResultSet qtiResultSet = OnyxResultManager.getResultSet(Long.parseLong(uniqueId));
if (qtiResultSet == null) {
log.error(NONEXISTING_RESULT + uniqueId);
throw new IllegalArgumentException(NONEXISTING_RESULT + uniqueId);
}
if (qtiResultSet.getOlatResource() == OnyxResultManager.IGNORE_PREVIEW_CASE) {
// delete the temp-result previews or calls from the
// learning-resource-tab
log.info("Delete resultset for preview-call: " + uniqueId);
QTIResultManager.getInstance().deleteResults(qtiResultSet);
DBFactory.getInstance().commitAndCloseSession();
} else {
boolean changed = false;
if (params != null) {
Map<String, String> parameterMap = params.getMap();
if (parameterMap != null) {
if (log.isDebug()) {
log.debug("Update properties for assessmentId : " + qtiResultSet.getAssessmentID());
}
boolean suspensionBlock = false;
for (String key : params.getMap().keySet()) {
// extract information if this result had been fully
// assessed
if (FULLY_ASSESSED.equalsIgnoreCase(key)) {
changed = true;
String accessedString = parameterMap.get(key);
if (accessedString != null && accessedString.length() > 0) {
Boolean accessed = Boolean.parseBoolean(accessedString);
qtiResultSet.setFullyAssessed(accessed);
} else {
log.error("Got accessed-parameter but it was empty : " + accessedString);
}
} else if (SUSPENDED.equals(key)) {
changed = true;
String suspensionString = parameterMap.get(key);
if (suspensionString != null && suspensionString.length() > 0) {
suspensionBlock = Boolean.parseBoolean(suspensionString);
qtiResultSet.setSuspended(suspensionBlock);
if (suspensionBlock) {
if (log.isDebug()) {
log.debug("Testrun had been suspended, will not update UserScoreEvaluation");
}
}
} else {
log.error("Got suspension-parameter but it was empty : " + suspensionString);
}
} else if (OnyxResultManager.SCORE.equalsIgnoreCase(key)) {
changed = true;
String scoreString = parameterMap.get(key);
if (scoreString != null && scoreString.length() > 0) {
Float score = Float.parseFloat(scoreString);
qtiResultSet.setScore(score);
} else {
log.error("Got score-parameter but it was empty : " + scoreString);
}
} else if (OnyxResultManager.PASS.equalsIgnoreCase(key)) {
changed = true;
String passedString = parameterMap.get(key);
if (passedString != null && passedString.length() > 0) {
Boolean passed = Boolean.parseBoolean(passedString);
qtiResultSet.setIsPassed(passed);
} else {
log.error("Got passed-parameter but it was empty : " + passedString);
}
} else {
if (log.isDebug()) {
log.debug("Got unhandled parameter: " + key + " with value " + parameterMap.get(key));
}
}
}
if (changed) {
DBFactory.getInstance().updateObject(qtiResultSet);
DBFactory.getInstance().commitAndCloseSession();
qtiResultSet = (QTIResultSet) DBFactory.getInstance().loadObject(qtiResultSet);
if (!suspensionBlock && OnyxResultManager.isLastTestTry(qtiResultSet)) {
Identity assessedIdentity = qtiResultSet.getIdentity();
Long resourceId = qtiResultSet.getOlatResource(); // this
// is
// the
// courseId
// and
// not
// the
// resourceId
// of
// the
// testResource
ICourse course = CourseFactory.loadCourse(resourceId);
CourseNode courseNode = course.getRunStructure().getNode(qtiResultSet.getOlatResourceDetail());
AssessmentManager am = course.getCourseEnvironment().getAssessmentManager();
// create an identenv with no roles, no
// attributes, no locale
IdentityEnvironment ienv = new IdentityEnvironment();
ienv.setIdentity(assessedIdentity);
UserCourseEnvironment userCourseEnvironment = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment());
AssessmentEntryStatus status = null;
if(qtiResultSet.getFullyAssessed() != null && qtiResultSet.getFullyAssessed().booleanValue()) {
status = AssessmentEntryStatus.done;
}
ScoreEvaluation scoreEvaluation = new ScoreEvaluation(qtiResultSet.getScore(), qtiResultSet.getIsPassed(),
status, Boolean.TRUE, qtiResultSet.getFullyAssessed(), qtiResultSet.getAssessmentID());
am.saveScoreEvaluation((AssessableCourseNode)courseNode, null, assessedIdentity, scoreEvaluation, userCourseEnvironment, false);
CoreSpringFactory.getImpl(AssessmentNotificationsHandler.class).markPublisherNews(assessedIdentity, resourceId);
}
} else {
if (log.isDebug()) {
log.debug("nothing new " + (changed) + " or suspended " + suspensionBlock);
}
}
}
} else {
if (log.isDebug()) {
log.debug("Found no parameters");
}
}
if (temp == null || temp.getAbsolutePath() == null) {
log.error("unauthorized request: saveResultLocal.getUniqueId()=" + uniqueId + " saveResultLocal.getResultLocalFile()=" + temp);
throw new java.lang.UnsupportedOperationException("unauthorized request, this event will be logged");
} else {
OnyxResultManager.persistOnyxResults(qtiResultSet, temp.getAbsolutePath());
}
}
// delete temp-file as last step, if an error occurred than this
// step is not reached and the file will be copied to the
// error-handling directory in the exception-handling
temp.delete();
} catch (FileNotFoundException e) {
log.error(e.getMessage(), e);
throw e;
} catch (IOException e) {
log.error(e.getMessage(), e);
throw e;
} catch (Exception e) {
log.error("Error while saving results.", e);
if (temp != null && temp.exists()) {
if (errorFolder == null) {
init();
}
try {
File outFile = new File(errorFolder, uniqueId + "_" + System.currentTimeMillis() + ".zip");
FileUtils.copyFileToFile(temp, outFile, false);
StringBuilder builder = new StringBuilder();
builder.append("Secured file to ").append(outFile.getAbsolutePath()).append(" uniqueId/assessmentId ").append(uniqueId).append(" parameters : ");
HashMap<String, String> parameterMap = params.getMap();
if (parameterMap != null) {
builder.append(parameterMap.toString());
}
log.info(builder.toString());
} catch (Exception subE) {
log.error("Unable to safe error-fallback for resultfile !", subE);
}
temp.delete();
} else {
log.warn("unable to save inexistend file");
}
throw e;
}
if (log.isDebug()) {
log.debug("leave ReturnWSService");
}
}
@WebMethod
public void saveResult(@WebParam(name = "uniqueId") String uniqueId, @WebParam(name = "resultFile") byte[] resultFile) throws Exception {
saveResult(uniqueId, resultFile, null);
}
@WebMethod
public void saveResultLocal(@WebParam(name = "uniqueId") String uniqueId, @WebParam(name = "resultLocalFile") String resultLocalFile) {
QTIResultSet qtiResultSet = OnyxResultManager.getResultSet(Long.parseLong(uniqueId));
if (resultLocalFile == null) {
log.error("unauthorized request: saveResultLocal.getUniqueId()=" + uniqueId + " saveResultLocal.getResultLocalFile()=" + resultLocalFile);
throw new java.lang.UnsupportedOperationException("unauthorized request, this event will be logged");
} else {
OnyxResultManager.persistOnyxResults(qtiResultSet, resultLocalFile);
}
return;
}
}