Skip to content

Commit 4e07d9c

Browse files
authored
Merge pull request #12225 from sazzer/lightrun
Source code for Lightrun articles
2 parents 7e3cdda + 177f912 commit 4e07d9c

54 files changed

Lines changed: 1460 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

lightrun/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Lightrun Example Application - Tasks Management
2+
3+
This application exists as an example for the Lightrun series of articles.
4+
5+
## Building
6+
This application requires [Apache Maven](https://maven.apache.org/) and [Java 17+](https://www.oracle.com/java/technologies/downloads/).
7+
8+
Building the code is done by executing:
9+
```
10+
$ mvn install
11+
```
12+
from the top level.
13+
14+
## Running
15+
The application consists of three services:
16+
* Tasks
17+
* Users
18+
* API
19+
20+
These are all Spring Boot applications.
21+
22+
The Tasks and Users services exist as microservices for managing one facet of data. Each uses a database, and utilise a JMS queue between them as well. For convenience this infrastructure is all embedded in the applications.
23+
24+
This does mean that the startup order is important. The JMS queue exists within the Tasks service and is connected to from the Users service. As such, the Tasks service must be started before the others.
25+
26+
Each service can be started either by executing `mvn spring-boot:run` from within the appropriate directory. Alternatively, as Spring Boot applications, the build will produce an executable JAR file within the `target` directory that can be executed as, for example:
27+
```
28+
$ java -jar ./target/tasks-service-0.0.1-SNAPSHOT.jar
29+
```

lightrun/api-service/.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
HELP.md
2+
target/
3+
!.mvn/wrapper/maven-wrapper.jar
4+
!**/src/main/**/target/
5+
!**/src/test/**/target/
6+
7+
### STS ###
8+
.apt_generated
9+
.classpath
10+
.factorypath
11+
.project
12+
.settings
13+
.springBeans
14+
.sts4-cache
15+
16+
### IntelliJ IDEA ###
17+
.idea
18+
*.iws
19+
*.iml
20+
*.ipr
21+
22+
### NetBeans ###
23+
/nbproject/private/
24+
/nbbuild/
25+
/dist/
26+
/nbdist/
27+
/.nb-gradle/
28+
build/
29+
!**/src/main/**/build/
30+
!**/src/test/**/build/
31+
32+
### VS Code ###
33+
.vscode/

lightrun/api-service/pom.xml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>2.6.7</version>
9+
<relativePath/> <!-- lookup parent from repository -->
10+
</parent>
11+
<groupId>com.baeldung</groupId>
12+
<artifactId>api-service</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
<name>api-service</name>
15+
<description>Aggregator Service for LightRun Article</description>
16+
<properties>
17+
<java.version>17</java.version>
18+
</properties>
19+
<dependencies>
20+
<dependency>
21+
<groupId>org.springframework.boot</groupId>
22+
<artifactId>spring-boot-starter-actuator</artifactId>
23+
</dependency>
24+
<dependency>
25+
<groupId>org.springframework.boot</groupId>
26+
<artifactId>spring-boot-starter-web</artifactId>
27+
</dependency>
28+
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-test</artifactId>
32+
<scope>test</scope>
33+
</dependency>
34+
</dependencies>
35+
36+
<build>
37+
<plugins>
38+
<plugin>
39+
<groupId>org.springframework.boot</groupId>
40+
<artifactId>spring-boot-maven-plugin</artifactId>
41+
</plugin>
42+
</plugins>
43+
</build>
44+
45+
</project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.apiservice;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class ApiServiceApplication {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(ApiServiceApplication.class, args);
11+
}
12+
13+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.apiservice;
2+
3+
import org.slf4j.MDC;
4+
import org.springframework.stereotype.Component;
5+
import org.springframework.web.context.request.RequestContextHolder;
6+
import org.springframework.web.servlet.HandlerInterceptor;
7+
import org.springframework.web.servlet.ModelAndView;
8+
9+
import javax.servlet.http.HttpServletRequest;
10+
import javax.servlet.http.HttpServletResponse;
11+
import java.util.UUID;
12+
13+
@Component
14+
public class RequestIdGenerator implements HandlerInterceptor {
15+
@Override
16+
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
17+
String requestId = UUID.randomUUID().toString();
18+
19+
MDC.put(RequestIdGenerator.class.getCanonicalName(), requestId);
20+
response.addHeader("X-Request-Id", requestId);
21+
22+
return true;
23+
}
24+
25+
@Override
26+
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
27+
MDC.remove(RequestIdGenerator.class.getCanonicalName());
28+
}
29+
30+
public static String getRequestId() {
31+
return MDC.get(RequestIdGenerator.class.getCanonicalName());
32+
}
33+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.baeldung.apiservice;
2+
3+
import org.springframework.boot.web.client.RestTemplateBuilder;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.web.client.RestTemplate;
7+
8+
@Configuration
9+
public class RestTemplateConfig {
10+
@Bean
11+
public RestTemplate restTemplate(RestTemplateBuilder builder) {
12+
return builder
13+
.additionalInterceptors((request, body, execution) -> {
14+
request.getHeaders().add("X-Request-Id", RequestIdGenerator.getRequestId());
15+
16+
return execution.execute(request, body);
17+
})
18+
.build();
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.baeldung.apiservice;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
6+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7+
8+
@Configuration
9+
public class WebConfig implements WebMvcConfigurer {
10+
@Autowired
11+
private RequestIdGenerator requestIdGenerator;
12+
13+
@Override
14+
public void addInterceptors(InterceptorRegistry registry) {
15+
registry.addInterceptor(requestIdGenerator);
16+
}
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.baeldung.apiservice.adapters.http;
2+
3+
import java.time.Instant;
4+
5+
public record TaskResponse(String id,
6+
String title,
7+
Instant created,
8+
UserResponse createdBy,
9+
UserResponse assignedTo,
10+
String status) {
11+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.baeldung.apiservice.adapters.http;
2+
3+
import com.baeldung.apiservice.adapters.tasks.Task;
4+
import com.baeldung.apiservice.adapters.tasks.TaskRepository;
5+
import com.baeldung.apiservice.adapters.users.UserRepository;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.web.bind.annotation.*;
9+
10+
@RequestMapping("/")
11+
@RestController
12+
public class TasksController {
13+
@Autowired
14+
private TaskRepository taskRepository;
15+
@Autowired
16+
private UserRepository userRepository;
17+
18+
@GetMapping("/{id}")
19+
public TaskResponse getTaskById(@PathVariable("id") String id) {
20+
Task task = taskRepository.getTaskById(id);
21+
22+
if (task == null) {
23+
throw new UnknownTaskException();
24+
}
25+
26+
return buildResponse(task);
27+
}
28+
29+
private TaskResponse buildResponse(Task task) {
30+
return new TaskResponse(task.id(),
31+
task.title(),
32+
task.created(),
33+
getUser(task.createdBy()),
34+
getUser(task.assignedTo()),
35+
task.status());
36+
}
37+
38+
private UserResponse getUser(String userId) {
39+
if (userId == null) {
40+
return null;
41+
}
42+
43+
var user = userRepository.getUserById(userId);
44+
if (user == null) {
45+
return null;
46+
}
47+
48+
return new UserResponse(user.id(), user.name());
49+
}
50+
@ExceptionHandler(UnknownTaskException.class)
51+
@ResponseStatus(HttpStatus.NOT_FOUND)
52+
public void handleUnknownTask() {
53+
}
54+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.baeldung.apiservice.adapters.http;
2+
3+
public class UnknownTaskException extends RuntimeException {
4+
}

0 commit comments

Comments
 (0)