ping performance
This commit is contained in:
parent
379c786064
commit
49abd4e5b0
3 changed files with 18 additions and 573 deletions
|
@ -26,13 +26,13 @@ import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestHeader;
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
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.bind.annotation.RestController;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
|
@ -270,29 +270,30 @@ public class ExamAPI_V1_Controller {
|
||||||
this.executor);
|
this.executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final ResponseEntity<String> EMPTY_PING_RESPONSE = ResponseEntity
|
|
||||||
.ok()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.EXAM_API_PING_ENDPOINT,
|
path = API.EXAM_API_PING_ENDPOINT,
|
||||||
method = RequestMethod.POST,
|
method = RequestMethod.POST,
|
||||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
public void ping(
|
public void ping(final HttpServletRequest request, final HttpServletResponse response) {
|
||||||
@RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
|
||||||
@RequestParam(name = API.EXAM_API_PING_TIMESTAMP, required = true) final long timestamp,
|
final String connectionToken = request.getHeader(API.EXAM_API_SEB_CONNECTION_TOKEN);
|
||||||
@RequestParam(name = API.EXAM_API_PING_NUMBER, required = false) final int pingNumber,
|
final String timeStampString = request.getParameter(API.EXAM_API_PING_TIMESTAMP);
|
||||||
final HttpServletResponse response) {
|
final String pingNumString = request.getParameter(API.EXAM_API_PING_NUMBER);
|
||||||
|
|
||||||
final String instruction = this.sebClientConnectionService
|
final String instruction = this.sebClientConnectionService
|
||||||
.notifyPing(connectionToken, timestamp, pingNumber);
|
.notifyPing(
|
||||||
|
connectionToken,
|
||||||
|
Long.parseLong(timeStampString),
|
||||||
|
pingNumString != null ? Integer.parseInt(pingNumString) : -1);
|
||||||
|
|
||||||
if (instruction == null) {
|
if (instruction == null) {
|
||||||
|
response.setStatus(HttpStatus.NO_CONTENT.value());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
response.setStatus(HttpStatus.OK.value());
|
||||||
response.getOutputStream().write(instruction.getBytes());
|
response.getOutputStream().write(instruction.getBytes());
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
log.error("Failed to send instruction as response: {}", connectionToken, e);
|
log.error("Failed to send instruction as response: {}", connectionToken, e);
|
||||||
|
@ -303,6 +304,7 @@ public class ExamAPI_V1_Controller {
|
||||||
path = API.EXAM_API_EVENT_ENDPOINT,
|
path = API.EXAM_API_EVENT_ENDPOINT,
|
||||||
method = RequestMethod.POST,
|
method = RequestMethod.POST,
|
||||||
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
public void event(
|
public void event(
|
||||||
@RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
@RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||||
@RequestBody(required = true) final ClientEvent event) {
|
@RequestBody(required = true) final ClientEvent event) {
|
||||||
|
|
|
@ -1,557 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 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;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
|
||||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
|
||||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
|
||||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
|
||||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
|
|
||||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
|
||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.RunningExamInfo;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
|
||||||
|
|
||||||
public class HTTPClientBot {
|
|
||||||
|
|
||||||
private static final long ONE_SECOND = 1000; // milliseconds
|
|
||||||
private static final long TEN_SECONDS = 10 * ONE_SECOND;
|
|
||||||
private static final long ONE_MINUTE = 60 * ONE_SECOND;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final long ONE_HOUR = 60 * ONE_MINUTE;
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(HTTPClientBot.class);
|
|
||||||
|
|
||||||
private final ExecutorService executorService = Executors.newFixedThreadPool(20);
|
|
||||||
|
|
||||||
private final List<String> scopes = Arrays.asList("read", "write");
|
|
||||||
|
|
||||||
private final String webserviceAddress;
|
|
||||||
private final String accessTokenEndpoint;
|
|
||||||
private final String clientId;
|
|
||||||
private final String clientSecret;
|
|
||||||
private final String apiPath;
|
|
||||||
private final String apiVersion;
|
|
||||||
private final String examId;
|
|
||||||
private final String institutionId;
|
|
||||||
|
|
||||||
private final int numberOfConnections;
|
|
||||||
|
|
||||||
private final long establishDelay;
|
|
||||||
private final long pingInterval;
|
|
||||||
private final long pingPause;
|
|
||||||
private final long pingPauseDelay;
|
|
||||||
private final long errorInterval;
|
|
||||||
private final long warnInterval;
|
|
||||||
private final long runtime;
|
|
||||||
private final int connectionAttempts;
|
|
||||||
|
|
||||||
private final Random random = new Random();
|
|
||||||
|
|
||||||
public HTTPClientBot(final Properties properties) {
|
|
||||||
|
|
||||||
//this.webserviceAddress = properties.getProperty("webserviceAddress", "http://ralph.ethz.ch:8080");
|
|
||||||
this.webserviceAddress = properties.getProperty("webserviceAddress", "http://localhost:8080");
|
|
||||||
//this.webserviceAddress = properties.getProperty("webserviceAddress", "https://seb.test-swissmooc.ch");
|
|
||||||
|
|
||||||
this.accessTokenEndpoint = properties.getProperty("accessTokenEndpoint", "/oauth/token");
|
|
||||||
this.clientId = properties.getProperty("clientId", "test");
|
|
||||||
this.clientSecret = properties.getProperty("clientSecret", "test");
|
|
||||||
//
|
|
||||||
// this.clientId = properties.getProperty("clientId", "B48_1~UnU3c0K]0c");
|
|
||||||
// this.clientSecret =
|
|
||||||
// properties.getProperty("clientSecret",
|
|
||||||
// "io0]PRpzUNVWv*Bg^B=@4!jH$r^Y$CmgheETsd}4ewIXEMq~XPHszIr+$a`S$z[(");
|
|
||||||
this.apiPath = properties.getProperty("apiPath", "/exam-api");
|
|
||||||
this.apiVersion = properties.getProperty("apiVersion", "v1");
|
|
||||||
// this.examId = properties.getProperty("examId", "2");
|
|
||||||
// this.institutionId = properties.getProperty("institutionId", "1");
|
|
||||||
this.examId = properties.getProperty("examId", "2");
|
|
||||||
this.institutionId = properties.getProperty("institutionId", "1");
|
|
||||||
this.numberOfConnections = Integer.parseInt(properties.getProperty("numberOfConnections", "100"));
|
|
||||||
this.pingInterval = Long.parseLong(properties.getProperty("pingInterval", "200"));
|
|
||||||
this.establishDelay = Long.parseLong(properties.getProperty("establishDelay", "0"));
|
|
||||||
this.pingPause = Long.parseLong(properties.getProperty("pingPause", "20000"));
|
|
||||||
this.pingPauseDelay = Long.parseLong(properties.getProperty("pingPauseDelay", "5000"));
|
|
||||||
this.errorInterval = Long.parseLong(properties.getProperty("errorInterval", String.valueOf(TEN_SECONDS)));
|
|
||||||
this.warnInterval = Long.parseLong(properties.getProperty("errorInterval", String.valueOf(TEN_SECONDS / 2)));
|
|
||||||
// this.runtime = Long.parseLong(properties.getProperty("runtime", String.valueOf(ONE_MINUTE)));
|
|
||||||
this.runtime = Long.parseLong(properties.getProperty("runtime", String.valueOf(ONE_MINUTE)));
|
|
||||||
this.connectionAttempts = Integer.parseInt(properties.getProperty("connectionAttempts", "1"));
|
|
||||||
|
|
||||||
for (int i = 0; i < this.numberOfConnections; i++) {
|
|
||||||
this.executorService.execute(new ConnectionBot("connection_" + getRandomName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.executorService.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getRandomName() {
|
|
||||||
final StringBuilder sb = new StringBuilder(String.valueOf(this.random.nextInt(100)));
|
|
||||||
while (sb.length() < 3) {
|
|
||||||
sb.insert(0, "0");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(final String[] args) {
|
|
||||||
new HTTPClientBot(System.getProperties());
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class ConnectionBot implements Runnable {
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
private final OAuth2RestTemplate restTemplate;
|
|
||||||
|
|
||||||
private final String handshakeURI = HTTPClientBot.this.webserviceAddress +
|
|
||||||
HTTPClientBot.this.apiPath + "/" +
|
|
||||||
HTTPClientBot.this.apiVersion + API.EXAM_API_HANDSHAKE_ENDPOINT;
|
|
||||||
private final String configurartionURI = HTTPClientBot.this.webserviceAddress +
|
|
||||||
HTTPClientBot.this.apiPath + "/" +
|
|
||||||
HTTPClientBot.this.apiVersion + API.EXAM_API_CONFIGURATION_REQUEST_ENDPOINT;
|
|
||||||
private final String pingURI = HTTPClientBot.this.webserviceAddress +
|
|
||||||
HTTPClientBot.this.apiPath + "/" +
|
|
||||||
HTTPClientBot.this.apiVersion + API.EXAM_API_PING_ENDPOINT;
|
|
||||||
private final String eventURI = HTTPClientBot.this.webserviceAddress +
|
|
||||||
HTTPClientBot.this.apiPath + "/" +
|
|
||||||
HTTPClientBot.this.apiVersion + API.EXAM_API_EVENT_ENDPOINT;
|
|
||||||
|
|
||||||
private final HttpEntity<?> connectBody;
|
|
||||||
|
|
||||||
protected ConnectionBot(final String name) {
|
|
||||||
this.name = name;
|
|
||||||
this.restTemplate = createRestTemplate(null);
|
|
||||||
final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
|
||||||
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
|
||||||
this.connectBody = new HttpEntity<>(API.PARAM_INSTITUTION_ID +
|
|
||||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
|
|
||||||
HTTPClientBot.this.institutionId
|
|
||||||
// + Constants.FORM_URL_ENCODED_SEPARATOR
|
|
||||||
// + API.EXAM_API_PARAM_EXAM_ID
|
|
||||||
// + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR
|
|
||||||
// + HTTPClientBot.this.examId
|
|
||||||
,
|
|
||||||
headers);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
log.info("ConnectionBot {} : Client-Connection-Bot started: {}\n"
|
|
||||||
+ "webserviceAddress: {}\n"
|
|
||||||
+ "accessTokenEndpoint: {}\n"
|
|
||||||
+ "clientId: {}\n"
|
|
||||||
+ "clientSecret: {}\n"
|
|
||||||
+ "apiPath: {}\n"
|
|
||||||
+ "apiVersion: {}\n"
|
|
||||||
+ "examId: {}\n"
|
|
||||||
+ "institutionId: {}\n"
|
|
||||||
+ "pingInterval: {}\n"
|
|
||||||
+ "errorInterval: {}\n"
|
|
||||||
+ "runtime: {}\n", this.name,
|
|
||||||
HTTPClientBot.this.webserviceAddress,
|
|
||||||
HTTPClientBot.this.accessTokenEndpoint,
|
|
||||||
HTTPClientBot.this.clientId,
|
|
||||||
HTTPClientBot.this.clientSecret,
|
|
||||||
HTTPClientBot.this.apiPath,
|
|
||||||
HTTPClientBot.this.apiVersion,
|
|
||||||
HTTPClientBot.this.examId,
|
|
||||||
HTTPClientBot.this.institutionId,
|
|
||||||
HTTPClientBot.this.pingInterval,
|
|
||||||
HTTPClientBot.this.errorInterval);
|
|
||||||
|
|
||||||
int attempt = 0;
|
|
||||||
String connectionToken = null;
|
|
||||||
|
|
||||||
while (connectionToken == null && attempt < HTTPClientBot.this.connectionAttempts) {
|
|
||||||
attempt++;
|
|
||||||
log.info("ConnectionBot {} : Try to request access-token; attempt: {}", this.name, attempt);
|
|
||||||
try {
|
|
||||||
|
|
||||||
final OAuth2AccessToken accessToken = this.restTemplate.getAccessToken();
|
|
||||||
log.info("ConnectionBot {} : Got access token: {}", this.name, accessToken);
|
|
||||||
connectionToken = createConnection();
|
|
||||||
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("ConnectionBot {} : Failed to request access-token: ", this.name, e);
|
|
||||||
if (attempt >= HTTPClientBot.this.connectionAttempts) {
|
|
||||||
log.error("ConnectionBot {} : Gave up afer {} connection attempts: ", this.name, attempt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
|
||||||
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
|
||||||
headers.set(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionToken);
|
|
||||||
|
|
||||||
final MultiValueMap<String, String> eventHeaders = new LinkedMultiValueMap<>();
|
|
||||||
eventHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
|
|
||||||
eventHeaders.set(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionToken);
|
|
||||||
|
|
||||||
if (connectionToken != null) {
|
|
||||||
if (getConfig(headers) && establishConnection(headers)) {
|
|
||||||
|
|
||||||
final PingEntity pingHeader = new PingEntity(headers);
|
|
||||||
final EventEntity errorHeader = new EventEntity(eventHeaders, "ERROR_LOG");
|
|
||||||
final EventEntity warnHeader = new EventEntity(eventHeaders, "WARN_LOG");
|
|
||||||
|
|
||||||
try {
|
|
||||||
final long startTime = System.currentTimeMillis();
|
|
||||||
final long endTime = startTime + HTTPClientBot.this.runtime;
|
|
||||||
final long pingPauseStart = startTime + HTTPClientBot.this.pingPauseDelay;
|
|
||||||
final long pingPauseEnd = pingPauseStart + HTTPClientBot.this.pingPause;
|
|
||||||
long currentTime = startTime;
|
|
||||||
long lastPingTime = startTime;
|
|
||||||
long lastErrorTime = startTime;
|
|
||||||
long lastWarnTime = startTime;
|
|
||||||
|
|
||||||
while (currentTime < endTime) {
|
|
||||||
if (currentTime - lastPingTime >= HTTPClientBot.this.pingInterval &&
|
|
||||||
!(currentTime > pingPauseStart && currentTime < pingPauseEnd)) {
|
|
||||||
|
|
||||||
pingHeader.next();
|
|
||||||
if (!sendPing(pingHeader)) {
|
|
||||||
// expecting a quit instruction was sent here
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastPingTime = currentTime;
|
|
||||||
}
|
|
||||||
if (currentTime - lastErrorTime >= HTTPClientBot.this.errorInterval) {
|
|
||||||
errorHeader.next();
|
|
||||||
sendEvent(errorHeader);
|
|
||||||
lastErrorTime = currentTime;
|
|
||||||
}
|
|
||||||
if (currentTime - lastWarnTime >= HTTPClientBot.this.warnInterval) {
|
|
||||||
warnHeader.next();
|
|
||||||
sendEvent(warnHeader);
|
|
||||||
lastWarnTime = currentTime;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep(50);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
}
|
|
||||||
currentTime = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
} catch (final Throwable t) {
|
|
||||||
log.error("ConnectionBot {} : Error sending events: ", this.name, t);
|
|
||||||
} finally {
|
|
||||||
disconnect(connectionToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createConnection() {
|
|
||||||
log.info("ConnectionBot {} : init connection", this.name);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final ResponseEntity<Collection<RunningExamInfo>> exchange = this.restTemplate.exchange(
|
|
||||||
this.handshakeURI,
|
|
||||||
HttpMethod.POST,
|
|
||||||
this.connectBody,
|
|
||||||
new ParameterizedTypeReference<Collection<RunningExamInfo>>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
final HttpStatus statusCode = exchange.getStatusCode();
|
|
||||||
if (statusCode.isError()) {
|
|
||||||
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
final Collection<RunningExamInfo> body = exchange.getBody();
|
|
||||||
final String token = exchange.getHeaders().getFirst(API.EXAM_API_SEB_CONNECTION_TOKEN);
|
|
||||||
|
|
||||||
log.info("ConnectionBot {} : successfully created connection, token: {} body: {} ", this.name, token,
|
|
||||||
body);
|
|
||||||
|
|
||||||
return token;
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("ConnectionBot {} : Failed to init connection", this.name, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getConfig(final MultiValueMap<String, String> headers) {
|
|
||||||
final HttpEntity<?> configHeader = new HttpEntity<>(headers);
|
|
||||||
|
|
||||||
log.info("ConnectionBot {} : get SEB Configuration", this.name);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final ResponseEntity<byte[]> exchange = this.restTemplate.exchange(
|
|
||||||
this.configurartionURI + "?" + API.EXAM_API_PARAM_EXAM_ID +
|
|
||||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
|
|
||||||
HTTPClientBot.this.examId,
|
|
||||||
HttpMethod.GET,
|
|
||||||
configHeader,
|
|
||||||
new ParameterizedTypeReference<byte[]>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
final HttpStatus statusCode = exchange.getStatusCode();
|
|
||||||
if (statusCode.isError()) {
|
|
||||||
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte[] config = exchange.getBody();
|
|
||||||
|
|
||||||
if (ArrayUtils.isEmpty(config)) {
|
|
||||||
log.error("No Exam config get from API. processing anyway");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("ConnectionBot {} : successfully requested exam config: " + Utils.toString(config),
|
|
||||||
this.name);
|
|
||||||
} else {
|
|
||||||
log.info("ConnectionBot {} : successfully requested exam config", this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("ConnectionBot {} : Failed get SEB Configuration", this.name, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean establishConnection(final MultiValueMap<String, String> headers) {
|
|
||||||
|
|
||||||
if (HTTPClientBot.this.establishDelay > 0) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
log.info("Wait for connection activation -> {}", HTTPClientBot.this.establishDelay);
|
|
||||||
|
|
||||||
Thread.sleep(HTTPClientBot.this.establishDelay);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("Failed to wait for connection activiation -> {} : {}", HTTPClientBot.this.establishDelay,
|
|
||||||
e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final HttpEntity<?> configHeader = new HttpEntity<>(
|
|
||||||
API.EXAM_API_USER_SESSION_ID +
|
|
||||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
|
|
||||||
this.name,
|
|
||||||
headers);
|
|
||||||
|
|
||||||
log.info("ConnectionBot {} : Trying to establish SEB client connection", this.name);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
final ResponseEntity<String> exchange = this.restTemplate.exchange(
|
|
||||||
this.handshakeURI,
|
|
||||||
HttpMethod.PUT,
|
|
||||||
configHeader,
|
|
||||||
new ParameterizedTypeReference<String>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
final HttpStatus statusCode = exchange.getStatusCode();
|
|
||||||
if (statusCode.isError()) {
|
|
||||||
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("ConnectionBot {} : successfully established SEB client connection", this.name);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("ConnectionBot {} : Failed get established SEB client connection", this.name, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean sendPing(final HttpEntity<String> pingHeader) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
final ResponseEntity<String> exchange = this.restTemplate.exchange(
|
|
||||||
this.pingURI,
|
|
||||||
HttpMethod.POST,
|
|
||||||
pingHeader,
|
|
||||||
new ParameterizedTypeReference<String>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exchange.hasBody() && exchange.getBody().contains("SEB_QUIT")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("ConnectionBot {} : Failed send ping", this.name, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean sendEvent(final HttpEntity<String> eventHeader) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
this.restTemplate.exchange(
|
|
||||||
this.eventURI,
|
|
||||||
HttpMethod.POST,
|
|
||||||
eventHeader,
|
|
||||||
new ParameterizedTypeReference<String>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("ConnectionBot {} : Failed send event", this.name, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean disconnect(final String connectionToken) {
|
|
||||||
final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
|
||||||
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
|
||||||
headers.set(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionToken);
|
|
||||||
final HttpEntity<?> configHeader = new HttpEntity<>(headers);
|
|
||||||
|
|
||||||
log.info("ConnectionBot {} : Trying to delete SEB client connection", this.name);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
final ResponseEntity<String> exchange = this.restTemplate.exchange(
|
|
||||||
this.handshakeURI,
|
|
||||||
HttpMethod.DELETE,
|
|
||||||
configHeader,
|
|
||||||
new ParameterizedTypeReference<String>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
final HttpStatus statusCode = exchange.getStatusCode();
|
|
||||||
if (statusCode.isError()) {
|
|
||||||
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("ConnectionBot {} : successfully deleted SEB client connection", this.name);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("ConnectionBot {} : Failed get deleted SEB client connection", this.name, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private OAuth2RestTemplate createRestTemplate(final String scopes) {
|
|
||||||
final ClientCredentialsResourceDetails clientCredentialsResourceDetails =
|
|
||||||
new ClientCredentialsResourceDetails();
|
|
||||||
clientCredentialsResourceDetails.setAccessTokenUri(this.webserviceAddress + this.accessTokenEndpoint);
|
|
||||||
clientCredentialsResourceDetails.setClientId(this.clientId);
|
|
||||||
clientCredentialsResourceDetails.setClientSecret(this.clientSecret);
|
|
||||||
if (StringUtils.isBlank(scopes)) {
|
|
||||||
clientCredentialsResourceDetails.setScope(this.scopes);
|
|
||||||
} else {
|
|
||||||
clientCredentialsResourceDetails.setScope(
|
|
||||||
Arrays.asList(StringUtils.split(scopes, Constants.LIST_SEPARATOR)));
|
|
||||||
}
|
|
||||||
|
|
||||||
final OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(clientCredentialsResourceDetails);
|
|
||||||
restTemplate.setErrorHandler(new OAuth2ErrorHandler(clientCredentialsResourceDetails) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleError(final ClientHttpResponse response) throws IOException {
|
|
||||||
System.out.println("********************** handleError: " + response.getStatusCode());
|
|
||||||
super.handleError(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
restTemplate
|
|
||||||
.getMessageConverters()
|
|
||||||
.add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
|
|
||||||
//restTemplate.setRetryBadAccessTokens(true);
|
|
||||||
|
|
||||||
final SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
|
|
||||||
simpleClientHttpRequestFactory.setReadTimeout(5000);
|
|
||||||
simpleClientHttpRequestFactory.setOutputStreaming(false);
|
|
||||||
restTemplate.setRequestFactory(simpleClientHttpRequestFactory);
|
|
||||||
|
|
||||||
return restTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PingEntity extends HttpEntity<String> {
|
|
||||||
private final String pingBodyTemplate = API.EXAM_API_PING_TIMESTAMP +
|
|
||||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
|
|
||||||
"%s" +
|
|
||||||
Constants.FORM_URL_ENCODED_SEPARATOR +
|
|
||||||
API.EXAM_API_PING_NUMBER +
|
|
||||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
|
|
||||||
"%s";
|
|
||||||
|
|
||||||
private long timestamp = 0;
|
|
||||||
private int count = 0;
|
|
||||||
|
|
||||||
protected PingEntity(final MultiValueMap<String, String> headers) {
|
|
||||||
super(headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
void next() {
|
|
||||||
this.timestamp = System.currentTimeMillis();
|
|
||||||
this.count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getBody() {
|
|
||||||
return String.format(this.pingBodyTemplate, this.timestamp, this.count);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasBody() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class EventEntity extends HttpEntity<String> {
|
|
||||||
private final String eventBodyTemplate =
|
|
||||||
"{ \"type\": \"%s\", \"timestamp\": %s, \"text\": \"some error " + UUID.randomUUID() + " \" }";
|
|
||||||
|
|
||||||
private long timestamp = 0;
|
|
||||||
private final String eventType;
|
|
||||||
|
|
||||||
protected EventEntity(final MultiValueMap<String, String> headers, final String eventType) {
|
|
||||||
super(headers);
|
|
||||||
this.eventType = eventType;
|
|
||||||
}
|
|
||||||
|
|
||||||
void next() {
|
|
||||||
this.timestamp = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getBody() {
|
|
||||||
return String.format(this.eventBodyTemplate, this.eventType, this.timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasBody() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -492,7 +492,7 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
|
|
||||||
final MockHttpServletResponse sendPing = super.sendPing(accessToken, connectionToken, 1);
|
final MockHttpServletResponse sendPing = super.sendPing(accessToken, connectionToken, 1);
|
||||||
// check correct response
|
// check correct response
|
||||||
assertTrue(HttpStatus.OK.value() == sendPing.getStatus());
|
assertTrue(HttpStatus.NO_CONTENT.value() == sendPing.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -536,7 +536,7 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
"testEvent1");
|
"testEvent1");
|
||||||
|
|
||||||
// check correct response
|
// check correct response
|
||||||
assertTrue(HttpStatus.OK.value() == sendEvent.getStatus());
|
assertTrue(HttpStatus.NO_CONTENT.value() == sendEvent.getStatus());
|
||||||
|
|
||||||
// check event stored on db
|
// check event stored on db
|
||||||
List<ClientEventRecord> events = this.clientEventRecordMapper
|
List<ClientEventRecord> events = this.clientEventRecordMapper
|
||||||
|
@ -563,7 +563,7 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
"testEvent2");
|
"testEvent2");
|
||||||
|
|
||||||
// check correct response
|
// check correct response
|
||||||
assertTrue(HttpStatus.OK.value() == sendEvent.getStatus());
|
assertTrue(HttpStatus.NO_CONTENT.value() == sendEvent.getStatus());
|
||||||
|
|
||||||
// check event stored on db
|
// check event stored on db
|
||||||
events = this.clientEventRecordMapper
|
events = this.clientEventRecordMapper
|
||||||
|
@ -595,7 +595,7 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
100.0,
|
100.0,
|
||||||
"testEvent1");
|
"testEvent1");
|
||||||
// check correct response
|
// check correct response
|
||||||
assertTrue(HttpStatus.OK.value() == sendEvent.getStatus());
|
assertTrue(HttpStatus.NO_CONTENT.value() == sendEvent.getStatus());
|
||||||
|
|
||||||
final List<ClientEventRecord> events = this.clientEventRecordMapper
|
final List<ClientEventRecord> events = this.clientEventRecordMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
|
@ -620,7 +620,7 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
100.0,
|
100.0,
|
||||||
"testEvent1");
|
"testEvent1");
|
||||||
// check correct response
|
// check correct response
|
||||||
assertTrue(HttpStatus.OK.value() == sendEvent.getStatus());
|
assertTrue(HttpStatus.NO_CONTENT.value() == sendEvent.getStatus());
|
||||||
|
|
||||||
final List<ClientEventRecord> events = this.clientEventRecordMapper
|
final List<ClientEventRecord> events = this.clientEventRecordMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
|
|
Loading…
Reference in a new issue