add java http example

Signed-off-by: Sarthak Sharma <sartsharma@microsoft.com>
This commit is contained in:
Sarthak Sharma 2022-11-22 16:11:55 +05:30
parent e7cfccf383
commit e40af0acaf
5 changed files with 277 additions and 0 deletions

View File

@ -0,0 +1,91 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
> **Note:** This example leverages HTTP `requests` only. If you are looking for the example using the Dapr Client SDK (recommended) [click here](../sdk/).
This quickstart includes one service:
- Java service `order-processor`
## Prerequisites
- [Maven 3.x](https://maven.apache.org/install.html)
- Java JDK 11 (or greater):
- [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11)
- [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11)
- [OpenJDK 11](https://jdk.java.net/11/)
- Locally running redis instance - a redis instance is automatically created as a docker container when you run `dapr init`
- Install Redis CLI - [Getting started with Redis | Redis](https://redis.io/docs/getting-started/). `redis-cli` is installed as part of redis setup
## Add configuration items to the config store
- Open a new terminal and set values for config items `orderId1` and `orderId2` using `redis-cli`
<!-- STEP
name: Add configuration items
-->
```bash
redis-cli -n 0 MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Build the Java file
<!-- STEP
name: Build Java file
-->
```bash
cd ./order-processor
mvn clean install
```
<!-- END_STEP -->
## Run order-processor
1. Navigate to `order-processor` directory.
2. Run the service app with Dapr.
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1:{"orderId1":{"value":"101"}}'
- '== APP == Configuration for orderId2:{"orderId2":{"value":"102"}}'
- '== APP == App subscribed to config changes with subscription id:'
- '= APP == App unsubscribed from config changes'
- '== APP == Shutting down spring app'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --app-port 6001 --components-path ../../../components -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using `redis-cli`
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
redis-cli -n 0 MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>com.service</groupId>
<artifactId>OrderProcessingService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>OrderProcessingService</name>
<description>Demo for Dapr Configuration API</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220924</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.4</version>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,113 @@
package com.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.json.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
@SpringBootApplication
public class OrderProcessingServiceApplication {
private static final String DAPR_CONFIGURATION_STORE = "configstore";
private static List<String> CONFIGURATION_ITEMS = List.of("orderId1",
"orderId2");
private static String DAPR_HOST = System.getenv().getOrDefault("DAPR_HOST",
"http://localhost");
private static String DAPR_HTTP_PORT = System.getenv().getOrDefault("DAPR_HTTP_PORT", "3500");
private static String APP_PORT = System.getenv().getOrDefault("APP_PORT", "6001");
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();
public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException {
URI baseUrl = new URI(DAPR_HOST + ":" + DAPR_HTTP_PORT);
// Get config items from the config store
try {
for (String configurationItem : CONFIGURATION_ITEMS) {
URI uri = baseUrl
.resolve(
"/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "?key=" +
configurationItem);
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(uri)
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Configuration for " + configurationItem + ":" +
response.body());
}
} catch (Exception e) {
System.out.println("Could not get config item, err:" + e.getMessage());
System.exit(1);
}
// Create Spring Application to listen to configuration updates
SpringApplication app = new SpringApplication(OrderProcessingServiceApplication.class);
app.setDefaultProperties(Collections.singletonMap("server.port", APP_PORT));
// Start the application
ConfigurableApplicationContext context = app.run(args);
// Add delay to allow app channel to be ready
Thread.sleep(3000);
// Subscribe to Configuration Updates
String subscriptionId = null;
try {
URI uri = baseUrl
.resolve("/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "/subscribe");
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(uri)
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
JSONObject subscription = new JSONObject(response.body());
subscriptionId = subscription.getString("id");
System.out.println("App subscribed to config changes with subscription id:" + subscriptionId);
} catch (Exception e) {
System.out.println("Error subscribing to config updates, err:" + e.getMessage());
System.exit(1);
}
// Receive config updates for 20 seconds, then unsubscribe from config updates and shutdown spring app
Thread.sleep(20000);
try {
// unsubscribe from config updates
URI uri = baseUrl
.resolve("/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "/" + subscriptionId
+ "/unsubscribe");
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(uri)
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.body().contains("true")) {
System.out.println("App unsubscribed from config changes");
} else {
System.out.println("Error unsubscribing from config updates: " + response.body());
}
} catch (Exception e) {
System.out.println("Error unsubscribing from config updates, err:" + e.getMessage());
System.exit(1);
}
// Shutdown spring app
System.out.println("Shutting down spring app");
SpringApplication.exit(context, () -> 0);
System.exit(0);
}
}

View File

@ -0,0 +1,24 @@
package com.service.controller;
import java.util.Map;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderProcessingServiceController {
/**
* Read configuration updates from config store
*
* @param body Request body
* @return ResponseEntity Returns ResponseEntity.ok()
*/
@PostMapping(path = "/configuration/configstore/{configItem}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> readUpdates(@RequestBody Map<String, Object> body) {
System.out.println("Configuration update "+ body.get("items"));
return ResponseEntity.ok().build();
}
}