Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java =================================================================== diff -u -r53b1f5c6dcfb9e0d74e56c9647da69f07b889a55 -r62f565df2936fcc7978cb55d3e6b3f9f5a9621a5 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 53b1f5c6dcfb9e0d74e56c9647da69f07b889a55) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 62f565df2936fcc7978cb55d3e6b3f9f5a9621a5) @@ -40,12 +40,13 @@ import java.util.TimeZone; import java.util.TreeMap; import java.util.TreeSet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.function.Function; import java.util.stream.Collectors; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -107,6 +108,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter.SseEventBuilder; import org.springframework.web.util.HtmlUtils; import com.fasterxml.jackson.core.JsonProcessingException; @@ -263,6 +266,52 @@ @ResponseBody public String getCompletionChartsData(@RequestParam long toolContentId, HttpServletResponse response) throws JsonProcessingException, IOException { + String chartData = getCompletionChartsData(toolContentId); + response.setContentType("application/json;charset=utf-8"); + return chartData; + } + +// @RequestMapping(path = "/getCompletionChartsDataFlux", method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE) +// @ResponseBody +// public Flux getCompletionChartsDataFlux(@RequestParam long toolContentId) +// throws JsonProcessingException, IOException { +// +// return Flux.interval(Duration.ofSeconds(5)).map(sequence -> { +// String chartData = null; +// try { +// chartData = getCompletionChartsData(toolContentId); +// } catch (IOException e) { +// log.error(e); +// } +// return chartData; +// }); +// } + + @RequestMapping(path = "/getCompletionChartsDataFlux", method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE) + @ResponseBody + public SseEmitter getCompletionChartsDataFlux(@RequestParam long toolContentId) { + + final SseEmitter emitter = new SseEmitter(Long.MAX_VALUE); + ExecutorService service = Executors.newSingleThreadExecutor(); + service.execute(() -> { + while (true) { + try { + SseEventBuilder event = SseEmitter.event().data(getCompletionChartsData(toolContentId)); + emitter.send(event); + + Thread.sleep(5000); + } catch (Exception e) { + log.error(e); + emitter.completeWithError(e); + return; + } + } + }); + + return emitter; + } + + private String getCompletionChartsData(long toolContentId) throws JsonProcessingException, IOException { ObjectNode chartJson = JsonNodeFactory.instance.objectNode(); chartJson.put("possibleLearners", service.getCountLessonLearnersByContentId(toolContentId)); @@ -277,8 +326,6 @@ .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().size())); chartJson.set("answeredQuestionsByUsersCount", JsonUtil.readObject(answeredQuestionsByUsersCount)); } - - response.setContentType("application/json;charset=utf-8"); return chartJson.toString(); } Index: lams_tool_assessment/web/WEB-INF/web.xml =================================================================== diff -u -r9986a8084b318ccc9c025ec56407dc09a705dd60 -r62f565df2936fcc7978cb55d3e6b3f9f5a9621a5 --- lams_tool_assessment/web/WEB-INF/web.xml (.../web.xml) (revision 9986a8084b318ccc9c025ec56407dc09a705dd60) +++ lams_tool_assessment/web/WEB-INF/web.xml (.../web.xml) (revision 62f565df2936fcc7978cb55d3e6b3f9f5a9621a5) @@ -28,6 +28,7 @@ org.springframework.orm.hibernate5.support.OpenSessionInViewFilter + true sessionFactoryBeanName coreSessionFactory @@ -39,12 +40,14 @@ org.lamsfoundation.lams.web.session.SystemSessionFilter + true LocaleFilter org.lamsfoundation.lams.web.filter.LocaleFilter + true encoding UTF-8 @@ -53,23 +56,32 @@ CSRFGuard org.owasp.csrfguard.CsrfGuardFilter + true hibernateFilter /* + REQUEST + ASYNC SystemSessionFilter /* + REQUEST + ASYNC LocaleFilter /* + REQUEST + ASYNC CSRFGuard *.do + REQUEST + ASYNC @@ -78,6 +90,7 @@ org.springframework.web.servlet.DispatcherServlet 1 + true @@ -106,7 +119,7 @@ 3 - + spring *.do Index: lams_tool_assessment/web/includes/javascript/chart.js =================================================================== diff -u -r8a1b8b9cba5668f9c9b47a716093214aeec87f30 -r62f565df2936fcc7978cb55d3e6b3f9f5a9621a5 --- lams_tool_assessment/web/includes/javascript/chart.js (.../chart.js) (revision 8a1b8b9cba5668f9c9b47a716093214aeec87f30) +++ lams_tool_assessment/web/includes/javascript/chart.js (.../chart.js) (revision 62f565df2936fcc7978cb55d3e6b3f9f5a9621a5) @@ -1,26 +1,11 @@ -function drawCompletionCharts(toolContentId, useGroups,animate) { - $.ajax({ - 'url' : WEB_APP_URL + 'monitoring/getCompletionChartsData.do', - 'data': { - 'toolContentId' : toolContentId - }, - 'dataType' : 'json', - 'success' : function(data) { - // draw charts for the first time - drawActivityCompletionChart(data, animate); - drawAnsweredQuestionsChart(data, useGroups, animate); - } - }); +function drawCompletionCharts(toolContentId, useGroups, animate) { - if (activityCompletionChart == null && answeredQuestionsChart == null && COMPLETION_CHART_UPDATE_INTERVAL > 0) { - if (typeof completionChartInterval != 'undefined' && completionChartInterval) { - window.clearInterval(completionChartInterval); - } - - // set up update interval for the charts - completionChartInterval = window.setInterval(function(){ - drawCompletionCharts(toolContentId, useGroups,animate); - }, COMPLETION_CHART_UPDATE_INTERVAL); + const source = new EventSource( WEB_APP_URL + 'monitoring/getCompletionChartsDataFlux.do?toolContentId=' + toolContentId); + + source.onmessage = function (event) { + var data = JSON.parse(event.data); + drawActivityCompletionChart(data, animate); + drawAnsweredQuestionsChart(data, useGroups, animate); } }