diff --git a/README.md b/README.md index 94d59e9..556aabf 100644 --- a/README.md +++ b/README.md @@ -23,26 +23,26 @@ Alternatively, you can build and run the project manually by using [gradle](https://gradle.org/) and launching the application with [docker-compose](https://docs.docker.com/compose/). ```shell -gradlew build +# build the modules +(cd ./applications/consumer/ && ./gradlew build) +(cd ./applications/converter/ && ./gradlew build) +(cd ./applications/producer/ && ./gradlew build) +# start the docker based on the docker-compose.yaml file docker compose up ``` ## Configuration -If you wish, you can modify the configuration of the `docker-compose.yaml` file to fit your needs. +The configuration can be modified in the [docker-compose.yaml](./docker-compose.yaml) file to fit your needs. -The container `application` can be easily modified with the following environment variables : - -| Name | Required | Format | Default | Description | -|------------------------------|----------|-----------------------------------------------------|--------------------------------------------------------------------|---------------------------------------------------------------| -| KAFKA_BOOTSTRAP_SERVERS | true | \[:port] | / | The Kafka server address | -| TOPIC_TEMPERATURE_CELSIUS | false | string of alphanumeric characters, ".", "_" and "-" | temperature-celsius | The name of the Kafka topic for the temperature in Celsius | -| TOPIC_TEMPERATURE_FAHRENHEIT | false | string of alphanumeric characters, ".", "_" and "-" | temperature-fahrenheit | The name of the Kafka topic for the temperature in Fahrenheit | -| TEMPERATURE_LOCATION | true | \, \ | 49.9, 2.3 ([Amiens, France](https://fr.wikipedia.org/wiki/Amiens)) | The coordinates where to get the temperatures from | +You can find a list for each module of the project containing their individual configuration : +- [producer](./applications/producer/README.md) +- [consumer](./applications/consumer/README.md) +- [converter](./applications/converter/README.md) ## Expectation The `application` container shall print the current temperature at the selected place in Fahrenheit every minute. -You can also access this value with the REST api at the `http://localhost:8080/temperature` endpoint. +You can also access this value with the REST api at the `http://localhost:8080/v1/temperature` endpoint. ## References -The project use the [Open-Meteo API](https://open-meteo.com/) to fetch the current temperature at the -given location. \ No newline at end of file +The project use the [Open-Meteo](https://open-meteo.com/) API to fetch the current temperature at the +given location. diff --git a/applications/common/README.md b/applications/common/README.md index 8a73f72..b0defed 100644 --- a/applications/common/README.md +++ b/applications/common/README.md @@ -1,58 +1,15 @@ -# common +# Module: Common -This project uses Quarkus, the Supersonic Subatomic Java Framework. +This module contain common code that could be used between the three others modules of the application. -If you want to learn more about Quarkus, please visit its website: . +It implements some errors or some useful functionalities and structure to avoid redefining them in all the modules +and making debugging easier by only modifying a single file to fix the corresponding issue everywhere. -## Running the application in dev mode +## Build -You can run your application in dev mode that enables live coding using: +This project is built automatically when building the others modules. -```shell script -./gradlew quarkusDev -``` - -> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at . - -## Packaging and running the application - -The application can be packaged using: - -```shell script +However, you can still build it manually with the following command : +```shell ./gradlew build ``` - -It produces the `quarkus-run.jar` file in the `build/quarkus-app/` directory. -Be aware that it’s not an _über-jar_ as the dependencies are copied into the `build/quarkus-app/lib/` directory. - -The application is now runnable using `java -jar build/quarkus-app/quarkus-run.jar`. - -If you want to build an _über-jar_, execute the following command: - -```shell script -./gradlew build -Dquarkus.package.jar.type=uber-jar -``` - -The application, packaged as an _über-jar_, is now runnable using `java -jar build/*-runner.jar`. - -## Creating a native executable - -You can create a native executable using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -``` - -Or, if you don't have GraalVM installed, you can run the native executable build in a container using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true -``` - -You can then execute your native executable with: `./build/common-1.0-SNAPSHOT-runner` - -If you want to learn more about building native executables, please consult . - -## Related Guides - -- Kotlin ([guide](https://quarkus.io/guides/kotlin)): Write your services in Kotlin diff --git a/applications/common/src/main/kotlin/fr/faraphel/common/kafka/AdminUtils.kt b/applications/common/src/main/kotlin/fr/faraphel/common/kafka/AdminUtils.kt deleted file mode 100644 index bc3b91a..0000000 --- a/applications/common/src/main/kotlin/fr/faraphel/common/kafka/AdminUtils.kt +++ /dev/null @@ -1,41 +0,0 @@ -package fr.faraphel.common.kafka - -import org.apache.kafka.clients.admin.Admin -import org.apache.kafka.clients.admin.AdminClientConfig -import org.apache.kafka.clients.admin.CreateTopicsResult -import org.apache.kafka.clients.admin.NewTopic -import java.util.* - - -/** - * A wrapper around KafkaAdminClient to simplify its configuration. - * @param server the kafka server address - * @param identifier the kafka identifier for the configuration - * @see Admin - */ -class AdminUtils( - private val server: String, - private val identifier: String = "admin" -) { - private val adminConfig = Properties().apply { - // set the identifier - this[AdminClientConfig.CLIENT_ID_CONFIG] = identifier - // set the server information - this[AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG] = server - } - - private val admin = Admin.create(adminConfig) - - /** - * Create the topics in the kafka server. - * @param topics the names of the topics to create. - * @return the result of the operation. - * @see Admin.createTopics - */ - fun createTopics(vararg topics: String): CreateTopicsResult { - // convert the topics name into the corresponding operation - val operations = topics.map { topic -> NewTopic(topic, 1, 1) } - // run the command - return this.admin.createTopics(operations) - } -} diff --git a/applications/common/src/main/kotlin/fr/faraphel/common/temperature/Temperature.kt b/applications/common/src/main/kotlin/fr/faraphel/common/temperature/Temperature.kt index 528af8f..77e567e 100644 --- a/applications/common/src/main/kotlin/fr/faraphel/common/temperature/Temperature.kt +++ b/applications/common/src/main/kotlin/fr/faraphel/common/temperature/Temperature.kt @@ -19,4 +19,3 @@ class Temperature( val asFahrenheit: Double get() = ((this.value - 273.15) * 1.8) + 32 } - diff --git a/applications/consumer/README.md b/applications/consumer/README.md index d10adac..2d16e3e 100644 --- a/applications/consumer/README.md +++ b/applications/consumer/README.md @@ -1,58 +1,22 @@ -# consumer +# Module: Consumer -This project uses Quarkus, the Supersonic Subatomic Java Framework. +This module contain the code responsible for receiving values, displaying them in the container output and hosting +the REST API where we can find the latest value received. -If you want to learn more about Quarkus, please visit its website: . +## Build -## Running the application in dev mode +This project is built automatically when using [docker-compose](https://docs.docker.com/compose/) at the root. -You can run your application in dev mode that enables live coding using: - -```shell script -./gradlew quarkusDev -``` - -> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at . - -## Packaging and running the application - -The application can be packaged using: - -```shell script +However, you can still build it manually with the following command : +```shell ./gradlew build ``` -It produces the `quarkus-run.jar` file in the `build/quarkus-app/` directory. -Be aware that it’s not an _über-jar_ as the dependencies are copied into the `build/quarkus-app/lib/` directory. +## Configuration -The application is now runnable using `java -jar build/quarkus-app/quarkus-run.jar`. +This module can be easily modified with the following environment variables : -If you want to build an _über-jar_, execute the following command: - -```shell script -./gradlew build -Dquarkus.package.jar.type=uber-jar -``` - -The application, packaged as an _über-jar_, is now runnable using `java -jar build/*-runner.jar`. - -## Creating a native executable - -You can create a native executable using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -``` - -Or, if you don't have GraalVM installed, you can run the native executable build in a container using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true -``` - -You can then execute your native executable with: `./build/consumer-1.0-SNAPSHOT-runner` - -If you want to learn more about building native executables, please consult . - -## Related Guides - -- Kotlin ([guide](https://quarkus.io/guides/kotlin)): Write your services in Kotlin +| Name | Required | Format | Default | Description | +|-------------------------|----------|-----------------------------------------------------|---------|---------------------------------------------------| +| KAFKA_BOOTSTRAP_SERVERS | true | \[:port] | / | The Kafka server address | +| TEMPERATURE_TOPIC | true | string of alphanumeric characters, ".", "_" and "-" | / | The Kafka topic were the temperature can be found | diff --git a/applications/consumer/build.gradle.kts b/applications/consumer/build.gradle.kts index 0e1d3b8..b937130 100644 --- a/applications/consumer/build.gradle.kts +++ b/applications/consumer/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { // libraries implementation("io.quarkus:quarkus-kafka-client") implementation("io.quarkus:quarkus-kafka-streams") + implementation("com.google.code.gson:gson:2.8.9") } group = "fr.faraphel" diff --git a/applications/consumer/src/main/kotlin/fr/faraphel/consumer/Main.kt b/applications/consumer/src/main/kotlin/fr/faraphel/consumer/Main.kt index 9315363..39c1709 100644 --- a/applications/consumer/src/main/kotlin/fr/faraphel/consumer/Main.kt +++ b/applications/consumer/src/main/kotlin/fr/faraphel/consumer/Main.kt @@ -24,12 +24,13 @@ class Main : QuarkusApplication { server=kafkaServer, topic=topicTemperature ) { message -> - // format the time of the message to a proper string - val time = timeFormatter.format(Instant.ofEpochMilli(message.timestamp())) + // clean the values in the record + val messageInstant = Instant.ofEpochMilli(message.timestamp()) + val messageContent = message.value() // print the value - println("[${time}] ${message.value()}°F") + println("[${timeFormatter.format(messageInstant)}] ${messageContent}°F") // update the value for the API - TemperatureEndpoint.setTemperature(message.value()) + TemperatureEndpoint.updateData(messageContent, messageInstant) } // indefinitely consume new values diff --git a/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/PingEndpoint.kt b/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/PingEndpoint.kt index a960a59..10a73d4 100644 --- a/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/PingEndpoint.kt +++ b/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/PingEndpoint.kt @@ -9,7 +9,7 @@ import jakarta.ws.rs.Path * Always answer "Pong!" * Can be used to test if the API can be reached */ -@Path("ping") +@Path("/v1/ping") class PingEndpoint { /** * Handler for a GET request on this endpoint diff --git a/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/TemperatureEndpoint.kt b/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/TemperatureEndpoint.kt index 569121c..c80bca4 100644 --- a/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/TemperatureEndpoint.kt +++ b/applications/consumer/src/main/kotlin/fr/faraphel/consumer/rest/TemperatureEndpoint.kt @@ -1,23 +1,31 @@ package fr.faraphel.consumer.rest +import com.google.gson.Gson import jakarta.ws.rs.GET import jakarta.ws.rs.Path +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import java.time.Instant /** * This API endpoint return the latest temperature measured (in Fahrenheit) */ -@Path("temperature") +@Path("/v1/temperature") class TemperatureEndpoint { companion object { + val jsonParser = Gson() ///< the json parser + private var temperature: Double? = null ///< the latest temperature value + private var time: Instant? = null /// < the time of the latest value /** * Setter to update the latest temperature value * @param temperature the new temperature value */ - fun setTemperature(temperature: Double) { + fun updateData(temperature: Double, time: Instant) { this.temperature = temperature + this.time = time } } @@ -26,7 +34,10 @@ class TemperatureEndpoint { * @return the latest temperature measured */ @GET - fun get(): Double? { - return temperature - } + @Produces(MediaType.APPLICATION_JSON) + fun get(): String = jsonParser.toJson(mapOf( + "value" to temperature, + "time" to time?.toEpochMilli(), + "unit" to "Fahrenheit" + )) } diff --git a/applications/converter/README.md b/applications/converter/README.md index 2c38fa9..617d602 100644 --- a/applications/converter/README.md +++ b/applications/converter/README.md @@ -1,58 +1,23 @@ -# converter +# Module: Converter -This project uses Quarkus, the Supersonic Subatomic Java Framework. +This module contain the code responsible for receiving values from a topic, converting them from +Celsius temperature to Fahrenheit and send it back into another topic. -If you want to learn more about Quarkus, please visit its website: . +## Build -## Running the application in dev mode +This project is built automatically when using [docker-compose](https://docs.docker.com/compose/) at the root. -You can run your application in dev mode that enables live coding using: - -```shell script -./gradlew quarkusDev -``` - -> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at . - -## Packaging and running the application - -The application can be packaged using: - -```shell script +However, you can still build it manually with the following command : +```shell ./gradlew build ``` -It produces the `quarkus-run.jar` file in the `build/quarkus-app/` directory. -Be aware that it’s not an _über-jar_ as the dependencies are copied into the `build/quarkus-app/lib/` directory. +## Configuration -The application is now runnable using `java -jar build/quarkus-app/quarkus-run.jar`. +This module can be easily modified with the following environment variables : -If you want to build an _über-jar_, execute the following command: - -```shell script -./gradlew build -Dquarkus.package.jar.type=uber-jar -``` - -The application, packaged as an _über-jar_, is now runnable using `java -jar build/*-runner.jar`. - -## Creating a native executable - -You can create a native executable using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -``` - -Or, if you don't have GraalVM installed, you can run the native executable build in a container using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true -``` - -You can then execute your native executable with: `./build/converter-1.0-SNAPSHOT-runner` - -If you want to learn more about building native executables, please consult . - -## Related Guides - -- Kotlin ([guide](https://quarkus.io/guides/kotlin)): Write your services in Kotlin +| Name | Required | Format | Default | Description | +|------------------------------|----------|-----------------------------------------------------|---------|-----------------------------------------------------------------| +| KAFKA_BOOTSTRAP_SERVERS | true | \[:port] | / | The Kafka server address | +| TEMPERATURE_CELSIUS_TOPIC | true | string of alphanumeric characters, ".", "_" and "-" | / | The Kafka topic were the temperature in celsius can be found | +| TEMPERATURE_FAHRENHEIT_TOPIC | true | string of alphanumeric characters, ".", "_" and "-" | / | The Kafka topic were the temperature in fahrenheit can be found | diff --git a/applications/producer/README.md b/applications/producer/README.md index 6e41d55..4ec7f47 100644 --- a/applications/producer/README.md +++ b/applications/producer/README.md @@ -1,58 +1,23 @@ -# producer +# Module: Converter -This project uses Quarkus, the Supersonic Subatomic Java Framework. +This module contain the code responsible for getting the current temperature at a given location thanks to the +[Open-Meteo](https://open-meteo.com/) API, and sending it into a topic. -If you want to learn more about Quarkus, please visit its website: . +## Build -## Running the application in dev mode +This project is built automatically when using [docker-compose](https://docs.docker.com/compose/) at the root. -You can run your application in dev mode that enables live coding using: - -```shell script -./gradlew quarkusDev -``` - -> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at . - -## Packaging and running the application - -The application can be packaged using: - -```shell script +However, you can still build it manually with the following command : +```shell ./gradlew build ``` -It produces the `quarkus-run.jar` file in the `build/quarkus-app/` directory. -Be aware that it’s not an _über-jar_ as the dependencies are copied into the `build/quarkus-app/lib/` directory. +## Configuration -The application is now runnable using `java -jar build/quarkus-app/quarkus-run.jar`. +This module can be easily modified with the following environment variables : -If you want to build an _über-jar_, execute the following command: - -```shell script -./gradlew build -Dquarkus.package.jar.type=uber-jar -``` - -The application, packaged as an _über-jar_, is now runnable using `java -jar build/*-runner.jar`. - -## Creating a native executable - -You can create a native executable using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -``` - -Or, if you don't have GraalVM installed, you can run the native executable build in a container using: - -```shell script -./gradlew build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true -``` - -You can then execute your native executable with: `./build/producer-1.0-SNAPSHOT-runner` - -If you want to learn more about building native executables, please consult . - -## Related Guides - -- Kotlin ([guide](https://quarkus.io/guides/kotlin)): Write your services in Kotlin +| Name | Required | Format | Default | Description | +|-------------------------|----------|-----------------------------------------------------|---------|--------------------------------------------------------------| +| KAFKA_BOOTSTRAP_SERVERS | true | \[:port] | / | The Kafka server address | +| TEMPERATURE_TOPIC | true | string of alphanumeric characters, ".", "_" and "-" | / | The Kafka topic were the temperature in celsius can be found | +| TEMPERATURE_LOCATION | true | \, \ | / | The coordinates where to get the temperatures from |