Search in sources :

Example 36 with NotificationRecorder

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;
}
Also used : ItemSessionControllerSettings(uk.ac.ed.ph.jqtiplus.running.ItemSessionControllerSettings) ItemProcessingMap(uk.ac.ed.ph.jqtiplus.state.ItemProcessingMap) Random(java.util.Random) ItemSessionState(uk.ac.ed.ph.jqtiplus.state.ItemSessionState) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) ItemProcessingInitializer(uk.ac.ed.ph.jqtiplus.running.ItemProcessingInitializer) ItemSessionController(uk.ac.ed.ph.jqtiplus.running.ItemSessionController) Date(java.util.Date)

Example 37 with NotificationRecorder

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);
}
Also used : QtiCandidateStateException(uk.ac.ed.ph.jqtiplus.exception.QtiCandidateStateException) CandidateItemEventType(org.olat.ims.qti21.model.audit.CandidateItemEventType) HashMap(java.util.HashMap) ItemSessionState(uk.ac.ed.ph.jqtiplus.state.ItemSessionState) FileResponseData(uk.ac.ed.ph.jqtiplus.types.FileResponseData) StringResponseData(uk.ac.ed.ph.jqtiplus.types.StringResponseData) AssessmentResponseData(org.olat.ims.qti21.model.audit.AssessmentResponseData) ResponseData(uk.ac.ed.ph.jqtiplus.types.ResponseData) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) FileInput(org.olat.ims.qti21.ui.ResponseInput.FileInput) AssessmentResponse(org.olat.ims.qti21.AssessmentResponse) Date(java.util.Date) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent) StringInput(org.olat.ims.qti21.ui.ResponseInput.StringInput) Identifier(uk.ac.ed.ph.jqtiplus.types.Identifier) StringResponseData(uk.ac.ed.ph.jqtiplus.types.StringResponseData) FileResponseData(uk.ac.ed.ph.jqtiplus.types.FileResponseData) Base64Input(org.olat.ims.qti21.ui.ResponseInput.Base64Input) File(java.io.File) AssessmentResponseData(org.olat.ims.qti21.model.audit.AssessmentResponseData)

Example 38 with NotificationRecorder

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);
}
Also used : TestSessionState(uk.ac.ed.ph.jqtiplus.state.TestSessionState) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) AssessmentResult(uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult) Date(java.util.Date) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent)

Example 39 with NotificationRecorder

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);
}
Also used : TestPlanNode(uk.ac.ed.ph.jqtiplus.state.TestPlanNode) TestSessionState(uk.ac.ed.ph.jqtiplus.state.TestSessionState) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) Date(java.util.Date) TestPlanNodeKey(uk.ac.ed.ph.jqtiplus.state.TestPlanNodeKey) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent)

Example 40 with NotificationRecorder

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;
}
Also used : OLATRuntimeException(org.olat.core.logging.OLATRuntimeException) TestSessionState(uk.ac.ed.ph.jqtiplus.state.TestSessionState) TestPart(uk.ac.ed.ph.jqtiplus.node.test.TestPart) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) AssessmentResult(uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult) Date(java.util.Date) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent)

Aggregations

NotificationRecorder (uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder)42 CandidateEvent (org.olat.ims.qti21.model.audit.CandidateEvent)36 Date (java.util.Date)34 TestSessionState (uk.ac.ed.ph.jqtiplus.state.TestSessionState)30 ItemSessionState (uk.ac.ed.ph.jqtiplus.state.ItemSessionState)20 OLATRuntimeException (org.olat.core.logging.OLATRuntimeException)18 QtiCandidateStateException (uk.ac.ed.ph.jqtiplus.exception.QtiCandidateStateException)17 AssessmentResult (uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult)16 TestPlanNode (uk.ac.ed.ph.jqtiplus.state.TestPlanNode)16 TestPlanNodeKey (uk.ac.ed.ph.jqtiplus.state.TestPlanNodeKey)16 ItemSessionController (uk.ac.ed.ph.jqtiplus.running.ItemSessionController)10 HashMap (java.util.HashMap)8 AssessmentResponse (org.olat.ims.qti21.AssessmentResponse)8 StringInput (org.olat.ims.qti21.ui.ResponseInput.StringInput)8 FileResponseData (uk.ac.ed.ph.jqtiplus.types.FileResponseData)8 Identifier (uk.ac.ed.ph.jqtiplus.types.Identifier)8 ResponseData (uk.ac.ed.ph.jqtiplus.types.ResponseData)8 StringResponseData (uk.ac.ed.ph.jqtiplus.types.StringResponseData)8 CandidateItemEventType (org.olat.ims.qti21.model.audit.CandidateItemEventType)6 CandidateTestEventType (org.olat.ims.qti21.model.audit.CandidateTestEventType)6