SEBSERV-445 using DerreferedResult for client connections
This commit is contained in:
parent
6ccf74f9c1
commit
9c82f20763
4 changed files with 259 additions and 142 deletions
|
@ -17,7 +17,6 @@ import org.springframework.scheduling.annotation.AsyncConfigurer;
|
|||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
|
@ -75,14 +74,14 @@ public class AsyncServiceSpringConfig implements AsyncConfigurer {
|
|||
return executor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
|
||||
final ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
|
||||
threadPoolTaskScheduler.setPoolSize(5);
|
||||
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(false);
|
||||
threadPoolTaskScheduler.setThreadNamePrefix("SEB-Server-BgTask-");
|
||||
return threadPoolTaskScheduler;
|
||||
}
|
||||
// @Bean
|
||||
// public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
|
||||
// final ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
|
||||
// threadPoolTaskScheduler.setPoolSize(5);
|
||||
// threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(false);
|
||||
// threadPoolTaskScheduler.setThreadNamePrefix("SEB-Server-BgTask-");
|
||||
// return threadPoolTaskScheduler;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
|
|
|
@ -46,7 +46,7 @@ public class SEBClientPingService {
|
|||
}
|
||||
|
||||
@Scheduled(
|
||||
fixedDelayString = "${sebserver.webservice.api.exam.session.ping.batch.interval:100}",
|
||||
fixedDelayString = "${sebserver.webservice.api.exam.session.ping.batch.interval:500}",
|
||||
initialDelay = 1000)
|
||||
public void processPings() {
|
||||
if (this.pings.isEmpty()) {
|
||||
|
@ -84,14 +84,10 @@ public class SEBClientPingService {
|
|||
}
|
||||
}
|
||||
|
||||
public String notifyPing(
|
||||
public final String notifyPing(
|
||||
final String connectionToken,
|
||||
final String instructionConfirm) {
|
||||
|
||||
if (connectionToken == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (instructionConfirm != null) {
|
||||
this.pings.put(connectionToken, instructionConfirm);
|
||||
} else if (!this.pings.containsKey(connectionToken)) {
|
||||
|
@ -106,6 +102,10 @@ public class SEBClientPingService {
|
|||
final String instructionConfirm,
|
||||
final long timestamp) {
|
||||
|
||||
if (connectionToken == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ClientConnectionDataInternal activeClientConnection = this.examSessionCacheService
|
||||
.getClientConnection(connectionToken);
|
||||
|
||||
|
|
|
@ -8,34 +8,28 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
||||
@EnableAsync
|
||||
@Configuration
|
||||
@WebServiceProfile
|
||||
//@EnableAsync
|
||||
//@Configuration
|
||||
//@WebServiceProfile
|
||||
@Deprecated
|
||||
public class ControllerConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
|
||||
configurer.setTaskExecutor(threadPoolTaskExecutor());
|
||||
configurer.setDefaultTimeout(30000);
|
||||
}
|
||||
|
||||
public AsyncTaskExecutor threadPoolTaskExecutor() {
|
||||
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(7);
|
||||
executor.setMaxPoolSize(42);
|
||||
executor.setQueueCapacity(11);
|
||||
executor.setThreadNamePrefix("mvc-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
// @Override
|
||||
// public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
|
||||
// configurer.setTaskExecutor(threadPoolTaskExecutor());
|
||||
// configurer.setDefaultTimeout(30000);
|
||||
// }
|
||||
//
|
||||
// public AsyncTaskExecutor threadPoolTaskExecutor() {
|
||||
// final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// executor.setCorePoolSize(7);
|
||||
// executor.setMaxPoolSize(42);
|
||||
// executor.setQueueCapacity(11);
|
||||
// executor.setThreadNamePrefix("mvc-");
|
||||
// executor.initialize();
|
||||
// return executor;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
|
@ -93,7 +94,7 @@ public class ExamAPI_V1_Controller {
|
|||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public CompletableFuture<Collection<RunningExamInfo>> handshakeCreate(
|
||||
public DeferredResult<Collection<RunningExamInfo>> handshakeCreate(
|
||||
@RequestParam(name = API.PARAM_INSTITUTION_ID, required = false) final Long instIdRequestParam,
|
||||
@RequestParam(name = API.EXAM_API_PARAM_EXAM_ID, required = false) final Long examIdRequestParam,
|
||||
@RequestParam(name = API.EXAM_API_PARAM_CLIENT_ID, required = false) final String clientIdRequestParam,
|
||||
|
@ -102,69 +103,133 @@ public class ExamAPI_V1_Controller {
|
|||
final HttpServletRequest request,
|
||||
final HttpServletResponse response) {
|
||||
|
||||
return CompletableFuture.supplyAsync(
|
||||
() -> {
|
||||
final DeferredResult<Collection<RunningExamInfo>> deferredResult = new DeferredResult<>();
|
||||
this.executor.execute(() -> {
|
||||
final POSTMapper mapper = new POSTMapper(formParams, request.getQueryString());
|
||||
|
||||
final POSTMapper mapper = new POSTMapper(formParams, request.getQueryString());
|
||||
final String remoteAddr = this.getClientAddress(request);
|
||||
final Long institutionId = (instIdRequestParam != null)
|
||||
? instIdRequestParam
|
||||
: mapper.getLong(API.PARAM_INSTITUTION_ID);
|
||||
final Long examId = (examIdRequestParam != null)
|
||||
? examIdRequestParam
|
||||
: mapper.getLong(API.EXAM_API_PARAM_EXAM_ID);
|
||||
final String clientId = (clientIdRequestParam != null)
|
||||
? clientIdRequestParam
|
||||
: mapper.getString(API.EXAM_API_PARAM_CLIENT_ID);
|
||||
|
||||
final String remoteAddr = this.getClientAddress(request);
|
||||
final Long institutionId = (instIdRequestParam != null)
|
||||
? instIdRequestParam
|
||||
: mapper.getLong(API.PARAM_INSTITUTION_ID);
|
||||
final Long examId = (examIdRequestParam != null)
|
||||
? examIdRequestParam
|
||||
: mapper.getLong(API.EXAM_API_PARAM_EXAM_ID);
|
||||
final String clientId = (clientIdRequestParam != null)
|
||||
? clientIdRequestParam
|
||||
: mapper.getString(API.EXAM_API_PARAM_CLIENT_ID);
|
||||
// Create and get new ClientConnection if all integrity checks passes
|
||||
final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
.createClientConnection(
|
||||
principal,
|
||||
institutionId,
|
||||
remoteAddr,
|
||||
mapper.getString(API.EXAM_API_PARAM_SEB_VERSION),
|
||||
mapper.getString(API.EXAM_API_PARAM_SEB_OS_NAME),
|
||||
mapper.getString(API.EXAM_API_PARAM_SEB_MACHINE_NAME),
|
||||
examId,
|
||||
clientId)
|
||||
.getOrThrow();
|
||||
|
||||
// Create and get new ClientConnection if all integrity checks passes
|
||||
final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
.createClientConnection(
|
||||
principal,
|
||||
institutionId,
|
||||
remoteAddr,
|
||||
mapper.getString(API.EXAM_API_PARAM_SEB_VERSION),
|
||||
mapper.getString(API.EXAM_API_PARAM_SEB_OS_NAME),
|
||||
mapper.getString(API.EXAM_API_PARAM_SEB_MACHINE_NAME),
|
||||
examId,
|
||||
clientId)
|
||||
.getOrThrow();
|
||||
response.setHeader(
|
||||
API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||
clientConnection.connectionToken);
|
||||
|
||||
response.setHeader(
|
||||
API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||
clientConnection.connectionToken);
|
||||
// Crate list of running exams
|
||||
List<RunningExamInfo> result;
|
||||
if (examId == null) {
|
||||
result = this.examSessionService.getRunningExamsForInstitution(institutionId)
|
||||
.getOrThrow()
|
||||
.stream()
|
||||
.map(this::createRunningExamInfo)
|
||||
.filter(this::checkConsistency)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
|
||||
// Crate list of running exams
|
||||
List<RunningExamInfo> result;
|
||||
if (examId == null) {
|
||||
result = this.examSessionService.getRunningExamsForInstitution(institutionId)
|
||||
.getOrThrow()
|
||||
.stream()
|
||||
.map(this::createRunningExamInfo)
|
||||
.filter(this::checkConsistency)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
final Exam exam = this.examSessionService
|
||||
.getExamDAO()
|
||||
.byPK(examId)
|
||||
.getOrThrow();
|
||||
|
||||
final Exam exam = this.examSessionService
|
||||
.getExamDAO()
|
||||
.byPK(examId)
|
||||
.getOrThrow();
|
||||
result = Arrays.asList(createRunningExamInfo(exam));
|
||||
processASKSalt(response, clientConnection);
|
||||
processAlternativeBEK(response, clientConnection.examId);
|
||||
}
|
||||
|
||||
result = Arrays.asList(createRunningExamInfo(exam));
|
||||
processASKSalt(response, clientConnection);
|
||||
processAlternativeBEK(response, clientConnection.examId);
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
log.warn(
|
||||
"There are no currently running exams for institution: {}. SEB connection creation denied",
|
||||
institutionId);
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
log.warn(
|
||||
"There are no currently running exams for institution: {}. SEB connection creation denied",
|
||||
institutionId);
|
||||
}
|
||||
deferredResult.setResult(result);
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
this.executor);
|
||||
return deferredResult;
|
||||
|
||||
// return CompletableFuture.supplyAsync(
|
||||
// () -> {
|
||||
//
|
||||
// final POSTMapper mapper = new POSTMapper(formParams, request.getQueryString());
|
||||
//
|
||||
// final String remoteAddr = this.getClientAddress(request);
|
||||
// final Long institutionId = (instIdRequestParam != null)
|
||||
// ? instIdRequestParam
|
||||
// : mapper.getLong(API.PARAM_INSTITUTION_ID);
|
||||
// final Long examId = (examIdRequestParam != null)
|
||||
// ? examIdRequestParam
|
||||
// : mapper.getLong(API.EXAM_API_PARAM_EXAM_ID);
|
||||
// final String clientId = (clientIdRequestParam != null)
|
||||
// ? clientIdRequestParam
|
||||
// : mapper.getString(API.EXAM_API_PARAM_CLIENT_ID);
|
||||
//
|
||||
// // Create and get new ClientConnection if all integrity checks passes
|
||||
// final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
// .createClientConnection(
|
||||
// principal,
|
||||
// institutionId,
|
||||
// remoteAddr,
|
||||
// mapper.getString(API.EXAM_API_PARAM_SEB_VERSION),
|
||||
// mapper.getString(API.EXAM_API_PARAM_SEB_OS_NAME),
|
||||
// mapper.getString(API.EXAM_API_PARAM_SEB_MACHINE_NAME),
|
||||
// examId,
|
||||
// clientId)
|
||||
// .getOrThrow();
|
||||
//
|
||||
// response.setHeader(
|
||||
// API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||
// clientConnection.connectionToken);
|
||||
//
|
||||
// // Crate list of running exams
|
||||
// List<RunningExamInfo> result;
|
||||
// if (examId == null) {
|
||||
// result = this.examSessionService.getRunningExamsForInstitution(institutionId)
|
||||
// .getOrThrow()
|
||||
// .stream()
|
||||
// .map(this::createRunningExamInfo)
|
||||
// .filter(this::checkConsistency)
|
||||
// .collect(Collectors.toList());
|
||||
// } else {
|
||||
//
|
||||
// final Exam exam = this.examSessionService
|
||||
// .getExamDAO()
|
||||
// .byPK(examId)
|
||||
// .getOrThrow();
|
||||
//
|
||||
// result = Arrays.asList(createRunningExamInfo(exam));
|
||||
// processASKSalt(response, clientConnection);
|
||||
// processAlternativeBEK(response, clientConnection.examId);
|
||||
// }
|
||||
//
|
||||
// if (result.isEmpty()) {
|
||||
// log.warn(
|
||||
// "There are no currently running exams for institution: {}. SEB connection creation denied",
|
||||
// institutionId);
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// },
|
||||
// this.executor);
|
||||
}
|
||||
|
||||
private boolean checkConsistency(final RunningExamInfo info) {
|
||||
|
@ -183,7 +248,7 @@ public class ExamAPI_V1_Controller {
|
|||
path = API.EXAM_API_HANDSHAKE_ENDPOINT,
|
||||
method = RequestMethod.PATCH,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public CompletableFuture<Void> handshakeUpdate(
|
||||
public DeferredResult<Void> handshakeUpdate(
|
||||
@RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||
@RequestParam(name = API.EXAM_API_PARAM_EXAM_ID, required = false) final Long examId,
|
||||
@RequestParam(name = API.EXAM_API_USER_SESSION_ID, required = false) final String userSessionId,
|
||||
|
@ -198,39 +263,71 @@ public class ExamAPI_V1_Controller {
|
|||
final HttpServletRequest request,
|
||||
final HttpServletResponse response) {
|
||||
|
||||
return CompletableFuture.runAsync(
|
||||
() -> {
|
||||
final DeferredResult<Void> deferredResult = new DeferredResult<>();
|
||||
this.executor.execute(() -> {
|
||||
{
|
||||
|
||||
final String remoteAddr = this.getClientAddress(request);
|
||||
final Long institutionId = getInstitutionId(principal);
|
||||
final String remoteAddr = this.getClientAddress(request);
|
||||
final Long institutionId = getInstitutionId(principal);
|
||||
|
||||
final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
.updateClientConnection(
|
||||
connectionToken,
|
||||
institutionId,
|
||||
examId,
|
||||
remoteAddr,
|
||||
sebVersion,
|
||||
sebOSName,
|
||||
sebMachinName,
|
||||
userSessionId,
|
||||
clientId,
|
||||
browserSignatureKey)
|
||||
.getOrThrow();
|
||||
final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
.updateClientConnection(
|
||||
connectionToken,
|
||||
institutionId,
|
||||
examId,
|
||||
remoteAddr,
|
||||
sebVersion,
|
||||
sebOSName,
|
||||
sebMachinName,
|
||||
userSessionId,
|
||||
clientId,
|
||||
browserSignatureKey)
|
||||
.getOrThrow();
|
||||
|
||||
if (clientConnection.examId != null) {
|
||||
processASKSalt(response, clientConnection);
|
||||
processAlternativeBEK(response, clientConnection.examId);
|
||||
}
|
||||
},
|
||||
this.executor);
|
||||
if (clientConnection.examId != null) {
|
||||
processASKSalt(response, clientConnection);
|
||||
processAlternativeBEK(response, clientConnection.examId);
|
||||
}
|
||||
|
||||
deferredResult.setResult(null);
|
||||
}
|
||||
});
|
||||
|
||||
return deferredResult;
|
||||
|
||||
// return CompletableFuture.runAsync(
|
||||
// () -> {
|
||||
//
|
||||
// final String remoteAddr = this.getClientAddress(request);
|
||||
// final Long institutionId = getInstitutionId(principal);
|
||||
//
|
||||
// final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
// .updateClientConnection(
|
||||
// connectionToken,
|
||||
// institutionId,
|
||||
// examId,
|
||||
// remoteAddr,
|
||||
// sebVersion,
|
||||
// sebOSName,
|
||||
// sebMachinName,
|
||||
// userSessionId,
|
||||
// clientId,
|
||||
// browserSignatureKey)
|
||||
// .getOrThrow();
|
||||
//
|
||||
// if (clientConnection.examId != null) {
|
||||
// processASKSalt(response, clientConnection);
|
||||
// processAlternativeBEK(response, clientConnection.examId);
|
||||
// }
|
||||
// },
|
||||
// this.executor);
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.EXAM_API_HANDSHAKE_ENDPOINT,
|
||||
method = RequestMethod.PUT,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public CompletableFuture<Void> handshakeEstablish(
|
||||
public DeferredResult<Void> handshakeEstablish(
|
||||
@RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||
@RequestParam(name = API.EXAM_API_PARAM_EXAM_ID, required = false) final Long examId,
|
||||
@RequestParam(name = API.EXAM_API_USER_SESSION_ID, required = false) final String userSessionId,
|
||||
|
@ -245,31 +342,58 @@ public class ExamAPI_V1_Controller {
|
|||
final HttpServletRequest request,
|
||||
final HttpServletResponse response) {
|
||||
|
||||
return CompletableFuture.runAsync(
|
||||
() -> {
|
||||
final DeferredResult<Void> deferredResult = new DeferredResult<>();
|
||||
this.executor.execute(() -> {
|
||||
|
||||
final String remoteAddr = this.getClientAddress(request);
|
||||
final Long institutionId = getInstitutionId(principal);
|
||||
final String remoteAddr = this.getClientAddress(request);
|
||||
final Long institutionId = getInstitutionId(principal);
|
||||
|
||||
final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
.establishClientConnection(
|
||||
connectionToken,
|
||||
institutionId,
|
||||
examId,
|
||||
remoteAddr,
|
||||
sebVersion,
|
||||
sebOSName,
|
||||
sebMachinName,
|
||||
userSessionId,
|
||||
clientId,
|
||||
browserSignatureKey)
|
||||
.getOrThrow();
|
||||
final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
.establishClientConnection(
|
||||
connectionToken,
|
||||
institutionId,
|
||||
examId,
|
||||
remoteAddr,
|
||||
sebVersion,
|
||||
sebOSName,
|
||||
sebMachinName,
|
||||
userSessionId,
|
||||
clientId,
|
||||
browserSignatureKey)
|
||||
.getOrThrow();
|
||||
|
||||
if (clientConnection.examId != null) {
|
||||
processAlternativeBEK(response, clientConnection.examId);
|
||||
}
|
||||
},
|
||||
this.executor);
|
||||
if (clientConnection.examId != null) {
|
||||
processAlternativeBEK(response, clientConnection.examId);
|
||||
}
|
||||
|
||||
deferredResult.setResult(null);
|
||||
});
|
||||
return deferredResult;
|
||||
// return CompletableFuture.runAsync(
|
||||
// () -> {
|
||||
//
|
||||
// final String remoteAddr = this.getClientAddress(request);
|
||||
// final Long institutionId = getInstitutionId(principal);
|
||||
//
|
||||
// final ClientConnection clientConnection = this.sebClientConnectionService
|
||||
// .establishClientConnection(
|
||||
// connectionToken,
|
||||
// institutionId,
|
||||
// examId,
|
||||
// remoteAddr,
|
||||
// sebVersion,
|
||||
// sebOSName,
|
||||
// sebMachinName,
|
||||
// userSessionId,
|
||||
// clientId,
|
||||
// browserSignatureKey)
|
||||
// .getOrThrow();
|
||||
//
|
||||
// if (clientConnection.examId != null) {
|
||||
// processAlternativeBEK(response, clientConnection.examId);
|
||||
// }
|
||||
// },
|
||||
// this.executor);
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
|
|
Loading…
Reference in a new issue