Skip to content

Commit

Permalink
Various Rpc & Transport API Enhancements (#60)
Browse files Browse the repository at this point in the history
* Various Rpc & Transport API Enhancements

The following change fixes the RpcClient, uTransport interfaces to have callbacks
not returning a value, to support UMessage as passed parameters to the various APIs.
This Change also introduces RpcServer interface that uServices call
to register a Rpc request listener to handle RPC requests.

#53

* More cleanup

* Add header and make responses CompletableFutures

* Remove uSubscription.java

* Fix isExpired()

* protect for negative ttl

* Added more documentation to the RpcClient interface

* Cannot use UAttributes in RpcClient, Should be CallOptions

* Missing test code

* Fix the readme

* Fix invokeMethod() parameter name

* Fixed the wrong attribute name...

* Fix isRpcMethod() and isRpcResponse()

* Pull in latest core-api changes

* minor comment fixes

* Adding UPayloadBuilder for evaluation

* Add test for build UResource using protobuf generated code.

Also updated to latest core-api version

* fix merge issue

* Pull in changes from core-api uauthority_fix branch

* Use 1.5.5 of core-api

* Renaming in pom.xml and fix README

* Remove unused import
  • Loading branch information
Steven Hartley authored Jan 18, 2024
1 parent 264f042 commit 851fe5b
Show file tree
Hide file tree
Showing 21 changed files with 499 additions and 183 deletions.
25 changes: 11 additions & 14 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,25 @@

This library implements the https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/languages.adoc[uProtocol Language Specific Library Requirements] for Java defined in https://github.com/eclipse-uprotocol/uprotocol-spec/tree/main[uProtocol Specifications]. The library is organized into packages that are described in <<sdk-packages>> below. Each package contains a README.adoc file that describes the purpose of the package and how to use it.

The module contains the factory methods, serializers, and validators for all data types defined in the specifications, and any data models that either haven't or couldn't be defined in uprotocol-core-api yet (ex. UPayload) This library fits into the big picture of the uProtocol SDK as seen in <<uprotocol-sdk>> below.

.uProtocol SDK
image:https://raw.githubusercontent.com/eclipse-uprotocol/uprotocol-spec/main/uprotocol_sdk.drawio.svg[#uprotocol-sdk,width=100%,align="center"]

The module contains the factory methods, serializers, and validators for all data types defined in the specifications, and any data models that either haven't or couldn't be defined in up-core-api yet.

== Getting Started

=== Importing the sdk
=== Importing the Library

To pull the SDK from maven central, add the following dependency to your pom.xml file:
To pull the Library from maven central, setting ${uprotocol.version} to the latest version of this library in your pom.xml file:
[source]
----
<!-- uProtocol Core -->
<dependency>
<groupId>org.eclipse.uprotocol</groupId>
<artifactId>uprotocol-java</artifactId>
<version>1.5.0</version>
<artifactId>up-java</artifactId>
<version>${uprotocol.version}</version>
</dependency>
----

=== Using The Sdk
=== Using The Library

The SDK is broken up into different packages that are described in <<sdk-packages>> below. Each package contains a README.adoc file that describes the purpose of the package and how to use it. Packages are organized into the following directories:

.Package Folders
[#pkg-folders,width=100%,cols="20%,80%",options="header"]
Expand Down Expand Up @@ -61,12 +56,14 @@ The SDK is broken up into different packages that are described in <<sdk-package
| link:src/main/java/org/eclipse/uprotocol/uuid/README.adoc[`*uuid*`]
| Identifier used to uniquely identify (and timestamp) messages that are sent

| link:src/main/java/org/eclipse/uprotocol/utransport/README.adoc[`*utransport*`]
| Interface and data model declaration used for bidirectional point-2-point communication between uEs. This interface is then implemented by https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/ulink.adoc[ulink] libraries for a given underlining transport (ex. Binder, MQTT, Zenoh, SOME/IP, DDS, HTTP, etc…​)
| link:src/main/java/org/eclipse/uprotocol/transport/README.adoc[`*transport*`]
| Interface declaration used for bidirectional point-2-point communication between uEs. This interface is then implemented by https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/upclient.adoc[uPClient] libraries for a given underlining transport (ex. Binder, MQTT, Zenoh, SOME/IP, DDS, HTTP, etc…​)

| link:src/main/java/org/eclipse/uprotocol/cloudevent/README.adoc[`*cloudevent*`]
| Common way to represent uProtocol messages using CloudEvent data model used by some transports (ex. MQTT, HTTP, etc…​)

| link:src/main/java/org/eclipse/uprotocol/rpc/README.adoc[`*rpc*`]
| RPC client and server-side interfaces that are to be implemented by uLink libraries

|===

NOTE: Please visit the READMEs in <<sdk-packages>> for examples of how to use the different data types and their factories, validators, and serializers.
20 changes: 10 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
<modelVersion>4.0.0</modelVersion>

<groupId>org.eclipse.uprotocol</groupId>
<artifactId>uprotocol-java</artifactId>
<name>Java SDK for uProtocol</name>
<artifactId>up-java</artifactId>
<name>Java Library for uProtocol</name>
<description>Language specific uProtocol library for building and using UUri, UUID, UAttributes, UTransport, and more</description>
<version>1.5.6-SNAPSHOT</version>
<packaging>jar</packaging>
<url>https://github.com/eclipse-uprotocol/uprotocol-java/</url>
<url>https://github.com/eclipse-uprotocol/up-java/</url>

<properties>
<java.version>11</java.version>
Expand All @@ -35,7 +35,7 @@
<slf4j.version>2.6.18</slf4j.version>
<cloudevents.version>2.4.2</cloudevents.version>
<protobuf.version>3.21.10</protobuf.version>
<git.tag.name>uprotocol-core-api-1.5.3</git.tag.name>
<git.tag.name>uprotocol-core-api-1.5.5</git.tag.name>
</properties>

<licenses>
Expand All @@ -58,7 +58,7 @@
<scm>
<connection>scm:git:${project.scm.url}</connection>
<developerConnection>scm:git:${project.scm.url}</developerConnection>
<url>https://github.com/eclipse-uprotocol/uprotocol-java.git</url>
<url>https://github.com/eclipse-uprotocol/up-java.git</url>
<tag>HEAD</tag>
</scm>

Expand Down Expand Up @@ -90,8 +90,8 @@
<argument>clone</argument>
<argument>--branch</argument>
<argument>${git.tag.name}</argument>
<argument>https://github.com/eclipse-uprotocol/uprotocol-core-api.git</argument>
<argument>${project.build.directory}/uprotocol-core-api</argument>
<argument>https://github.com/eclipse-uprotocol/up-core-api.git</argument>
<argument>${project.build.directory}/up-core-api</argument>
</arguments>
<!-- Allow non-zero exit code (error) -->
<successCodes>
Expand All @@ -108,7 +108,7 @@
</goals>
<configuration>
<executable>git</executable>
<workingDirectory>${project.build.directory}/uprotocol-core-api</workingDirectory>
<workingDirectory>${project.build.directory}/up-core-api</workingDirectory>
<arguments>
<argument>pull</argument>
<argument>origin</argument>
Expand Down Expand Up @@ -147,13 +147,12 @@
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.17.3:exe:${os.detected.classifier}</protocArtifact>
<protoSourceRoot>${project.build.directory}/uprotocol-core-api/src/main/proto</protoSourceRoot>
<protoSourceRoot>${project.build.directory}/up-core-api/uprotocol</protoSourceRoot>
<outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>

</configuration>
Expand Down Expand Up @@ -237,6 +236,7 @@
<executions>
<execution>
<id>license-check</id>
<phase>deploy</phase>
<goals>
<goal>license-check</goal>
</goals>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ static UMessage toMessage(CloudEvent event) {

}



/**
* Get the Cloudevent from the UMessage<br>
* <b>Note: For now, only the value format of UPayload is supported in the SDK.If the UPayload has a reference, it
Expand All @@ -398,22 +400,38 @@ static UMessage toMessage(CloudEvent event) {
* @return returns the cloud event
*/
static CloudEvent fromMessage(UMessage message) {
UAttributes attributes = message.getAttributes();
return fromMessageParts(message.getSource(), message.getAttributes(), message.getPayload());
}


/**
* Get the Cloudevent from the UMessage Parts (UUri, UAttributes, and UPayload) <br>
* <b>Note: For now, only the value format of UPayload is supported in the SDK.If the UPayload has a reference, it
* needs to be copied to CloudEvent.</b>
* @param source The UUri source address for the message
* @param attributes The UMessage attributes
* @param payload The UMessage payload
* @return returns the cloud event from message parts
*/
static CloudEvent fromMessageParts(UUri source, UAttributes attributes, UPayload payload) {
source = Objects.requireNonNullElse(source, UUri.getDefaultInstance());
attributes = Objects.requireNonNullElse(attributes, UAttributes.getDefaultInstance());
payload = Objects.requireNonNullElse(payload, UPayload.getDefaultInstance());

CloudEventBuilder cloudEventBuilder =
CloudEventBuilder.v1().withId(LongUuidSerializer.instance().serialize(attributes.getId()));

cloudEventBuilder.withType(getEventType(attributes.getType()));

cloudEventBuilder.withSource(URI.create(LongUriSerializer.instance().serialize(message.getSource())));
cloudEventBuilder.withSource(URI.create(LongUriSerializer.instance().serialize(source)));

final String contentType = getContentTypeFromUPayloadFormat(message.getPayload().getFormat());
final String contentType = getContentTypeFromUPayloadFormat(payload.getFormat());
if(!contentType.isEmpty()){
cloudEventBuilder.withDataContentType(contentType);
}
// IMPORTANT: Currently, ONLY the VALUE format is supported in the SDK!
if (message.getPayload().hasValue())
cloudEventBuilder.withData(message.getPayload().getValue().toByteArray());
if (payload.hasValue())
cloudEventBuilder.withData(payload.getValue().toByteArray());

if (attributes.hasTtl())
cloudEventBuilder.withExtension("ttl",attributes.getTtl());
Expand Down Expand Up @@ -448,7 +466,7 @@ static CloudEvent fromMessage(UMessage message) {
*/
static UPayloadFormat getUPayloadFormatFromContentType(String contentType){
if(contentType == null)
return UPayloadFormat.UPAYLOAD_FORMAT_PROTOBUF;
return UPayloadFormat.UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY;

switch (contentType){
case "application/json":
Expand All @@ -461,8 +479,10 @@ static UPayloadFormat getUPayloadFormatFromContentType(String contentType){
return UPayloadFormat.UPAYLOAD_FORMAT_SOMEIP;
case "application/x-someip_tlv":
return UPayloadFormat.UPAYLOAD_FORMAT_SOMEIP_TLV;
default:
case "application/protobuf":
return UPayloadFormat.UPAYLOAD_FORMAT_PROTOBUF;
default:
return UPayloadFormat.UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY;

}
}
Expand All @@ -485,6 +505,8 @@ static String getContentTypeFromUPayloadFormat(UPayloadFormat format){
return "application/x-someip";
case UPAYLOAD_FORMAT_SOMEIP_TLV:
return "application/x-someip_tlv";
case UPAYLOAD_FORMAT_PROTOBUF:
return "application/protobuf";
default:
return "";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@

import io.cloudevents.CloudEvent;
import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent;
import org.eclipse.uprotocol.v1.UResource;
import org.eclipse.uprotocol.v1.UUri;
import org.eclipse.uprotocol.v1.UStatus;
import org.eclipse.uprotocol.v1.UCode;
import org.eclipse.uprotocol.v1.*;
import org.eclipse.uprotocol.validation.ValidationResult;
import org.eclipse.uprotocol.uri.serializer.LongUriSerializer;
import org.eclipse.uprotocol.uri.validator.UriValidator;
Expand Down
24 changes: 13 additions & 11 deletions src/main/java/org/eclipse/uprotocol/rpc/RpcClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,27 @@

import java.util.concurrent.CompletionStage;

import org.eclipse.uprotocol.v1.UPayload;
import org.eclipse.uprotocol.v1.UAttributes;
import org.eclipse.uprotocol.v1.UUri;
import org.eclipse.uprotocol.v1.*;

/**
* RpcClient is an interface used by code generators for uProtocol services defined in proto files such as
* the core uProtocol services found in https://github.com/eclipse-uprotocol/uprotocol-core-api. the interface
* provides a clean contract for all transports to implement to be able to support RPC on their platform. Each
* platform MUST implement this interface. For more details please refer to
* provides a clean contract for mapping a RPC request to a response. For more details please refer to
* https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l2/README.adoc[RpcClient Specifications]
*/
public interface RpcClient {

/**
* Support for RPC method invocation.
* @param topic topic of the method to be invoked (i.e. the name of the API we are calling).
* @param payload The request message to be sent to the server.
* @param attributes Metadata for the method invocation (i.e. priority, timeout, etc.)
* @return Returns the CompletionStage with the result or exception.
* API for clients to invoke a method (send an RPC request) and receive the response (the returned
* {@link CompletionStage} {@link UPayload}. <br>
* Client will set method to be the URI of the method they want to invoke,
* payload to the request message, and attributes with the various metadata for the
* method invocation.
* @param methodUri The method URI to be invoked, ex (long form): /example.hello_world/1/rpc.SayHello.
* @param requestPayload The request message to be sent to the server.
* @param options RPC method invocation call options, see {@link CallOptions}
* @return Returns the CompletionStage with the response message (payload) or exception with the failure
* reason as {@link UStatus}.
*/
CompletionStage<UPayload> invokeMethod(UUri topic, UPayload payload, UAttributes attributes);
CompletionStage<UPayload> invokeMethod(UUri methodUri, UPayload requestPayload, CallOptions options);
}
53 changes: 53 additions & 0 deletions src/main/java/org/eclipse/uprotocol/rpc/RpcServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 General Motors GTO LLC
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* SPDX-FileType: SOURCE
* SPDX-FileCopyrightText: 2023 General Motors GTO LLC
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.uprotocol.rpc;

import org.eclipse.uprotocol.v1.*;

/**
* RpcServer is an interface called by uServices to register method listeners for incoming RPC requests
* from clients.
*/
public interface RpcServer {

/**
* Register a listener for a particular method URI to be notified when requests are sent against said method.
*
* <p>Note: Only one listener is allowed to be registered per method URI.
*
* @param method Uri for the method to register the listener for.
* @param listener The listener for handling the request method.
* @return Returns the status of registering the RpcListener.
*/
UStatus registerRpcListener(UUri method, URpcListener listener);

/**
* Unregister an RPC listener for a given method Uri. Messages arriving on this topic will no longer be processed
* by this listener.
* @param method Resolved UUri for where the listener was registered to receive messages from.
* @param listener The method to execute to process the date for the topic.
* @return Returns status of registering the RpcListener.
*/
UStatus unregisterRpcListener(UUri method, URpcListener listener);
}
20 changes: 20 additions & 0 deletions src/main/java/org/eclipse/uprotocol/rpc/URpcListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.eclipse.uprotocol.rpc;

import java.util.concurrent.CompletableFuture;
import org.eclipse.uprotocol.v1.*;

/**
* uService (servers) implement this to receive requests messages from clients. <br>
* The service must implement the {@link #onReceive(UMessage, CompletableFuture)} method to handle
* the request and then complete the future passed to the method that triggers the uLink library to
* send (over the transport) the response.
*/
public interface URpcListener {

/**
* Method called to handle/process events.
* @param message Message received.
*/
void onReceive(UMessage message, CompletableFuture<UPayload> responseFuture);

}
17 changes: 12 additions & 5 deletions src/main/java/org/eclipse/uprotocol/transport/UListener.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package org.eclipse.uprotocol.transport;

import org.eclipse.uprotocol.v1.UStatus;
import org.eclipse.uprotocol.v1.UAttributes;
import org.eclipse.uprotocol.v1.UUri;
import org.eclipse.uprotocol.v1.UPayload;
import org.eclipse.uprotocol.v1.*;

/**
* For any implementation that defines some kind of callback or function that will be called to handle incoming messages.
Expand All @@ -17,6 +14,16 @@ public interface UListener {
* @param attributes Transportation attributes
* @return Returns an Ack every time a message is received and processed.
*/
UStatus onReceive(UUri topic, UPayload payload, UAttributes attributes);
void onReceive(UUri topic, UPayload payload, UAttributes attributes);


/**
* Method called to handle/process events.
* @param message Message received.
* @return Returns an Ack every time a message is received and processed.
*/
default void onReceive(UMessage message) {
onReceive(message.getSource(), message.getPayload(), message.getAttributes());
}

}
Loading

0 comments on commit 851fe5b

Please sign in to comment.