- Framework : Spring Boot (v2.7.2)
- Build tool : Gradle (v.7.4.1)
- Language : Kotlin (v.1.6.21)
- API dev : Spring Web
- Website dev : Mustache
- DB access : Spring Data JPA
- App metrics : Actuator
Since the build tool is gradle, standard build tasks are used. For build and unit testing, just run:
$ ./gradlew build
For starting the system, just use standard Spring boot gradle tasks:
$ ./gradlew bootRun
15:01:40.362 [Thread-0] DEBUG org.springframework.boot.devtools.restart.classloader.RestartClassLoader - Created RestartClassLoader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@49eeff94
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.2)
2022-08-19 15:01:40.573 INFO 13198 --- [ restartedMain] e.m.s.kotlin.dep_checker.ApplicationKt : Starting ApplicationKt using Java 17 on asus with PID 13198 (/home/mac/IdeaProjects/dep_checker/build/classes/kotlin/main started by mac in /home/mac/IdeaProjects/dep_checker)
2022-08-19 15:01:40.574 INFO 13198 --- [ restartedMain] e.m.s.kotlin.dep_checker.ApplicationKt : No active profile set, falling back to 1 default profile: "default"
2022-08-19 15:01:40.609 INFO 13198 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2022-08-19 15:01:40.609 INFO 13198 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2022-08-19 15:01:41.099 INFO 13198 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2022-08-19 15:01:41.124 INFO 13198 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 20 ms. Found 3 JPA repository interfaces.
2022-08-19 15:01:41.460 INFO 13198 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-08-19 15:01:41.466 INFO 13198 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-08-19 15:01:41.467 INFO 13198 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.65]
...
A Tomcat embedded web server is started at http://localhost:8080. This Tomcat server is used to expose 2 different web-based microservices:
- REST API
- Website
A third microservice (a Kafka listener) is also started but it doesn’t have any frontend. It also requires a kafka server and a topic up and running.
In order to fully understand the microservices and it’s source code packages, check next chapter.
The source code follows a hexagonal/clean architecture. The main target of this repo is to gain experience with this software architecture.
The project is divided in 3 main subsystems built on Spring Boot. All technological details (exchange formats, database technologies, integrations with messaging systems, etc) are placed in the adapter layer.
In this section, the exposed interfaces (input adapters in the hexagonal architecture terminology) that external systems invoke to communicate with the system are described. The source code is placed in the in adapter.in package
Source code for the REST API is in the adapter.in.api package.
All API endpoints are placed under this preffix : http://localhost:8080/api/.
Currently, the only endpoints implemented are regarding 'IngestedFile' entity. One example is this service: http://localhost:8080/api/ingestedFile/
Source code for the operational website is in the adapter.in.web package.
The website microservice is exposed at: http://localhost:8080/
Source code for the Kafka consumer is in the adapter.in.events package.
This input interface requires a kafka broker available in order to boot. A great introductory documentation for Apache Kafka is the official kickstart guide .
In order to start a local kafka server, just follow the guide. Once installed, start zookeeper and kafka servers:
$ bin/zookeeper-server-start.sh config/zookeeper.properties
$ bin/kafka-server-start.sh config/server.properties
This microservice listens to a kafka topic fed by a file ingestor batch engine. When a file ingestion starts and finishes, an event is sent to the topic by this external component.
In order to simulate that external integration in a local development environment, the easiest way is to send a message to the local topic using the kafka-console-producer tool. The messages exchanged between the file ingestion engine and the dependency tracker are simple strings structured as JSON messages.
The kafka topic name is set in the application.yml file. By default, it is set to: 'ingestion'. A topic with this name should be created using:
$ bin/kafka-topics.sh --create --topic ingestion --bootstrap-server localhost:9092
One example of how to send a JSON-based message to a topic using the kafka-console-producer is:
$ bin/kafka-console-producer.sh --topic ingestion --bootstrap-server localhost:9092
{"event_type": "ingested_file", "camIngestor": "AAAAA", "fileKey": "fich1", "partition1": "199206", "duration": "20", "user": "user1", "status": "RUNNING"}
The goal of the kafka consumer microservice is to store specific business events (like IngestedFiles) into de IngestedFile database table.
Output ports are used in the hexagonal architecture by the application core to communicate with external dependencies. In this example, the only external dependency is the persistence engine and the source code is placed in the adapter.out package.
In the example, it’s used a relational jdbc-based in-memory database engine like H2. Application core use the interfaces defined in the output ports to isolate specifics of a given persistence engine behind the output port interface.
All domain core entities are placed in the domain package.