Skip to content

Commit 375e867

Browse files
MregXNartursouzachampelmukundansundar
authored
Add PubSub subscriber examples over gPRC (#833)
* add grpc subscriber Signed-off-by: MregXN <[email protected]> * modify README.md Signed-off-by: MregXN <[email protected]> * modify README.md in examples Signed-off-by: MregXN <[email protected]> * Modify DaprApplication to support examples where protocol is not specified. Signed-off-by: MregXN <[email protected]> * modify formatter to pass checkstyle Signed-off-by: MregXN <[email protected]> * Update springboot to latest minor.patch version. (#826) Signed-off-by: MregXN <[email protected]> * Use runtime 1.10.0-rc.X and CLI 1.10.0-rc.X (#827) Signed-off-by: Artur Souza <[email protected]> Signed-off-by: MregXN <[email protected]> * Upgrade the version to 1.9.0-SNAPSHOT (#829) Signed-off-by: Artur Souza <[email protected]> Signed-off-by: MregXN <[email protected]> * Generate updated javadocs for 1.8.0 (#836) Signed-off-by: Artur Souza <[email protected]> Signed-off-by: MregXN <[email protected]> * Update Dapr runtime and CLI to 1.10. (#837) Signed-off-by: Artur Souza <[email protected]> Signed-off-by: MregXN <[email protected]> * Inject autoconfiguration in the Spring Boot 3 style (#831) * Bump from spring boot 2.3.5.RELEASE to 2.7.8 Signed-off-by: Sergio <[email protected]> (cherry picked from commit 9152c91) * Ensure old versions of spring boot are still compatible Signed-off-by: Sergio <[email protected]> --------- Signed-off-by: champel <[email protected]> Signed-off-by: Sergio <[email protected]> Signed-off-by: MregXN <[email protected]> * Bump from reactor 2.3.5.RELEASE to 2.7.8 (#830) * Bump from reactor 2.3.5.RELEASE to 2.7.8 Signed-off-by: Sergio <[email protected]> * Simplification Signed-off-by: Sergio <[email protected]> --------- Signed-off-by: Sergio <[email protected]> Signed-off-by: MregXN <[email protected]> * rerun checks Signed-off-by: MregXN <[email protected]> * modify the way of grpc server starts Signed-off-by: MregXN <[email protected]> * modify README Signed-off-by: MregXN <[email protected]> * Update pom.xml Signed-off-by: MregXN <[email protected]> --------- Signed-off-by: MregXN <[email protected]> Signed-off-by: Artur Souza <[email protected]> Signed-off-by: champel <[email protected]> Signed-off-by: Sergio <[email protected]> Signed-off-by: MregXN <[email protected]> Co-authored-by: Artur Souza <[email protected]> Co-authored-by: champel <[email protected]> Co-authored-by: Mukundan Sundararajan <[email protected]>
1 parent aaa5f7b commit 375e867

File tree

7 files changed

+234
-13
lines changed

7 files changed

+234
-13
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Try the following examples to learn more about Dapr's Java SDK:
104104
* [Invoking a Http service](./examples/src/main/java/io/dapr/examples/invoke/http)
105105
* [Invoking a Grpc service](./examples/src/main/java/io/dapr/examples/invoke/grpc)
106106
* [State management](./examples/src/main/java/io/dapr/examples/state)
107-
* [PubSub with subscriber over Http](./examples/src/main/java/io/dapr/examples/pubsub/http)
107+
* [PubSub with subscriber](./examples/src/main/java/io/dapr/examples/pubsub/)
108108
* [Binding with input over Http](./examples/src/main/java/io/dapr/examples/bindings/http)
109109
* [Actors](./examples/src/main/java/io/dapr/examples/actors/)
110110
* [Secrets management](./examples/src/main/java/io/dapr/examples/secrets)

examples/src/main/java/io/dapr/examples/DaprApplication.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,42 @@
1717
import org.springframework.boot.autoconfigure.SpringBootApplication;
1818

1919
/**
20-
* Dapr's HTTP callback implementation via SpringBoot.
20+
* Dapr's callback implementation via SpringBoot.
2121
*/
2222
@SpringBootApplication
2323
public class DaprApplication {
2424

2525
/**
26-
* Starts Dapr's callback in a given port.
26+
* Starts Dapr's callback in a given port and specified protocal.
27+
*
28+
* @param port Port to listen to.
29+
* @param protocal select Http or gRPC to run.
30+
*/
31+
public static void start(String protocal, int port) {
32+
SpringApplication app = new SpringApplication(DaprApplication.class);
33+
34+
String args;
35+
if (protocal.equals("grpc")) {
36+
args = String.format("--grpc.server.port=%d", port);
37+
} else if (protocal.equals("http")) {
38+
args = String.format("--server.port=%d", port);
39+
} else {
40+
System.out.println("please select protocal in grpc or http.");
41+
return;
42+
}
43+
44+
app.run(args);
45+
}
46+
47+
/**
48+
* Starts Dapr's callback in a given port. HTTP is used by default.
49+
*
2750
* @param port Port to listen to.
2851
*/
2952
public static void start(int port) {
53+
3054
SpringApplication app = new SpringApplication(DaprApplication.class);
55+
3156
app.run(String.format("--server.port=%d", port));
3257
}
3358

examples/src/main/java/io/dapr/examples/pubsub/README.md

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,23 @@ cd examples
4040

4141
### Running the subscriber
4242

43-
The first is the subscriber. It will subscribe to the topic to be used by the publisher and read the messages published. The Subscriber uses the Spring Boot´s DaprApplication class for initializing the `SubscriberController`. In `Subscriber.java` file, you will find the `Subscriber` class and the `main` method. See the code snippet below:
43+
The first is the subscriber. It will subscribe to the topic to be used by the publisher and read the messages published. The Subscriber uses the Spring Boot´s DaprApplication class for initializing the `SubscriberController`. There are gRPC version and HTTP version of subscriber in grpc and http folders. In `Subscriber.java` file, you will find the `Subscriber` class and the `main` method. See the code snippet below:
4444

4545
```java
4646
public class Subscriber {
4747

4848
public static void main(String[] args) throws Exception {
4949
///...
5050
// Start Dapr's callback endpoint.
51-
DaprApplication.start(port);
51+
DaprApplication.start([PROTOCAL],port);
5252
}
5353
}
5454
```
55-
`DaprApplication.start()` Method will run an Spring Boot application that registers the `SubscriberController`, which exposes the message retrieval as a POST request. The Dapr's sidecar is the one that performs the actual call to the controller, based on the pubsub features.
55+
`DaprApplication.start()` Method will run an Spring Boot application that registers the `SubscriberController`, which exposes the message retrieval as a POST request, or the `SubscriberGrpcService`, which implemente the grpc methods that sidecar will call.
5656

57-
This Spring Controller handles the message endpoint, printing the message which is received as the POST body.
57+
**HTTP Version**
58+
59+
The Dapr's sidecar is the one that performs the actual call to the controller, based on the pubsub features. This Spring Controller handles the message endpoint, printing the message which is received as the POST body.
5860

5961
The subscription's topic in Dapr is handled automatically via the `@Topic` annotation - which also supports the same expressions in
6062
[Spring's @Value annotations](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-value-annotations).
@@ -116,7 +118,9 @@ public class SubscriberController {
116118
}
117119
```
118120

119-
Execute the follow script in order to run the Subscriber example:
121+
122+
123+
Execute the follow script in order to run the HTTP Subscriber example:
120124

121125
<!-- STEP
122126
name: Run Subscriber
@@ -133,11 +137,66 @@ sleep: 5
133137
-->
134138

135139
```bash
136-
dapr run --components-path ./components/pubsub --app-id subscriber --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Subscriber -p 3000
140+
dapr run --components-path ./components/pubsub --app-id subscriber --app-port 3000 --app-protocol http -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.http.Subscriber -p 3000
137141
```
138142

139143
<!-- END_STEP -->
140144

145+
**gRPC Version**
146+
147+
The Spring GrpcService implements the methods required for gRPC communication with Dapr\`s sidecar.
148+
149+
The `SubscriberGrpcService.java` snippet below shows the details. Dapr\`s sidecar will call `listTopicSubscriptions` to get topic and pubsubname that are contained in response before subscription starts. After the pubsub component in sidecar subscribes successfully from the specified topic, message will be sent to the method `onTopicEvent` in request parameter.
150+
151+
```java
152+
@GrpcService
153+
public class SubscriberGrpcService extends AppCallbackGrpc.AppCallbackImplBase {
154+
private final List<DaprAppCallbackProtos.TopicSubscription> topicSubscriptionList = new ArrayList<>();
155+
private final DaprObjectSerializer objectSerializer = new DefaultObjectSerializer();
156+
157+
@Override
158+
public void listTopicSubscriptions(Empty request,
159+
StreamObserver<DaprAppCallbackProtos.ListTopicSubscriptionsResponse> responseObserver) {
160+
registerConsumer("messagebus","testingtopic");
161+
try {
162+
DaprAppCallbackProtos.ListTopicSubscriptionsResponse.Builder builder = DaprAppCallbackProtos.ListTopicSubscriptionsResponse
163+
.newBuilder();
164+
topicSubscriptionList.forEach(builder::addSubscriptions);
165+
DaprAppCallbackProtos.ListTopicSubscriptionsResponse response = builder.build();
166+
responseObserver.onNext(response);
167+
} catch (Throwable e) {
168+
responseObserver.onError(e);
169+
} finally {
170+
responseObserver.onCompleted();
171+
}
172+
}
173+
174+
@Override
175+
public void onTopicEvent(DaprAppCallbackProtos.TopicEventRequest request,
176+
StreamObserver<DaprAppCallbackProtos.TopicEventResponse> responseObserver) {
177+
try {
178+
System.out.println("Subscriber got: " + request.getData());
179+
DaprAppCallbackProtos.TopicEventResponse response = DaprAppCallbackProtos.TopicEventResponse.newBuilder()
180+
.setStatus(DaprAppCallbackProtos.TopicEventResponse.TopicEventResponseStatus.SUCCESS)
181+
.build();
182+
responseObserver.onNext(response);
183+
responseObserver.onCompleted();
184+
} catch (Throwable e) {
185+
responseObserver.onError(e);
186+
}
187+
}
188+
///...
189+
}
190+
```
191+
192+
193+
Execute the follow script in order to run the gRPC Subscriber example:
194+
195+
```bash
196+
dapr run --components-path ./components/pubsub --app-id subscriber --app-port 3000 --app-protocol grpc -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.grpc.Subscriber -p 3000
197+
```
198+
199+
141200
### Running the publisher
142201

143202
Another component is the publisher. It is a simple java application with a main method that uses the Dapr gRPC Client to publish 10 messages to a specific topic.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2021 The Dapr Authors
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package io.dapr.examples.pubsub.grpc;
15+
16+
import io.dapr.examples.DaprApplication;
17+
import io.grpc.Server;
18+
import io.grpc.ServerBuilder;
19+
import org.apache.commons.cli.CommandLine;
20+
import org.apache.commons.cli.CommandLineParser;
21+
import org.apache.commons.cli.DefaultParser;
22+
import org.apache.commons.cli.Options;
23+
24+
/**
25+
* Service for subscriber.
26+
* 1. Build and install jars:
27+
* mvn clean install
28+
* 2. cd [repo root]/examples
29+
* 3. Run the server:
30+
* dapr run --components-path ./components/pubsub --app-id subscriber --app-port 3000 -- \
31+
* java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.grpc.Subscriber -p 3000
32+
*/
33+
public class Subscriber {
34+
35+
/**
36+
* This is the entry point for this example app, which subscribes to a topic.
37+
* @param args The port this app will listen on.
38+
* @throws Exception An Exception on startup.
39+
*/
40+
public static void main(String[] args) throws Exception {
41+
Options options = new Options();
42+
options.addRequiredOption("p", "port", true, "The port this app will listen on");
43+
44+
CommandLineParser parser = new DefaultParser();
45+
CommandLine cmd = parser.parse(options, args);
46+
47+
// If port string is not valid, it will throw an exception.
48+
int port = Integer.parseInt(cmd.getOptionValue("port"));
49+
50+
//start a grpc server
51+
Server server = ServerBuilder.forPort(port)
52+
.addService(new SubscriberGrpcService())
53+
.build();
54+
server.start();
55+
server.awaitTermination();
56+
57+
// Start Dapr's callback endpoint.
58+
DaprApplication.start("grpc",port);
59+
}
60+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2021 The Dapr Authors
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package io.dapr.examples.pubsub.grpc;
15+
16+
import com.google.protobuf.Empty;
17+
import io.dapr.v1.AppCallbackGrpc;
18+
import io.dapr.v1.DaprAppCallbackProtos;
19+
import io.grpc.stub.StreamObserver;
20+
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
24+
/**
25+
* Class that encapsulates all client-side logic for Grpc.
26+
*/
27+
public class SubscriberGrpcService extends AppCallbackGrpc.AppCallbackImplBase {
28+
private final List<DaprAppCallbackProtos.TopicSubscription> topicSubscriptionList = new ArrayList<>();
29+
30+
@Override
31+
public void listTopicSubscriptions(Empty request,
32+
StreamObserver<DaprAppCallbackProtos.ListTopicSubscriptionsResponse> responseObserver) {
33+
registerConsumer("messagebus","testingtopic");
34+
try {
35+
DaprAppCallbackProtos.ListTopicSubscriptionsResponse.Builder builder = DaprAppCallbackProtos
36+
.ListTopicSubscriptionsResponse.newBuilder();
37+
topicSubscriptionList.forEach(builder::addSubscriptions);
38+
DaprAppCallbackProtos.ListTopicSubscriptionsResponse response = builder.build();
39+
responseObserver.onNext(response);
40+
} catch (Throwable e) {
41+
responseObserver.onError(e);
42+
} finally {
43+
responseObserver.onCompleted();
44+
}
45+
}
46+
47+
@Override
48+
public void onTopicEvent(DaprAppCallbackProtos.TopicEventRequest request,
49+
StreamObserver<DaprAppCallbackProtos.TopicEventResponse> responseObserver) {
50+
try {
51+
String data = request.getData().toStringUtf8().replace("\"", "");
52+
System.out.println("Subscriber got: " + data);
53+
DaprAppCallbackProtos.TopicEventResponse response = DaprAppCallbackProtos.TopicEventResponse.newBuilder()
54+
.setStatus(DaprAppCallbackProtos.TopicEventResponse.TopicEventResponseStatus.SUCCESS)
55+
.build();
56+
responseObserver.onNext(response);
57+
responseObserver.onCompleted();
58+
} catch (Throwable e) {
59+
responseObserver.onError(e);
60+
}
61+
}
62+
63+
/**
64+
* Add pubsub name and topic to topicSubscriptionList.
65+
*
66+
* @param topic the topic
67+
* @param pubsubName the pubsub name
68+
*/
69+
public void registerConsumer(String pubsubName, String topic) {
70+
topicSubscriptionList.add(DaprAppCallbackProtos.TopicSubscription
71+
.newBuilder()
72+
.setPubsubName(pubsubName)
73+
.setTopic(topic)
74+
.build());
75+
}
76+
}
77+

examples/src/main/java/io/dapr/examples/pubsub/Subscriber.java renamed to examples/src/main/java/io/dapr/examples/pubsub/http/Subscriber.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
limitations under the License.
1212
*/
1313

14-
package io.dapr.examples.pubsub;
14+
package io.dapr.examples.pubsub.http;
1515

1616
import io.dapr.examples.DaprApplication;
1717
import org.apache.commons.cli.CommandLine;
@@ -26,7 +26,7 @@
2626
* 2. cd [repo root]/examples
2727
* 3. Run the server:
2828
* dapr run --components-path ./components/pubsub --app-id subscriber --app-port 3000 -- \
29-
* java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Subscriber -p 3000
29+
* java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.http.Subscriber -p 3000
3030
*/
3131
public class Subscriber {
3232

@@ -46,6 +46,6 @@ public static void main(String[] args) throws Exception {
4646
int port = Integer.parseInt(cmd.getOptionValue("port"));
4747

4848
// Start Dapr's callback endpoint.
49-
DaprApplication.start(port);
49+
DaprApplication.start("http",port);
5050
}
5151
}

examples/src/main/java/io/dapr/examples/pubsub/SubscriberController.java renamed to examples/src/main/java/io/dapr/examples/pubsub/http/SubscriberController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
limitations under the License.
1212
*/
1313

14-
package io.dapr.examples.pubsub;
14+
package io.dapr.examples.pubsub.http;
1515

1616
import com.fasterxml.jackson.databind.ObjectMapper;
1717
import io.dapr.Rule;

0 commit comments

Comments
 (0)