Skip to content

Commit 8d418f8

Browse files
author
Liviu Ilea
committed
Added project parent pom + http-adapter
1 parent a2dfc4f commit 8d418f8

File tree

20 files changed

+665
-0
lines changed

20 files changed

+665
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea
2+
*.iml
3+
target

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Description
2+
This repository contains samples of various prototype projects built with Spring Boot 2 and Spring WebFlux.
3+
4+
## Projects
5+
6+
### http-adapter
7+
Sample of an HTTP integration service between a client using one API and a backend using a different API.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<groupId>org.codemental.samples.webflux.java.http.adapter</groupId>
7+
<artifactId>http-adapter</artifactId>
8+
<version>1.0.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>http-adapter-integration-test</artifactId>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>org.codemental.samples.webflux.java.http.adapter</groupId>
17+
<artifactId>http-adapter-service</artifactId>
18+
</dependency>
19+
<dependency>
20+
<groupId>com.consol.citrus</groupId>
21+
<artifactId>citrus-core</artifactId>
22+
</dependency>
23+
<dependency>
24+
<groupId>com.consol.citrus</groupId>
25+
<artifactId>citrus-java-dsl</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>com.consol.citrus</groupId>
29+
<artifactId>citrus-http</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.testng</groupId>
33+
<artifactId>testng</artifactId>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.apache.logging.log4j</groupId>
37+
<artifactId>log4j-slf4j-impl</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>org.apache.logging.log4j</groupId>
41+
<artifactId>log4j-core</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.slf4j</groupId>
45+
<artifactId>slf4j-log4j12</artifactId>
46+
</dependency>
47+
</dependencies>
48+
49+
<build>
50+
<plugins>
51+
<!-- disable running unit tests -->
52+
<plugin>
53+
<groupId>org.apache.maven.plugins</groupId>
54+
<artifactId>maven-surefire-plugin</artifactId>
55+
<configuration>
56+
<skipTests>true</skipTests>
57+
</configuration>
58+
</plugin>
59+
<!-- setup running integration tests -->
60+
<plugin>
61+
<groupId>org.apache.maven.plugins</groupId>
62+
<artifactId>maven-failsafe-plugin</artifactId>
63+
<executions>
64+
<execution>
65+
<id>integration-tests</id>
66+
<goals>
67+
<goal>integration-test</goal>
68+
<goal>verify</goal>
69+
</goals>
70+
</execution>
71+
</executions>
72+
</plugin>
73+
<plugin>
74+
<groupId>org.springframework.boot</groupId>
75+
<artifactId>spring-boot-maven-plugin</artifactId>
76+
<executions>
77+
<execution>
78+
<id>start-app</id>
79+
<phase>pre-integration-test</phase>
80+
<goals>
81+
<goal>start</goal>
82+
</goals>
83+
</execution>
84+
<execution>
85+
<id>stop-app</id>
86+
<phase>post-integration-test</phase>
87+
<goals>
88+
<goal>stop</goal>
89+
</goals>
90+
</execution>
91+
</executions>
92+
<configuration>
93+
<mainClass>org.codemental.samples.webflux.java.http.adapter.main.HttpAdapterApplication</mainClass>
94+
</configuration>
95+
</plugin>
96+
</plugins>
97+
</build>
98+
99+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.codemental.samples.webflux.java.http.adapter.integration.config;
2+
3+
import com.consol.citrus.dsl.endpoint.CitrusEndpoints;
4+
import com.consol.citrus.http.client.HttpClient;
5+
import com.consol.citrus.http.server.HttpServer;
6+
import org.springframework.beans.factory.annotation.Value;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Import;
9+
import org.springframework.context.annotation.PropertySource;
10+
import org.springframework.http.MediaType;
11+
import org.springframework.test.context.ContextConfiguration;
12+
13+
14+
@ContextConfiguration()
15+
@PropertySource(value = "citrus.properties")
16+
@Import({})// you can import more configuration classes here
17+
public class CitrusConfiguration {
18+
19+
@Value("${http.adapter.service.url}")
20+
private String serviceUrl;
21+
@Value("${external.api.mock.port}")
22+
private int externalApiMockPort;
23+
24+
@Bean
25+
public HttpClient inboundClient() {
26+
return CitrusEndpoints.http()
27+
.client()
28+
.requestUrl("http://" + serviceUrl)
29+
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
30+
.build();
31+
}
32+
33+
@Bean
34+
public HttpServer externalApiMock() {
35+
return CitrusEndpoints.http()
36+
.server()
37+
.port(externalApiMockPort)
38+
.autoStart(true)
39+
.timeout(5000)
40+
.build();
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.codemental.samples.webflux.java.http.adapter.integration.test;
2+
3+
import com.consol.citrus.annotations.CitrusTest;
4+
import com.consol.citrus.dsl.testng.TestNGCitrusTestRunner;
5+
import com.consol.citrus.http.client.HttpClient;
6+
import com.consol.citrus.http.server.HttpServer;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.http.HttpStatus;
9+
import org.springframework.http.MediaType;
10+
import org.testng.annotations.Test;
11+
12+
@Test
13+
public class HttpAdapterIT extends TestNGCitrusTestRunner {
14+
15+
@Autowired
16+
private HttpClient httpClient;
17+
@Autowired
18+
private HttpServer httpServer;
19+
20+
@CitrusTest
21+
public void test() {
22+
http(action -> action.client(httpClient)
23+
.send()
24+
.post("inbound")
25+
.payload("{" +
26+
"\"userName\": \"Bruce.Wayne\"," +
27+
"\"operation\": \"call-a-pizza\"" +
28+
"}")
29+
.fork(true));
30+
31+
http(action -> action.server(httpServer)
32+
.receive()
33+
.post("/api")
34+
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
35+
.payload("{" +
36+
"\"information\": \"User: Bruce.Wayne called operation: call-a-pizza\"," +
37+
"\"timestamp\": \"@ignore@\"" +
38+
"}"));
39+
40+
http(action -> action.server(httpServer)
41+
.respond(HttpStatus.OK)
42+
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
43+
.payload("{" +
44+
"\"allowed\": true" +
45+
"}"));
46+
47+
http(action -> action.client(httpClient)
48+
.receive()
49+
.response(HttpStatus.OK)
50+
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
51+
.payload("{" +
52+
"\"success\": true" +
53+
"}"));
54+
}
55+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# citrus internal configuration
2+
citrus.spring.java.config=org.codemental.samples.webflux.java.http.adapter.integration.config.CitrusConfiguration
3+
citrus.html.report.enabled=false
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
http.adapter.service.url=localhost:8080
2+
external.api.mock.port=9090
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration packages="com.bmw.cd.logging">
3+
4+
<Properties>
5+
<Property name="path">target</Property>
6+
<Property name="logFileName">integration-tests-logs</Property>
7+
<Property name="logPattern">%d{HH:mm:ss,SSS} %-5.5p %28.28c{2}| %m%n</Property>
8+
</Properties>
9+
10+
<Appenders>
11+
<Console name="console" target="SYSTEM_OUT">
12+
<PatternLayout pattern="${logPattern}"/>
13+
</Console>
14+
<File name="logfile" fileName="${path}/${logFileName}.log" append="true">
15+
<PatternLayout pattern="${logPattern}"/>
16+
</File>
17+
</Appenders>
18+
19+
<Loggers>
20+
<Root level="DEBUG">
21+
<AppenderRef ref="console"/>
22+
<AppenderRef ref="logfile"/>
23+
</Root>
24+
<Logger name="org.eclipse.jetty" level="INFO" additivity="false">
25+
<AppenderRef ref="console"/>
26+
</Logger>
27+
</Loggers>
28+
</Configuration>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<groupId>org.codemental.samples.webflux.java.http.adapter</groupId>
7+
<artifactId>http-adapter</artifactId>
8+
<version>1.0.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>http-adapter-service</artifactId>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>org.springframework.boot</groupId>
17+
<artifactId>spring-boot-starter-webflux</artifactId>
18+
<exclusions>
19+
<exclusion>
20+
<groupId>org.springframework.boot</groupId>
21+
<artifactId>spring-boot-starter-logging</artifactId>
22+
</exclusion>
23+
<exclusion>
24+
<groupId>org.springframework.boot</groupId>
25+
<artifactId>spring-boot-starter-tomcat</artifactId>
26+
</exclusion>
27+
</exclusions>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-log4j2</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>io.netty</groupId>
35+
<artifactId>netty-transport-native-epoll</artifactId>
36+
</dependency>
37+
</dependencies>
38+
39+
<build>
40+
<plugins>
41+
<plugin>
42+
<groupId>org.springframework.boot</groupId>
43+
<artifactId>spring-boot-maven-plugin</artifactId>
44+
</plugin>
45+
<plugin>
46+
<groupId>org.apache.maven.plugins</groupId>
47+
<artifactId>maven-enforcer-plugin</artifactId>
48+
</plugin>
49+
</plugins>
50+
</build>
51+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.codemental.samples.webflux.java.http.adapter.controller;
2+
3+
4+
import org.codemental.samples.webflux.java.http.adapter.model.inbound.NotificationRequest;
5+
import org.codemental.samples.webflux.java.http.adapter.model.inbound.NotificationResponse;
6+
import org.codemental.samples.webflux.java.http.adapter.model.outbound.ReportRequest;
7+
import org.codemental.samples.webflux.java.http.adapter.model.outbound.ReportResponse;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.http.HttpStatus;
10+
import org.springframework.http.MediaType;
11+
import org.springframework.web.bind.annotation.PostMapping;
12+
import org.springframework.web.bind.annotation.RequestBody;
13+
import org.springframework.web.bind.annotation.RequestMapping;
14+
import org.springframework.web.bind.annotation.RestController;
15+
import org.springframework.web.reactive.function.BodyInserters;
16+
import org.springframework.web.reactive.function.client.WebClient;
17+
import reactor.core.publisher.Mono;
18+
19+
import java.time.LocalDateTime;
20+
21+
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;
22+
23+
@RestController
24+
@RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
25+
public class InboundApiController {
26+
27+
@Autowired
28+
private WebClient outboundApiClient;
29+
30+
@PostMapping("/inbound")
31+
Mono<NotificationResponse> notify(@RequestBody NotificationRequest notificationRequest) {
32+
return Mono.justOrEmpty(notificationRequest)
33+
.log()
34+
.map(this::mapToReqOut)
35+
.flatMap(reqOut -> outboundApiClient.post()
36+
.uri("/api")
37+
.body(BodyInserters.fromObject(reqOut))
38+
.accept(APPLICATION_JSON_UTF8)
39+
.exchange()
40+
.filter(resIn -> resIn.statusCode() == HttpStatus.OK)
41+
.flatMap(resIn -> resIn.bodyToMono(ReportResponse.class))
42+
.map(this::mapToResOut));
43+
}
44+
45+
private ReportRequest mapToReqOut(NotificationRequest inboundReq) {
46+
ReportRequest reqOut = new ReportRequest();
47+
reqOut.setInformation("User: " + inboundReq.getUserName()
48+
+ " called operation: " + inboundReq.getOperation());
49+
reqOut.setTimestamp(LocalDateTime.now());
50+
return reqOut;
51+
}
52+
53+
private NotificationResponse mapToResOut(ReportResponse inboundRes) {
54+
NotificationResponse resOut = new NotificationResponse();
55+
resOut.setSuccess(inboundRes.isAllowed());
56+
57+
return resOut;
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.codemental.samples.webflux.java.http.adapter.main;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.context.annotation.Import;
7+
import org.springframework.context.annotation.Profile;
8+
import org.springframework.web.reactive.config.EnableWebFlux;
9+
10+
@Configuration
11+
@EnableAutoConfiguration
12+
@EnableWebFlux
13+
@Profile({"default"})
14+
@Import({HttpConfiguration.class})
15+
public class HttpAdapterApplication {
16+
17+
public static void main(String[] args) {
18+
SpringApplication.run(HttpAdapterApplication.class, args);
19+
}
20+
}

0 commit comments

Comments
 (0)