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…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti