1. Summary
This project illustrate a compilation of different concepts and technical solution for a "modern".[1] technology stack.
The key requirements for this blueprint are:
-
onion architecture
-
SOLID, especially focus on D=Dependency inversion principle
-
-
reactivate
-
well documented
-
maintainable
2. Overview
This documentation gives an overview of the architecture and the existing interfaces (interfaces).
3. Requirements
The application complies with the following functional and non-functional requirements. However the focus on this blueprint are more the non-functional requirements.
3.1. Functional Requirements
See for a draft overview of the business use cases.
3.2. Non functional Requirements
-
Fulfil a clean/onion architecture
-
SOLID
-
No layer in the inner circle (lower layer) has a relationship to the outer (upper) layer
-
-
Resilience
-
Provide enough information to maintaine the application
-
Monitoring information
-
Log files
-
Metrics
-
Codahale metrics
-
Spring Actuactor
-
-
-
-
Provide a documentation of the application and interfaces
-
Documentation and Code at the same place
-
Generate the documentation
-
4. Architecture
The key benefit of the Blueprint application is the administration of notes. A note is a set of content data, tags, rubric, attachments and possible due date.
The application provides different endpoints and stores the data in a persistent storage.
The main concept is the onion architecture, mainly the Dependency inversion principle. The architecture contains the following "layers":
-
Core: which represents all the code for implementing the bounded context (Domain classes, services implementation). Main requirement is, that this layer do not know anything from the layers above. No dependencies to external libs (JAX-RS, JPA, Spring etc) are allowed. Every logic, which will be implemented with a 3rd lib, should provide an interface. This interface will be implemented in an other layer and this core layer stay loose coupled.
-
Infrastructure: Knows only the core layer. Realize some of the interface from the core layer using if necessary 3rd libs. Like repository implementation using a JPA implementation (EclipseLink, Spring Data JPA etc). Contains also own domain classes, like entity classes. Do not use the domain classes from the core layer for JPA logic. Otherwise is it necessary to add JPA annotations to the domain classes in the core layer. This violates the requirement, that the lower layer knows nothing from any upper one.
-
UI: Knows only infra and core layers. Represents any endpoint logic and libs, like REST, JSF etc. It is possible to use here the domain classes from the core layer, however it is not advisable to spread them out.
4.1. Components
4.1.1. Blueprint App
Regarding the clean/onion architecture looks the distribution of the components as follows:
The main idea behind the architecture is the concept of Dependency inversion principle.
5. Interfaces
5.1. Overview
This chapters gives an overview of the existing interfaces. The interface documentation is completely generated with swagger.
5.2. Swagger
The rest interfaces are documented with swagger. The endpoint to the swagger UI is http://localhost:8099/swagger-ui.html
The swagger capabilities is reached with the following libs:
-
springfox-swagger2
-
springfox-swagger-ui: The UI
5.3. Swagger AsciiDoctor Integration
Swagger (or now https://www.openapis.org/) provides the toolset for defining a REST interface. The Swagger JSON definition will be used to generate AsciiDoc files which holds the information for every interface; totally generated. To achieve this is the following tool chain necessary
-
springfox
-
Configure and enable Swagger support
-
Generate swagger.json in a test unit using the /v2/api-docs?group=Note endpoint
-
Generate REST snippets (Request and Response examples) tbd
-
-
swagger2markup
-
Configure to generate based on swagger.json a documentation
-
include the generated adoc
-
Know bugs
-
AsciiDoctor-PDF: The generation a PDF from swagger documentation fails. The reason is a missing initialization in the internal lib
Open
-
Refactor the test unit to separate class
5.4. References
See Note API.
6. Monitoring
6.1. Overview
This chapter gives an overview about the monitoring mechanism in this application to fulfill different aspects like:
-
Application logs: represents the state of the application on business and technical point of view
-
Application metrics: Structured view on pre-defined measurement points, as well on business and technical point of view
-
System metrics: Any technical information outside of the application, like network traffic and system load
-
Request tracing: Trace the request and responses on the one hand, and the different hops caused from a client request
-
Health monitoring: Any information to monitor the stability and availability of the application
This rough categorization of the relevant monitoring facets have different requirements regarding the tooling, topicality and amount of data.
The spring (boot) ecosystem provides here a good integrated set of modules to gather and expose such data. In addition exists further enhancements to extend the interpretability of the collected data. This chapter goes into the usage and integration of the available spring modules and further enhancing modules, like:
-
Spring Actuator
-
Spring Sleuth
-
Codahale Metrics
-
Zipkin
-
Elastisearch and Beats (Metricbeat, Packetbeat, Filebeat, Heartbeat)
-
Prometheus
Extras
-
Jolokia and Metricbeat
-
Zipkin Chrome Extension
6.2. Spring Actuator
With the Spring actuator extension gather the application a lot of information like
-
Configuration information (http://localhost:8099/autoconfig)
-
Available beans (http://localhost:8099/beans)
-
Perform a Thread dump (http://localhost:8099/dump)
-
Health information with disk space (http://localhost:8099/health)
-
Metrics. If Codahale Metrics is in classpath than contains this endpoints also this information (http://localhost:8099/metrics)
-
Trace information, the last 100 request (http://localhost:8099/trace)
Some of the information are very sensitive, this is reason why the security is in general active and disallows the access without credentials. To deactivate - for dev purposes ;-) - use this parameter in application.properties
management.security.enabled=false
.
A detailed list of the availabe endpoints and configuratoin possibilities are described here: https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html
To activate this module is only a dependency necessary
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
6.3. Coda Hale Metrics
Coda Hale metrics is one of the most famous metrics implementation. For providing own metrics is it advisable to use this lib for gather and deliver different kinds of metric information.
Spring automatically determine the existence of Coda Hale Metrics in the classpath and replace some of the own implementations with the one from Coda Hale/Dropwizard. The metrics will be also exposed via the /metrics endpoint.
To integrate Coda Hale/Dropwizard metrics add this dependency to the pom.xml
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${dropwizard.metrics.version}</version>
</dependency>
For an usage look at the com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring<T>
implementation and the result at the metrics endpoint; see in the next listing a result with the own metrics
-
com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.*: A timer metric holding different values for the response time
-
com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.executed-events: Representing a counter metrics representing the number of events
{
"mem": 508751,
"mem.free": 216697,
"processors": 2,
"instance.uptime": 93563,
"uptime": 105687,
"systemload.average": 1.37,
"heap.committed": 437248,
"heap.init": 129024,
"heap.used": 220550,
"heap": 1815040,
"nonheap.committed": 73488,
"nonheap.init": 2496,
"nonheap.used": 71503,
"nonheap": 0,
"threads.peak": 21,
"threads.daemon": 19,
"threads.totalStarted": 26,
"threads": 21,
"classes": 10317,
"classes.loaded": 10317,
"classes.unloaded": 0,
"gc.ps_scavenge.count": 10,
"gc.ps_scavenge.time": 195,
"gc.ps_marksweep.count": 2,
"gc.ps_marksweep.time": 189,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.mean": 1,
"gauge.response.metrics": 16.0,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.executed-events": 4,
"gauge.response.note.v1.note": 18.0,
"counter.status.200.note.v1.note": 4,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.75thPercentile": 2,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.95thPercentile": 3,
"gauge.response.star-star.favicon.ico": 4.0,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.999thPercentile": 3,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.98thPercentile": 3,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.min": 0,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.max": 3,
"counter.status.200.star-star.favicon.ico": 4,
"counter.status.200.metrics": 4,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.meanRate": 0.04149518995882756,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.median": 2,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.stdDev": 0,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.fifteenMinuteRate": 0.0044076009778713995,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.fiveMinuteRate": 0.013005185767779516,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.count": 4,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.snapshot.99thPercentile": 3,
"com.haddouti.pg.blueprint.note.infra.monitoring.NoteEventMonitoring.responses.oneMinuteRate": 0.05895238133346083,
"httpsessions.max": -1,
"httpsessions.active": 0
}
6.4. Spring Cloud Sleuth
Spring Cloud Sleuth helps tracing a request from the ingress to the egress, including all hops. Every new incoming request represents a trace with a trace ID. Every hop to a component during processing this request is a new span with a span ID. A span may contains additional information like tags or metadata. Common tags are start and end timestamp.
Once added Spring Cloud Sleuth to the project, instruments automatically common communication channels:
-
Any Spring Cloud Stream binder (exists for Apache Kafka, RabbitMQ etc)
-
HTTP headers received over Spring MVC Controller
-
Any request made with Springs RestTemplate
6.4.1. Intregation
To integrate Spring Cloud Sleuth use this dependency
<dependencyManagement>
<!-- Spring Cloud: Sleuth. Place this AFTER boot-dependencies to avoid
the usage of 1.5.4 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth</artifactId>
<version>${spring.sleuth.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
Every usage of SLF4J like
private static Logger log = LoggerFactory.getLogger(RestNoteMaintenance.class);
// ...
log.info("putNote(): request={}", req);
produces an output using SLF4J MDC
2017-09-30 20:17:17.560 INFO [-,72eb71ec78f71000,72eb71ec78f71000,false] 5268 --- [nio-8099-exec-1] c.h.p.b.web.rest.RestNoteMaintenance : putNote(): request=NoteRequest [items=[]]
Relevant are the following new information
[bp,36ab5fc28f679a34,36ab5fc28f679a34,false]
with the format [appname,traceId,spanId,exportable]
.
-
appname: defined in
spring.application.name
, e.g. in application.yml or bootstrap.yml -
traceId: generated, represents a unique request
-
spanId: generated, every hop gets an own ID
-
exportable: whether the log should be exported to Zipkin or not.
7. Docker
7.1. Overview
This application provides also a docker image.
7.2. Docker Maven
For creating the docker image the dockerfile-maven-plugin is used. This plugin expects in a working directory (contextDirectory) all the necessary files, like Dockerfile, libs/jars etc. To achieve this, we used the maven-resources-plugin and maven-dependency-plugin to copy the Dockerfile and builded jar file(s) into the context directory.
See the blueprint-web/pom.xml for details. To build the docker image run use the profile dockerbuild:
mvn -Pdockerbuild package
To start the docker container:
docker run -it --rm -p 8099:8099 haf-tech/blueprint:0.0.1-SNAPSHOT
8. Docu
8.1. Overview
This chapters gives an overview over of the documentation and how is it generated. The toolchain for the documentation generated consists of a combination of AsciiDoctor, AsciiDoctorJ and some further AsciiDoctorJ Extensions like AsciiDoctorJ-Diagram for PlantUML usage.
8.2. Toolchain
Name | URL | Note |
---|---|---|
AsciiDoctor |
AsciiDoctor is the main tool which provides the logic and markup for the whole files. The markup is similar to Markdown with some extensions. |
|
AsciiDoctorJ |
Is an AsciiDoctor extension for Java integration. Maven plugins exist |
|
AsciiDoctorJ PDF |
PDF extension for AsciiDoctorJ |
|
AsciiDoctorJ Diagram |
Extension to integrate ascii art for creating diagrams, using different syntaxs, like PlantUML integration. |
|
PlantUML |
Lib for generating different UML diagrams (UseCase, component, sequence etc) in ascii. In general this lib needs Graphviz and/dot as external execution. However PlantUML contains a alpha support for internal ploting logic (!pragma graphviz_dot jdot) |
|
Swagger2Markup |
Swagger2Markup, here AsciiDoc, using swagger.json to generate the AsciiDoc files. |
8.3. Generation
The documentation will be generated with maven using the profile documentation:
mvn generate-resources -Pdocumentation
9. References
This chapter list all the relevant references.
9.1. Libs
Name | URL | Note |
---|---|---|
Springfox |
Lib for Swagger Support with Spring. Generates the necessary JSON docu |
|
Swagger2Markup |
Swagger to AsciiDoctor support |
|
Swagger2Markup Maven plugin |
https://github.com/Swagger2Markup/swagger2markup-maven-plugin |
Swagger to AsciiDoctor Maven plugin |
Swagger2Markup Maven plugin: Demo |
https://github.com/Swagger2Markup/spring-swagger2markup-demo |
Swagger2Markup Demo |
Dockerfile Maven Plugin |
Dockerfile maven plugin. Uses a Dockerfile to create a new docker image |
Note Maintenance
10. Overview
Note Maintenance
10.1. Version information
Version : 2.0
10.2. Contact information
Contact : Hafid Haddouti
10.3. License information
License : Apache License Version 2.0
License URL : exmaple.org/LICENSE
Terms of service : http://example.org
10.4. URI scheme
Host : localhost
BasePath : /
10.5. Tags
-
rest-note-maintenance : Rest Note Maintenance
11. Resources
11.1. Rest-note-maintenance
Rest Note Maintenance
11.1.1. getAllNotes
GET /note/v1/note
Responses
HTTP Code | Description | Schema |
---|---|---|
200 |
OK |
|
401 |
Unauthorized |
No Content |
403 |
Forbidden |
No Content |
404 |
Not Found |
No Content |
Consumes
-
application/json
Produces
-
/
11.1.2. putNote
PUT /note/v1/note
Parameters
Type | Name | Description | Schema |
---|---|---|---|
Body |
req |
req |
Responses
HTTP Code | Description | Schema |
---|---|---|
200 |
OK |
|
201 |
Created |
No Content |
401 |
Unauthorized |
No Content |
403 |
Forbidden |
No Content |
404 |
Not Found |
No Content |
Consumes
-
application/xml
-
application/json
Produces
-
/
11.1.3. deleteNote
DELETE /note/v1/note
Parameters
Type | Name | Description | Schema |
---|---|---|---|
Body |
req |
req |
Responses
HTTP Code | Description | Schema |
---|---|---|
200 |
OK |
|
204 |
No Content |
No Content |
401 |
Unauthorized |
No Content |
403 |
Forbidden |
No Content |
Consumes
-
application/xml
-
application/json
Produces
-
/
12. Definitions
12.1. NoteItem
Name | Schema |
---|---|
content |
string |
id |
integer (int64) |
reminderAt |
string (date-time) |
title |
string |
userId |
string |
12.2. NoteRequest
Name | Schema |
---|---|
items |
< NoteItem > array |
12.3. NoteResponse
Name | Schema |
---|---|
items |
< NoteItem > array |
resultStatus |
< StatusCode > array |
12.4. StatusCode
Name | Schema |
---|---|
code |
string |
text |
string |