Code Monkey home page Code Monkey logo

java-sdk's Introduction

Dapr SDK for Java

Maven Central GitHub Actions Workflow Status codecov GitHub License FOSSA Status GitHub issue custom search in repo Discord YouTube Channel Views X (formerly Twitter) Follow

This is the Dapr SDK for Java, including the following features:

  • PubSub
  • Service Invocation
  • Binding
  • State Store
  • Actors

Getting Started

Pre-Requisites

Install JDK

If using SDKMAN!, execute sdk env install to install the required JDK.

Importing Dapr's Java SDK

For a Maven project, add the following to your pom.xml file:

<project>
  ...
  <dependencies>
    ...
     <!-- Dapr's core SDK with all features, except Actors. -->
    <dependency>
      <groupId>io.dapr</groupId>
      <artifactId>dapr-sdk</artifactId>
      <version>1.11.0</version>
    </dependency>
    <!-- Dapr's SDK for Actors (optional). -->
    <dependency>
      <groupId>io.dapr</groupId>
      <artifactId>dapr-sdk-actors</artifactId>
      <version>1.11.0</version>
    </dependency>
    <!-- Dapr's SDK integration with SpringBoot (optional). -->
    <dependency>
      <groupId>io.dapr</groupId>
      <artifactId>dapr-sdk-springboot</artifactId>
      <version>1.11.0</version>
    </dependency>
    ...
  </dependencies>
  ...
</project>

For a Gradle project, add the following to your build.gradle file:

dependencies {
...
    // Dapr's core SDK with all features, except Actors.
    compile('io.dapr:dapr-sdk:1.11.0')
    // Dapr's SDK for Actors (optional).
    compile('io.dapr:dapr-sdk-actors:1.11.0')
    // Dapr's SDK integration with SpringBoot (optional).
    compile('io.dapr:dapr-sdk-springboot:1.11.0')
}

Running the examples

Clone this repository including the submodules:

git clone https://github.com/dapr/java-sdk.git

Then head over to build the Maven (Apache Maven version 3.x) project:

# make sure you are in the `java-sdk` directory.
./mvnw clean install

Try the following examples to learn more about Dapr's Java SDK:

API Documentation

Please, refer to our Javadoc website.

Reactor API

The Java SDK for Dapr is built using Project Reactor. It provides an asynchronous API for Java. A result is consumed synchronously by using the block() method, as shown in the examples referenced above.

The code below does not make any API call, it simply returns the Mono publisher object. Nothing happens until the application subscribes or blocks on the result:

Mono<Void> result = daprClient.publishEvent("mytopic", "my message");

To start execution and receive the result object synchronously (void or Void becomes an empty result), use block(). The code below shows how to execute the call and consume an empty response:

Mono<Void> result = daprClient.publishEvent("mytopic", "my message");
result.block();

How to use a custom serializer

This SDK provides a basic serialization for request/response objects, and state objects. Applications should provide their own serialization for production scenarios.

  1. Implement the DaprObjectSerializer interface. See this class as an example.
  2. Use your serializer class in the following scenarios:
    DaprClient client = (new DaprClientBuilder())
        .withObjectSerializer(new MyObjectSerializer()) // for request/response objects.
        .withStateSerializer(new MyStateSerializer()) // for state objects.
        .build();
    • When registering an Actor Type:
    ActorRuntime.getInstance().registerActor(
      DemoActorImpl.class,
      new MyObjectSerializer(), // for request/response objects.
      new MyStateSerializer()); // for state objects.
    • When building a new instance of ActorProxy to invoke an Actor instance, use the same serializer as when registering the Actor Type:
    try (ActorClient actorClient = new ActorClient()) {
      DemoActor actor = (new ActorProxyBuilder(DemoActor.class, actorClient))
          .withObjectSerializer(new MyObjectSerializer()) // for request/response objects.
          .build(new ActorId("100"));
    }

Debug a Java application or Dapr's Java SDK

In IntelliJ Community Edition, consider debugging in IntelliJ.

In Visual Studio Code, consider debugging in Visual Studio Code.

If you need to debug your Application, run the Dapr sidecar separately, and then start the application from your IDE (IntelliJ or Eclipse, for example). For Linux and MacOS:

