1 package org.openecomp.simulator.controller;
3 import com.fasterxml.jackson.databind.DeserializationFeature;
4 import com.fasterxml.jackson.databind.ObjectMapper;
5 import org.mockserver.integration.ClientAndServer;
6 import org.mockserver.matchers.Times;
7 import org.mockserver.model.HttpRequest;
8 import org.mockserver.model.HttpResponse;
9 import static org.mockserver.model.HttpRequest.request;
10 import static org.mockserver.model.HttpResponse.response;
12 import org.openecomp.simulator.errorHandling.VidSimulatorException;
13 import org.openecomp.simulator.model.SimulatorRequestResponseExpectation;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.springframework.core.io.ClassPathResource;
17 import org.springframework.core.io.Resource;
18 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
19 import org.springframework.core.io.support.PropertiesLoaderUtils;
20 import org.springframework.core.io.support.ResourcePatternResolver;
21 import org.springframework.http.HttpStatus;
22 import org.springframework.http.ResponseEntity;
23 import org.springframework.stereotype.Component;
24 import org.springframework.web.bind.annotation.*;
25 import org.springframework.web.servlet.HandlerMapping;
26 import org.springframework.web.servlet.View;
28 import javax.annotation.PostConstruct;
29 import javax.annotation.PreDestroy;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
33 import java.util.List;
35 import java.io.UnsupportedEncodingException;
36 import java.net.URLEncoder;
37 import java.util.Properties;
38 import java.util.Scanner;
40 import static org.mockserver.integration.ClientAndServer.startClientAndServer;
41 import static org.mockserver.matchers.Times.exactly;
45 public class SimulatorController {
47 private static final Times DEFAULT_NUMBER_OF_TIMES = Times.unlimited();
48 private ClientAndServer mockServer;
49 private String mockServerProtocol;
50 private String mockServerHost;
51 private Integer mockServerPort;
52 private Boolean enablePresetRegistration;
55 Logger logger = LoggerFactory.getLogger(SimulatorController.class);
59 logger.info("Starting VID Simulator....");
61 mockServer = startClientAndServer(mockServerPort);
66 public void tearDown(){
67 logger.info("Stopping VID Simulator....");
72 private void presetRegister() {
74 if (enablePresetRegistration == null || !enablePresetRegistration){
75 logger.info("Preset registration property is false or not set - skipping preset registration...");
78 ClassLoader cl = this.getClass().getClassLoader();
79 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
82 resources = resolver.getResources("/preset_registration/*.json");
83 } catch (IOException e) {
84 logger.error("Error performing preset registration, error: ", e);
87 logger.info("Starting preset registrations, number of requests: {}", resources.length);
88 for (Resource resource: resources){
92 file = resource.getFile();
93 content = new Scanner(file).useDelimiter("\\Z").next();
94 } catch (IOException e){
95 logger.error("Error reading preset registration file {},skipping to next one. Error: ", resource.getFilename(), e);
98 //registrating the preset request
101 } catch (VidSimulatorException e) {
102 logger.error("Error proceeding preset registration file {},skipping to next one. Check if the JSON is in correct format. Error: ", resource.getFilename(), e);
110 private void setProperties() {
111 Resource resource = new ClassPathResource("simulator.properties");
112 Properties props = new Properties();
114 props = PropertiesLoaderUtils.loadProperties(resource);
115 } catch (IOException e) {
116 logger.error("Error loading simulator properties, error: ", e);
119 logger.info("Simulator properties are {}", props);
120 mockServerProtocol = (String)props.get("simulator.mockserver.protocol");
121 mockServerHost = (String)props.get("simulator.mockserver.host");
122 mockServerPort = Integer.parseInt((String)props.get("simulator.mockserver.port"));
123 enablePresetRegistration = Boolean.parseBoolean((String)props.get("simulator.enablePresetRegistration"));
126 @RequestMapping(value = {"/registerToVidSimulator"}, method = RequestMethod.POST)
128 ResponseEntity registerRequest(HttpServletRequest request, @RequestBody String expectation) {
130 register(expectation);
131 } catch (VidSimulatorException e) {
132 return new ResponseEntity<>("Registration failure! Error: "+e.getMessage(),HttpStatus.BAD_REQUEST);
134 return new ResponseEntity<>("Registration successful!",HttpStatus.OK);
137 // @RequestMapping(value = {"/registerToVidSimulator"}, method = RequestMethod.GET)
138 // public ResponseEntity<String> getAllRegisteredRequests() throws JsonProcessingException {
139 // final Expectation[] expectations = mockServer.retrieveExistingExpectations(null);
140 // return new ResponseEntity<>(new ObjectMapper()
141 // .configure(SerializationFeature.INDENT_OUTPUT, true)
142 // .writeValueAsString(expectations), HttpStatus.OK);
145 @RequestMapping(value = {"/registerToVidSimulator"}, method = RequestMethod.DELETE)
146 @ResponseStatus(value = HttpStatus.OK)
147 public void wipeOutAllExpectations() {
151 private void register(String expectation) throws VidSimulatorException{
152 ObjectMapper mapper = new ObjectMapper()
153 .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
155 SimulatorRequestResponseExpectation[] expectationModels;
157 expectationModels = mapper.readValue(expectation, SimulatorRequestResponseExpectation[].class);
158 } catch (IOException e) {
159 logger.error("Couldn't deserialize register expectation {}, error:", expectation, e);
160 throw new VidSimulatorException(e.getMessage());
163 for (SimulatorRequestResponseExpectation expectationModel : expectationModels) {
164 logger.info("Proceeding registration request: {}", expectationModel);
165 register(expectationModel);
170 @RequestMapping(value = {"/**"})
171 public String redirectToMockServer(HttpServletRequest request, HttpServletResponse response) {
172 //Currently, the easiest logic is redirecting
174 //This is needed to allow POST redirect - see http://www.baeldung.com/spring-redirect-and-forward
175 request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
177 //Building the redirect URL
178 String restOfTheUrl = (String) request.getAttribute(
179 HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
181 //TODO encode only characters like spaces, not slashes
183 restOfTheUrl = URLEncoder.encode(restOfTheUrl, "UTF-8");
184 restOfTheUrl = restOfTheUrl.replaceAll("%2F", "/");
185 } catch (UnsupportedEncodingException e) {
189 StringBuilder sb = new StringBuilder();
190 sb.append(mockServerProtocol+"://"+mockServerHost+":"+mockServerPort+"/"+restOfTheUrl);
191 String queryString = request.getQueryString();
192 if (queryString != null){
193 sb.append("?").append(queryString);
195 String redirectUrl = sb.toString();
196 logger.info("Redirecting the request to : {}", redirectUrl);
197 return ("redirect:"+redirectUrl);
199 //This was a try to setup a proxy instead of redirect
200 //Abandoned this direction when trying to return the original HTTP error code which was registered to mock server, instead of wrapped up HTTP 500.
202 /* String restOfTheUrl = "/"+(String) request.getAttribute(
203 HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
206 uri = new URI("http", null, "localhost", 1080, restOfTheUrl, request.getQueryString(), null);
207 } catch (URISyntaxException e) {
208 logger.error("Error during proxying request {}, error: ", request.getRequestURI(), e.getMessage());
209 return new ResponseEntity(e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
211 RestTemplate restTemplate = new RestTemplate();
212 //Preparing the headers
213 HttpHeaders headers = new HttpHeaders();
214 Enumeration<String> headerNames = request.getHeaderNames();
215 while (headerNames.hasMoreElements()){
216 String headerToSet = headerNames.nextElement();
217 headers.set(headerToSet, request.getHeader(headerToSet));
220 ResponseEntity<String> responseEntity =
221 restTemplate.exchange(uri, HttpMethod.resolve(request.getMethod()), new HttpEntity<String>(body, headers), String.class);
223 return responseEntity;*/
226 private void register(SimulatorRequestResponseExpectation expectationModel) throws VidSimulatorException{
227 //Setting request according to what is passed
228 HttpRequest request = HttpRequest.request();
229 String id = expectationModel.getSimulatorRequest().getId();
231 request.withHeader("x-simulator-id", id);
233 String method = expectationModel.getSimulatorRequest().getMethod();
234 if (method != null) {
235 request.withMethod(method);
237 String path = expectationModel.getSimulatorRequest().getPath();
239 request.withPath(path);
241 String body = expectationModel.getSimulatorRequest().getBody();
243 request.withBody(body);
247 final Map<String, List<String>> queryParams = expectationModel.getSimulatorRequest().getQueryParams();
248 if (queryParams != null){
249 String[] arr = new String[0];
250 queryParams.entrySet().stream().forEach(x -> {
251 request.withQueryStringParameter(x.getKey(), x.getValue().toArray(arr));
255 //Setting response according to what is passed
256 HttpResponse response = HttpResponse.response();
257 Integer responseCode = expectationModel.getSimulatorResponse().getResponseCode();
258 if (responseCode != null) {
259 response.withStatusCode(responseCode);
261 logger.error("Invalid registration - response code cannot be empty");
262 throw new VidSimulatorException("Invalid registration - response code cannot be empty");
265 String respBody = expectationModel.getSimulatorResponse().getBody();
266 if (respBody != null) {
267 response.withBody(respBody);
270 String file = expectationModel.getSimulatorResponse().getFile();
272 response.withBody(loadFileString(file));
275 Map<String, String> responseHeaders = expectationModel.getSimulatorResponse().getResponseHeaders();
276 if (responseHeaders != null) {
277 responseHeaders.forEach(response::withHeader);
280 Times numberOfTimes = getExpectationNumberOfTimes(expectationModel);
282 if (expectationModel.getMisc().getReplace()) {
283 logger.info("Unregistering request expectation, if previously set, request: {}", expectationModel.getSimulatorRequest());
284 mockServer.clear(request);
288 .when(request, numberOfTimes).respond(response);
292 private byte[] loadFileString(String filePath) {
295 File file = new ClassPathResource("download_files/" + filePath).getFile();
296 bytes = new byte[(int)file.length()];
297 DataInputStream dataInputStream = null;
299 dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(file.getPath())));
300 dataInputStream.readFully(bytes);
301 dataInputStream.close();
302 } catch (FileNotFoundException e) {
303 logger.error("File not found for file:" + filePath);
305 } catch (IOException e) {
306 logger.error("Error reading file:" + filePath);
312 private Times getExpectationNumberOfTimes(SimulatorRequestResponseExpectation expectationModel) {
313 Integer expectationModelNumberOfTimes = expectationModel.getMisc().getNumberOfTimes();
314 Times effectiveNumberOfTimes;
315 if (expectationModelNumberOfTimes == null || expectationModelNumberOfTimes < 0) {
316 effectiveNumberOfTimes = DEFAULT_NUMBER_OF_TIMES;
318 effectiveNumberOfTimes = exactly(expectationModelNumberOfTimes);
320 return effectiveNumberOfTimes;