Index: lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java =================================================================== diff -u -r33829c670fd8c90447d62ea3300498a103905e7a -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java (.../CentralConstants.java) (revision 33829c670fd8c90447d62ea3300498a103905e7a) +++ lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java (.../CentralConstants.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -21,7 +21,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.util; public class CentralConstants { @@ -104,7 +103,7 @@ public static final String METHOD_VERIFY_EXT_SERVER = "verify"; public static final String METHOD_LIST_MONITOR = "listMonitor"; - + public static final String METHOD_CHECK_LESSON_FOR_NUMERIC_TOOL_OUTPUTS = "checkLessonForNumericToolOutputs"; public static final String ATTR_COURSE_ID = "courseId"; @@ -152,7 +151,7 @@ public static final String MONITORING_SERVICE_BEAN_NAME = "monitoringService"; public static final String CENTRAL_MESSAGE_SERVICE_BEAN_NAME = "centralMessageService"; - + public static final String TOOL_SERVICE_BEAN_NAME = "lamsToolService"; public static final String ATTR_NODE = "node"; @@ -176,8 +175,8 @@ public static final String PARAM_LEARNER_PRESENCE_ENABLE = "learnerSeeOnline"; public static final String PARAM_LEARNER_IM_ENABLE = "learnerInstantMessaging"; - + public static final String PARAM_ENABLE_NOTIFICATIONS = "enableNotifications"; - + public static final String PARAM_ALLOW_LEARNER_RESTART = "allowLearnerRestart"; } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/flux/FluxRegistry.java =================================================================== diff -u -r4dbd12afbfcb6eb768ceb772768779e7619dc2f8 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_common/src/java/org/lamsfoundation/lams/flux/FluxRegistry.java (.../FluxRegistry.java) (revision 4dbd12afbfcb6eb768ceb772768779e7619dc2f8) +++ lams_common/src/java/org/lamsfoundation/lams/flux/FluxRegistry.java (.../FluxRegistry.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -10,29 +10,32 @@ private static final Map fluxRegistry = new ConcurrentHashMap<>(); private static final Map sinkRegistry = new ConcurrentHashMap<>(); - public static void initSink(String sinkName) { - if (sinkRegistry.containsKey(sinkName)) { - throw new IllegalArgumentException("Sink for \"" + sinkName + "\" was already initialised"); + public static SharedSink initSink(String sinkName) { + SharedSink sink = sinkRegistry.get(sinkName); + if (sink != null) { + return sink; } - SharedSink sink = new SharedSink<>(sinkName); + sink = new SharedSink<>(sinkName); sinkRegistry.put(sinkName, sink); + return sink; } - public static void initFluxMap(String fluxName, String sinkName, Function fetchFunction, + public static void initFluxMap(String fluxName, String sinkName, Function fetchFunction, Integer throttleSeconds, Integer timeoutSeconds) { if (fluxRegistry.containsKey(fluxName)) { throw new IllegalArgumentException("FluxMap for \"" + fluxName + "\" was already initialised"); } SharedSink sink = sinkRegistry.get(sinkName); if (sink == null) { - throw new IllegalArgumentException("Sink for \"" + sinkName + "\" was not initialised"); + sink = FluxRegistry.initSink(sinkName); } - FluxMap fluxMap = new FluxMap<>(fluxName, sink.getFlux(), fetchFunction, throttleSeconds, timeoutSeconds); + FluxMap fluxMap = new FluxMap<>(fluxName, sink.getFlux(), fetchFunction, throttleSeconds, + timeoutSeconds); fluxRegistry.put(fluxName, fluxMap); } - public static Flux get(String fluxName, T key) { - FluxMap fluxMap = fluxRegistry.get(fluxName); + public static Flux get(String fluxName, T key) { + FluxMap fluxMap = fluxRegistry.get(fluxName); if (fluxMap == null) { throw new IllegalArgumentException("FluxMap for \"" + fluxName + "\" was not initialised"); } Index: lams_common/src/java/org/lamsfoundation/lams/util/CommonConstants.java =================================================================== diff -u -r0c0c19b682e95c31de267d8e3a7d8b174c9c511a -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_common/src/java/org/lamsfoundation/lams/util/CommonConstants.java (.../CommonConstants.java) (revision 0c0c19b682e95c31de267d8e3a7d8b174c9c511a) +++ lams_common/src/java/org/lamsfoundation/lams/util/CommonConstants.java (.../CommonConstants.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -14,7 +14,7 @@ public static final String PARAM_SEARCH_STRING = "searchString"; // default coordinate used if the entry came from Flash is 0 or less. - public static final Integer DEFAULT_COORD = new Integer(10); + public static final Integer DEFAULT_COORD = 10; // XML Elemetns public static final String ELEMENT_ROWS = "rows"; @@ -66,4 +66,7 @@ "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW" }; + + // flux management + public static final String ACTIVITY_COMPLETED_SINK_NAME = "activity completed"; } Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/controller/CompleteActivityController.java =================================================================== diff -u -r598df4e0799935ff45fbd855b6b388d7e0443248 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/controller/CompleteActivityController.java (.../CompleteActivityController.java) (revision 598df4e0799935ff45fbd855b6b388d7e0443248) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/controller/CompleteActivityController.java (.../CompleteActivityController.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -31,13 +31,15 @@ import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.flux.FluxRegistry; import org.lamsfoundation.lams.integration.service.IIntegrationService; import org.lamsfoundation.lams.learning.service.ILearnerFullService; import org.lamsfoundation.lams.learning.service.LearnerServiceException; import org.lamsfoundation.lams.learning.web.util.ActivityMapping; import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.lesson.LearnerProgress; +import org.lamsfoundation.lams.util.CommonConstants; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.beans.factory.annotation.Autowired; @@ -86,8 +88,9 @@ return null; } + long lessonId = progress.getLesson().getLessonId(); if (progress.isComplete() && progress.getLesson().getAllowLearnerRestart()) { - request.setAttribute("lessonID", progress.getLesson().getLessonId()); + request.setAttribute("lessonID", lessonId); } try { @@ -116,6 +119,10 @@ forward = WebUtil.appendParameterToURL(forward, "finishedActivityId", String.valueOf(activityId)); } } + + // notify all event subscribers that a learner finished an activity + FluxRegistry.emit(CommonConstants.ACTIVITY_COMPLETED_SINK_NAME, lessonId); + return forward; } catch (LearnerServiceException e) { Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/MonitoringConstants.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/MonitoringConstants.java (.../MonitoringConstants.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/MonitoringConstants.java (.../MonitoringConstants.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -21,7 +21,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.monitoring; public class MonitoringConstants { @@ -37,7 +36,7 @@ public static final String KEY_STAFF = "staff"; public static final String KEY_LEARNER = "learners"; public static final String PARAM_LESSON_START_DATE = "lessonStartDate"; - public static final String PARAM_LESSON_END_DATE = "lessonEndDate"; + public static final String PARAM_LESSON_END_DATE = "lessonEndDate"; public static final String PARAM_SCHEDULED_NUMBER_DAYS_TO_LESSON_FINISH = "scheduledNumberDaysToLessonFinish"; public static final String PARAM_LEARNER_ID = "learnerID"; public static final String PARAM_REMOVE_LEARNER_CONTENT = "removeContent"; @@ -66,4 +65,7 @@ // how many times show info box in sequence tab public static final short SEQUENCE_TAB_SHOW_INFO_MAX_COUNT = 2; + + // flux management + public static final String CANVAS_REFRESH_FLUX_NAME = "canvas refresh"; } \ No newline at end of file Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringController.java =================================================================== diff -u -r7995d20f4e604098bb81ddf134697767dd2412a4 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringController.java (.../MonitoringController.java) (revision 7995d20f4e604098bb81ddf134697767dd2412a4) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringController.java (.../MonitoringController.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -42,6 +42,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.Vector; +import java.util.function.Function; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -51,6 +52,8 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.authoring.IAuthoringService; +import org.lamsfoundation.lams.flux.FluxMap; +import org.lamsfoundation.lams.flux.FluxRegistry; import org.lamsfoundation.lams.learning.service.ILearnerService; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.BranchingActivity; @@ -95,17 +98,21 @@ import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.util.HtmlUtils; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; +import reactor.core.publisher.Flux; + /** * The action servlet that provide all the monitoring functionalities. It interact with the teacher via JSP monitoring * interface. @@ -123,6 +130,8 @@ private static final int LATEST_LEARNER_PROGRESS_ACTIVITY_DISPLAY_LIMIT = 7; private static final int USER_PAGE_SIZE = 10; + private static final int CANVAS_REFRESH_FLUX_THROTTLE = 10; + @Autowired private ILogEventService logEventService; @Autowired @@ -145,6 +154,12 @@ @Autowired private IAuthoringService authoringService; + public MonitoringController() { + FluxRegistry.initFluxMap(MonitoringConstants.CANVAS_REFRESH_FLUX_NAME, + CommonConstants.ACTIVITY_COMPLETED_SINK_NAME, (Function) lessonId -> "doRefresh", + CANVAS_REFRESH_FLUX_THROTTLE, FluxMap.STANDARD_TIMEOUT); + } + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); @@ -161,6 +176,13 @@ return null; } + @RequestMapping(path = "/getLearnerProgressUpdateFlux", method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE) + @ResponseBody + public Flux getLearnerProgressUpdateFlux(@RequestParam long lessonId) + throws JsonProcessingException, IOException { + return FluxRegistry.get(MonitoringConstants.CANVAS_REFRESH_FLUX_NAME, lessonId); + } + /** * Initializes a lesson for specific learning design with the given lesson title and lesson description. If * initialization is successful, this method will the ID of new lesson. @@ -1107,7 +1129,7 @@ completedJSON.put("value", Math.round(completedLearnersCount.doubleValue() / possibleLearnersCount * 100)); completedJSON.put("raw", completedLearnersCount); responseJSON.withArray("data").add(completedJSON); - + ObjectNode notStartedJSON = JsonNodeFactory.instance.objectNode(); notStartedJSON.put("name", messageService.getMessage("lesson.chart.not.completed")); notStartedJSON.put("value", Math.round(notCompletedLearnersCount.doubleValue() / possibleLearnersCount * 100)); Index: lams_monitoring/web/WEB-INF/spring-servlet.xml =================================================================== diff -u -r7ff6d4b34cd71ac45741cb7c8d0c3ef6909eadf4 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_monitoring/web/WEB-INF/spring-servlet.xml (.../spring-servlet.xml) (revision 7ff6d4b34cd71ac45741cb7c8d0c3ef6909eadf4) +++ lams_monitoring/web/WEB-INF/spring-servlet.xml (.../spring-servlet.xml) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -11,8 +11,10 @@ http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> - + + Index: lams_monitoring/web/WEB-INF/web.xml =================================================================== diff -u -r9986a8084b318ccc9c025ec56407dc09a705dd60 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_monitoring/web/WEB-INF/web.xml (.../web.xml) (revision 9986a8084b318ccc9c025ec56407dc09a705dd60) +++ lams_monitoring/web/WEB-INF/web.xml (.../web.xml) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -18,16 +18,19 @@ org.lamsfoundation.lams.web.session.SystemSessionFilter + true LocaleFilter org.lamsfoundation.lams.web.filter.LocaleFilter + true HibernateFilter org.springframework.orm.hibernate5.support.OpenSessionInViewFilter + true sessionFactoryBeanName coreSessionFactory @@ -40,27 +43,38 @@ CSRFGuard org.owasp.csrfguard.CsrfGuardFilter + true SystemSessionFilter /* + REQUEST + ASYNC LocaleFilter /* + REQUEST + ASYNC HibernateFilter /* + REQUEST + ASYNC HibernateFilter *.jsp + REQUEST + ASYNC CSRFGuard *.do + REQUEST + ASYNC @@ -74,6 +88,7 @@ org.springframework.web.servlet.DispatcherServlet + true 1 Index: lams_monitoring/web/includes/javascript/monitorLesson5.js =================================================================== diff -u -rbfa7dfb5557d54767b137652b34dd89c13fb1227 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_monitoring/web/includes/javascript/monitorLesson5.js (.../monitorLesson5.js) (revision bfa7dfb5557d54767b137652b34dd89c13fb1227) +++ lams_monitoring/web/includes/javascript/monitorLesson5.js (.../monitorLesson5.js) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -1329,6 +1329,13 @@ }).find('.modal-header').remove(); $('#sequenceInfoDialog .modal-body').empty().append($('#sequenceInfoDialogContents').show()); + + const learnerProgressUpdateSource = new EventSource(LAMS_URL + 'monitoring/monitoring/getLearnerProgressUpdateFlux.do?lessonId=' + lessonId); + learnerProgressUpdateSource.onmessage = function (event) { + if ("doRefresh" == event.data){ + updateSequenceTab(); + } + } } function showIntroductionDialog(lessonId) { @@ -1353,6 +1360,7 @@ autoRefreshBlocked = false; $('#introductionDialog').remove(); } + /** * Updates learner progress in sequence tab according to respose sent to refreshMonitor() */ @@ -1369,7 +1377,7 @@ if (originalSequenceCanvas) { // put bottom layer, LD SVG - sequenceCanvas.html(originalSequenceCanvas); +// sequenceCanvas.html(originalSequenceCanvas); } else { var exit = loadLearningDesignSVG(); if (exit) { Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java =================================================================== diff -u -r4dbd12afbfcb6eb768ceb772768779e7619dc2f8 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision 4dbd12afbfcb6eb768ceb772768779e7619dc2f8) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -219,7 +219,7 @@ public static final String ATTR_ALL_GROUP_USERS = "allGroupUsers"; //flux management - public static final String ANSWERS_UPDATED_SINK_NAME = "assessment learner answers update"; + public static final String ANSWERS_UPDATED_SINK_NAME = "assessment learner answers updated"; - public static final String COMPLETION_CHARTS_UPDATE_FLUX_NAME = "assessment completion chart update"; + public static final String COMPLETION_CHARTS_UPDATE_FLUX_NAME = "assessment completion chart updated"; } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -rad1a281e94cbe882469d957666ba8e560ac214d9 -rc1e3ca12a9ccb265363e2330dd91ce7bedbcfa35 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision ad1a281e94cbe882469d957666ba8e560ac214d9) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision c1e3ca12a9ccb265363e2330dd91ce7bedbcfa35) @@ -200,7 +200,6 @@ private ILearnerInteractionService learnerInteractionService; public AssessmentServiceImpl() { - FluxRegistry.initSink(AssessmentConstants.ANSWERS_UPDATED_SINK_NAME); FluxRegistry.initFluxMap(AssessmentConstants.COMPLETION_CHARTS_UPDATE_FLUX_NAME, AssessmentConstants.ANSWERS_UPDATED_SINK_NAME, (Function) toolContentId -> getCompletionChartsData(toolContentId),