dapr run --app-id testapp --app-port 3000 --dapr-http-port 3500 --dapr-grpc-port 5001

Note: confirm the correct port that the app will listen to and that the Dapr ports above are free, changing the ports if necessary.

When running your Java application from your IDE, make sure the following environment variables are set, so the Java SDK knows how to connect to Dapr's sidecar:

DAPR_HTTP_PORT=3500
DAPR_GRPC_PORT=5001

Now you can go to your IDE and debug your Java application, using port 3500 to call Dapr while also listening to port 3000 to expose Dapr's callback endpoint.

Exception handling

Most exceptions thrown from the SDK are instances of DaprException. DaprException extends from RuntimeException, making it compatible with Project Reactor. See the exception example for more details.

Development

Update URL to fetch proto files

Change the dapr.proto.baseurl property below in pom.xml to point to the URL for the desired commit hash in Git if you need to target a proto file that is not been merged into master yet.

Note: You may need to run ./mvnw clean after changing this setting to remove any auto-generated files so that the new proto files get downloaded and compiled.

<project>
  ...
  <properties>
    ...
    <!-- change this .... -->
    <dapr.proto.baseurl>https://raw.githubusercontent.com/dapr/dapr/(current ref in pom.xml)/dapr/proto</dapr.proto.baseurl>
    <!-- to something like this: -->
    <dapr.proto.baseurl>https://raw.githubusercontent.com/dapr/dapr/1ac5d0e8590a7d6772c9957c236351ed992ccb19/dapr/proto</dapr.proto.baseurl>
    ...
  </properties>
  ...
</project>

Running Integration Tests (ITs)

Pre-Requisites

Code

The code for the tests are present inside the project sdk-tests. This module alone can be imported as a separate project in IDEs. This project depends on the rest of the JARs built by the other modules in the repo like sdk, sdk-springboot etc.

As a starting point for running the Integration Tests, first run ./mvnw clean install from the root of the repo to build the JARs for the different modules, except the sdk-tests module.

Run all the dependent services spun up during build

During normal CI build, docker compose is used to bring up services like MongoDB, Hashicorp Vault, Apache Zookeeper, Kafka etc.

Similarly, all of these need to be run for running the ITs either individually or as a whole.

Run the following commands from the root of the repo to start all the docker containers that the tests depend on.

docker-compose -f ./sdk-tests/deploy/local-test.yml up -d

To stop the containers and services, run the following commands.

docker-compose -f ./sdk-tests/deploy/local-test.yml down

Run all ITs from command line

From the java-sdk repo root, change to the sdk-tests directory and run the following command.

## with current directory as /java-sdk/sdk-tests/

../mvnw clean install

The above command runs all the integration tests present in the sdk-tests project.

Run Individual tests from IntelliJ

In IntelliJ, go to File > New > Project from Existing Sources.... Import the sdk-tests project.

Once the project has been imported, the individual tests can be run normally as any Unit Tests, from the IDE itself.

intellij-integration-test.

Sometimes when the sdk-tests project does not build correctly, try File > Invalidate Caches... and try restarting IntelliJ.

You should be able to set breakpoints and Debug the test directly from IntelliJ itself as seen from the above image.

java-sdk's People

Contributors

aaroncrawfis avatar addjuarez avatar andresroblesmx avatar arghya88 avatar artur-ciocanu avatar artursouza avatar berndverst avatar brendandburns avatar brunoborges avatar cicoyle avatar dependabot[bot] avatar ejba avatar greenie-msft avatar halspang avatar hhunter-ms avatar juanjose-herrera avatar kaibocai avatar lmwf avatar marcosreyes05 avatar mregxn avatar mthmulders avatar mukundansundar avatar pravinpushkar avatar pruthvidhodda avatar shalabhms avatar shubham1172 avatar skyao avatar tcnghia avatar wcs1only avatar yaron2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

java-sdk's Issues

Revisit locking in the sdk

There were discussions earlier about what areas need locks and which do not, because of turn-based concurrency. I believe the conceptual discussions were resolved. This issue is just a reminder to revisit locking in the code to ensure we are not locking where we do not need to.

Simplify Serializer

Change default serializer to be straight JSON and not have a custom logic to handle primitive types.

Move DaprRuntime to test only + add CloudEvent serializer

DaprRuntime and related classes in io.dapr.runtime are not supposed to be exported as part of the SDK yet. Customer feedback is needed before we can offer a prescriptive solution like that.

On the other hand, offer a way for user to deserialize CloudEventEnvelope to process PubSub messages.

[java-sdk] Repackaging proposal to support Actors

Repackage the project into different projects (jars) and add support for Actors.

Proposed packages with corresponding jar name and java packages.

1. dapr-sdk-version.jar

Single project that clients can depend on to use Dapr in Java. There should be minimal (or none) use of 3rd party dependencies.

Java Packages:
io.dapr.client -> core interfaces and classes to communicate to Dapr's API
io.dapr.actors -> interfaces and classes for actors shared between actors' client and server side.
io.dapr.actors.common -> utility classes and interfaces shared between actor's client and server side.
io.dapr.actors.client-> interfaces and classes for actors' client side.
io.dapr.actors.runtime -> interfaces and classes for actors' server side.

Examples of possible interfaces in this jar:
io.dapr.client.HttpClient
io.dapr.client.GrpcClient

io.dapr.actors.Actor
io.dapr.actors.ActorId
io.dapr.actors.ActorService

io.dapr.actors.client.ActorProxy

io.dapr.actors.common.Utility

io.dapr.actors.runtime.ActorManager
io.dapr.actors.runtime.ActorReminder
io.dapr.actors.runtime.ActorTimer
io.dapr.actors.runtime.Remindable

2. dapr-sdk-callback-framework-version.jar

Multiple projects that clients can integrate with to easily create a callback API for Dapr to call to, for example: SpringBoot, Play, Netty, Spark (http://sparkjava.com/, not Apache Spark).

If we need to support different major versions of the same 3rd party framework, it should be handled as separate jars mainly due to avoid dependency conflicts.

Examples:
dapr-sdk-callback-springboot-2.jar
dapr-sdk-callback-play-1.jar
dapr-sdk-callback-play-2.jar

Java packages:
io.dapr.callback.framework -> one parent Java package per project.

Examples of possible classes in this jar:
io.dapr.callback.springboot.DaprController.java
io.dapr.callback.netty.DaprController.java

3. dapr-examples-version.jar

Samples that users can look into to understand how to use the API. There cannot be examples for multiple versions of the same 3rd party framework since there will be conflicting dependencies.

Java packages:
io.dapr.examples -> basic examples
io.dapr.examples.bindings -> examples using bindings
io.dapr.examples.pubsub -> examples using pubsub
io.dapr.examples.invoke-> examples using invoke
io.dapr.examples.actors-> examples using actors

Examples of possible classes in this package:
io.dapr.examples.HelloWorld.java
io.dapr.examples.actors.MyFirstActor.java

[java-sdk] Dapr HTTP Client for Actors

Create a Dapr client to make http calls directly (without using auto-gen client).
Implement all APIs needed to support Actors.

This overlaps with #22. While issue #22 will create a complete version of the Dapr client for Java, this one will unblock Actors work first, making HTTP calls directly.

[java-sdk] Adds checkstyle and bug finder

  • Adds a checkstyle to Java SDK and make build fail due to style violations.
  • Adds SpotBugs and make build fail due to violations.
  • Fixes existing violations.
  • Generated code should be excluded from static analysis.

Change DaprClient generic classes with correct Dapr API structures

The current DaprClient doesn't expose or conform to the Dapr API.

The generic classes that are currently used require the user to hand-craft the payload sent to Dapr.
An SDK should encapsulate the Dapr API surface into strongly-typed classes for ease of use and understanding.

A partial list of the features that need to be exposed by the DaprClient:

  1. State consistency
  2. State concurrency
  3. State metadata
  4. Pub/Sub metadata
  5. Service invocation metadata
  6. Bindings metadata

This can be remedied by including custom classes instead of generic classes, similar to the gRPC auto-generated classes (envelopes).

Hide actor APIs from DaprClient

DaprClient exposes actor APIs even though they are not for direct consumption. Move the APIs into internal classes in the Actor SDK.

[java-sdk] New jar to allow Dapr's callback API in SpringBoot

A SpringBoot Application can easily depend on this jar and have Dapr's callback API running with a simple configuration change and implementing a base class/interface.

As an alternative to a base class, annotations can also be used, similar to how the .Net SDK does with ASP.Net.

[java-sdk] Dapr's base Client

  • Define interface for the Dapr's Client - wrapper on top of the auto-generated code.
  • Implement Adapter for GRPC.
  • Implement Adapter for HTTP.

Detail below:

Interface DaprClient { // customer will use this interface.
// methods defined as part of this work.
// actor APIs re defined here too.
}

Class GrpcDapClient implements DaprClient { // customers don’t talk to this one directly
DaprGrpc grpcClient;
// implements methods from interface
// throws exceptions for all actor APIs since actors are http only for now.
}

Class HttpDaprClient implements DaprClient { // customers don’t talk to this directly.
DaprHttpClient httpClient;
// implements methods from interface
// implements actors APIs as well
}

[java-sdk] Java Actor runtime

Creating the Java Actor runtime classes, similar to the one in the Dotnet sdk.

Implementing the API endpoints for the SDK. The business logic should be (preferably) identical to the one in the Dotnet SDK.

Following are some of the few classes in C# SDK;

ActorRuntime: This is the actor runtime in SDK and contains information about registered types. It contains a mapping of ActorType and ActorManager. Actor types are registered with ActorRuntime.

ActorManager: It manages actors instances for an actor type, activates, deactivates them and make method calls to them.

ActorStateManager: Abstracts state management for Actors, provides a cache for Actor states, so that states which have already been worked on are not fetched again from Dapr for an active actor.

Actor: Base class for Actors. (In Java it can be called DaprActor)

DaprStateProvide: ActorStateManager uses it to interact with Dapr for state management.

RouterBuilderExtensions: This is for registering routes with aspnetcore, it registers the required routes (urls) on which Dapr runtime will call into user service code.

Move method logic inside Mono for GRPC Adapter

Expected Behavior

There should be no state or API call outside Mono.

Actual Behavior

Code in GRPC Adapter is making API call outside Mono.

Steps to Reproduce the Problem

As example, create an unit test for publishEvent() method doing the following:

  1. Have a futureClient mock and create the GRPC adapter instance.
  2. Call publishEvent() to get the Mono object but do NOT call block() on it.
  3. Validate there was NO call to the futureClient mock.
  4. block() on the mono object.
  5. Validate there WAS call to the futueClient mock.

See code below as example of problem vs solution:

  @Override
  public <T> Mono<Void> publishEvent(String topic, T event, Map<String, String> metadata) {
    try {
      byte[] byteEvent = objectSerializer.serialize(event);
      Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteEvent)).build();
      // TODO: handle metadata.

      DaprProtos.PublishEventEnvelope envelope = DaprProtos.PublishEventEnvelope.newBuilder()
          .setTopic(topic).setData(data).build();
      ListenableFuture<Empty> futureEmpty = client.publishEvent(envelope);
      return Mono.just(futureEmpty).flatMap(f -> {
        try {
          f.get();
        } catch (Exception ex) {
          return Mono.error(ex);
        }
        return Mono.empty();
      });
    } catch (Exception ex) {
      return Mono.error(ex);
    }
  }

Possible solution:

  @Override
  public <T> Mono<Void> publishEvent(String topic, T event, Map<String, String> metadata) {
  return Mono.fromSupplier(() -> {
      byte[] byteEvent = objectSerializer.serialize(event);
      Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteEvent)).build();
      // TODO: handle metadata.

      DaprProtos.PublishEventEnvelope envelope = DaprProtos.PublishEventEnvelope.newBuilder()
          .setTopic(topic).setData(data).build();
      return envelope;
    }).map(envelope -> client.publishEvent(envelope))
      .map(future -> {
        try {
          future.get();
        } catch (Exception ex) {
          throw new RuntimeException(e);
        }
      });
  }

Unit tests for stateful actors

Cover unit tests for the following scenarios for stateful actors:

Inheritance Input Type Output Type State management (CRUD operations) Exception in Actor's methods Exception in Actor's runtime Custom Serializer
No String String Yes No No No
No String String Yes No Yes No
No String String Yes Yes No No
No Class Class Yes No No No
No Class Class Yes No No Yes
Yes int int Yes No No No
Yes int int Yes No Yes No
Yes int int Yes Yes No No

Validations for all scenario (when applicable):

  • Output is as expected
  • Exception is as expected
  • State is saved as expected.
  • Methods are invoked in the Actor class: onActivate(), onDeactivate(), onPreActorMethod(), onPostActorMethod()
  • Timer is invoked()
  • Reminder is invoked()

Review all 3rd party dependencies

Expected Behavior

Dapr's java-sdk has 3rd party dependencies.

Actual Behavior

Move them to an approved version/alternative when possible and identify exceptions.

Approved libraries should be in one of the references below:
https://azure.github.io/azure-sdk/java_implementation.html#dependencies
https://github.com/Azure/azure-sdk-for-java
https://github.com/Azure/azure-cosmosdb-java
(any other official Azure SDK)

Steps to Reproduce the Problem

Look at all our direct dependencies.

[java-sdk] Code coverage

  • Check for code coverage in Java SDK and output current line and branch coverage.

  • Fail build if line or branch coverage is < 80% (examples excluded)

  • Keep coverage threshold under 80% for this issue. We will switch to 80% in the end.

[java-sdk E2E] Actor activation/deactivation test

Implement tests for java-sdk following same requirements as dapr/dapr#820:

Dapr config should be changed to support configuration and allow short time out (5s).
Implement a fake application listening to dapr.
app should implement actor related controller methods.
app should implement an extra method to return a "log" of events.

Add logic to add log entries for this test.
After actor is activated, add record to log array.
After actor method is invoked, add record to log array.
After actor is deactivated, add record to log array.

In test code:
Use ActorProxyImpl to invoke a method in the actor.
Sleep 5 seconds.
Make an API call to retrieve the log entries.
Validate the log entries contain: activate, deactivate and method invocation.

[java-sdk e2e] Actor features tests

Implement E2E tests for Java-SDK following requirements as per dapr/dapr#821

Applicable scenarios:
Test 1: Actor Reminder
Test 2: Actor Timer
Test 3: Turn based concurrency when calling the same method from same actor ID
Test 4: Turn based concurrency when calling the same method from different actor IDs
Test 5: Actor - user service failover from 1 node to another

[sample] Add sample for Actors

Create a sample (in dapr/java-sdk) showing all features of Actors in Java:

  1. Once all features for Actors in Dapr’s Java SDK are available, implement a sample showing how to use all Actor features. Sample using the SDK will be in this repo.
  2. Add documentation, so users can execute in Windows, Linux and MacOS.
  3. Add the original files used to generate any image, so external contributors can update documentation in the future.

Reach parity with Dapr features

Describe the proposal

Missing functionality that needs to be addressed:

  1. Subscribe to topics
  2. Bindings callbacks
  3. Service invocation callback

I assume this is likely to be implemented in DaprClient

[java-sdk E2E] Create E2E foundation for Java-SDK

Create a E2E test foundation, so dapr's SDK can be tested with Dapr:

  1. E2E tests run in standalone mode.
  2. E2E tests can be kicked-off from PR comment (similar do dapr/dapr E2E).
  3. All E2E code is written in Java, including sample apps.
  4. Implement one hello-world test case, showcasing E2E tests for Java-SDK.

Unit tests for stateless actors

Cover unit tests for the following scenarios for stateless actors:

Inheritance Input Type Output Type State management (CRUD operations) Exception in Actor's methods Exception in Actor's runtime Custom Serializer
No String String No No No No
No String Boolean No No Yes No
No String void No Yes No No
No Class Class No No No No
Yes int int No No No No
Yes int int No No Yes No
Yes int int No Yes No No

Validations for all scenario (when applicable):

  • Output is as expected
  • Exception is as expected
  • Methods are invoked in the Actor class: onActivate(), onDeactivate(), onPreActorMethod(), onPostActorMethod()
  • Timer is invoked()
  • Reminder is invoked()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.