SEBSERV-139 refactoring of townhall and instruction service
This commit is contained in:
parent
8e04e43bfa
commit
53bb378d0b
8 changed files with 184 additions and 73 deletions
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.ethz.seb.sebserver.gbl.util;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
|
||||||
|
public class SizedArrayNonBlockingQueue<T> extends ArrayBlockingQueue<T> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -4235702373708064610L;
|
||||||
|
|
||||||
|
private final int size;
|
||||||
|
|
||||||
|
public SizedArrayNonBlockingQueue(final int size) {
|
||||||
|
super(size);
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
synchronized public boolean add(final T element) {
|
||||||
|
// Check if queue full already?
|
||||||
|
if (super.size() == this.size) {
|
||||||
|
// remove element from queue if queue is full
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
|
return super.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -334,26 +334,19 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
|
|
||||||
if (proctoringSettings != null && proctoringSettings.enableProctoring) {
|
if (proctoringSettings != null && proctoringSettings.enableProctoring) {
|
||||||
|
|
||||||
final RemoteProctoringRoom townhall = restService.getBuilder(GetTownhallRoom.class)
|
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
|
||||||
.call()
|
|
||||||
.getOr(null);
|
|
||||||
|
|
||||||
final boolean townhallActive = townhall != null && townhall.id != null;
|
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withExec(this::openTownhallRoom)
|
.withExec(this::toggleTownhallRoom)
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publish();
|
.publish();
|
||||||
|
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)
|
if (isTownhallRoomActive(entityKey.modelId)) {
|
||||||
.withEntityKey(entityKey)
|
|
||||||
.withExec(this::closeTownhallRoom)
|
|
||||||
.noEventPropagation()
|
|
||||||
.publish();
|
|
||||||
if (!townhallActive) {
|
|
||||||
this.pageService.firePageEvent(
|
this.pageService.firePageEvent(
|
||||||
new ActionActivationEvent(false, ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM),
|
new ActionActivationEvent(
|
||||||
|
true,
|
||||||
|
new Tuple<>(
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
|
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
|
||||||
pageContext);
|
pageContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +369,40 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isTownhallRoomActive(final String examModelId) {
|
||||||
|
final RemoteProctoringRoom townhall = this.pageService.getRestService()
|
||||||
|
.getBuilder(GetTownhallRoom.class)
|
||||||
|
.withURIVariable(API.PARAM_MODEL_ID, examModelId)
|
||||||
|
.call()
|
||||||
|
.getOr(null);
|
||||||
|
|
||||||
|
return townhall != null && townhall.id != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageAction toggleTownhallRoom(final PageAction action) {
|
||||||
|
if (isTownhallRoomActive(action.getEntityKey().modelId)) {
|
||||||
|
closeTownhallRoom(action);
|
||||||
|
this.pageService.firePageEvent(
|
||||||
|
new ActionActivationEvent(
|
||||||
|
true,
|
||||||
|
new Tuple<>(
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)),
|
||||||
|
action.pageContext());
|
||||||
|
return action;
|
||||||
|
} else {
|
||||||
|
openTownhallRoom(action);
|
||||||
|
this.pageService.firePageEvent(
|
||||||
|
new ActionActivationEvent(
|
||||||
|
true,
|
||||||
|
new Tuple<>(
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
|
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
|
||||||
|
action.pageContext());
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private PageAction openTownhallRoom(final PageAction action) {
|
private PageAction openTownhallRoom(final PageAction action) {
|
||||||
final EntityKey examId = action.getEntityKey();
|
final EntityKey examId = action.getEntityKey();
|
||||||
|
|
||||||
|
@ -407,11 +434,6 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
this.remoteProctoringEndpoint);
|
this.remoteProctoringEndpoint);
|
||||||
javaScriptExecutor.execute(script);
|
javaScriptExecutor.execute(script);
|
||||||
proctoringGUIService.registerProctoringWindow(activeAllRoomName);
|
proctoringGUIService.registerProctoringWindow(activeAllRoomName);
|
||||||
this.pageService.firePageEvent(
|
|
||||||
new ActionActivationEvent(
|
|
||||||
true,
|
|
||||||
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM),
|
|
||||||
action.pageContext());
|
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,12 +453,27 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
.getProctoringGUIService();
|
.getProctoringGUIService();
|
||||||
|
|
||||||
proctoringGUIService.closeRoom(townhall.name);
|
proctoringGUIService.closeRoom(townhall.name);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTownhallButton(final EntityKey entityKey, final PageContext pageContext) {
|
||||||
|
if (isTownhallRoomActive(entityKey.modelId)) {
|
||||||
this.pageService.firePageEvent(
|
this.pageService.firePageEvent(
|
||||||
new ActionActivationEvent(
|
new ActionActivationEvent(
|
||||||
false,
|
true,
|
||||||
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM),
|
new Tuple<>(
|
||||||
action.pageContext());
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
return action;
|
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
|
||||||
|
pageContext);
|
||||||
|
} else {
|
||||||
|
this.pageService.firePageEvent(
|
||||||
|
new ActionActivationEvent(
|
||||||
|
true,
|
||||||
|
new Tuple<>(
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)),
|
||||||
|
pageContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRoomActions(
|
private void updateRoomActions(
|
||||||
|
@ -446,6 +483,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
final PageActionBuilder actionBuilder,
|
final PageActionBuilder actionBuilder,
|
||||||
final ProctoringSettings proctoringSettings) {
|
final ProctoringSettings proctoringSettings) {
|
||||||
|
|
||||||
|
updateTownhallButton(entityKey, pageContext);
|
||||||
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
||||||
this.pageService.getRestService().getBuilder(GetProcotringRooms.class)
|
this.pageService.getRestService().getBuilder(GetProcotringRooms.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||||
|
|
|
@ -711,7 +711,7 @@ public enum ActionDefinition {
|
||||||
ActionCategory.PROCTORING),
|
ActionCategory.PROCTORING),
|
||||||
MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM(
|
MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM(
|
||||||
new LocTextKey("sebserver.monitoring.exam.action.proctoring.closeTownhall"),
|
new LocTextKey("sebserver.monitoring.exam.action.proctoring.closeTownhall"),
|
||||||
ImageIcon.PROCTOR_ROOM,
|
ImageIcon.CANCEL,
|
||||||
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
|
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
|
||||||
ActionCategory.PROCTORING),
|
ActionCategory.PROCTORING),
|
||||||
|
|
||||||
|
|
|
@ -135,13 +135,11 @@ public class ActionPane implements TemplateComposer {
|
||||||
|
|
||||||
if (event.decoration != null) {
|
if (event.decoration != null) {
|
||||||
final TreeItem actionItemToDecorate = findAction(actionTrees, parent, event.decoration._1);
|
final TreeItem actionItemToDecorate = findAction(actionTrees, parent, event.decoration._1);
|
||||||
final PageAction action = (PageAction) actionItemToDecorate.getData(ACTION_EVENT_CALL_KEY);
|
|
||||||
if (actionItemToDecorate != null && event.decoration._2 != null) {
|
if (actionItemToDecorate != null && event.decoration._2 != null) {
|
||||||
actionItemToDecorate.setImage(0,
|
actionItemToDecorate.setImage(0,
|
||||||
event.decoration._2.icon.getImage(parent.getDisplay()));
|
event.decoration._2.icon.getImage(parent.getDisplay()));
|
||||||
ActionPane.this.pageService.getPolyglotPageService().injectI18n(
|
ActionPane.this.pageService.getPolyglotPageService().injectI18n(
|
||||||
actionItemToDecorate,
|
actionItemToDecorate, event.decoration._2.title);
|
||||||
(action != null) ? action.getTitle() : event.decoration._2.title);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,12 +29,10 @@ import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerT
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.GuiServiceInfo;
|
import ch.ethz.seb.sebserver.gui.GuiServiceInfo;
|
||||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.RemoteProctoringView;
|
import ch.ethz.seb.sebserver.gui.service.page.RemoteProctoringView;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEvent;
|
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.SendProctoringBroadcastAttributes;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.SendProctoringBroadcastAttributes;
|
||||||
import ch.ethz.seb.sebserver.gui.service.session.ProctoringGUIService;
|
import ch.ethz.seb.sebserver.gui.service.session.ProctoringGUIService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.session.ProctoringGUIService.ProctoringWindowData;
|
import ch.ethz.seb.sebserver.gui.service.session.ProctoringGUIService.ProctoringWindowData;
|
||||||
|
@ -92,7 +90,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
final GridData headerCell = new GridData(SWT.FILL, SWT.FILL, true, true);
|
final GridData headerCell = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||||
content.setLayoutData(headerCell);
|
content.setLayoutData(headerCell);
|
||||||
|
|
||||||
parent.addListener(SWT.Dispose, event -> closeRoom(proctoringWindowData, pageContext));
|
parent.addListener(SWT.Dispose, event -> closeRoom(proctoringWindowData));
|
||||||
|
|
||||||
final String url = this.guiServiceInfo
|
final String url = this.guiServiceInfo
|
||||||
.getExternalServerURIBuilder()
|
.getExternalServerURIBuilder()
|
||||||
|
@ -122,7 +120,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
|
|
||||||
final Button closeAction = widgetFactory.buttonLocalized(footer, CLOSE_WINDOW_TEXT_KEY);
|
final Button closeAction = widgetFactory.buttonLocalized(footer, CLOSE_WINDOW_TEXT_KEY);
|
||||||
closeAction.setLayoutData(new RowData(150, 30));
|
closeAction.setLayoutData(new RowData(150, 30));
|
||||||
closeAction.addListener(SWT.Selection, event -> closeRoom(proctoringWindowData, pageContext));
|
closeAction.addListener(SWT.Selection, event -> closeRoom(proctoringWindowData));
|
||||||
|
|
||||||
final BroadcastActionState broadcastActionState = new BroadcastActionState();
|
final BroadcastActionState broadcastActionState = new BroadcastActionState();
|
||||||
final String connectionTokens = getConnectionTokens(proctoringWindowData);
|
final String connectionTokens = getConnectionTokens(proctoringWindowData);
|
||||||
|
@ -258,16 +256,11 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
boolean chat = false;
|
boolean chat = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeRoom(final ProctoringWindowData proctoringWindowData, final PageContext pageContext) {
|
private void closeRoom(final ProctoringWindowData proctoringWindowData) {
|
||||||
this.pageService
|
this.pageService
|
||||||
.getCurrentUser()
|
.getCurrentUser()
|
||||||
.getProctoringGUIService()
|
.getProctoringGUIService()
|
||||||
.closeRoom(proctoringWindowData.connectionData.roomName);
|
.closeRoom(proctoringWindowData.connectionData.roomName);
|
||||||
this.pageService.firePageEvent(
|
|
||||||
new ActionActivationEvent(
|
|
||||||
false,
|
|
||||||
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM),
|
|
||||||
pageContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,11 @@ public class ProctoringGUIService {
|
||||||
this.restService.getBuilder(SendProctoringBroadcastAttributes.class)
|
this.restService.getBuilder(SendProctoringBroadcastAttributes.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomConnectionData.roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomConnectionData.roomName)
|
||||||
|
.withFormParam(
|
||||||
|
API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||||
|
roomConnectionData.connections.isEmpty()
|
||||||
|
? ""
|
||||||
|
: StringUtils.join(roomConnectionData.connections, Constants.LIST_SEPARATOR_CHAR))
|
||||||
.call()
|
.call()
|
||||||
.onError(error -> log.error(
|
.onError(error -> log.error(
|
||||||
"Failed to send reset broadcast attribute instruction call for room: {}, cause: {}",
|
"Failed to send reset broadcast attribute instruction call for room: {}, cause: {}",
|
||||||
|
@ -229,7 +234,9 @@ public class ProctoringGUIService {
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
|
||||||
if (!this.rooms.isEmpty()) {
|
if (!this.rooms.isEmpty()) {
|
||||||
this.rooms.keySet().stream().forEach(this::closeRoom);
|
this.rooms.keySet()
|
||||||
|
.stream()
|
||||||
|
.forEach(this::closeRoom);
|
||||||
this.rooms.clear();
|
this.rooms.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.DateTimeZone;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
@ -31,6 +29,7 @@ import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.SizedArrayNonBlockingQueue;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientInstructionRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientInstructionRecord;
|
||||||
|
@ -45,6 +44,7 @@ public class SEBInstructionServiceImpl implements SEBInstructionService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SEBInstructionServiceImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(SEBInstructionServiceImpl.class);
|
||||||
|
|
||||||
|
private static final int INSTRUCTION_QUEUE_MAX_SIZE = 10;
|
||||||
private static final String JSON_INST = "instruction";
|
private static final String JSON_INST = "instruction";
|
||||||
private static final String JSON_ATTR = "attributes";
|
private static final String JSON_ATTR = "attributes";
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ public class SEBInstructionServiceImpl implements SEBInstructionService {
|
||||||
private final ClientInstructionDAO clientInstructionDAO;
|
private final ClientInstructionDAO clientInstructionDAO;
|
||||||
private final JSONMapper jsonMapper;
|
private final JSONMapper jsonMapper;
|
||||||
|
|
||||||
private final Map<String, ClientInstructionRecord> instructions;
|
private final Map<String, SizedArrayNonBlockingQueue<ClientInstructionRecord>> instructions;
|
||||||
|
|
||||||
private long lastRefresh = 0;
|
private long lastRefresh = 0;
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ public class SEBInstructionServiceImpl implements SEBInstructionService {
|
||||||
final String attributesString = this.jsonMapper.writeValueAsString(attributes);
|
final String attributesString = this.jsonMapper.writeValueAsString(attributes);
|
||||||
this.clientInstructionDAO
|
this.clientInstructionDAO
|
||||||
.insert(examId, type, attributesString, connectionToken, needsConfirm)
|
.insert(examId, type, attributesString, connectionToken, needsConfirm)
|
||||||
.map(this::chacheInstruction)
|
.map(this::putToCacheIfAbsent)
|
||||||
.onError(error -> log.error("Failed to register instruction: {}", error.getMessage()))
|
.onError(error -> log.error("Failed to register instruction: {}", error.getMessage()))
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
@ -146,7 +146,7 @@ public class SEBInstructionServiceImpl implements SEBInstructionService {
|
||||||
error -> log.error("Failed to register instruction: {}", error.getMessage()),
|
error -> log.error("Failed to register instruction: {}", error.getMessage()),
|
||||||
() -> null))
|
() -> null))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.forEach(this::chacheInstruction);
|
.forEach(this::putToCacheIfAbsent);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -162,10 +162,19 @@ public class SEBInstructionServiceImpl implements SEBInstructionService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ClientInstructionRecord clientInstruction = this.instructions.get(connectionToken);
|
final SizedArrayNonBlockingQueue<ClientInstructionRecord> queue = this.instructions.get(connectionToken);
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClientInstructionRecord clientInstruction = queue.peek();
|
||||||
|
if (clientInstruction == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final boolean needsConfirm = BooleanUtils.toBoolean(clientInstruction.getNeedsConfirmation());
|
final boolean needsConfirm = BooleanUtils.toBoolean(clientInstruction.getNeedsConfirmation());
|
||||||
if (!needsConfirm) {
|
if (!needsConfirm) {
|
||||||
this.instructions.remove(connectionToken);
|
queue.poll();
|
||||||
final Result<Void> delete = this.clientInstructionDAO.delete(clientInstruction.getId());
|
final Result<Void> delete = this.clientInstructionDAO.delete(clientInstruction.getId());
|
||||||
if (delete.hasError()) {
|
if (delete.hasError()) {
|
||||||
log.error("Failed to delete SEB client instruction on persistent storage: ", delete.getError());
|
log.error("Failed to delete SEB client instruction on persistent storage: ", delete.getError());
|
||||||
|
@ -207,13 +216,26 @@ public class SEBInstructionServiceImpl implements SEBInstructionService {
|
||||||
@Override
|
@Override
|
||||||
public void confirmInstructionDone(final String connectionToken, final String instructionConfirm) {
|
public void confirmInstructionDone(final String connectionToken, final String instructionConfirm) {
|
||||||
try {
|
try {
|
||||||
this.instructions.remove(connectionToken);
|
final SizedArrayNonBlockingQueue<ClientInstructionRecord> queue = this.instructions.get(connectionToken);
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClientInstructionRecord instruction = queue.peek();
|
||||||
|
if (String.valueOf(instruction.getId()).equals(String.valueOf(instruction.getId()))) {
|
||||||
|
queue.poll();
|
||||||
this.clientInstructionDAO.delete(Long.valueOf(instructionConfirm));
|
this.clientInstructionDAO.delete(Long.valueOf(instructionConfirm));
|
||||||
|
} else {
|
||||||
|
log.warn("SEB instruction confirmation mismatch. Sent instructionConfirm: {} pending instruction: {}",
|
||||||
|
instructionConfirm,
|
||||||
|
instruction.getId());
|
||||||
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error(
|
log.error(
|
||||||
"Failed to remove SEB instruction after confirmation: connectionToken: {} instructionConfirm: {}",
|
"Failed to remove SEB instruction after confirmation: connectionToken: {} instructionConfirm: {} connectionToken: {}",
|
||||||
connectionToken,
|
connectionToken,
|
||||||
instructionConfirm);
|
instructionConfirm,
|
||||||
|
connectionToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,33 +258,53 @@ public class SEBInstructionServiceImpl implements SEBInstructionService {
|
||||||
private Result<Void> loadInstructions() {
|
private Result<Void> loadInstructions() {
|
||||||
return Result.tryCatch(() -> this.clientInstructionDAO.getAllActive()
|
return Result.tryCatch(() -> this.clientInstructionDAO.getAllActive()
|
||||||
.getOrThrow()
|
.getOrThrow()
|
||||||
.forEach(inst -> this.instructions.putIfAbsent(inst.getConnectionToken(), inst)));
|
.forEach(this::putToCacheIfAbsent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientInstructionRecord chacheInstruction(final ClientInstructionRecord instruction) {
|
// private ClientInstructionRecord chacheInstruction(final ClientInstructionRecord instruction) {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// final String connectionToken = instruction.getConnectionToken();
|
||||||
|
// if (this.instructions.containsKey(connectionToken)) {
|
||||||
|
// // check if previous instruction is still valid
|
||||||
|
// final ClientInstructionRecord clientInstructionRecord = this.instructions.get(connectionToken);
|
||||||
|
//
|
||||||
|
// System.out.println("************* previous instruction still active: " + clientInstructionRecord);
|
||||||
|
//
|
||||||
|
// if (BooleanUtils.toBoolean(BooleanUtils.toBooleanObject(clientInstructionRecord.getNeedsConfirmation()))) {
|
||||||
|
// // check if time is out
|
||||||
|
// final long now = DateTime.now(DateTimeZone.UTC).getMillis();
|
||||||
|
// final Long timestamp = clientInstructionRecord.getTimestamp();
|
||||||
|
// if (timestamp != null && now - timestamp > Constants.MINUTE_IN_MILLIS) {
|
||||||
|
// // remove old instruction and add new one
|
||||||
|
// System.out.println("************* remove old instruction and put new: ");
|
||||||
|
// this.instructions.put(connectionToken, instruction);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// this.instructions.put(connectionToken, instruction);
|
||||||
|
// }
|
||||||
|
// return instruction;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private ClientInstructionRecord putToCacheIfAbsent(final ClientInstructionRecord instruction) {
|
||||||
|
final SizedArrayNonBlockingQueue<ClientInstructionRecord> queue = this.instructions.computeIfAbsent(
|
||||||
|
instruction.getConnectionToken(),
|
||||||
|
key -> new SizedArrayNonBlockingQueue<>(INSTRUCTION_QUEUE_MAX_SIZE));
|
||||||
|
|
||||||
|
if (queue.contains(instruction)) {
|
||||||
|
log.warn("Instruction alread in the queue: {}", instruction);
|
||||||
|
return instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Put SEB instruction into instruction queue: {}", instruction);
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println("************* register instruction: " + instruction);
|
System.out.println("************* register instruction: " + instruction);
|
||||||
|
|
||||||
final String connectionToken = instruction.getConnectionToken();
|
queue.add(instruction);
|
||||||
if (this.instructions.containsKey(connectionToken)) {
|
|
||||||
// check if previous instruction is still valid
|
|
||||||
final ClientInstructionRecord clientInstructionRecord = this.instructions.get(connectionToken);
|
|
||||||
|
|
||||||
System.out.println("************* previous instruction still active: " + clientInstructionRecord);
|
|
||||||
|
|
||||||
if (BooleanUtils.toBoolean(BooleanUtils.toBooleanObject(clientInstructionRecord.getNeedsConfirmation()))) {
|
|
||||||
// check if time is out
|
|
||||||
final long now = DateTime.now(DateTimeZone.UTC).getMillis();
|
|
||||||
final Long timestamp = clientInstructionRecord.getTimestamp();
|
|
||||||
if (timestamp != null && now - timestamp > Constants.MINUTE_IN_MILLIS) {
|
|
||||||
// remove old instruction and add new one
|
|
||||||
System.out.println("************* remove old instruction and put new: ");
|
|
||||||
this.instructions.put(connectionToken, instruction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.instructions.put(connectionToken, instruction);
|
|
||||||
}
|
|
||||||
return instruction;
|
return instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
################################
|
|
||||||
# Overall
|
# Overall
|
||||||
################################
|
################################
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue