1 package org.onap.simulator.controller;
3 import com.fasterxml.jackson.databind.DeserializationFeature;
4 import com.fasterxml.jackson.databind.ObjectMapper;
5 import com.google.gson.Gson;
6 import org.mockserver.integration.ClientAndServer;
7 import org.mockserver.matchers.MatchType;
8 import org.mockserver.matchers.Times;
9 import org.mockserver.model.HttpRequest;
10 import org.mockserver.model.HttpResponse;
11 import org.mockserver.model.JsonBody;
12 import org.onap.simulator.db.entities.Function;
13 import org.onap.simulator.db.entities.User;
14 import org.onap.simulator.errorHandling.VidSimulatorException;
15 import org.onap.simulator.model.SimulatorRequestResponseExpectation;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18 import org.springframework.core.io.ClassPathResource;
19 import org.springframework.core.io.Resource;
20 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
21 import org.springframework.core.io.support.PropertiesLoaderUtils;
22 import org.springframework.core.io.support.ResourcePatternResolver;
23 import org.springframework.http.*;
24 import org.springframework.stereotype.Component;
25 import org.springframework.web.bind.annotation.*;
26 import org.springframework.web.client.HttpClientErrorException;
27 import org.springframework.web.client.RestTemplate;
28 import org.springframework.web.servlet.View;
30 import javax.annotation.PostConstruct;
31 import javax.annotation.PreDestroy;
32 import javax.persistence.EntityManager;
33 import javax.persistence.EntityManagerFactory;
34 import javax.persistence.Persistence;
35 import javax.persistence.TypedQuery;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.http.HttpServletResponse;
40 import java.net.URISyntaxException;
41 import java.net.URLEncoder;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.nio.file.Paths;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
49 import static org.mockserver.integration.ClientAndServer.startClientAndServer;
50 import static org.mockserver.matchers.Times.exactly;
51 import static org.mockserver.model.JsonBody.json;
55 public class SimulatorController {
57 private static final Times DEFAULT_NUMBER_OF_TIMES = Times.unlimited();
58 private ClientAndServer mockServer;
59 private String mockServerProtocol;
60 private String mockServerHost;
61 private Integer mockServerPort;
62 private Boolean enablePresetRegistration;
63 private Boolean enableJPA;
64 private volatile boolean isInitialized = false;
66 private EntityManager entityManager;
67 private EntityManagerFactory entityManagerFactory;
70 private static final Logger logger = LoggerFactory.getLogger(SimulatorController.class);
74 logger.info("Starting VID Simulator....");
76 mockServer = startClientAndServer(mockServerPort);
80 } catch (RuntimeException e) {
81 isInitialized = false;
82 logger.error("Error during the JPA initialization:", e);
86 logger.info("VID Simulator started successfully");
89 private void initJPA() {
91 entityManagerFactory = Persistence.createEntityManagerFactory("vid");
92 entityManager = entityManagerFactory.createEntityManager();
97 public void tearDown(){
98 logger.info("Stopping VID Simulator....");
99 entityManager.close();
100 entityManagerFactory.close();
101 isInitialized = false;
102 mockServer.stop(false);
106 private void presetRegister() {
108 if (enablePresetRegistration == null || !enablePresetRegistration){
109 logger.info("Preset registration property is false or not set - skipping preset registration...");
112 ClassLoader cl = this.getClass().getClassLoader();
113 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
114 List<Path> resources = new ArrayList<>();
116 File presetDir = resolver.getResource("/preset_registration/").getFile();
117 if (presetDir.exists() && presetDir.isDirectory()) {
118 try (Stream<Path> files = Files.walk(Paths.get(presetDir.getPath()))) {
120 .filter(p -> p.toString().endsWith(".json"))
121 .collect(Collectors.toList());
124 logger.error("preset_registration directory is not exists");
126 } catch (IOException e) {
127 logger.error("Error performing preset registration, error: ", e);
130 logger.info("Starting preset registrations, number of requests: {}", resources.size());
131 for (Path resource: resources){
133 try (Scanner scanner = new Scanner(resource).useDelimiter("\\Z")){
134 content = scanner.next();
135 } catch (IOException e){
136 logger.error("Error reading preset registration file {}, skipping to next one. Error: ", resource.getFileName(), e);
139 //register the preset request
142 } catch (VidSimulatorException e) {
143 logger.error("Error proceeding preset registration file {},skipping to next one. Check if the JSON is in correct format. Error: ", resource.getFileName(), e);
150 private void setProperties() {
151 Resource resource = new ClassPathResource("simulator.properties");
152 Properties props = new Properties();
154 props = PropertiesLoaderUtils.loadProperties(resource);
155 } catch (IOException e) {
156 logger.error("Error loading simulator properties, error: ", e);
159 logger.info("Simulator properties are {}", props);
160 mockServerProtocol = (String)props.get("simulator.mockserver.protocol");
161 mockServerHost = (String)props.get("simulator.mockserver.host");
162 mockServerPort = Integer.parseInt((String)props.get("simulator.mockserver.port"));
163 enablePresetRegistration = Boolean.parseBoolean((String)props.get("simulator.enablePresetRegistration"));
164 enableJPA = Boolean.parseBoolean((String)props.get("simulator.enableCentralizedRoleAccess"));
167 @RequestMapping(value = {"/registerToVidSimulator"}, method = RequestMethod.POST)
169 ResponseEntity registerRequest(HttpServletRequest request, @RequestBody String expectation) {
171 register(expectation);
172 } catch (VidSimulatorException e) {
173 return new ResponseEntity<>("Registration failure! Error: "+e.getMessage(),HttpStatus.BAD_REQUEST);
175 return new ResponseEntity<>("Registration successful!",HttpStatus.OK);
178 @RequestMapping(value = {"/echo"}, method = RequestMethod.GET)
179 ResponseEntity echo(HttpServletRequest request) {
180 return isInitialized ? new ResponseEntity<>("",HttpStatus.OK) : new ResponseEntity<>("",HttpStatus.SERVICE_UNAVAILABLE);
183 @RequestMapping(value = {"/retrieveRecordedRequests"}, method = RequestMethod.GET)
184 public List<HttpRequest> retrieveRecordedRequests() {
185 return Arrays.asList(mockServer.retrieveRecordedRequests(null));
188 @RequestMapping(value = {"/registerToVidSimulator"}, method = RequestMethod.DELETE)
189 @ResponseStatus(value = HttpStatus.OK)
190 public void wipeOutAllExpectations() {
194 private void register(String expectation) throws VidSimulatorException{
195 ObjectMapper mapper = new ObjectMapper()
196 .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
198 SimulatorRequestResponseExpectation[] expectationModels;
200 expectationModels = mapper.readValue(expectation, SimulatorRequestResponseExpectation[].class);
201 } catch (IOException e) {
202 logger.error("Couldn't deserialize register expectation {}, error:", expectation, e);
203 throw new VidSimulatorException(e.getMessage());
206 for (SimulatorRequestResponseExpectation expectationModel : expectationModels) {
207 logger.info("Proceeding registration request: {}", expectationModel);
208 register(expectationModel);
212 //*******portal role access simulator (added by ag137v)
214 @RequestMapping(value = {"/ecompportal_att/auxapi//{ver}/user/*", "/ONAPPORTAL/auxapi//{ver}/user/*"}, method = RequestMethod.GET)
216 ResponseEntity auxapiGetUser(HttpServletRequest request) {
218 return new ResponseEntity<>("Centralized Role Access is disabled", HttpStatus.SERVICE_UNAVAILABLE);
220 entityManager.clear();
221 String reqUri = request.getRequestURI();
222 String userName = reqUri.substring(reqUri.lastIndexOf('/') + 1);
223 TypedQuery<User> userQuery = entityManager.createQuery("select u from fn_user u where u.loginId = :userName", User.class);
224 userQuery.setParameter("userName", userName);
225 User user = userQuery.getSingleResult();
228 String jsonString = g.toJson(user);
230 return new ResponseEntity<>(jsonString, HttpStatus.OK);
234 @RequestMapping(value = {"/ecompportal_att/auxapi//{ver}/functions", "/ONAPPORTAL/auxapi//{ver}/functions"}, method = RequestMethod.GET)
236 ResponseEntity auxapiGetFunctions(HttpServletRequest request) {
238 return new ResponseEntity<>("Centralized Role Access is disabled", HttpStatus.SERVICE_UNAVAILABLE);
240 TypedQuery<Function> userQuery = entityManager.createQuery("select f from fn_function f", Function.class);
241 List<Function> functions = userQuery.getResultList();
243 String jsonString = g.toJson(functions);
245 return new ResponseEntity<>(jsonString, HttpStatus.OK);
248 //*******portal role access simulator end
251 @RequestMapping(value = {"/**"})
252 public ResponseEntity redirectToMockServer(HttpServletRequest request, HttpServletResponse response) throws IOException {
253 //This is needed to allow POST redirect - see http://www.baeldung.com/spring-redirect-and-forward
254 request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
256 //Building the redirect URL
257 // String restOfTheUrl = (String) request.getAttribute(
258 // HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
259 String requestUri = URLEncoder.encode(request.getRequestURI(), "UTF-8");
260 requestUri = requestUri.replaceAll("%2F", "/");
261 String restOfTheUrl = requestUri.replaceFirst(request.getContextPath(), "");
263 StringBuilder sb = new StringBuilder();
264 sb.append(mockServerProtocol).append("://").append(mockServerHost).append(":").append(mockServerPort).append(restOfTheUrl);
265 String queryString = request.getQueryString();
266 if (queryString != null){
267 sb.append("?").append(queryString);
269 String redirectUrl = sb.toString();
270 logger.info("Redirecting the request to : {}", redirectUrl);
274 uri = new URI("http", null, "localhost", 1080, restOfTheUrl, request.getQueryString(), null);
275 } catch (URISyntaxException e) {
276 logger.error("Error during proxying request {}, error: ", request.getRequestURI(), e.getMessage());
277 return new ResponseEntity(e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
279 RestTemplate restTemplate = new RestTemplate();
280 //Preparing the headers
281 HttpHeaders headers = new HttpHeaders();
282 Enumeration<String> headerNames = request.getHeaderNames();
283 while (headerNames.hasMoreElements()){
284 String headerToSet = headerNames.nextElement();
285 headers.set(headerToSet, request.getHeader(headerToSet));
287 HttpEntity<String> proxyRequest;
288 if ("POST".equalsIgnoreCase(request.getMethod()))
290 String body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
291 proxyRequest = new HttpEntity<>(body, headers);
293 proxyRequest = new HttpEntity<>(headers);
296 ResponseEntity<String> responseEntity;
299 restTemplate.exchange(uri, HttpMethod.resolve(request.getMethod()), proxyRequest, String.class);
300 } catch (HttpClientErrorException exception) {
301 responseEntity = new ResponseEntity<>(exception.getResponseBodyAsString(), exception.getStatusCode());
304 return responseEntity;
307 private void register(SimulatorRequestResponseExpectation expectationModel) throws VidSimulatorException{
308 //Setting request according to what is passed
309 HttpRequest request = HttpRequest.request();
310 String id = expectationModel.getSimulatorRequest().getId();
312 request.withHeader("x-simulator-id", id);
315 if (expectationModel.getSimulatorRequest().getHeaders()!=null) {
316 expectationModel.getSimulatorRequest().getHeaders().forEach(
317 request::withHeader);
320 String method = expectationModel.getSimulatorRequest().getMethod();
321 if (method != null) {
322 request.withMethod(method);
324 String path = expectationModel.getSimulatorRequest().getPath();
326 request.withPath(path);
328 String body = expectationModel.getSimulatorRequest().getBody();
330 if (expectationModel.getSimulatorRequest().getStrict()) {
331 request.withBody(json(body, MatchType.STRICT));
333 request.withBody(new JsonBody(body));
338 final Map<String, List<String>> queryParams = expectationModel.getSimulatorRequest().getQueryParams();
339 if (queryParams != null){
340 String[] arr = new String[0];
341 queryParams.forEach((key, value) -> request.withQueryStringParameter(key, value.toArray(arr)));
344 //Setting response according to what is passed
345 HttpResponse response = HttpResponse.response();
346 Integer responseCode = expectationModel.getSimulatorResponse().getResponseCode();
347 if (responseCode != null) {
348 response.withStatusCode(responseCode);
350 logger.error("Invalid registration - response code cannot be empty");
351 throw new VidSimulatorException("Invalid registration - response code cannot be empty");
354 String respBody = expectationModel.getSimulatorResponse().getBody();
355 if (respBody != null) {
356 response.withBody(respBody);
359 String file = expectationModel.getSimulatorResponse().getFile();
361 response.withBody(loadFileString(file));
364 Map<String, String> responseHeaders = expectationModel.getSimulatorResponse().getResponseHeaders();
365 if (responseHeaders != null) {
366 responseHeaders.forEach(response::withHeader);
369 Times numberOfTimes = getExpectationNumberOfTimes(expectationModel);
371 if (expectationModel.getMisc().getReplace()) {
372 logger.info("Unregistering request expectation, if previously set, request: {}", expectationModel.getSimulatorRequest());
373 mockServer.clear(request);
377 .when(request, numberOfTimes).respond(response);
381 private byte[] loadFileString(String filePath) {
385 file = new ClassPathResource("download_files/" + filePath).getFile();
386 try(DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(file.getPath())))) {
387 bytes = new byte[(int)file.length()];
388 dataInputStream.readFully(bytes);
390 } catch (FileNotFoundException e) {
391 logger.error("File not found for file:" + filePath);
393 } catch (IOException e) {
394 logger.error("Error reading file:" + filePath);
400 private Times getExpectationNumberOfTimes(SimulatorRequestResponseExpectation expectationModel) {
401 Integer expectationModelNumberOfTimes = expectationModel.getMisc().getNumberOfTimes();
402 Times effectiveNumberOfTimes;
403 if (expectationModelNumberOfTimes == null || expectationModelNumberOfTimes < 0) {
404 effectiveNumberOfTimes = DEFAULT_NUMBER_OF_TIMES;
406 effectiveNumberOfTimes = exactly(expectationModelNumberOfTimes);
408 return effectiveNumberOfTimes;