use of uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder in project OpenOLAT by OpenOLAT.
the class UnkownItemEditorController method createNewItemSessionStateAndController.
private ItemSessionController createNewItemSessionStateAndController() {
/* Resolve the underlying JQTI+ object */
final ItemProcessingMap itemProcessingMap = new ItemProcessingInitializer(resolvedAssessmentItem, true).initialize();
/* Create fresh state for session */
final ItemSessionState itemSessionState = new ItemSessionState();
final ItemSessionControllerSettings itemSessionControllerSettings = new ItemSessionControllerSettings();
itemSessionControllerSettings.setTemplateProcessingLimit(25);
itemSessionControllerSettings.setMaxAttempts(10);
/* Create controller and wire up notification recorder */
final ItemSessionController sessionController = new ItemSessionController(qtiService.jqtiExtensionManager(), itemSessionControllerSettings, itemProcessingMap, itemSessionState);
sessionController.addNotificationListener(new NotificationRecorder(NotificationLevel.ERROR));
Long randomSeed = new Random().nextLong();
sessionController.setRandomSeed(randomSeed);
sessionController.initialize(new Date());
sessionController.performTemplateProcessing(new Date());
return sessionController;
}
use of uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder in project openolat by klemens.
the class AssessmentItemDisplayController method handleResponses.
public void handleResponses(UserRequest ureq, Map<Identifier, ResponseInput> stringResponseMap, Map<Identifier, ResponseInput> fileResponseMap, String candidateComment) {
/* Retrieve current JQTI state and set up JQTI controller */
NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO);
ItemSessionState itemSessionState = itemSessionController.getItemSessionState();
/* Make sure an attempt is allowed */
if (itemSessionState.isEnded()) {
candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.RESPONSES_NOT_EXPECTED, null);
logError("RESPONSES_NOT_EXPECTED", null);
return;
}
/* Build response map in required format for JQTI+.
* NB: The following doesn't test for duplicate keys in the two maps. I'm not sure
* it's worth the effort.
*/
final Map<Identifier, ResponseData> responseDataMap = new HashMap<>();
// final Map<Identifier, CandidateFileSubmission> fileSubmissionMap = new HashMap<>();
final Map<Identifier, AssessmentResponse> assessmentResponseDataMap = new HashMap<>();
if (stringResponseMap != null) {
for (final Entry<Identifier, ResponseInput> stringResponseEntry : stringResponseMap.entrySet()) {
Identifier identifier = stringResponseEntry.getKey();
ResponseInput responseData = stringResponseEntry.getValue();
if (responseData instanceof StringInput) {
responseDataMap.put(identifier, new StringResponseData(((StringInput) responseData).getResponseData()));
} else if (responseData instanceof Base64Input) {
// TODO
} else if (responseData instanceof FileInput) {
}
}
}
if (fileResponseMap != null) {
for (final Entry<Identifier, ResponseInput> fileResponseEntry : fileResponseMap.entrySet()) {
final Identifier identifier = fileResponseEntry.getKey();
final FileInput multipartFile = (FileInput) fileResponseEntry.getValue();
if (!multipartFile.isEmpty()) {
// final CandidateFileSubmission fileSubmission = candidateUploadService.importFileSubmission(candidateSession, multipartFile);
File storedFile = qtiService.importFileSubmission(candidateSession, multipartFile.getMultipartFileInfos());
final FileResponseData fileResponseData = new FileResponseData(storedFile, multipartFile.getContentType(), multipartFile.getFileName());
responseDataMap.put(identifier, fileResponseData);
assessmentResponseDataMap.put(identifier, new AssessmentResponseData(identifier, fileResponseData));
// fileSubmissionMap.put(identifier, fileSubmission);
}
}
}
/* Submit comment (if provided)
* NB: Do this first in case next actions end the item session.
*/
final Date timestamp = ureq.getRequestTimestamp();
if (candidateComment != null) {
try {
itemSessionController.setCandidateComment(timestamp, candidateComment);
} catch (final QtiCandidateStateException e) {
candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANDIDATE_COMMENT_FORBIDDEN, e);
logError("CANDIDATE_COMMENT_FORBIDDEN", null);
return;
} catch (final RuntimeException e) {
logError("", e);
// handleExplosion(e, candidateSession);
return;
}
}
/* Attempt to bind responses */
boolean allResponsesValid = false, allResponsesBound = false;
try {
itemSessionController.bindResponses(timestamp, responseDataMap);
/* Note any responses that failed to bind */
final Set<Identifier> badResponseIdentifiers = itemSessionState.getUnboundResponseIdentifiers();
allResponsesBound = badResponseIdentifiers.isEmpty();
/* Now validate the responses according to any constraints specified by the interactions */
if (allResponsesBound) {
final Set<Identifier> invalidResponseIdentifiers = itemSessionState.getInvalidResponseIdentifiers();
allResponsesValid = invalidResponseIdentifiers.isEmpty();
}
/* (We commit responses immediately here) */
itemSessionController.commitResponses(timestamp);
/* Invoke response processing (only if responses are valid) */
if (allResponsesValid) {
itemSessionController.performResponseProcessing(timestamp);
}
} catch (final QtiCandidateStateException e) {
candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.RESPONSES_NOT_EXPECTED, null);
logError("RESPONSES_NOT_EXPECTED", e);
return;
} catch (final RuntimeException e) {
logError("", e);
// handleExplosion(e, candidateSession);
return;
}
/* Record resulting attempt and event */
final CandidateItemEventType eventType = allResponsesBound ? (allResponsesValid ? CandidateItemEventType.ATTEMPT_VALID : CandidateItemEventType.RESPONSE_INVALID) : CandidateItemEventType.RESPONSE_BAD;
final CandidateEvent candidateEvent = qtiService.recordCandidateItemEvent(candidateSession, null, entry, eventType, itemSessionState, notificationRecorder);
candidateAuditLogger.logCandidateEvent(candidateEvent, assessmentResponseDataMap);
lastEvent = candidateEvent;
/* Record current result state, or finish session */
updateSessionFinishedStatus(ureq);
}
use of uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder in project openolat by klemens.
the class AssessmentTestDisplayController method processExitTestAfterTimeLimit.
private void processExitTestAfterTimeLimit(UserRequest ureq) {
synchronized (testSessionController) {
// make sure the ajax call and a user click don't close both the session
NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO);
TestSessionState testSessionState = testSessionController.getTestSessionState();
if (testSessionState.isEnded() || testSessionState.isExited())
return;
// close duration
testSessionController.touchDurations(currentRequestTimestamp);
final Date requestTimestamp = ureq.getRequestTimestamp();
testSessionController.exitTestIncomplete(requestTimestamp);
candidateSession.setTerminationTime(requestTimestamp);
// Record current result state
final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(requestTimestamp, testSessionState, true);
candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, requestTimestamp, getDigitalSignatureOptions(), getIdentity());
qtiWorksCtrl.updateStatusAndResults(ureq);
/* Record and log event */
final CandidateEvent candidateTestEvent = qtiService.recordCandidateTestEvent(candidateSession, testEntry, entry, CandidateTestEventType.EXIT_DUE_TIME_LIMIT, testSessionState, notificationRecorder);
candidateAuditLogger.logCandidateEvent(candidateTestEvent);
this.lastEvent = candidateTestEvent;
}
doExitTest(ureq);
}
use of uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder in project openolat by klemens.
the class AssessmentTestDisplayController method processSelectItem.
private void processSelectItem(UserRequest ureq, String key) {
if (checkConcurrentExit(ureq)) {
return;
}
TestPlanNodeKey nodeKey = TestPlanNodeKey.fromString(key);
Date requestTimestamp = ureq.getRequestTimestamp();
TestPlanNode selectedNode = testSessionController.selectItemNonlinear(requestTimestamp, nodeKey);
/* Record and log event */
TestPlanNodeKey selectedNodeKey = (selectedNode == null ? null : selectedNode.getKey());
NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO);
TestSessionState testSessionState = testSessionController.getTestSessionState();
CandidateEvent candidateEvent = qtiService.recordCandidateTestEvent(candidateSession, testEntry, entry, CandidateTestEventType.SELECT_MENU, null, selectedNodeKey, testSessionState, notificationRecorder);
candidateAuditLogger.logCandidateEvent(candidateEvent);
}
use of uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder in project openolat by klemens.
the class AssessmentTestDisplayController method enterSession.
// private CandidateSession enterCandidateSession(final CandidateSession candidateSession)
private TestSessionController enterSession(UserRequest ureq) {
/* Set up listener to record any notifications */
final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO);
/* Create fresh JQTI+ state & controller for it */
testSessionController = createNewTestSessionStateAndController(notificationRecorder);
if (testSessionController == null) {
return null;
}
/* Initialise test state and enter test */
final TestSessionState testSessionState = testSessionController.getTestSessionState();
final Date timestamp = ureq.getRequestTimestamp();
try {
testSessionController.initialize(timestamp);
final int testPartCount = testSessionController.enterTest(timestamp);
if (testPartCount == 1) {
/* If there is only testPart, then enter this (if possible).
* (Note that this may cause the test to exit immediately if there is a failed
* preCondition on this part.)
*/
testSessionController.enterNextAvailableTestPart(timestamp);
} else {
/* Don't enter first testPart yet - we shall tell candidate that
* there are multiple parts and let them enter manually.
*/
}
} catch (final RuntimeException e) {
logError("", e);
return null;
}
/* Record and log event */
final CandidateEvent candidateEvent = qtiService.recordCandidateTestEvent(candidateSession, testEntry, entry, CandidateTestEventType.ENTER_TEST, testSessionState, notificationRecorder);
candidateAuditLogger.logCandidateEvent(candidateEvent);
this.lastEvent = candidateEvent;
boolean ended = testSessionState.isEnded();
/* Record current result state */
final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(timestamp, testSessionState, ended);
/* Handle immediate end of test session */
if (ended) {
candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, timestamp, getDigitalSignatureOptions(), getIdentity());
} else {
TestPart currentTestPart = testSessionController.getCurrentTestPart();
if (currentTestPart != null && currentTestPart.getNavigationMode() == NavigationMode.NONLINEAR) {
// go to the first assessment item
if (testSessionController.hasFollowingNonLinearItem()) {
testSessionController.selectFollowingItemNonLinear(currentRequestTimestamp);
}
}
}
return testSessionController;
}
Aggregations