From 71ebb3a7db44a5f121b704fc1f37c676a16de6a2 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Fri, 2 Oct 2015 08:29:08 +0200 Subject: [PATCH] OO-1635: make the code more efficient, use cache for stylesheet and MathML... --- .../olat/course/nodes/IQTESTCourseNode.java | 2 +- .../iq/QTI21AssessmentRunController.java | 4 +- .../java/org/olat/ims/qti21/QTI21Service.java | 27 ++++ .../ims/qti21/manager/OnyxToQTIWorks.java | 34 ----- .../ims/qti21/manager/QTI21ServiceImpl.java | 102 ++++++++++----- .../handlers/QTI21AssessmentTestHandler.java | 6 +- .../ims/qti21/restapi/MathWebService.java | 6 +- .../ui/AssessmentItemDisplayController.java | 56 +++------ .../ui/AssessmentTestDisplayController.java | 119 +++++++----------- .../AssessmentObjectComponentRenderer.java | 6 +- .../AssessmentTestComponentRenderer.java | 7 +- 11 files changed, 183 insertions(+), 186 deletions(-) delete mode 100644 src/main/java/org/olat/ims/qti21/manager/OnyxToQTIWorks.java diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java index cd474f2ffda..c60c2ef5e4c 100644 --- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java +++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java @@ -437,7 +437,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements As AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); try { - am.saveScoreEvaluation(this, coachingIdentity, mySelf, scoreEvaluation, userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, scoreEvaluation, userCourseEnvironment, incrementAttempts); } catch(DBRuntimeException ex) { throw new KnownIssueException("DBRuntimeException - Row was updated or deleted...", 3570, ex); } diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java index 87fd076e5c5..172b3c92ae4 100644 --- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java +++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java @@ -282,8 +282,8 @@ public class QTI21AssessmentRunController extends BasicController implements Gen @Override public void updateOutcomes(Float score, Boolean pass) { - ScoreEvaluation sceval = new ScoreEvaluation(score, pass, Boolean.FALSE); - courseNode.updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), false); + //ScoreEvaluation sceval = new ScoreEvaluation(score, pass, Boolean.FALSE); + //courseNode.updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), false); } @Override diff --git a/src/main/java/org/olat/ims/qti21/QTI21Service.java b/src/main/java/org/olat/ims/qti21/QTI21Service.java index 5970e910f21..d0d60d7c5d6 100644 --- a/src/main/java/org/olat/ims/qti21/QTI21Service.java +++ b/src/main/java/org/olat/ims/qti21/QTI21Service.java @@ -34,12 +34,16 @@ import org.olat.modules.assessment.AssessmentEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; +import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult; import uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentObject; +import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; import uk.ac.ed.ph.jqtiplus.state.ItemSessionState; import uk.ac.ed.ph.jqtiplus.state.TestPlanNodeKey; import uk.ac.ed.ph.jqtiplus.state.TestSessionState; +import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetCache; +import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetManager; /** * @@ -49,6 +53,29 @@ import uk.ac.ed.ph.jqtiplus.state.TestSessionState; */ public interface QTI21Service { + /** + * New QTI serializer + * @return + */ + public QtiSerializer qtiSerializer(); + + /** + * The manager for custom extensions to QTI (MathExtensio ) + * @return + */ + public JqtiExtensionManager jqtiExtensionManager(); + + /** + * @return The cache for stylesheets used by MathML transformation + */ + public XsltStylesheetCache getXsltStylesheetCache(); + + /** + * @return The stylesheets manager used by MathML transformation + */ + public XsltStylesheetManager getXsltStylesheetManager(); + + public URI createAssessmentObjectUri(File resourceDirectory); public <E extends ResolvedAssessmentObject<?>> E loadAndResolveAssessmentObject(File resourceDirectory); diff --git a/src/main/java/org/olat/ims/qti21/manager/OnyxToQTIWorks.java b/src/main/java/org/olat/ims/qti21/manager/OnyxToQTIWorks.java deleted file mode 100644 index f5dc1e331bb..00000000000 --- a/src/main/java/org/olat/ims/qti21/manager/OnyxToQTIWorks.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * <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.qti21.manager; - -/** - * - * - * //TODO <rubricBlock><div></div></rubricBlock>: add a div - * //TODO <prompt><p></p></prompt>: remove the p's - * - * Initial date: 11.05.2015<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class OnyxToQTIWorks { - -} diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java index d761e4f3d5f..b89578b7712 100644 --- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java +++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java @@ -44,6 +44,8 @@ import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.FileUtils; +import org.olat.core.util.cache.CacheWrapper; +import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; import org.olat.ims.qti21.QTI21Constants; @@ -58,8 +60,9 @@ import org.olat.ims.qti21.ui.rendering.XmlUtilities; import org.olat.modules.assessment.AssessmentEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import org.w3c.dom.Document; @@ -88,8 +91,10 @@ import uk.ac.ed.ph.jqtiplus.value.NumberValue; import uk.ac.ed.ph.jqtiplus.value.RecordValue; import uk.ac.ed.ph.jqtiplus.value.SingleValue; import uk.ac.ed.ph.jqtiplus.value.Value; +import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ClassPathResourceLocator; import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltSerializationOptions; +import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetCache; import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetManager; import uk.ac.ed.ph.qtiworks.mathassess.GlueValueBinder; import uk.ac.ed.ph.qtiworks.mathassess.MathAssessConstants; @@ -102,7 +107,7 @@ import uk.ac.ed.ph.qtiworks.mathassess.MathAssessExtensionPackage; * */ @Service -public class QTI21ServiceImpl implements QTI21Service { +public class QTI21ServiceImpl implements QTI21Service, InitializingBean, DisposableBean { private static final OLog log = Tracing.createLoggerFor(QTI21ServiceImpl.class); @@ -114,53 +119,93 @@ public class QTI21ServiceImpl implements QTI21Service { private QTI21Storage storage; @Autowired private QTI21Module qtiModule; - + @Autowired + private CoordinatorManager coordinatorManager; + + private JqtiExtensionManager jqtiExtensionManager; + private XsltStylesheetManager xsltStylesheetManager; private InfinispanXsltStylesheetCache xsltStylesheetCache; + private CacheWrapper<File,ResolvedAssessmentObject<?>> assessmentTestsAndItemsCache; @Autowired public QTI21ServiceImpl(InfinispanXsltStylesheetCache xsltStylesheetCache) { this.xsltStylesheetCache = xsltStylesheetCache; } - - @Bean(initMethod="init", destroyMethod="destroy") - public JqtiExtensionManager jqtiExtensionManager() { - final List<JqtiExtensionPackage<?>> extensionPackages = new ArrayList<JqtiExtensionPackage<?>>(); + + @Override + public void afterPropertiesSet() throws Exception { + final List<JqtiExtensionPackage<?>> extensionPackages = new ArrayList<JqtiExtensionPackage<?>>(); /* Enable MathAssess extensions if requested */ if (qtiModule.isMathAssessExtensionEnabled()) { log.info("Enabling the MathAssess extensions"); extensionPackages.add(new MathAssessExtensionPackage(xsltStylesheetCache)); } + jqtiExtensionManager = new JqtiExtensionManager(extensionPackages); + xsltStylesheetManager = new XsltStylesheetManager(new ClassPathResourceLocator(), xsltStylesheetCache); + + jqtiExtensionManager.init(); + + assessmentTestsAndItemsCache = coordinatorManager.getInstance().getCoordinator().getCacher().getCache("QTIWorks", "assessmentTestsAndItems"); + } + + @Override + public void destroy() throws Exception { + if(jqtiExtensionManager != null) { + jqtiExtensionManager.destroy(); + } + } + + @Override + public XsltStylesheetCache getXsltStylesheetCache() { + return xsltStylesheetCache; + } - return new JqtiExtensionManager(extensionPackages); + @Override + public XsltStylesheetManager getXsltStylesheetManager() { + return xsltStylesheetManager; + } + + @Override + public JqtiExtensionManager jqtiExtensionManager() { + return jqtiExtensionManager; } - @Bean + @Override public QtiSerializer qtiSerializer() { return new QtiSerializer(jqtiExtensionManager()); } + + @SuppressWarnings("unchecked") @Override - public <E extends ResolvedAssessmentObject<?>> E loadAndResolveAssessmentObject(File resourceDirectory) { - QtiXmlReader qtiXmlReader = new QtiXmlReader(jqtiExtensionManager()); - - ResourceLocator fileResourceLocator = new PathResourceLocator(resourceDirectory.toPath()); - final ResourceLocator inputResourceLocator = - ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator); - final URI assessmentObjectSystemId = createAssessmentObjectUri(resourceDirectory); - final AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, inputResourceLocator); - final AssessmentObjectType assessmentObjectType = AssessmentObjectType.ASSESSMENT_TEST; - E result; - if (assessmentObjectType==AssessmentObjectType.ASSESSMENT_ITEM) { - result = (E) assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId); - } - else if (assessmentObjectType==AssessmentObjectType.ASSESSMENT_TEST) { - result = (E) assessmentObjectXmlLoader.loadAndResolveAssessmentTest(assessmentObjectSystemId); - } - else { - throw new OLATRuntimeException("Unexpected branch " + assessmentObjectType, null); - } + public ResolvedAssessmentObject<?> loadAndResolveAssessmentObject(File resourceDirectory) { + ResolvedAssessmentObject<?> result; + if(assessmentTestsAndItemsCache.containsKey(resourceDirectory)) { + return assessmentTestsAndItemsCache.get(resourceDirectory); + } else { + QtiXmlReader qtiXmlReader = new QtiXmlReader(jqtiExtensionManager()); + ResourceLocator fileResourceLocator = new PathResourceLocator(resourceDirectory.toPath()); + final ResourceLocator inputResourceLocator = + ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator); + final URI assessmentObjectSystemId = createAssessmentObjectUri(resourceDirectory); + final AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, inputResourceLocator); + final AssessmentObjectType assessmentObjectType = AssessmentObjectType.ASSESSMENT_TEST; + + if (assessmentObjectType==AssessmentObjectType.ASSESSMENT_ITEM) { + result = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId); + } else if (assessmentObjectType==AssessmentObjectType.ASSESSMENT_TEST) { + result = assessmentObjectXmlLoader.loadAndResolveAssessmentTest(assessmentObjectSystemId); + } else { + throw new OLATRuntimeException("Unexpected branch " + assessmentObjectType, null); + } + + ResolvedAssessmentObject<?> cachedResult = assessmentTestsAndItemsCache.putIfAbsent(resourceDirectory, result); + if(cachedResult != null) { + result = cachedResult; + } + } return result; } @@ -386,7 +431,6 @@ public class QTI21ServiceImpl implements QTI21Service { } } - @Override public UserTestSession finishItemSession(UserTestSession candidateSession, AssessmentResult assessmentResult, Date timestamp) { /* Mark session as finished */ diff --git a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java index b1d5c40c88a..3ca9f5b5e07 100644 --- a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java +++ b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java @@ -62,6 +62,7 @@ import org.olat.fileresource.ZippedDirectoryMediaResource; import org.olat.fileresource.types.FileResource; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.fileresource.types.ResourceEvaluation; +import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.xml.AssessmentItemFactory; import org.olat.ims.qti21.model.xml.AssessmentTestFactory; @@ -83,7 +84,6 @@ import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.springframework.stereotype.Service; -import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest; @@ -134,11 +134,13 @@ public class QTI21AssessmentTestHandler extends FileHandler { public void createMinimalAssessmentTest(String displayName, File directory) { ManifestType manifestType = ManifestPackage.createEmptyManifest(); + + QTI21Service qti21Service = CoreSpringFactory.getImpl(QTI21Service.class); //single choice File itemFile = new File(directory, IdentifierGenerator.newAssessmentTestFilename()); AssessmentItem assessmentItem = AssessmentItemFactory.createSingleChoice(); - QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); + QtiSerializer qtiSerializer = qti21Service.qtiSerializer(); ManifestPackage.appendAssessmentItem(itemFile.getName(), manifestType); //test diff --git a/src/main/java/org/olat/ims/qti21/restapi/MathWebService.java b/src/main/java/org/olat/ims/qti21/restapi/MathWebService.java index a1432cb8725..ecebee4e7d8 100644 --- a/src/main/java/org/olat/ims/qti21/restapi/MathWebService.java +++ b/src/main/java/org/olat/ims/qti21/restapi/MathWebService.java @@ -30,7 +30,9 @@ import javax.ws.rs.core.CacheControl; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.SimpleXsltStylesheetCache; +import org.olat.core.CoreSpringFactory; +import org.olat.ims.qti21.QTI21Service; + import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetCache; import uk.ac.ed.ph.qtiworks.mathassess.XsltStylesheetCacheAdapter; import uk.ac.ed.ph.qtiworks.mathassess.glue.AsciiMathHelper; @@ -55,7 +57,7 @@ public class MathWebService { @Path("verifyAsciiMath") @Produces({MediaType.APPLICATION_JSON}) public Response verifyAsciiMath(@FormParam("input") String asciiMathInput) { - XsltStylesheetCache stylesheetCache = new SimpleXsltStylesheetCache(); + XsltStylesheetCache stylesheetCache = CoreSpringFactory.getImpl(QTI21Service.class).getXsltStylesheetCache(); AsciiMathHelper asciiMathHelper = new AsciiMathHelper(new XsltStylesheetCacheAdapter(stylesheetCache)); Map<String, String> upConvertedAsciiMathInput = asciiMathHelper.upConvertAsciiMathInput(asciiMathInput); return Response.ok(upConvertedAsciiMathInput).lastModified(new Date()).cacheControl(cc).build(); diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java index 0e6d4763b29..15d18d08205 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java @@ -52,7 +52,6 @@ import org.olat.modules.assessment.AssessmentEntry; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; -import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.JqtiPlus; import uk.ac.ed.ph.jqtiplus.exception.QtiCandidateStateException; import uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult; @@ -95,8 +94,6 @@ public class AssessmentItemDisplayController extends BasicController implements @Autowired private QTI21Service qtiService; - @Autowired - private JqtiExtensionManager jqtiExtensionManager; public AssessmentItemDisplayController(UserRequest ureq, WindowControl wControl, RepositoryEntry testEntry, AssessmentEntry assessmentEntry, boolean authorMode, @@ -171,10 +168,6 @@ public class AssessmentItemDisplayController extends BasicController implements } super.event(ureq, source, event); } - - protected CandidateEvent assertSessionEntered(UserTestSession candidateSession) { - return lastEvent; - } private void processQTIEvent(UserRequest ureq, QTIWorksAssessmentItemEvent qe) { currentRequestTimestamp = ureq.getRequestTimestamp(); @@ -219,7 +212,7 @@ public class AssessmentItemDisplayController extends BasicController implements final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); /* Create fresh JQTI+ state Object and try to create controller */ - final ItemSessionController itemSessionController = createNewItemSessionStateAndController(notificationRecorder); + itemSessionController = createNewItemSessionStateAndController(notificationRecorder); if (itemSessionController==null) { logError("", null); return null;//handleExplosion(null, candidateSession); @@ -244,7 +237,7 @@ public class AssessmentItemDisplayController extends BasicController implements lastEvent = candidateEvent; /* Record current result state */ - final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq, candidateSession, itemSessionController); + final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq); /* Handle immediate end of session */ if (itemSessionState.isEnded()) { @@ -270,7 +263,7 @@ public class AssessmentItemDisplayController extends BasicController implements itemSessionControllerSettings.setMaxAttempts(10 /*itemDeliverySettings.getMaxAttempts() */); /* Create controller and wire up notification recorder */ - final ItemSessionController result = new ItemSessionController(jqtiExtensionManager, + final ItemSessionController result = new ItemSessionController(qtiService.jqtiExtensionManager(), itemSessionControllerSettings, itemProcessingMap, itemSessionState); if (notificationRecorder != null) { result.addNotificationListener(notificationRecorder); @@ -302,10 +295,9 @@ public class AssessmentItemDisplayController extends BasicController implements // assertSessionNotTerminated(candidateSession); /* Retrieve current JQTI state and set up JQTI controller */ - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); //final ItemSessionController itemSessionController = this.candidateDataService.createItemSessionController(mostRecentEvent, notificationRecorder); - final ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); + ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); /* Make sure an attempt is allowed */ if (itemSessionState.isEnded()) { @@ -410,13 +402,13 @@ public class AssessmentItemDisplayController extends BasicController implements lastEvent = candidateEvent; /* Record current result state, or finish session */ - updateSessionFinishedStatus(ureq, candidateSession, itemSessionController); + updateSessionFinishedStatus(ureq); } - private UserTestSession updateSessionFinishedStatus(UserRequest ureq, UserTestSession candidateSession, ItemSessionController itemSessionController) { + private UserTestSession updateSessionFinishedStatus(UserRequest ureq) { /* Record current result state and maybe close session */ final ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); - final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq, candidateSession, itemSessionController); + final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq); if (itemSessionState.isEnded()) { qtiService.finishItemSession(candidateSession, assessmentResult, null); } @@ -430,13 +422,13 @@ public class AssessmentItemDisplayController extends BasicController implements return candidateSession; } - public AssessmentResult computeAndRecordItemAssessmentResult(UserRequest ureq, UserTestSession candidateSession, ItemSessionController itemSessionController) { - final AssessmentResult assessmentResult = computeItemAssessmentResult(ureq, candidateSession, itemSessionController); + public AssessmentResult computeAndRecordItemAssessmentResult(UserRequest ureq) { + final AssessmentResult assessmentResult = computeItemAssessmentResult(ureq); qtiService.recordItemAssessmentResult(candidateSession, assessmentResult); return assessmentResult; } - public AssessmentResult computeItemAssessmentResult(UserRequest ureq, UserTestSession candidateSession, ItemSessionController itemSessionController) { + public AssessmentResult computeItemAssessmentResult(UserRequest ureq) { String baseUrl = "http://localhost:8080/olat"; final URI sessionIdentifierSourceId = URI.create(baseUrl); final String sessionIdentifier = "itemsession/" + (candidateSession == null ? "sdfj" : candidateSession.getKey()); @@ -449,11 +441,8 @@ public class AssessmentItemDisplayController extends BasicController implements //final CandidateSession candidateSession = candidateSessionContext.getCandidateSession(); //assertSessionNotTerminated(candidateSession); - /* Retrieve current JQTI state and set up JQTI controller */ - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - //final ItemSessionController itemSessionController = candidateDataService.createItemSessionController(mostRecentEvent, notificationRecorder); - final ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); /* Make sure caller may do this */ boolean allowSolutionWhenOpen = true;//itemDeliverySettings.isAllowSolutionWhenOpen() @@ -486,7 +475,7 @@ public class AssessmentItemDisplayController extends BasicController implements } /* Record current result state, and maybe close session */ - final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq, candidateSession, itemSessionController); + final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq); if (isClosingSession) { qtiService.finishItemSession(candidateSession, assessmentResult, timestamp); } @@ -505,11 +494,9 @@ public class AssessmentItemDisplayController extends BasicController implements //final CandidateSession candidateSession = candidateSessionContext.getCandidateSession(); //assertSessionNotTerminated(candidateSession); - /* Retrieve current JQTI state and set up JQTI controller */ - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); //final ItemSessionController itemSessionController = candidateDataService.createItemSessionController(mostRecentEvent, notificationRecorder); - final ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); + ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); /* Check this is allowed in current state */ @@ -538,7 +525,7 @@ public class AssessmentItemDisplayController extends BasicController implements } /* Record current result state */ - final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq, candidateSession, itemSessionController); + final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq); /* Record and log event */ final CandidateEvent candidateEvent = qtiService.recordCandidateItemEvent(candidateSession, @@ -558,11 +545,8 @@ public class AssessmentItemDisplayController extends BasicController implements //final CandidateSession candidateSession = candidateSessionContext.getCandidateSession(); //assertSessionNotTerminated(candidateSession); - /* Retrieve current JQTI state and set up JQTI controller */ - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - //final ItemSessionController itemSessionController = candidateDataService.createItemSessionController(mostRecentEvent, notificationRecorder); - final ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + ItemSessionState itemSessionState = itemSessionController.getItemSessionState(); /* Are we terminating a session that hasn't already been ended? If so end the session and record final result. */ final Date currentTimestamp = ureq.getRequestTimestamp(); @@ -573,7 +557,7 @@ public class AssessmentItemDisplayController extends BasicController implements logError("", e); return;// handleExplosion(e, candidateSession); } - final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq, candidateSession, itemSessionController); + final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq); qtiService.finishItemSession(candidateSession, assessmentResult, currentTimestamp); } diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java index 98b0f67d8d9..fb9d0a0e1bb 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java @@ -23,6 +23,7 @@ import java.io.File; import java.net.URI; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -41,6 +42,10 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.util.resource.OresHelper; import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; @@ -57,7 +62,6 @@ import org.olat.modules.assessment.AssessmentService; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; -import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.JqtiPlus; import uk.ac.ed.ph.jqtiplus.exception.QtiCandidateStateException; import uk.ac.ed.ph.jqtiplus.node.result.AbstractResult; @@ -117,8 +121,6 @@ public class AssessmentTestDisplayController extends BasicController implements private QTI21Service qtiService; @Autowired private AssessmentService assessmentService; - @Autowired - private JqtiExtensionManager jqtiExtensionManager; /** * @@ -160,7 +162,7 @@ public class AssessmentTestDisplayController extends BasicController implements } /* Handle immediate end of test session */ - if (testSessionController.getTestSessionState().isEnded()) { + if (testSessionController.getTestSessionState() != null && testSessionController.getTestSessionState().isEnded()) { AssessmentResult assessmentResult = null; qtiService.finishTestSession(candidateSession, assessmentResult, ureq.getRequestTimestamp()); mainVC = createVelocityContainer("end"); @@ -203,10 +205,6 @@ public class AssessmentTestDisplayController extends BasicController implements return currentRequestTimestamp; } - protected CandidateEvent assertSessionEntered(UserTestSession candidateSession) { - return lastEvent; - } - @Override protected void event(UserRequest ureq, Component source, Event event) { // @@ -245,7 +243,7 @@ public class AssessmentTestDisplayController extends BasicController implements processReviewItem(ureq, qe.getSubCommand()); break; case itemSolution: - processItemSolution(qe.getSubCommand()); + processItemSolution(ureq, qe.getSubCommand()); break; case testPartNavigation: processTestPartNavigation(ureq); @@ -291,15 +289,10 @@ public class AssessmentTestDisplayController extends BasicController implements private void processReviewItem(UserRequest ureq, String key) { TestPlanNodeKey itemKey = TestPlanNodeKey.fromString(key); - Date requestTimestamp = ureq.getRequestTimestamp(); - //Assert.notNull(itemKey, "itemKey"); - /* Get current JQTI state and create JQTI controller */ - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - //final TestSessionController testSessionController = candidateDataService.createTestSessionController(mostRecentEvent, notificationRecorder); - final TestSessionState testSessionState = testSessionController.getTestSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + TestSessionState testSessionState = testSessionController.getTestSessionState(); /* Make sure caller may do this */ //assertSessionNotTerminated(candidateSession); @@ -319,7 +312,7 @@ public class AssessmentTestDisplayController extends BasicController implements } /* Record current result state */ - computeAndRecordTestAssessmentResult(candidateSession, testSessionController, false); + computeAndRecordTestAssessmentResult(ureq, false); /* Record and log event */ final CandidateEvent candidateTestEvent = qtiService.recordCandidateTestEvent(candidateSession, @@ -328,13 +321,10 @@ public class AssessmentTestDisplayController extends BasicController implements //candidateAuditLogger.logCandidateEvent(candidateTestEvent); } - private void processItemSolution(String key) { + private void processItemSolution(UserRequest ureq, String key) { TestPlanNodeKey itemKey = TestPlanNodeKey.fromString(key); - /* Get current JQTI state and create JQTI controller */ NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - //final TestSessionController testSessionController = candidateDataService.createTestSessionController(mostRecentEvent, notificationRecorder); TestSessionState testSessionState = testSessionController.getTestSessionState(); /* Make sure caller may do this */ @@ -356,7 +346,7 @@ public class AssessmentTestDisplayController extends BasicController implements } /* Record current result state */ - computeAndRecordTestAssessmentResult(candidateSession, testSessionController, false); + computeAndRecordTestAssessmentResult(ureq, false); /* Record and log event */ CandidateEvent candidateTestEvent = qtiService.recordCandidateTestEvent(candidateSession, @@ -368,12 +358,8 @@ public class AssessmentTestDisplayController extends BasicController implements //public CandidateSession finishLinearItem(final CandidateSessionContext candidateSessionContext) // throws CandidateException { private void processFinish(UserRequest ureq) { - - /* Get current JQTI state and create JQTI controller */ - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - //final TestSessionController testSessionController = candidateDataService.createTestSessionController(mostRecentEvent, notificationRecorder); - final TestSessionState testSessionState = testSessionController.getTestSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + TestSessionState testSessionState = testSessionController.getTestSessionState(); try { if (!testSessionController.mayAdvanceItemLinear()) { @@ -392,10 +378,10 @@ public class AssessmentTestDisplayController extends BasicController implements final Date requestTimestamp = ureq.getRequestTimestamp(); final TestPlanNode nextItemNode = testSessionController.advanceItemLinear(requestTimestamp); - boolean terminated = nextItemNode == null && testSessionController.findNextEnterableTestPart() == null; + //boolean terminated = nextItemNode == null && testSessionController.findNextEnterableTestPart() == null; // Record current result state - final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(candidateSession, testSessionController, terminated); + final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(ureq, false); /* If we ended the testPart and there are now no more available testParts, then finish the session now */ if (nextItemNode==null && testSessionController.findNextEnterableTestPart()==null) { @@ -427,11 +413,8 @@ public class AssessmentTestDisplayController extends BasicController implements //final CandidateSession candidateSession = candidateSessionContext.getCandidateSession(); //assertSessionNotTerminated(candidateSession); - /* Get current JQTI state and create JQTI controller */ - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - //final TestSessionController testSessionController = candidateDataService.createTestSessionController(mostRecentEvent, notificationRecorder); - final TestSessionState testSessionState = testSessionController.getTestSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + TestSessionState testSessionState = testSessionController.getTestSessionState(); final Map<Identifier, ResponseData> responseDataMap = new HashMap<Identifier, ResponseData>(); if (stringResponseMap != null) { @@ -495,7 +478,7 @@ public class AssessmentTestDisplayController extends BasicController implements /* Record current result state */ - computeAndRecordTestAssessmentResult(candidateSession, testSessionController, false); + computeAndRecordTestAssessmentResult(ureq, false); /* Save any change to session state */ candidateSession = qtiService.updateTestSession(candidateSession); @@ -517,13 +500,9 @@ public class AssessmentTestDisplayController extends BasicController implements } private void processAdvanceTestPart(UserRequest ureq) { - - //final CandidateSessionContext candidateSessionContext = getCandidateSessionContext(); - /* Get current JQTI state and create JQTI controller */ - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - final TestSessionState testSessionState = testSessionController.getTestSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + TestSessionState testSessionState = testSessionController.getTestSessionState(); /* Perform action */ final TestPlanNode nextTestPart; @@ -563,7 +542,7 @@ public class AssessmentTestDisplayController extends BasicController implements boolean terminated = isTerminated(); /* Record current result state */ - computeAndRecordTestAssessmentResult(candidateSession, testSessionController, terminated); + computeAndRecordTestAssessmentResult(ureq, terminated); /* Record and log event */ final CandidateEvent candidateTestEvent = qtiService.recordCandidateTestEvent(candidateSession, @@ -577,17 +556,12 @@ public class AssessmentTestDisplayController extends BasicController implements } private void processReviewTestPart() { - - /* Get current JQTI state and create JQTI controller */ - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - //final TestSessionController testSessionController = candidateDataService.createTestSessionController(mostRecentEvent, notificationRecorder); - final TestSessionState testSessionState = testSessionController.getTestSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + TestSessionState testSessionState = testSessionController.getTestSessionState(); /* Make sure caller may do this */ //assertSessionNotTerminated(candidateSession); if (testSessionState.getCurrentTestPartKey()==null || !testSessionState.getCurrentTestPartSessionState().isEnded()) { - // candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANNOT_REVIEW_TEST_PART); logError("CANNOT_REVIEW_TEST_PART", null); return; @@ -604,12 +578,8 @@ public class AssessmentTestDisplayController extends BasicController implements * Exit multi-part tests */ private void processExitTest(UserRequest ureq) { - - /* Get current JQTI state and create JQTI controller */ - final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); - final CandidateEvent mostRecentEvent = assertSessionEntered(candidateSession); - //final TestSessionController testSessionController = candidateDataService.createTestSessionController(mostRecentEvent, notificationRecorder); - final TestSessionState testSessionState = testSessionController.getTestSessionState(); + NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); + TestSessionState testSessionState = testSessionController.getTestSessionState(); /* Perform action */ final Date currentTimestamp = ureq.getRequestTimestamp(); @@ -629,7 +599,7 @@ public class AssessmentTestDisplayController extends BasicController implements candidateSession = qtiService.updateTestSession(candidateSession); /* Record current result state (final) */ - computeAndRecordTestAssessmentResult(candidateSession, testSessionController, true); + computeAndRecordTestAssessmentResult(ureq, true); /* Record and log event */ final CandidateEvent candidateTestEvent = qtiService.recordCandidateTestEvent(candidateSession, @@ -646,7 +616,7 @@ public class AssessmentTestDisplayController extends BasicController implements final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); /* Create fresh JQTI+ state & controller for it */ - TestSessionController testSessionController = createNewTestSessionStateAndController(notificationRecorder); + testSessionController = createNewTestSessionStateAndController(notificationRecorder); if (testSessionController == null) { return null; } @@ -684,7 +654,7 @@ public class AssessmentTestDisplayController extends BasicController implements boolean ended = testSessionState.isEnded(); /* Record current result state */ - final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(candidateSession, testSessionController, ended); + final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(ureq, ended); /* Handle immediate end of test session */ if (ended) { @@ -709,7 +679,7 @@ public class AssessmentTestDisplayController extends BasicController implements testSessionControllerSettings.setTemplateProcessingLimit(computeTemplateProcessingLimit()); /* Create controller and wire up notification recorder */ - final TestSessionController result = new TestSessionController(jqtiExtensionManager, + final TestSessionController result = new TestSessionController(qtiService.jqtiExtensionManager(), testSessionControllerSettings, testProcessingMap, testSessionState); if (notificationRecorder!=null) { result.addNotificationListener(notificationRecorder); @@ -739,7 +709,7 @@ public class AssessmentTestDisplayController extends BasicController implements testSessionControllerSettings.setTemplateProcessingLimit(computeTemplateProcessingLimit()); /* Create controller and wire up notification recorder (if passed) */ - final TestSessionController result = new TestSessionController(jqtiExtensionManager, + final TestSessionController result = new TestSessionController(qtiService.jqtiExtensionManager(), testSessionControllerSettings, testProcessingMap, testSessionState); if (notificationRecorder!=null) { result.addNotificationListener(notificationRecorder); @@ -748,9 +718,8 @@ public class AssessmentTestDisplayController extends BasicController implements return result; } - private AssessmentResult computeAndRecordTestAssessmentResult(UserTestSession candidateSession, - TestSessionController testSessionController, boolean submit) { - AssessmentResult assessmentResult = computeTestAssessmentResult(candidateSession, testSessionController); + private AssessmentResult computeAndRecordTestAssessmentResult(UserRequest ureq, boolean submit) { + AssessmentResult assessmentResult = computeTestAssessmentResult(ureq, candidateSession); qtiService.recordTestAssessmentResult(candidateSession, assessmentResult); processOutcomeVariables(assessmentResult.getTestResult(), submit); return assessmentResult; @@ -778,22 +747,24 @@ public class AssessmentTestDisplayController extends BasicController implements } } - if(score != null) { + if(score != null || pass != null) { if(submit) { - outcomesListener.updateOutcomes(score, pass); - } else { outcomesListener.submit(score, pass); + } else { + outcomesListener.updateOutcomes(score, pass); } } } - private AssessmentResult computeTestAssessmentResult(final UserTestSession candidateSession, final TestSessionController testSessionController) { - String baseUrl = "http://localhost:8080/olat"; - final URI sessionIdentifierSourceId = URI.create(baseUrl); - final String sessionIdentifier = "testsession/" + candidateSession.getKey(); - - Date timestamp = new Date();//requestTimestampContext.getCurrentRequestTimestamp(); - return testSessionController.computeAssessmentResult(timestamp, sessionIdentifier, sessionIdentifierSourceId); + private AssessmentResult computeTestAssessmentResult(UserRequest ureq, final UserTestSession testSession) { + List<ContextEntry> entries = getWindowControl().getBusinessControl().getEntries(); + OLATResourceable testSessionOres = OresHelper.createOLATResourceableInstance("TestSession", testSession.getKey()); + entries.add(BusinessControlFactory.getInstance().createContextEntry(testSessionOres)); + String url = BusinessControlFactory.getInstance().getAsAuthURIString(entries, true); + final URI sessionIdentifierSourceId = URI.create(url); + final String sessionIdentifier = "testsession/" + testSession.getKey(); + return testSessionController + .computeAssessmentResult(ureq.getRequestTimestamp(), sessionIdentifier, sessionIdentifierSourceId); } private TestProcessingMap getTestProcessingMap() { diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java index 221a8a01938..4c63f1b1dd1 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java @@ -63,6 +63,7 @@ import javax.xml.transform.stream.StreamResult; import org.apache.commons.io.IOUtils; import org.apache.velocity.VelocityContext; import org.apache.velocity.context.Context; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.components.DefaultComponentRenderer; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormUIFactory; @@ -79,6 +80,7 @@ import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; +import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.ui.rendering.XmlUtilities; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; @@ -142,8 +144,6 @@ import uk.ac.ed.ph.jqtiplus.value.BaseType; import uk.ac.ed.ph.jqtiplus.value.Cardinality; import uk.ac.ed.ph.jqtiplus.value.SingleValue; import uk.ac.ed.ph.jqtiplus.value.Value; -import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ClassPathResourceLocator; -import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.SimpleXsltStylesheetCache; import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetManager; import uk.ac.ed.ph.qtiworks.mathassess.MathEntryInteraction; @@ -1023,7 +1023,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent return; } - XsltStylesheetManager stylesheetManager = new XsltStylesheetManager(new ClassPathResourceLocator(), new SimpleXsltStylesheetCache()); + XsltStylesheetManager stylesheetManager = CoreSpringFactory.getImpl(QTI21Service.class).getXsltStylesheetManager(); final TransformerHandler mathmlTransformerHandler = stylesheetManager.getCompiledStylesheetHandler(ctopXsltUri, null); try { diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java index be713d6a5b4..505e859d82e 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java @@ -36,6 +36,7 @@ import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormJSHelper; @@ -47,6 +48,7 @@ import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.util.StringHelper; +import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.UserTestSession; import org.olat.ims.qti21.model.CandidateTestEventType; import org.olat.ims.qti21.model.jpa.CandidateEvent; @@ -54,7 +56,6 @@ import org.olat.ims.qti21.ui.CandidateSessionContext; import org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event; import org.w3c.dom.Element; -import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.node.ForeignElement; import uk.ac.ed.ph.jqtiplus.node.QtiNode; import uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun; @@ -532,7 +533,7 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe || (!identifierMatch && testFeedback.getVisibilityMode() == VisibilityMode.HIDE_IF_MATCH)) { sb.append("<h2>Feedback</h2>"); - final QtiSerializer serializer = new QtiSerializer(new JqtiExtensionManager()); + final QtiSerializer serializer = CoreSpringFactory.getImpl(QTI21Service.class).qtiSerializer(); //TODO QTI flow: need to handle url, feedbackBlock... --> testFeedback.getChildren().forEach((flow) -> sb.append(serializer.serializeJqtiObject(flow))); } @@ -569,7 +570,7 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe } String endTestTitle = multiPartTest ? translator.translate("assessment.test.end.testPart") : translator.translate("assessment.test.end.test"); - sb.append(";\" class='btn btn-default'").append(" disabled", !allowedToEndTestPart).append("><span>") + sb.append(";\" class='btn btn-default o_sel_end_testpart'").append(" disabled", !allowedToEndTestPart).append("><span>") .append(endTestTitle).append("</span>"); sb.append("</button>"); -- GitLab