diff --git a/sdk/java-sdk/README-zh.md b/sdk/java-sdk/README-zh.md index bffda113df..1f726202e4 100644 --- a/sdk/java-sdk/README-zh.md +++ b/sdk/java-sdk/README-zh.md @@ -152,4 +152,4 @@ PS: 建议用maven插件`protoc-gen-grpc-java`生成protobuf和grpc的java代码 如果您在使用 [IntelliJ IDEA](https://www.jetbrains.com/help/idea/discover-intellij-idea.html) ,双击 Maven插件中的 `compile` , IDE 会自动帮你编译 proto 文件: -![img.png](../../docs/img/sdk/img.png) +![img.png](img.png) diff --git a/sdk/java-sdk/README.md b/sdk/java-sdk/README.md index ad241c07d8..7ee55ef43c 100644 --- a/sdk/java-sdk/README.md +++ b/sdk/java-sdk/README.md @@ -93,3 +93,6 @@ protoc -I=. --java_out=../../../../sdk/java-sdk/sdk/src/main/java/ appcallback. ``` PS: We recommend that you use the maven plugin `protoc-gen-grpc-java` to generate these protobuf and grpc related java code. +If you are using [IntelliJ IDEA](https://www.jetbrains.com/help/idea/discover-intellij-idea.html) ,just double click `compile` in the Maven tab and the IDE will generate proto files automatically: + +![img.png](img.png) diff --git a/sdk/java-sdk/examples/src/test/java/io/mosn/layotto/examples/file/File.java b/sdk/java-sdk/examples/src/test/java/io/mosn/layotto/examples/file/File.java index d5ccd1acae..43f2fc196e 100644 --- a/sdk/java-sdk/examples/src/test/java/io/mosn/layotto/examples/file/File.java +++ b/sdk/java-sdk/examples/src/test/java/io/mosn/layotto/examples/file/File.java @@ -16,22 +16,23 @@ import io.mosn.layotto.v1.RuntimeClientBuilder; import io.mosn.layotto.v1.config.RuntimeProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import spec.sdk.runtime.v1.client.RuntimeClient; -import spec.sdk.runtime.v1.domain.file.PutFileRequest; -import spec.sdk.runtime.v1.domain.file.GetFileRequest; -import spec.sdk.runtime.v1.domain.file.ListFileRequest; -import spec.sdk.runtime.v1.domain.file.GetMetaRequest; import spec.sdk.runtime.v1.domain.file.DelFileRequest; -import spec.sdk.runtime.v1.domain.file.GetFileResponse; -import spec.sdk.runtime.v1.domain.file.ListFileResponse; import spec.sdk.runtime.v1.domain.file.FileInfo; +import spec.sdk.runtime.v1.domain.file.GetFileRequest; +import spec.sdk.runtime.v1.domain.file.GetFileResponse; +import spec.sdk.runtime.v1.domain.file.GetMetaRequest; import spec.sdk.runtime.v1.domain.file.GetMeteResponse; +import spec.sdk.runtime.v1.domain.file.ListFileRequest; +import spec.sdk.runtime.v1.domain.file.ListFileResponse; +import spec.sdk.runtime.v1.domain.file.PutFileRequest; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.HashMap; import java.util.Map; -import java.util.logging.Logger; /** * Specially @@ -41,7 +42,7 @@ */ public class File { - private static final Logger logger = Logger.getLogger(File.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(File.class.getName()); static String storeName = "local"; static String fileName = "/tmp/test.log"; diff --git a/sdk/java-sdk/img.png b/sdk/java-sdk/img.png new file mode 100644 index 0000000000..a826585294 Binary files /dev/null and b/sdk/java-sdk/img.png differ diff --git a/sdk/java-sdk/pom.xml b/sdk/java-sdk/pom.xml index 8539decf36..d57ab0ac0f 100644 --- a/sdk/java-sdk/pom.xml +++ b/sdk/java-sdk/pom.xml @@ -15,6 +15,8 @@ sdk examples + sdk-reactor + spec @@ -36,10 +38,9 @@ io.mosn.layotto - examples + runtime-spec-pb ${project.version} - com.alibaba @@ -60,7 +61,21 @@ grpc-all ${grpc.version} - + + io.grpc + grpc-netty + ${grpc.version} + + + io.grpc + grpc-protobuf + ${grpc.version} + + + io.grpc + grpc-stub + ${grpc.version} + org.mockito diff --git a/sdk/java-sdk/sdk-reactor/pom.xml b/sdk/java-sdk/sdk-reactor/pom.xml new file mode 100644 index 0000000000..ae43a865d1 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/pom.xml @@ -0,0 +1,53 @@ + + + + 4.0.0 + + + io.mosn.layotto + runtime-sdk-parent + 1.1.0-SNAPSHOT + + + runtime-sdk-reactor + + runtime-sdk-reactor + reactor-style SDK for Runtime + jar + + + + io.mosn.layotto + runtime-spec-pb + + + org.slf4j + slf4j-api + + + io.projectreactor + reactor-core + 3.3.11.RELEASE + + + + com.fasterxml.jackson.core + jackson-databind + 2.11.3 + + + + com.squareup.okhttp3 + okhttp + 4.9.0 + + + + org.apache.tomcat + annotations-api + 6.0.53 + provided + + + diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/package-info.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/package-info.java new file mode 100644 index 0000000000..3b6fc726de --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/package-info.java @@ -0,0 +1,18 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +/** + * SDK JVM Client. + */ +package io.mosn.layotto.v1.client; \ No newline at end of file diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/AbstractLayottoReactorClient.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/AbstractLayottoReactorClient.java new file mode 100644 index 0000000000..bca2ae6d54 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/AbstractLayottoReactorClient.java @@ -0,0 +1,300 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.client.reactor; + +import io.mosn.layotto.v1.serializer.LayottoObjectSerializer; +import reactor.core.publisher.Mono; +import spec.sdk.reactor.v1.domain.core.invocation.HttpExtension; +import spec.sdk.reactor.v1.domain.core.invocation.InvokeMethodRequest; +import spec.sdk.reactor.v1.domain.core.pubsub.PublishEventRequest; +import spec.sdk.reactor.v1.domain.core.state.DeleteStateRequest; +import spec.sdk.reactor.v1.domain.core.state.ExecuteStateTransactionRequest; +import spec.sdk.reactor.v1.domain.core.state.GetBulkStateRequest; +import spec.sdk.reactor.v1.domain.core.state.GetStateRequest; +import spec.sdk.reactor.v1.domain.core.state.SaveStateRequest; +import spec.sdk.reactor.v1.domain.core.state.State; +import spec.sdk.reactor.v1.domain.core.state.StateOptions; +import spec.sdk.reactor.v1.domain.core.state.TransactionalStateOperation; +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +abstract class AbstractLayottoReactorClient implements LayottoReactorClient { + + /** + * A utility class for serialize and deserialize the transient objects. + */ + protected LayottoObjectSerializer objectSerializer; + + /** + * A utility class for serialize and deserialize state objects. + */ + protected LayottoObjectSerializer stateSerializer; + + /** + * Common constructor for implementations of this class. + * + * @param objectSerializer Serializer for transient request/response objects. + * @param stateSerializer Serializer for state objects. + */ + AbstractLayottoReactorClient(LayottoObjectSerializer objectSerializer, + LayottoObjectSerializer stateSerializer) { + this.objectSerializer = objectSerializer; + this.stateSerializer = stateSerializer; + } + + /** + * {@inheritDoc} + */ + @Override + public Mono publishEvent(String pubsubName, String topicName, Object data) { + return this.publishEvent(pubsubName, topicName, data, null); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono publishEvent(String pubsubName, String topicName, Object data, Map metadata) { + PublishEventRequest req = new PublishEventRequest(pubsubName, topicName, data) + .setMetadata(metadata); + return this.publishEvent(req).then(); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + Object data, + HttpExtension httpExtension, + Map metadata, + TypeRef type) { + InvokeMethodRequest req = new InvokeMethodRequest(appId, methodName) + .setBody(data) + .setHttpExtension(httpExtension) + .setContentType(objectSerializer.getContentType()); + return this.invokeMethod(req, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, + String methodName, + Object request, + HttpExtension httpExtension, + Map metadata, + Class clazz) { + return this.invokeMethod(appId, methodName, request, httpExtension, metadata, TypeRef.get(clazz)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, + Map metadata, TypeRef type) { + return this.invokeMethod(appId, methodName, null, httpExtension, metadata, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, + Map metadata, Class clazz) { + return this.invokeMethod(appId, methodName, null, httpExtension, metadata, TypeRef.get(clazz)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + TypeRef type) { + return this.invokeMethod(appId, methodName, request, httpExtension, null, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Class clazz) { + return this.invokeMethod(appId, methodName, request, httpExtension, null, TypeRef.get(clazz)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension) { + return this.invokeMethod(appId, methodName, request, httpExtension, null, TypeRef.BYTE_ARRAY).then(); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Map metadata) { + return this.invokeMethod(appId, methodName, request, httpExtension, metadata, TypeRef.BYTE_ARRAY).then(); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, + Map metadata) { + return this.invokeMethod(appId, methodName, null, httpExtension, metadata, TypeRef.BYTE_ARRAY).then(); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono invokeMethod(String appId, String methodName, byte[] request, HttpExtension httpExtension, + Map metadata) { + return this.invokeMethod(appId, methodName, request, httpExtension, metadata, TypeRef.BYTE_ARRAY); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, State state, TypeRef type) { + return this.getState(storeName, state.getKey(), state.getOptions(), type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, State state, Class clazz) { + return this.getState(storeName, state.getKey(), state.getOptions(), TypeRef.get(clazz)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, TypeRef type) { + return this.getState(storeName, key, null, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, Class clazz) { + return this.getState(storeName, key, null, TypeRef.get(clazz)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, StateOptions options, TypeRef type) { + GetStateRequest request = new GetStateRequest(storeName, key) + .setStateOptions(options); + return this.getState(request, type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono> getState(String storeName, String key, StateOptions options, Class clazz) { + return this.getState(storeName, key, options, TypeRef.get(clazz)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkState(String storeName, List keys, TypeRef type) { + return this.getBulkState(new GetBulkStateRequest(storeName, keys), type); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono>> getBulkState(String storeName, List keys, Class clazz) { + return this.getBulkState(storeName, keys, TypeRef.get(clazz)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono executeStateTransaction(String storeName, List> operations) { + ExecuteStateTransactionRequest request = new ExecuteStateTransactionRequest(storeName) + .setOperations(operations); + return executeStateTransaction(request).then(); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono saveBulkState(String storeName, List> states) { + SaveStateRequest request = new SaveStateRequest(storeName) + .setStates(states); + return this.saveBulkState(request).then(); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono saveState(String storeName, String key, Object value) { + return this.saveState(storeName, key, null, value, null); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono saveState(String storeName, String key, String etag, Object value, StateOptions options) { + State state = new State<>(key, value, etag, options); + return this.saveBulkState(storeName, Collections.singletonList(state)); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono deleteState(String storeName, String key) { + return this.deleteState(storeName, key, null, null); + } + + /** + * {@inheritDoc} + */ + @Override + public Mono deleteState(String storeName, String key, String etag, StateOptions options) { + DeleteStateRequest request = new DeleteStateRequest(storeName, key) + .setEtag(etag) + .setStateOptions(options); + return deleteState(request).then(); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClient.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClient.java new file mode 100644 index 0000000000..dc8ea270d7 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClient.java @@ -0,0 +1,171 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.client.reactor; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import spec.sdk.reactor.v1.client.CloudRuntimesClient; +import spec.sdk.reactor.v1.domain.core.configuration.ConfigurationItem; +import spec.sdk.reactor.v1.domain.core.configuration.ConfigurationRequestItem; +import spec.sdk.reactor.v1.domain.core.configuration.SaveConfigurationRequest; +import spec.sdk.reactor.v1.domain.core.configuration.SubConfigurationResp; +import spec.sdk.reactor.v1.domain.core.invocation.HttpExtension; +import spec.sdk.reactor.v1.domain.core.invocation.InvokeMethodRequest; +import spec.sdk.reactor.v1.domain.core.pubsub.PublishEventRequest; +import spec.sdk.reactor.v1.domain.core.state.DeleteStateRequest; +import spec.sdk.reactor.v1.domain.core.state.ExecuteStateTransactionRequest; +import spec.sdk.reactor.v1.domain.core.state.GetBulkStateRequest; +import spec.sdk.reactor.v1.domain.core.state.GetStateRequest; +import spec.sdk.reactor.v1.domain.core.state.SaveStateRequest; +import spec.sdk.reactor.v1.domain.core.state.State; +import spec.sdk.reactor.v1.domain.core.state.StateOptions; +import spec.sdk.reactor.v1.domain.core.state.TransactionalStateOperation; +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.util.List; +import java.util.Map; + +public interface LayottoReactorClient extends CloudRuntimesClient { + + @Override + Mono waitForSidecar(int timeoutInMilliseconds); + + @Override + Mono shutdown(); + + @Override + void close() throws Exception; + + @Override + Mono>> getConfiguration(ConfigurationRequestItem configurationRequestItem, + TypeRef type); + + @Override + Mono saveConfiguration(SaveConfigurationRequest saveConfigurationRequest); + + @Override + Mono deleteConfiguration(ConfigurationRequestItem configurationRequestItem); + + @Override + Flux> subscribeConfiguration(ConfigurationRequestItem configurationRequestItem, + TypeRef type); + + @Override + Mono invokeMethod(String appId, String methodName, Object data, HttpExtension httpExtension, + Map metadata, TypeRef type); + + @Override + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Map metadata, Class clazz); + + @Override + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + TypeRef type); + + @Override + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Class clazz); + + @Override + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, + Map metadata, TypeRef type); + + @Override + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, + Map metadata, Class clazz); + + @Override + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Map metadata); + + @Override + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension); + + @Override + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map metadata); + + @Override + Mono invokeMethod(String appId, String methodName, byte[] request, HttpExtension httpExtension, + Map metadata); + + @Override + Mono invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type); + + @Override + Mono publishEvent(String pubsubName, String topicName, Object data); + + @Override + Mono publishEvent(String pubsubName, String topicName, Object data, Map metadata); + + @Override + Mono publishEvent(PublishEventRequest request); + + @Override + Mono> getState(String storeName, State state, TypeRef type); + + @Override + Mono> getState(String storeName, State state, Class clazz); + + @Override + Mono> getState(String storeName, String key, TypeRef type); + + @Override + Mono> getState(String storeName, String key, Class clazz); + + @Override + Mono> getState(String storeName, String key, StateOptions options, TypeRef type); + + @Override + Mono> getState(String storeName, String key, StateOptions options, Class clazz); + + @Override + Mono> getState(GetStateRequest request, TypeRef type); + + @Override + Mono>> getBulkState(String storeName, List keys, TypeRef type); + + @Override + Mono>> getBulkState(String storeName, List keys, Class clazz); + + @Override + Mono>> getBulkState(GetBulkStateRequest request, TypeRef type); + + @Override + Mono executeStateTransaction(String storeName, List> operations); + + @Override + Mono executeStateTransaction(ExecuteStateTransactionRequest request); + + @Override + Mono saveBulkState(String storeName, List> states); + + @Override + Mono saveBulkState(SaveStateRequest request); + + @Override + Mono saveState(String storeName, String key, Object value); + + @Override + Mono saveState(String storeName, String key, String etag, Object value, StateOptions options); + + @Override + Mono deleteState(String storeName, String key); + + @Override + Mono deleteState(String storeName, String key, String etag, StateOptions options); + + @Override + Mono deleteState(DeleteStateRequest request); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClientBuilder.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClientBuilder.java new file mode 100644 index 0000000000..ae51d48e61 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClientBuilder.java @@ -0,0 +1,148 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.client.reactor; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.mosn.layotto.v1.config.Properties; +import io.mosn.layotto.v1.serializer.DefaultObjectSerializer; +import io.mosn.layotto.v1.serializer.LayottoObjectSerializer; +import io.mosn.layotto.v1.value.LayottoApiProtocol; +import spec.proto.runtime.v1.RuntimeGrpc; + +import java.io.Closeable; + +/** + * A builder for the LayottoClient, Currently only gRPC Client will be supported. + */ +public class LayottoReactorClientBuilder { + + /** + * Determine if this builder will create GRPC clients instead of HTTP clients. + */ + private final LayottoApiProtocol apiProtocol; + + /** + * Serializer used for request and response objects in LayottoClient. + */ + private LayottoObjectSerializer objectSerializer; + + /** + * Serializer used for state objects in LayottoClient. + */ + private LayottoObjectSerializer stateSerializer; + + /** + * Creates a constructor for LayottoClient. + *

+ * {@link DefaultObjectSerializer} is used for object and state serializers by default but is not recommended + * for production scenarios. + */ + public LayottoReactorClientBuilder() { + this.objectSerializer = new DefaultObjectSerializer(); + this.stateSerializer = new DefaultObjectSerializer(); + this.apiProtocol = Properties.API_PROTOCOL.get(); + } + + /** + * Sets the serializer for objects to be sent and received from Layotto. + * See {@link DefaultObjectSerializer} as possible serializer for non-production scenarios. + * + * @param objectSerializer Serializer for objects to be sent and received from Layotto. + * @return This instance. + */ + public LayottoReactorClientBuilder withObjectSerializer(LayottoObjectSerializer objectSerializer) { + if (objectSerializer == null) { + throw new IllegalArgumentException("Object serializer is required"); + } + + if (objectSerializer.getContentType() == null || objectSerializer.getContentType().isEmpty()) { + throw new IllegalArgumentException("Content Type should not be null or empty"); + } + + this.objectSerializer = objectSerializer; + return this; + } + + /** + * Sets the serializer for objects to be persisted. + * See {@link DefaultObjectSerializer} as possible serializer for non-production scenarios. + * + * @param stateSerializer Serializer for objects to be persisted. + * @return This instance. + */ + public LayottoReactorClientBuilder withStateSerializer(LayottoObjectSerializer stateSerializer) { + if (stateSerializer == null) { + throw new IllegalArgumentException("State serializer is required"); + } + + this.stateSerializer = stateSerializer; + return this; + } + + /** + * Build an instance of the Client based on the provided setup. + * + * @return an instance of the setup Client + * @throws java.lang.IllegalStateException if any required field is missing + */ + public LayottoReactorClient build() { + return buildLayottoClient(this.apiProtocol); + } + + /** + * Creates an instance of a Layotto Client based on the chosen protocol. + * + * @param protocol Layotto API's protocol. + * @return the GRPC Client. + * @throws java.lang.IllegalStateException if either host is missing or if port is missing or a negative number. + */ + private LayottoReactorClient buildLayottoClient(LayottoApiProtocol protocol) { + if (protocol == null) { + throw new IllegalStateException("Protocol is required."); + } + + switch (protocol) { + case GRPC: + return buildLayottoClientGrpc(); + default: + throw new IllegalStateException("Unsupported protocol: " + protocol.name()); + } + } + + /** + * Creates an instance of the GPRC Client. + * + * @return the GRPC Client. + * @throws java.lang.IllegalStateException if either host is missing or if port is missing or a negative number. + */ + private LayottoReactorClient buildLayottoClientGrpc() { + int port = Properties.GRPC_PORT.get(); + if (port <= 0) { + throw new IllegalArgumentException("Invalid port."); + } + ManagedChannel channel = ManagedChannelBuilder + .forAddress(Properties.SIDECAR_IP.get(), port) + .usePlaintext() + .build(); + Closeable closeableChannel = () -> { + if (channel != null && !channel.isShutdown()) { + channel.shutdown(); + } + }; + RuntimeGrpc.RuntimeStub asyncStub = RuntimeGrpc.newStub(channel); + return new LayottoReactorClientGrpc(this.objectSerializer, this.stateSerializer, closeableChannel, asyncStub); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClientGrpc.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClientGrpc.java new file mode 100644 index 0000000000..996502c4ed --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/client/reactor/LayottoReactorClientGrpc.java @@ -0,0 +1,624 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.client.reactor; + +import com.google.common.base.Strings; +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import com.google.protobuf.Empty; +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; +import io.grpc.stub.StreamObserver; +import io.mosn.layotto.v1.config.Properties; +import io.mosn.layotto.v1.exceptions.LayottoException; +import io.mosn.layotto.v1.serializer.LayottoObjectSerializer; +import io.mosn.layotto.v1.utils.GrpcWrapper; +import io.mosn.layotto.v1.utils.NetworkUtils; +import io.mosn.layotto.v1.value.Headers; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.publisher.MonoSink; +import reactor.util.context.Context; +import spec.proto.runtime.v1.RuntimeGrpc; +import spec.proto.runtime.v1.RuntimeProto; +import spec.sdk.reactor.v1.domain.core.configuration.ConfigurationItem; +import spec.sdk.reactor.v1.domain.core.configuration.ConfigurationRequestItem; +import spec.sdk.reactor.v1.domain.core.configuration.SaveConfigurationRequest; +import spec.sdk.reactor.v1.domain.core.configuration.SubConfigurationResp; +import spec.sdk.reactor.v1.domain.core.invocation.HttpExtension; +import spec.sdk.reactor.v1.domain.core.invocation.InvokeMethodRequest; +import spec.sdk.reactor.v1.domain.core.pubsub.PublishEventRequest; +import spec.sdk.reactor.v1.domain.core.state.DeleteStateRequest; +import spec.sdk.reactor.v1.domain.core.state.ExecuteStateTransactionRequest; +import spec.sdk.reactor.v1.domain.core.state.GetBulkStateRequest; +import spec.sdk.reactor.v1.domain.core.state.GetStateRequest; +import spec.sdk.reactor.v1.domain.core.state.SaveStateRequest; +import spec.sdk.reactor.v1.domain.core.state.State; +import spec.sdk.reactor.v1.domain.core.state.StateOptions; +import spec.sdk.reactor.v1.domain.core.state.TransactionalStateOperation; +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.io.Closeable; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public class LayottoReactorClientGrpc extends AbstractLayottoReactorClient { + + /** + * The GRPC managed channel to be used. + */ + private final Closeable channel; + + /** + * The async gRPC stub. + */ + private final RuntimeGrpc.RuntimeStub asyncStub; + + /** + * Default access level constructor, in order to create an instance of this class. + * + * @param closeableChannel A closeable for a Managed GRPC channel + * @param asyncStub async gRPC stub + */ + LayottoReactorClientGrpc(LayottoObjectSerializer objectSerializer, + LayottoObjectSerializer stateSerializer, + Closeable closeableChannel, + RuntimeGrpc.RuntimeStub asyncStub) { + super(objectSerializer, stateSerializer); + this.channel = closeableChannel; + this.asyncStub = intercept(asyncStub); + } + + @Override + public Mono>> getConfiguration(ConfigurationRequestItem configurationRequestItem, + TypeRef type) { + // TODO: 2021/9/26 + return null; + } + + @Override + public Mono saveConfiguration(SaveConfigurationRequest saveConfigurationRequest) { + // TODO: 2021/9/26 + return null; + } + + @Override + public Mono deleteConfiguration(ConfigurationRequestItem configurationRequestItem) { + // TODO: 2021/9/26 + return null; + } + + @Override + public Flux> subscribeConfiguration(ConfigurationRequestItem configurationRequestItem, + TypeRef type) { + // TODO: 2021/9/26 + return null; + } + + @Override + public Mono invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type) { + try { + String appId = invokeMethodRequest.getAppId(); + String method = invokeMethodRequest.getMethod(); + Object body = invokeMethodRequest.getBody(); + HttpExtension httpExtension = invokeMethodRequest.getHttpExtension(); + RuntimeProto.InvokeServiceRequest envelope = this.buildInvokeServiceRequest( + httpExtension, + appId, + method, + body); + // Regarding missing metadata in method invocation for gRPC: + // gRPC to gRPC does not handle metadata in Layotto runtime proto. + // gRPC to HTTP does not map correctly in Layotto runtime as per https://github.com/layotto/layotto/issues/2342 + + return Mono.subscriberContext().flatMap( + context -> this.createMono( + it -> intercept(context, asyncStub).invokeService(envelope, it) + ) + ).flatMap( + it -> { + try { + return Mono.justOrEmpty(objectSerializer.deserialize(it.getData().getValue().toByteArray(), type)); + } catch (IOException e) { + throw LayottoException.propagate(e); + } + } + ); + } catch (Exception ex) { + return LayottoException.wrapMono(ex); + } + } + + @Override + public Mono publishEvent(PublishEventRequest request) { + try { + String pubsubName = request.getPubsubName(); + String topic = request.getTopic(); + Object data = request.getData(); + RuntimeProto.PublishEventRequest.Builder envelopeBuilder = RuntimeProto.PublishEventRequest.newBuilder() + .setTopic(topic) + .setPubsubName(pubsubName) + .setData(ByteString.copyFrom(objectSerializer.serialize(data))); + + // Content-type can be overwritten on a per-request basis. + // It allows CloudEvents to be handled differently, for example. + String contentType = request.getContentType(); + if (contentType == null || contentType.isEmpty()) { + contentType = objectSerializer.getContentType(); + } + envelopeBuilder.setDataContentType(contentType); + + Map metadata = request.getMetadata(); + if (metadata != null) { + envelopeBuilder.putAllMetadata(metadata); + } + + return Mono.subscriberContext().flatMap( + context -> + this.createMono( + it -> intercept(context, asyncStub).publishEvent(envelopeBuilder.build(), it) + ) + ).then(); + } catch (Exception ex) { + return LayottoException.wrapMono(ex); + } + } + + @Override + public Mono> getState(GetStateRequest request, TypeRef type) { + try { + final String stateStoreName = request.getStoreName(); + final String key = request.getKey(); + final StateOptions options = request.getStateOptions(); + final Map metadata = request.getMetadata(); + + if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { + throw new IllegalArgumentException("State store name cannot be null or empty."); + } + if ((key == null) || (key.trim().isEmpty())) { + throw new IllegalArgumentException("Key cannot be null or empty."); + } + RuntimeProto.GetStateRequest.Builder builder = RuntimeProto.GetStateRequest.newBuilder() + .setStoreName(stateStoreName) + .setKey(key); + if (metadata != null) { + builder.putAllMetadata(metadata); + } + if (options != null && options.getConsistency() != null) { + builder.setConsistency(getGrpcStateConsistency(options)); + } + + RuntimeProto.GetStateRequest envelope = builder.build(); + + return Mono.subscriberContext().flatMap( + context -> + this.createMono( + it -> intercept(context, asyncStub).getState(envelope, it) + ) + ).map( + it -> { + try { + return buildStateKeyValue(it, key, options, type); + } catch (IOException ex) { + throw LayottoException.propagate(ex); + } + } + ); + } catch (Exception ex) { + return LayottoException.wrapMono(ex); + } + } + + @Override + public Mono>> getBulkState(GetBulkStateRequest request, TypeRef type) { + try { + final String stateStoreName = request.getStoreName(); + final List keys = request.getKeys(); + final int parallelism = request.getParallelism(); + final Map metadata = request.getMetadata(); + if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { + throw new IllegalArgumentException("State store name cannot be null or empty."); + } + if (keys == null || keys.isEmpty()) { + throw new IllegalArgumentException("Key cannot be null or empty."); + } + + if (parallelism < 0) { + throw new IllegalArgumentException("Parallelism cannot be negative."); + } + RuntimeProto.GetBulkStateRequest.Builder builder = RuntimeProto.GetBulkStateRequest.newBuilder() + .setStoreName(stateStoreName) + .addAllKeys(keys) + .setParallelism(parallelism); + if (metadata != null) { + builder.putAllMetadata(metadata); + } + + RuntimeProto.GetBulkStateRequest envelope = builder.build(); + + return Mono.subscriberContext().flatMap( + context -> this.createMono(it -> intercept(context, asyncStub) + .getBulkState(envelope, it) + ) + ).map( + it -> + it + .getItemsList() + .stream() + .map(b -> { + try { + return buildStateKeyValue(b, type); + } catch (Exception e) { + throw LayottoException.propagate(e); + } + }) + .collect(Collectors.toList()) + ); + } catch (Exception ex) { + return LayottoException.wrapMono(ex); + } + } + + @Override + public Mono executeStateTransaction(ExecuteStateTransactionRequest request) { + try { + final String stateStoreName = request.getStateStoreName(); + final List> operations = request.getOperations(); + final Map metadata = request.getMetadata(); + if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { + throw new IllegalArgumentException("State store name cannot be null or empty."); + } + RuntimeProto.ExecuteStateTransactionRequest.Builder builder = RuntimeProto.ExecuteStateTransactionRequest + .newBuilder(); + builder.setStoreName(stateStoreName); + if (metadata != null) { + builder.putAllMetadata(metadata); + } + for (TransactionalStateOperation operation : operations) { + RuntimeProto.TransactionalStateOperation.Builder operationBuilder = RuntimeProto.TransactionalStateOperation + .newBuilder(); + operationBuilder.setOperationType(operation.getOperation().toString().toLowerCase()); + operationBuilder.setRequest(buildStateRequest(operation.getRequest()).build()); + builder.addOperations(operationBuilder.build()); + } + RuntimeProto.ExecuteStateTransactionRequest req = builder.build(); + + return Mono.subscriberContext().flatMap( + context -> this.createMono(it -> intercept(context, asyncStub).executeStateTransaction(req, it)) + ).then(); + } catch (Exception e) { + return LayottoException.wrapMono(e); + } + } + + @Override + public Mono saveBulkState(SaveStateRequest request) { + try { + final String stateStoreName = request.getStoreName(); + final List> states = request.getStates(); + if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { + throw new IllegalArgumentException("State store name cannot be null or empty."); + } + RuntimeProto.SaveStateRequest.Builder builder = RuntimeProto.SaveStateRequest.newBuilder(); + builder.setStoreName(stateStoreName); + for (State state : states) { + builder.addStates(buildStateRequest(state).build()); + } + RuntimeProto.SaveStateRequest req = builder.build(); + + return Mono.subscriberContext().flatMap( + context -> this.createMono(it -> intercept(context, asyncStub).saveState(req, it)) + ).then(); + } catch (Exception ex) { + return LayottoException.wrapMono(ex); + } + } + + @Override + public Mono deleteState(DeleteStateRequest request) { + try { + final String stateStoreName = request.getStateStoreName(); + final String key = request.getKey(); + final StateOptions options = request.getStateOptions(); + final String etag = request.getEtag(); + final Map metadata = request.getMetadata(); + + if ((stateStoreName == null) || (stateStoreName.trim().isEmpty())) { + throw new IllegalArgumentException("State store name cannot be null or empty."); + } + if ((key == null) || (key.trim().isEmpty())) { + throw new IllegalArgumentException("Key cannot be null or empty."); + } + + RuntimeProto.StateOptions.Builder optionBuilder = null; + if (options != null) { + optionBuilder = RuntimeProto.StateOptions.newBuilder(); + if (options.getConcurrency() != null) { + optionBuilder.setConcurrency(getGrpcStateConcurrency(options)); + } + if (options.getConsistency() != null) { + optionBuilder.setConsistency(getGrpcStateConsistency(options)); + } + } + RuntimeProto.DeleteStateRequest.Builder builder = RuntimeProto.DeleteStateRequest.newBuilder() + .setStoreName(stateStoreName) + .setKey(key); + if (metadata != null) { + builder.putAllMetadata(metadata); + } + if (etag != null) { + builder.setEtag(RuntimeProto.Etag.newBuilder().setValue(etag).build()); + } + + if (optionBuilder != null) { + builder.setOptions(optionBuilder.build()); + } + + RuntimeProto.DeleteStateRequest req = builder.build(); + + return Mono.subscriberContext().flatMap( + context -> this.createMono(it -> intercept(context, asyncStub).deleteState(req, it)) + ).then(); + } catch (Exception ex) { + return LayottoException.wrapMono(ex); + } + } + + /** + * Builds the object io.layotto.{@link RuntimeProto.InvokeServiceRequest} to be send based on the parameters. + * + * @param httpExtension Object for HttpExtension + * @param appId The application id to be invoked + * @param method The application method to be invoked + * @param body The body of the request to be send as part of the invocation + * @param The Type of the Body + * @return The object to be sent as part of the invocation. + * @throws IOException If there's an issue serializing the request. + */ + private RuntimeProto.InvokeServiceRequest buildInvokeServiceRequest( + HttpExtension httpExtension, + String appId, + String method, + K body) throws IOException { + if (httpExtension == null) { + throw new IllegalArgumentException("HttpExtension cannot be null. Use HttpExtension.NONE instead."); + } + RuntimeProto.CommonInvokeRequest.Builder requestBuilder = RuntimeProto.CommonInvokeRequest.newBuilder(); + requestBuilder.setMethod(method); + if (body != null) { + byte[] byteRequest = objectSerializer.serialize(body); + Any data = Any.newBuilder().setValue(ByteString.copyFrom(byteRequest)).build(); + requestBuilder.setData(data); + } else { + requestBuilder.setData(Any.newBuilder().build()); + } + RuntimeProto.HTTPExtension.Builder httpExtensionBuilder = RuntimeProto.HTTPExtension.newBuilder(); + + httpExtensionBuilder.setVerb(RuntimeProto.HTTPExtension.Verb.valueOf(httpExtension.getMethod().toString())) + .setQuerystring(httpExtension.encodeQueryString()); + requestBuilder.setHttpExtension(httpExtensionBuilder.build()); + + requestBuilder.setContentType(objectSerializer.getContentType()); + + RuntimeProto.InvokeServiceRequest.Builder envelopeBuilder = RuntimeProto.InvokeServiceRequest.newBuilder() + .setId(appId) + .setMessage(requestBuilder.build()); + return envelopeBuilder.build(); + } + + private State buildStateKeyValue( + RuntimeProto.BulkStateItem item, + TypeRef type) throws IOException { + String key = item.getKey(); + String error = item.getError(); + if (!Strings.isNullOrEmpty(error)) { + return new State<>(key, error); + } + + ByteString payload = item.getData(); + byte[] data = payload == null ? null : payload.toByteArray(); + T value = stateSerializer.deserialize(data, type); + String etag = item.getEtag(); + if (etag.equals("")) { + etag = null; + } + return new State<>(key, value, etag, item.getMetadataMap(), null); + } + + private State buildStateKeyValue( + RuntimeProto.GetStateResponse response, + String requestedKey, + StateOptions stateOptions, + TypeRef type) throws IOException { + ByteString payload = response.getData(); + byte[] data = payload == null ? null : payload.toByteArray(); + T value = stateSerializer.deserialize(data, type); + String etag = response.getEtag(); + if (etag.equals("")) { + etag = null; + } + return new State<>(requestedKey, value, etag, response.getMetadataMap(), stateOptions); + } + + private RuntimeProto.StateItem.Builder buildStateRequest(State state) throws IOException { + byte[] bytes = stateSerializer.serialize(state.getValue()); + + RuntimeProto.StateItem.Builder stateBuilder = RuntimeProto.StateItem.newBuilder(); + if (state.getEtag() != null) { + stateBuilder.setEtag(RuntimeProto.Etag.newBuilder().setValue(state.getEtag()).build()); + } + if (state.getMetadata() != null) { + stateBuilder.putAllMetadata(state.getMetadata()); + } + if (bytes != null) { + stateBuilder.setValue(ByteString.copyFrom(bytes)); + } + stateBuilder.setKey(state.getKey()); + RuntimeProto.StateOptions.Builder optionBuilder = null; + if (state.getOptions() != null) { + StateOptions options = state.getOptions(); + optionBuilder = RuntimeProto.StateOptions.newBuilder(); + if (options.getConcurrency() != null) { + optionBuilder.setConcurrency(getGrpcStateConcurrency(options)); + } + if (options.getConsistency() != null) { + optionBuilder.setConsistency(getGrpcStateConsistency(options)); + } + } + if (optionBuilder != null) { + stateBuilder.setOptions(optionBuilder.build()); + } + return stateBuilder; + } + + private RuntimeProto.StateOptions.StateConsistency getGrpcStateConsistency(StateOptions options) { + switch (options.getConsistency()) { + case EVENTUAL: + return RuntimeProto.StateOptions.StateConsistency.CONSISTENCY_EVENTUAL; + case STRONG: + return RuntimeProto.StateOptions.StateConsistency.CONSISTENCY_STRONG; + default: + throw new IllegalArgumentException("Missing Consistency mapping to gRPC Consistency enum"); + } + } + + private RuntimeProto.StateOptions.StateConcurrency getGrpcStateConcurrency(StateOptions options) { + switch (options.getConcurrency()) { + case FIRST_WRITE: + return RuntimeProto.StateOptions.StateConcurrency.CONCURRENCY_FIRST_WRITE; + case LAST_WRITE: + return RuntimeProto.StateOptions.StateConcurrency.CONCURRENCY_LAST_WRITE; + default: + throw new IllegalArgumentException("Missing StateConcurrency mapping to gRPC Concurrency enum"); + } + } + + // -- Lifecycle Functions + + @Override + public Mono waitForSidecar(int timeoutInMilliseconds) { + return Mono.fromRunnable(() -> { + try { + NetworkUtils.waitForSocket(Properties.SIDECAR_IP.get(), Properties.GRPC_PORT.get(), timeoutInMilliseconds); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + } + + @Override + public Mono shutdown() { + return Mono.subscriberContext() + // FIXME: 2021/9/26 Refer to Dapr + // .flatMap(context -> + // this.createMono(it -> + // intercept(context, asyncStub) + // .shutdown(Empty.getDefaultInstance(), it))) + .then(); + } + + private Mono createMono(Consumer> consumer) { + return Mono.create(sink -> + LayottoException + .wrap(() -> consumer.accept(createStreamObserver(sink))) + .run()); + } + + private StreamObserver createStreamObserver(MonoSink sink) { + return new StreamObserver() { + @Override + public void onNext(T value) { + sink.success(value); + } + + @Override + public void onError(Throwable t) { + sink.error(LayottoException.propagate(new ExecutionException(t))); + } + + @Override + public void onCompleted() { + sink.success(); + } + }; + } + + /** + * Closes the ManagedChannel for GRPC. + * + * @throws IOException on exception. + * @see io.grpc.ManagedChannel#shutdown() + */ + @Override + public void close() throws Exception { + if (channel != null) { + LayottoException + .wrap(() -> { + channel.close(); + return true; + }) + .call(); + } + } + + /** + * Populates GRPC client with interceptors for telemetry. + * + * @param context Reactor's context. + * @param client GRPC client for Layotto. + * @return Client after adding interceptors. + */ + private static RuntimeGrpc.RuntimeStub intercept(Context context, RuntimeGrpc.RuntimeStub client) { + return GrpcWrapper.intercept(context, client); + } + + /** + * Populates GRPC client with interceptors. + * + * @param client GRPC client for Layotto. + * @return Client after adding interceptors. + */ + private static RuntimeGrpc.RuntimeStub intercept(RuntimeGrpc.RuntimeStub client) { + ClientInterceptor interceptor = new ClientInterceptor() { + @Override + public ClientCall interceptCall(MethodDescriptor methodDescriptor, + CallOptions callOptions, + Channel channel) { + ClientCall clientCall = channel.newCall(methodDescriptor, callOptions); + return new ForwardingClientCall.SimpleForwardingClientCall(clientCall) { + @Override + public void start(final Listener responseListener, final Metadata metadata) { + String layottoApiToken = Properties.API_TOKEN.get(); + if (layottoApiToken != null) { + metadata.put(Metadata.Key.of(Headers.DAPR_API_TOKEN, Metadata.ASCII_STRING_MARSHALLER), + layottoApiToken); + } + super.start(responseListener, metadata); + } + }; + } + }; + return client.withInterceptors(interceptor); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/BooleanProperty.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/BooleanProperty.java new file mode 100644 index 0000000000..d2211cda62 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/BooleanProperty.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.config; + +/** + * Boolean configuration property. + */ +public class BooleanProperty extends Property { + + /** + * {@inheritDoc} + */ + BooleanProperty(String name, String envName, Boolean defaultValue) { + super(name, envName, defaultValue); + } + + /** + * {@inheritDoc} + */ + @Override + protected Boolean parse(String value) { + return Boolean.valueOf(value); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/GenericProperty.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/GenericProperty.java new file mode 100644 index 0000000000..3c060b0f83 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/GenericProperty.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.config; + +import java.util.function.Function; + +/** + * Configuration property for any type. + */ +public class GenericProperty extends Property { + + private final Function parser; + + /** + * {@inheritDoc} + */ + GenericProperty(String name, String envName, T defaultValue, Function parser) { + super(name, envName, defaultValue); + this.parser = parser; + } + + /** + * {@inheritDoc} + */ + @Override + protected T parse(String value) { + return parser.apply(value); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/IntegerProperty.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/IntegerProperty.java new file mode 100644 index 0000000000..8eb6e0be25 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/IntegerProperty.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.config; + +/** + * Integer configuration property. + */ +public class IntegerProperty extends Property { + + /** + * {@inheritDoc} + */ + IntegerProperty(String name, String envName, Integer defaultValue) { + super(name, envName, defaultValue); + } + + /** + * {@inheritDoc} + */ + @Override + protected Integer parse(String value) { + return Integer.valueOf(value); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/Properties.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/Properties.java new file mode 100644 index 0000000000..78b0caa062 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/Properties.java @@ -0,0 +1,89 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.config; + + +import io.mosn.layotto.v1.value.LayottoApiProtocol; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * Global properties for Layotto's SDK, using Supplier so they are dynamically resolved. + */ +public class Properties { + + /** + * Layotto's default IP for gRPC communication. + */ + private static final String DEFAULT_SIDECAR_IP = "127.0.0.1"; + + /** + * Layotto's default gRPC port. + */ + private static final Integer DEFAULT_GRPC_PORT = 34904; + + /** + * Layotto's default use of gRPC. + */ + private static final LayottoApiProtocol DEFAULT_API_PROTOCOL = LayottoApiProtocol.GRPC; + + /** + * Layotto's default String encoding: UTF-8. + */ + private static final Charset DEFAULT_STRING_CHARSET = StandardCharsets.UTF_8; + + /** + * IP for Layotto's sidecar. + */ + public static final Property SIDECAR_IP = new StringProperty( + "layotto.sidecar.ip", + "LAYOTTO_SIDECAR_IP", + DEFAULT_SIDECAR_IP); + + /** + * GRPC port for Layotto after checking system property and environment variable. + */ + public static final Property GRPC_PORT = new IntegerProperty( + "layotto.grpc.port", + "LAYOTTO_GRPC_PORT", + DEFAULT_GRPC_PORT); + + /** + * Determines if Layotto client will use gRPC to talk to Layotto's sidecar. + */ + public static final Property API_PROTOCOL = new GenericProperty<>( + "layotto.api.protocol", + "LAYOTTO_API_PROTOCOL", + DEFAULT_API_PROTOCOL, + (s) -> LayottoApiProtocol.valueOf(s.toUpperCase())); + + /** + * API token for authentication between App and Layotto's sidecar. + */ + public static final Property API_TOKEN = new StringProperty( + "layotto.api.token", + "LAYOTTO_API_TOKEN", + null); + + /** + * Determines which string encoding is used in Layotto's Java SDK. + */ + public static final Property STRING_CHARSET = new GenericProperty<>( + "layotto.string.charset", + "LAYOTTO_STRING_CHARSET", + DEFAULT_STRING_CHARSET, + (s) -> Charset.forName(s)); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/Property.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/Property.java new file mode 100644 index 0000000000..f9801e1e3e --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/Property.java @@ -0,0 +1,109 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A configuration property in the Layotto's SDK. + */ +public abstract class Property { + + private static final Logger LOGGER = LoggerFactory.getLogger(Property.class.getName()); + + /** + * Property's name as a Java Property. + */ + private final String name; + + /** + * Property's name as a environment variable. + */ + private final String envName; + + /** + * Default value. + */ + private final T defaultValue; + + /** + * Instantiates a new configuration property. + * + * @param name Java property name. + * @param envName Environment variable name. + * @param defaultValue Default value. + */ + Property(String name, String envName, T defaultValue) { + this.name = name; + this.envName = envName; + this.defaultValue = defaultValue; + } + + /** + * Gets the Java property's name. + * + * @return Name. + */ + public String getName() { + return this.name; + } + + /** + * Gets the environment variable's name. + * + * @return Name. + */ + public String getEnvName() { + return this.envName; + } + + /** + * Gets the value defined by system property first, then env variable or sticks to default. + * + * @return Value from system property (1st) or env variable (2nd) or default (last). + */ + public T get() { + String propValue = System.getProperty(this.name); + if (propValue != null && !propValue.trim().isEmpty()) { + try { + return this.parse(propValue); + } catch (IllegalArgumentException e) { + LOGGER.warn(String.format("Invalid value in property: %s", this.name)); + // OK, we tried. Falling back to system environment variable. + } + } + + String envValue = System.getenv(this.envName); + if (envValue != null && !envValue.trim().isEmpty()) { + try { + return this.parse(envValue); + } catch (IllegalArgumentException e) { + LOGGER.warn(String.format("Invalid value in environment variable: %s", this.envName)); + // OK, we tried. Falling back to default. + } + } + + return this.defaultValue; + } + + /** + * Parses the value to the specific type. + * + * @param value String value to be parsed. + * @return Value in the specific type. + */ + protected abstract T parse(String value); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/StringProperty.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/StringProperty.java new file mode 100644 index 0000000000..34939aa047 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/config/StringProperty.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.config; + +/** + * String configuration property. + */ +public class StringProperty extends Property { + + /** + * {@inheritDoc} + */ + StringProperty(String name, String envName, String defaultValue) { + super(name, envName, defaultValue); + } + + /** + * {@inheritDoc} + */ + @Override + protected String parse(String value) { + return value; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/domain/CloudEvent.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/domain/CloudEvent.java new file mode 100644 index 0000000000..312c36d5b3 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/domain/CloudEvent.java @@ -0,0 +1,306 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.domain; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Objects; + +/** + * A cloud event in Layotto. + * + * @param The type of the payload. + */ +public final class CloudEvent { + + /** + * Mime type used for CloudEvent. + */ + public static final String CONTENT_TYPE = "application/cloudevents+json"; + + /** + * Shared Json serializer/deserializer as per Jackson's documentation. + */ + protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, + false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL); + + /** + * Identifier of the message being processed. + */ + private String id; + + /** + * Event's source. + */ + private String source; + + /** + * Envelope type. + */ + private String type; + + /** + * Version of the specification. + */ + private String specversion; + + /** + * Type of the data's content. + */ + private String datacontenttype; + + /** + * Cloud event specs says data can be a JSON object or string. + */ + private T data; + + /** + * Cloud event specs says binary data should be in data_base64. + */ + @JsonProperty("data_base64") + private byte[] binaryData; + + /** + * Instantiates a CloudEvent. + */ + public CloudEvent() { + } + + /** + * Instantiates a CloudEvent. + * + * @param id Identifier of the message being processed. + * @param source Source for this event. + * @param type Type of event. + * @param specversion Version of the event spec. + * @param datacontenttype Type of the payload. + * @param data Payload. + */ + public CloudEvent( + String id, + String source, + String type, + String specversion, + String datacontenttype, + T data) { + this.id = id; + this.source = source; + this.type = type; + this.specversion = specversion; + this.datacontenttype = datacontenttype; + this.data = data; + } + + /** + * Instantiates a CloudEvent. + * + * @param id Identifier of the message being processed. + * @param source Source for this event. + * @param type Type of event. + * @param specversion Version of the event spec. + * @param binaryData Payload. + */ + public CloudEvent( + String id, + String source, + String type, + String specversion, + byte[] binaryData) { + this.id = id; + this.source = source; + this.type = type; + this.specversion = specversion; + this.datacontenttype = "application/octet-stream"; + this.binaryData = binaryData == null ? null : Arrays.copyOf(binaryData, binaryData.length); + ; + } + + /** + * Deserialize a message topic from Layotto. + * + * @param payload Payload sent from Layotto. + * @return Message (can be null if input is null) + * @throws IOException If cannot parse. + */ + public static CloudEvent deserialize(byte[] payload) throws IOException { + if (payload == null) { + return null; + } + + return OBJECT_MAPPER.readValue(payload, CloudEvent.class); + } + + /** + * Gets the identifier of the message being processed. + * + * @return Identifier of the message being processed. + */ + public String getId() { + return id; + } + + /** + * Sets the identifier of the message being processed. + * + * @param id Identifier of the message being processed. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Gets the event's source. + * + * @return Event's source. + */ + public String getSource() { + return source; + } + + /** + * Sets the event's source. + * + * @param source Event's source. + */ + public void setSource(String source) { + this.source = source; + } + + /** + * Gets the envelope type. + * + * @return Envelope type. + */ + public String getType() { + return type; + } + + /** + * Sets the envelope type. + * + * @param type Envelope type. + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the version of the specification. + * + * @return Version of the specification. + */ + public String getSpecversion() { + return specversion; + } + + /** + * Sets the version of the specification. + * + * @param specversion Version of the specification. + */ + public void setSpecversion(String specversion) { + this.specversion = specversion; + } + + /** + * Gets the type of the data's content. + * + * @return Type of the data's content. + */ + public String getDatacontenttype() { + return datacontenttype; + } + + /** + * Sets the type of the data's content. + * + * @param datacontenttype Type of the data's content. + */ + public void setDatacontenttype(String datacontenttype) { + this.datacontenttype = datacontenttype; + } + + /** + * Gets the cloud event data. + * + * @return Cloud event's data. As per specs, data can be a JSON object or string. + */ + public T getData() { + return data; + } + + /** + * Sets the cloud event data. As per specs, data can be a JSON object or string. + * + * @param data Cloud event's data. As per specs, data can be a JSON object or string. + */ + public void setData(T data) { + this.data = data; + } + + /** + * Gets the cloud event's binary data. + * + * @return Cloud event's binary data. + */ + public byte[] getBinaryData() { + return this.binaryData == null ? null : Arrays.copyOf(this.binaryData, this.binaryData.length); + } + + /** + * Sets the cloud event's binary data. + * + * @param binaryData Cloud event's binary data. + */ + public void setBinaryData(byte[] binaryData) { + this.binaryData = binaryData == null ? null : Arrays.copyOf(binaryData, binaryData.length); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CloudEvent that = (CloudEvent) o; + return Objects.equals(id, that.id) + && Objects.equals(source, that.source) + && Objects.equals(type, that.type) + && Objects.equals(specversion, that.specversion) + && Objects.equals(datacontenttype, that.datacontenttype) + && Objects.equals(data, that.data) + && Arrays.equals(binaryData, that.binaryData); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hash(id, source, type, specversion, datacontenttype, data, binaryData); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/exceptions/LayottoError.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/exceptions/LayottoError.java new file mode 100644 index 0000000000..c7ddaa0f10 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/exceptions/LayottoError.java @@ -0,0 +1,83 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.exceptions; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import io.grpc.Status; + +/** + * Represents an error message from Layotto. + */ +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +public class LayottoError { + + /** + * Error code. + */ + private String errorCode; + + /** + * Error Message. + */ + private String message; + + /** + * Error code from gRPC. + */ + private Integer code; + + /** + * Gets the error code. + * + * @return Error code. + */ + public String getErrorCode() { + if ((errorCode == null) && (code != null)) { + return Status.fromCodeValue(code).getCode().name(); + } + return errorCode; + } + + /** + * Sets the error code. + * + * @param errorCode Error code. + * @return This instance. + */ + public LayottoError setErrorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } + + /** + * Gets the error message. + * + * @return Error message. + */ + public String getMessage() { + return message; + } + + /** + * Sets the error message. + * + * @param message Error message. + * @return This instance. + */ + public LayottoError setMessage(String message) { + this.message = message; + return this; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/exceptions/LayottoException.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/exceptions/LayottoException.java new file mode 100644 index 0000000000..dedadef353 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/exceptions/LayottoException.java @@ -0,0 +1,203 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.exceptions; + +import io.grpc.StatusRuntimeException; +import reactor.core.Exceptions; +import reactor.core.publisher.Mono; + +import java.util.concurrent.Callable; + +/** + * A Layotto's specific exception. + */ +public class LayottoException extends RuntimeException { + + /** + * Layotto's error code for this exception. + */ + private final String errorCode; + + /** + * New exception from a server-side generated error code and message. + * + * @param daprError Server-side error. + */ + public LayottoException(LayottoError daprError) { + this(daprError.getErrorCode(), daprError.getMessage()); + } + + /** + * New exception from a server-side generated error code and message. + * + * @param daprError Client-side error. + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + */ + public LayottoException(LayottoError daprError, Throwable cause) { + this(daprError.getErrorCode(), daprError.getMessage(), cause); + } + + /** + * Wraps an exception into a LayottoException. + * + * @param exception the exception to be wrapped. + */ + public LayottoException(Throwable exception) { + this("UNKNOWN", exception.getMessage(), exception); + } + + /** + * New Exception from a client-side generated error code and message. + * + * @param errorCode Client-side error code. + * @param message Client-side error message. + */ + public LayottoException(String errorCode, String message) { + super(String.format("%s: %s", errorCode, message)); + this.errorCode = errorCode; + } + + /** + * New exception from a server-side generated error code and message. + * + * @param errorCode Client-side error code. + * @param message Client-side error message. + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + */ + public LayottoException(String errorCode, String message, Throwable cause) { + super(String.format("%s: %s", errorCode, emptyIfNull(message)), cause); + this.errorCode = errorCode; + } + + /** + * Returns the exception's error code. + * + * @return Error code. + */ + public String getErrorCode() { + return this.errorCode; + } + + /** + * Wraps an exception into LayottoException (if not already LayottoException). + * + * @param exception Exception to be wrapped. + */ + public static void wrap(Throwable exception) { + if (exception == null) { + return; + } + + throw propagate(exception); + } + + /** + * Wraps a callable with a try-catch to throw LayottoException. + * + * @param callable callable to be invoked. + * @param type to be returned + * @return object of type T. + */ + public static Callable wrap(Callable callable) { + return () -> { + try { + return callable.call(); + } catch (Exception e) { + wrap(e); + return null; + } + }; + } + + /** + * Wraps a runnable with a try-catch to throw LayottoException. + * + * @param runnable runnable to be invoked. + * @return object of type T. + */ + public static Runnable wrap(Runnable runnable) { + return () -> { + try { + runnable.run(); + } catch (Exception e) { + wrap(e); + } + }; + } + + /** + * Wraps an exception into LayottoException (if not already LayottoException). + * + * @param exception Exception to be wrapped. + * @param Mono's response type. + * @return Mono containing LayottoException. + */ + public static Mono wrapMono(Exception exception) { + try { + wrap(exception); + } catch (Exception e) { + return Mono.error(e); + } + + return Mono.empty(); + } + + /** + * Wraps an exception into LayottoException (if not already LayottoException). + * + * @param exception Exception to be wrapped. + * @return wrapped RuntimeException + */ + public static RuntimeException propagate(Throwable exception) { + Exceptions.throwIfFatal(exception); + + if (exception instanceof LayottoException) { + return (LayottoException) exception; + } + + Throwable e = exception; + while (e != null) { + if (e instanceof StatusRuntimeException) { + StatusRuntimeException statusRuntimeException = (StatusRuntimeException) e; + return new LayottoException( + statusRuntimeException.getStatus().getCode().toString(), + statusRuntimeException.getStatus().getDescription(), + exception); + } + + e = e.getCause(); + } + + if (exception instanceof IllegalArgumentException) { + return (IllegalArgumentException) exception; + } + + return new LayottoException(exception); + } + + private static String emptyIfNull(String str) { + if (str == null) { + return ""; + } + + return str; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/DefaultObjectSerializer.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/DefaultObjectSerializer.java new file mode 100644 index 0000000000..e049d96212 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/DefaultObjectSerializer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.serializer; + +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.io.IOException; + +/** + * Default serializer/deserializer for request/response objects and for state objects too. + */ +public class DefaultObjectSerializer extends ObjectSerializer implements LayottoObjectSerializer { + + /** + * {@inheritDoc} + */ + @Override + public byte[] serialize(Object o) throws IOException { + return super.serialize(o); + } + + /** + * {@inheritDoc} + */ + @Override + public T deserialize(byte[] data, TypeRef type) throws IOException { + return super.deserialize(data, type); + } + + /** + * {@inheritDoc} + */ + @Override + public String getContentType() { + return "application/json"; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/LayottoObjectSerializer.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/LayottoObjectSerializer.java new file mode 100644 index 0000000000..6d74a6315f --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/LayottoObjectSerializer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.serializer; + +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.io.IOException; + +/** + * Serializes and deserializes application's objects. + */ +public interface LayottoObjectSerializer { + + /** + * Serializes the given object as byte[]. + * + * @param o Object to be serialized. + * @return Serialized object. + * @throws IOException If cannot serialize. + */ + byte[] serialize(Object o) throws IOException; + + /** + * Deserializes the given byte[] into a object. + * + * @param data Data to be deserialized. + * @param type Type of object to be deserialized. + * @param Type of object to be deserialized. + * @return Deserialized object. + * @throws IOException If cannot deserialize object. + */ + T deserialize(byte[] data, TypeRef type) throws IOException; + + /** + * Returns the content type of the request. + * + * @return content type of the request + */ + String getContentType(); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/ObjectSerializer.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/ObjectSerializer.java new file mode 100644 index 0000000000..f09ace378c --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/serializer/ObjectSerializer.java @@ -0,0 +1,205 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.serializer; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.protobuf.MessageLite; +import io.mosn.layotto.v1.domain.CloudEvent; +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.io.IOException; +import java.lang.reflect.Method; + +/** + * Serializes and deserializes an internal object. + */ +public class ObjectSerializer { + + /** + * Shared Json serializer/deserializer as per Jackson's documentation. + */ + protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, + false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL); + + /** + * Default constructor to avoid class from being instantiated outside package but still inherited. + */ + protected ObjectSerializer() { + } + + /** + * Serializes a given state object into byte array. + * + * @param state State object to be serialized. + * @return Array of bytes[] with the serialized content. + * @throws IOException In case state cannot be serialized. + */ + public byte[] serialize(Object state) throws IOException { + if (state == null) { + return null; + } + + if (state.getClass() == Void.class) { + return null; + } + + // Have this check here to be consistent with deserialization (see deserialize() method below). + if (state instanceof byte[]) { + return (byte[]) state; + } + + // Proto buffer class is serialized directly. + if (state instanceof MessageLite) { + return ((MessageLite) state).toByteArray(); + } + + // Not string, not primitive, so it is a complex type: we use JSON for that. + return OBJECT_MAPPER.writeValueAsBytes(state); + } + + /** + * Deserializes the byte array into the original object. + * + * @param content Content to be parsed. + * @param type Type of the object being deserialized. + * @param Generic type of the object being deserialized. + * @return Object of type T. + * @throws IOException In case content cannot be deserialized. + */ + public T deserialize(byte[] content, TypeRef type) throws IOException { + return deserialize(content, OBJECT_MAPPER.constructType(type.getType())); + } + + /** + * Deserializes the byte array into the original object. + * + * @param content Content to be parsed. + * @param clazz Type of the object being deserialized. + * @param Generic type of the object being deserialized. + * @return Object of type T. + * @throws IOException In case content cannot be deserialized. + */ + public T deserialize(byte[] content, Class clazz) throws IOException { + return deserialize(content, OBJECT_MAPPER.constructType(clazz)); + } + + private T deserialize(byte[] content, JavaType javaType) throws IOException { + if ((javaType == null) || javaType.isTypeOrSubTypeOf(Void.class)) { + return null; + } + + if (javaType.isPrimitive()) { + return deserializePrimitives(content, javaType); + } + + if (content == null) { + return null; + } + + // Deserialization of GRPC response fails without this check since it does not come as base64 encoded byte[]. + if (javaType.hasRawClass(byte[].class)) { + return (T) content; + } + + if (content.length == 0) { + return null; + } + + if (javaType.hasRawClass(CloudEvent.class)) { + return (T) CloudEvent.deserialize(content); + } + + if (javaType.isTypeOrSubTypeOf(MessageLite.class)) { + try { + Method method = javaType.getRawClass().getDeclaredMethod("parseFrom", byte[].class); + if (method != null) { + return (T) method.invoke(null, content); + } + } catch (NoSuchMethodException e) { + // It was a best effort. Skip this try. + } catch (Exception e) { + throw new IOException(e); + } + } + + return OBJECT_MAPPER.readValue(content, javaType); + } + + /** + * Parses the JSON content into a node for fine-grained processing. + * + * @param content JSON content. + * @return JsonNode. + * @throws IOException In case content cannot be parsed. + */ + public JsonNode parseNode(byte[] content) throws IOException { + return OBJECT_MAPPER.readTree(content); + } + + /** + * Parses a given String to the corresponding object defined by class. + * + * @param content Value to be parsed. + * @param javaType Type of the expected result type. + * @param Result type. + * @return Result as corresponding type. + * @throws IOException if cannot deserialize primitive time. + */ + private static T deserializePrimitives(byte[] content, JavaType javaType) throws IOException { + if ((content == null) || (content.length == 0)) { + if (javaType.hasRawClass(boolean.class)) { + return (T) Boolean.FALSE; + } + + if (javaType.hasRawClass(byte.class)) { + return (T) Byte.valueOf((byte) 0); + } + + if (javaType.hasRawClass(short.class)) { + return (T) Short.valueOf((short) 0); + } + + if (javaType.hasRawClass(int.class)) { + return (T) Integer.valueOf(0); + } + + if (javaType.hasRawClass(long.class)) { + return (T) Long.valueOf(0L); + } + + if (javaType.hasRawClass(float.class)) { + return (T) Float.valueOf(0); + } + + if (javaType.hasRawClass(double.class)) { + return (T) Double.valueOf(0); + } + + if (javaType.hasRawClass(char.class)) { + return (T) Character.valueOf(Character.MIN_VALUE); + } + + return null; + } + + return OBJECT_MAPPER.readValue(content, javaType); + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/utils/GrpcWrapper.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/utils/GrpcWrapper.java new file mode 100644 index 0000000000..ab40749a0e --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/utils/GrpcWrapper.java @@ -0,0 +1,77 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.utils; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; +import io.mosn.layotto.v1.config.Property; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.util.context.Context; +import spec.proto.runtime.v1.RuntimeGrpc; + +/** + * Wraps a Layotto gRPC stub with telemetry interceptor. + */ +public final class GrpcWrapper { + + private static final Logger LOGGER = LoggerFactory.getLogger(Property.class.getName()); + + private static final Metadata.Key GRPC_TRACE_BIN_KEY = + Metadata.Key.of("grpc-trace-bin", + Metadata.BINARY_BYTE_MARSHALLER); + + private static final Metadata.Key TRACEPARENT_KEY = + Metadata.Key.of("traceparent", + Metadata.ASCII_STRING_MARSHALLER); + + private static final Metadata.Key TRACESTATE_KEY = + Metadata.Key.of("tracestate", + Metadata.ASCII_STRING_MARSHALLER); + + private GrpcWrapper() { + } + + /** + * Populates GRPC client with interceptors. + * + * @param context Reactor's context. + * @param client GRPC client for Layotto. + * @return Client after adding interceptors. + */ + public static RuntimeGrpc.RuntimeStub intercept(final Context context, RuntimeGrpc.RuntimeStub client) { + ClientInterceptor interceptor = new ClientInterceptor() { + @Override + public ClientCall interceptCall(MethodDescriptor methodDescriptor, + CallOptions callOptions, + Channel channel) { + ClientCall clientCall = channel.newCall(methodDescriptor, callOptions); + return new ForwardingClientCall.SimpleForwardingClientCall(clientCall) { + @Override + public void start(final Listener responseListener, final Metadata metadata) { + // FIXME: 2021/9/26 Refer to Dapr + super.start(responseListener, metadata); + } + }; + } + }; + return client.withInterceptors(interceptor); + } +} \ No newline at end of file diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/utils/NetworkUtils.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/utils/NetworkUtils.java new file mode 100644 index 0000000000..4faa324aab --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/utils/NetworkUtils.java @@ -0,0 +1,87 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.utils; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +/** + * Utility methods for network, internal to Dapr SDK. + */ +public final class NetworkUtils { + + private NetworkUtils() { + } + + /** + * Tries to connect to a socket, retrying every 1 second. + * + * @param host Host to connect to. + * @param port Port to connect to. + * @param timeoutInMilliseconds Timeout in milliseconds to give up trying. + * @throws InterruptedException If retry is interrupted. + */ + public static void waitForSocket(String host, int port, int timeoutInMilliseconds) throws InterruptedException { + long started = System.currentTimeMillis(); + Retry.callWithRetry(() -> { + try { + try (Socket socket = new Socket()) { + // timeout cannot be negative. + // zero timeout means infinite, so 1 is the practical minimum. + int remainingTimeout = (int) Math.max(1, timeoutInMilliseconds - (System.currentTimeMillis() - started)); + socket.connect(new InetSocketAddress(host, port), remainingTimeout); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }, timeoutInMilliseconds); + } +} + +class Retry { + + private static final long RETRY_WAIT_MILLISECONDS = 1000; + + private Retry() { + } + + static void callWithRetry(Runnable function, long retryTimeoutMilliseconds) throws InterruptedException { + long started = System.currentTimeMillis(); + while (true) { + Throwable exception; + try { + function.run(); + return; + } catch (Exception e) { + exception = e; + } catch (AssertionError e) { + exception = e; + } + + long elapsed = System.currentTimeMillis() - started; + if (elapsed >= retryTimeoutMilliseconds) { + if (exception instanceof RuntimeException) { + throw (RuntimeException) exception; + } + + throw new RuntimeException(exception); + } + + long remaining = retryTimeoutMilliseconds - elapsed; + Thread.sleep(Math.min(remaining, RETRY_WAIT_MILLISECONDS)); + } + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/value/Headers.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/value/Headers.java new file mode 100644 index 0000000000..c8b9cde328 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/value/Headers.java @@ -0,0 +1,31 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.value; + +/** + * Common headers for GRPC and HTTP communication. + */ +public class Headers { + + /** + * OpenCensus's metadata for GRPC. + */ + public static final String GRPC_TRACE_BIN = "grpc-trace-bin"; + + /** + * Token for authentication from Application to Layotto runtime. + */ + public static final String DAPR_API_TOKEN = "layotto-api-token"; +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/value/LayottoApiProtocol.java b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/value/LayottoApiProtocol.java new file mode 100644 index 0000000000..223b264fb7 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/io/mosn/layotto/v1/value/LayottoApiProtocol.java @@ -0,0 +1,23 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package io.mosn.layotto.v1.value; + +/** + * Transport protocol for Layotto's API. + */ +public enum LayottoApiProtocol { + + GRPC; +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/CoreCloudRuntimes.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/CoreCloudRuntimes.java new file mode 100644 index 0000000000..b4e2266217 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/CoreCloudRuntimes.java @@ -0,0 +1,32 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1; + +import spec.sdk.reactor.v1.domain.core.ConfigurationRuntimes; +import spec.sdk.reactor.v1.domain.core.InvocationRuntimes; +import spec.sdk.reactor.v1.domain.core.PubSubRuntimes; +import spec.sdk.reactor.v1.domain.core.StateRuntimes; + +/** + * Core Cloud Runtimes standard API defined. + */ +public interface CoreCloudRuntimes extends + InvocationRuntimes, + PubSubRuntimes, + // BindingRuntimes, + StateRuntimes, + // SecretsRuntimes, + ConfigurationRuntimes { +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/EnhancedCloudRuntimes.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/EnhancedCloudRuntimes.java new file mode 100644 index 0000000000..63f243b847 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/EnhancedCloudRuntimes.java @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1; + +import spec.sdk.reactor.v1.domain.enhanced.MetricsRuntimes; + +/** + * Enhanced Cloud Runtimes standard API defined. + */ +public interface EnhancedCloudRuntimes extends + MetricsRuntimes { +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/README.md b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/README.md new file mode 100644 index 0000000000..70996cf7c3 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/README.md @@ -0,0 +1 @@ +This package was copied from [cloud-runtimes-jvm](https://github.com/reactivegroup/cloud-runtimes-jvm) and [Dapr java sdk](https://github.com/dapr/java-sdk) \ No newline at end of file diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/client/CloudRuntimesClient.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/client/CloudRuntimesClient.java new file mode 100644 index 0000000000..60b19c9bb2 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/client/CloudRuntimesClient.java @@ -0,0 +1,40 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.client; + +import reactor.core.publisher.Mono; +import spec.sdk.reactor.v1.CoreCloudRuntimes; +import spec.sdk.reactor.v1.EnhancedCloudRuntimes; + +/** + * Cloud Runtimes JVM Client. + */ +public interface CloudRuntimesClient extends AutoCloseable, CoreCloudRuntimes, EnhancedCloudRuntimes { + + /** + * Waits for the sidecar, giving up after timeout. + * + * @param timeoutInMilliseconds Timeout in milliseconds to wait for sidecar. + * @return a Mono plan of type Void. + */ + Mono waitForSidecar(int timeoutInMilliseconds); + + /** + * Gracefully shutdown the cloud-runtimes runtime. + * + * @return a Mono plan of type Void. + */ + Mono shutdown(); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/ConfigurationRuntimes.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/ConfigurationRuntimes.java new file mode 100644 index 0000000000..2a726fbb83 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/ConfigurationRuntimes.java @@ -0,0 +1,69 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import spec.sdk.reactor.v1.domain.core.configuration.ConfigurationItem; +import spec.sdk.reactor.v1.domain.core.configuration.ConfigurationRequestItem; +import spec.sdk.reactor.v1.domain.core.configuration.SaveConfigurationRequest; +import spec.sdk.reactor.v1.domain.core.configuration.SubConfigurationResp; +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.util.List; + +/** + * Configuration Runtimes standard API defined. + */ +public interface ConfigurationRuntimes { + + /** + * Gets configuration from configuration store + * + * @param The Type of the return. + * @param configurationRequestItem Request object. + * @param type The Type needed as return for the call. + * @return A Mono Plan of response with type T. + */ + Mono>> getConfiguration(ConfigurationRequestItem configurationRequestItem, + TypeRef type); + + /** + * Saves configuration into configuration store. + * + * @param saveConfigurationRequest Request object. + * @return A Mono Plan of invocation. + */ + Mono saveConfiguration(SaveConfigurationRequest saveConfigurationRequest); + + /** + * Deletes configuration from configuration store. + * + * @param configurationRequestItem Request object. + * @return A Mono Plan of invocation. + */ + Mono deleteConfiguration(ConfigurationRequestItem configurationRequestItem); + + /** + * Gets configuration from configuration store and subscribe the updates. + * + * @param The Type of the return. + * @param configurationRequestItem Request object. + * @param type The Type needed as return for the call. + * @return A Flux Plan of response with type T. Subscribe update listener. + */ + Flux> subscribeConfiguration(ConfigurationRequestItem configurationRequestItem, + TypeRef type); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/InvocationRuntimes.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/InvocationRuntimes.java new file mode 100644 index 0000000000..7d9f20bb05 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/InvocationRuntimes.java @@ -0,0 +1,184 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core; + +import reactor.core.publisher.Mono; +import spec.sdk.reactor.v1.domain.core.invocation.HttpExtension; +import spec.sdk.reactor.v1.domain.core.invocation.InvokeMethodRequest; +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.util.Map; + +/** + * Service-to-Service Invocation Runtimes standard API defined. + */ +public interface InvocationRuntimes { + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param data The data to be sent to invoke the service, use byte[] to skip serialization. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in data. + * @param type The Type needed as return for the call. + * @param The Type of the return, use byte[] to skip serialization. + * @return A Mono Plan of type T. + */ + Mono invokeMethod(String appId, String methodName, Object data, HttpExtension httpExtension, + Map metadata, TypeRef type); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param request The request to be sent to invoke the service, use byte[] to skip serialization. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. + * @param clazz The type needed as return for the call. + * @param The Type of the return, use byte[] to skip serialization. + * @return A Mono Plan of type T. + */ + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Map metadata, Class clazz); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param request The request to be sent to invoke the service, use byte[] to skip serialization. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param type The Type needed as return for the call. + * @param The Type of the return, use byte[] to skip serialization. + * @return A Mono Plan of type T. + */ + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + TypeRef type); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param request The request to be sent to invoke the service, use byte[] to skip serialization. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param clazz The type needed as return for the call. + * @param The Type of the return, use byte[] to skip serialization. + * @return A Mono Plan of type T. + */ + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Class clazz); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. + * @param type The Type needed as return for the call. + * @param The Type of the return, use byte[] to skip serialization. + * @return A Mono Plan of type T. + */ + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, + Map metadata, + TypeRef type); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. + * @param clazz The type needed as return for the call. + * @param The Type of the return, use byte[] to skip serialization. + * @return A Mono Plan of type T. + */ + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, + Map metadata, + Class clazz); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param request The request to be sent to invoke the service, use byte[] to skip serialization. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. + * @return A Mono Plan of type Void. + */ + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, + Map metadata); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param request The request to be sent to invoke the service, use byte[] to skip serialization. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @return A Mono Plan of type Void. + */ + Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension); + + /** + * Invoke a service method, using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. + * @return A Mono Plan of type Void. + */ + Mono invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map metadata); + + /** + * Invoke a service method, without using serialization. + * + * @param appId The Application ID where the service is. + * @param methodName The actual Method to be call in the application. + * @param request The request to be sent to invoke the service, use byte[] to skip serialization. + * @param httpExtension Additional fields that are needed if the receiving app is listening on + * HTTP, {@link HttpExtension#NONE} otherwise. + * @param metadata Metadata (in GRPC) or headers (in HTTP) to be sent in request. + * @return A Mono Plan of type byte[]. + */ + Mono invokeMethod(String appId, String methodName, byte[] request, HttpExtension httpExtension, + Map metadata); + + /** + * Invoke a service method. + * + * @param invokeMethodRequest Request object. + * @param type The Type needed as return for the call. + * @param The Type of the return, use byte[] to skip serialization. + * @return A Mono Plan of type T. + */ + Mono invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef type); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/PubSubRuntimes.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/PubSubRuntimes.java new file mode 100644 index 0000000000..c09b6b1dc6 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/PubSubRuntimes.java @@ -0,0 +1,55 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core; + +import reactor.core.publisher.Mono; +import spec.sdk.reactor.v1.domain.core.pubsub.PublishEventRequest; + +import java.util.Map; + +/** + * Publish and Subscribe Runtimes standard API defined. + */ +public interface PubSubRuntimes { + + /** + * Publish an event. + * + * @param pubsubName the pubsub name we will publish the event to + * @param topicName the topicName where the event will be published. + * @param data the event's data to be published, use byte[] for skipping serialization. + * @return a Mono plan of type Void. + */ + Mono publishEvent(String pubsubName, String topicName, Object data); + + /** + * Publish an event. + * + * @param pubsubName the pubsub name we will publish the event to + * @param topicName the topicName where the event will be published. + * @param data the event's data to be published, use byte[] for skipping serialization. + * @param metadata The metadata for the published event. + * @return a Mono plan of type Void. + */ + Mono publishEvent(String pubsubName, String topicName, Object data, Map metadata); + + /** + * Publish an event. + * + * @param request the request for the publish event. + * @return a Mono plan of a CloudRuntimes's void response. + */ + Mono publishEvent(PublishEventRequest request); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/StateRuntimes.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/StateRuntimes.java new file mode 100644 index 0000000000..465de5f5d5 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/StateRuntimes.java @@ -0,0 +1,229 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core; + +import reactor.core.publisher.Mono; +import spec.sdk.reactor.v1.domain.core.state.DeleteStateRequest; +import spec.sdk.reactor.v1.domain.core.state.ExecuteStateTransactionRequest; +import spec.sdk.reactor.v1.domain.core.state.GetBulkStateRequest; +import spec.sdk.reactor.v1.domain.core.state.GetStateRequest; +import spec.sdk.reactor.v1.domain.core.state.SaveStateRequest; +import spec.sdk.reactor.v1.domain.core.state.State; +import spec.sdk.reactor.v1.domain.core.state.StateOptions; +import spec.sdk.reactor.v1.domain.core.state.TransactionalStateOperation; +import spec.sdk.reactor.v1.utils.TypeRef; + +import java.util.List; + +/** + * State Management Runtimes standard API defined. + */ +public interface StateRuntimes { + + /** + * Retrieve a State based on their key. + * + * @param storeName The name of the state store. + * @param state State to be re-retrieved. + * @param type The type of State needed as return. + * @param The type of the return. + * @return A Mono Plan for the requested State. + */ + Mono> getState(String storeName, State state, TypeRef type); + + /** + * Retrieve a State based on their key. + * + * @param storeName The name of the state store. + * @param state State to be re-retrieved. + * @param clazz The type of State needed as return. + * @param The type of the return. + * @return A Mono Plan for the requested State. + */ + Mono> getState(String storeName, State state, Class clazz); + + /** + * Retrieve a State based on their key. + * + * @param storeName The name of the state store. + * @param key The key of the State to be retrieved. + * @param type The type of State needed as return. + * @param The type of the return. + * @return A Mono Plan for the requested State. + */ + Mono> getState(String storeName, String key, TypeRef type); + + /** + * Retrieve a State based on their key. + * + * @param storeName The name of the state store. + * @param key The key of the State to be retrieved. + * @param clazz The type of State needed as return. + * @param The type of the return. + * @return A Mono Plan for the requested State. + */ + Mono> getState(String storeName, String key, Class clazz); + + /** + * Retrieve a State based on their key. + * + * @param storeName The name of the state store. + * @param key The key of the State to be retrieved. + * @param options Optional settings for retrieve operation. + * @param type The Type of State needed as return. + * @param The Type of the return. + * @return A Mono Plan for the requested State. + */ + Mono> getState(String storeName, String key, StateOptions options, TypeRef type); + + /** + * Retrieve a State based on their key. + * + * @param storeName The name of the state store. + * @param key The key of the State to be retrieved. + * @param options Optional settings for retrieve operation. + * @param clazz The Type of State needed as return. + * @param The Type of the return. + * @return A Mono Plan for the requested State. + */ + Mono> getState(String storeName, String key, StateOptions options, Class clazz); + + /** + * Retrieve a State based on their key. + * + * @param request The request to get state. + * @param type The Type of State needed as return. + * @param The Type of the return. + * @return A Mono Plan for the requested State. + */ + Mono> getState(GetStateRequest request, TypeRef type); + + /** + * Retrieve bulk States based on their keys. + * + * @param storeName The name of the state store. + * @param keys The keys of the State to be retrieved. + * @param type The type of State needed as return. + * @param The type of the return. + * @return A Mono Plan for the requested State. + */ + Mono>> getBulkState(String storeName, List keys, TypeRef type); + + /** + * Retrieve bulk States based on their keys. + * + * @param storeName The name of the state store. + * @param keys The keys of the State to be retrieved. + * @param clazz The type of State needed as return. + * @param The type of the return. + * @return A Mono Plan for the requested State. + */ + Mono>> getBulkState(String storeName, List keys, Class clazz); + + /** + * Retrieve bulk States based on their keys. + * + * @param request The request to get state. + * @param type The Type of State needed as return. + * @param The Type of the return. + * @return A Mono Plan for the requested State. + */ + Mono>> getBulkState(GetBulkStateRequest request, TypeRef type); + + /** + * Execute a transaction. + * + * @param storeName The name of the state store. + * @param operations The operations to be performed. + * @return a Mono plan of type Void + */ + Mono executeStateTransaction(String storeName, + List> operations); + + /** + * Execute a transaction. + * + * @param request Request to execute transaction. + * @return a Mono plan of type Response Void + */ + Mono executeStateTransaction(ExecuteStateTransactionRequest request); + + /** + * Save/Update a list of states. + * + * @param storeName The name of the state store. + * @param states The States to be saved. + * @return a Mono plan of type Void. + */ + Mono saveBulkState(String storeName, List> states); + + /** + * Save/Update a list of states. + * + * @param request Request to save states. + * @return a Mono plan of type Void. + */ + Mono saveBulkState(SaveStateRequest request); + + /** + * Save/Update a state. + * + * @param storeName The name of the state store. + * @param key The key of the state. + * @param value The value of the state. + * @return a Mono plan of type Void. + */ + Mono saveState(String storeName, String key, Object value); + + /** + * Save/Update a state. + * + * @param storeName The name of the state store. + * @param key The key of the state. + * @param etag The etag to be used. + * @param value The value of the state. + * @param options The Options to use for each state. + * @return a Mono plan of type Void. + */ + Mono saveState(String storeName, String key, String etag, Object value, StateOptions options); + + /** + * Delete a state. + * + * @param storeName The name of the state store. + * @param key The key of the State to be removed. + * @return a Mono plan of type Void. + */ + Mono deleteState(String storeName, String key); + + /** + * Delete a state. + * + * @param storeName The name of the state store. + * @param key The key of the State to be removed. + * @param etag Optional etag for conditional delete. + * @param options Optional settings for state operation. + * @return a Mono plan of type Void. + */ + Mono deleteState(String storeName, String key, String etag, StateOptions options); + + /** + * Delete a state. + * + * @param request Request to delete a state. + * @return a Mono plan of type Void. + */ + Mono deleteState(DeleteStateRequest request); +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationItem.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationItem.java new file mode 100644 index 0000000000..a456d87dcd --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationItem.java @@ -0,0 +1,94 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.configuration; + +import java.util.Map; + +public class ConfigurationItem { + + /** + * Required. The key of configuration item + */ + private String key; + /** + * The content of configuration item + * Empty if the configuration is not set, including the case that the configuration is changed from value-set to value-not-set. + */ + private T content; + /** + * The group of configuration item. + */ + private String group; + /** + * The label of configuration item. + */ + private String label; + /** + * The tag list of configuration item. + */ + private Map tags; + /** + * The metadata which will be passed to configuration store component. + */ + private Map metadata; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public T getContent() { + return content; + } + + public void setContent(T content) { + this.content = content; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public Map getTags() { + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationRequestItem.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationRequestItem.java new file mode 100644 index 0000000000..3c937dd28e --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationRequestItem.java @@ -0,0 +1,98 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.configuration; + +import java.util.List; +import java.util.Map; + +/** + * ConfigurationRequestItem used for GET,DEL,SUB request + */ +public class ConfigurationRequestItem { + + /** + * The name of configuration store. + */ + private String storeName; + /** + * The application id which + * Only used for admin, Ignored and reset for normal client + */ + private String appId; + /** + * The group of keys. + */ + private String group; + /** + * The label for keys. + */ + private String label; + /** + * The keys to get. + */ + private List keys; + /** + * The metadata which will be sent to configuration store components. + */ + private Map metadata; + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public List getKeys() { + return keys; + } + + public void setKeys(List keys) { + this.keys = keys; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationRequestItemBuilder.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationRequestItemBuilder.java new file mode 100644 index 0000000000..1c2ad765a8 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/ConfigurationRequestItemBuilder.java @@ -0,0 +1,77 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.configuration; + +import java.util.List; +import java.util.Map; + +/** + * Builds a request to invoke configuration. + */ +public class ConfigurationRequestItemBuilder { + + private final String storeName; + + private final String appId; + + private String group; + + private String label; + + private List keys; + + private Map metadata; + + public ConfigurationRequestItemBuilder(String storeName, String appId) { + this.storeName = storeName; + this.appId = appId; + } + + public ConfigurationRequestItemBuilder withGroup(String group) { + this.group = group; + return this; + } + + public ConfigurationRequestItemBuilder withLabel(String label) { + this.label = label; + return this; + } + + public ConfigurationRequestItemBuilder withKeys(List keys) { + this.keys = keys; + return this; + } + + public ConfigurationRequestItemBuilder withMetadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Builds a request object. + * + * @return Request object. + */ + public ConfigurationRequestItem build() { + ConfigurationRequestItem request = new ConfigurationRequestItem(); + request.setStoreName(this.appId); + request.setAppId(this.appId); + request.setGroup(this.group); + request.setLabel(this.label); + request.setKeys(this.keys); + request.setMetadata(this.metadata); + return request; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/SaveConfigurationRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/SaveConfigurationRequest.java new file mode 100644 index 0000000000..9fc5cf6155 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/SaveConfigurationRequest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.configuration; + +import java.util.List; +import java.util.Map; + +public class SaveConfigurationRequest { + + /** + * The name of configuration store. + */ + private String storeName; + /** + * The application id which + * Only used for admin, Ignored and reset for normal client + */ + private String appId; + /** + * The list of configuration items to save. + * To delete a exist item, set the key (also label) and let content to be empty + */ + private List> items; + /** + * The metadata which will be sent to configuration store components. + */ + private Map metadata; + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public List> getItems() { + return items; + } + + public void setItems(List> items) { + this.items = items; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/SubConfigurationResp.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/SubConfigurationResp.java new file mode 100644 index 0000000000..4fe44aea9a --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/configuration/SubConfigurationResp.java @@ -0,0 +1,59 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.configuration; + +import java.util.List; + +public class SubConfigurationResp { + + /** + * The name of configuration store. + */ + private String storeName; + /** + * The application id which + * Only used for admin, Ignored and reset for normal client + */ + private String appId; + /** + * The list of configuration items to save. + * To delete a exist item, set the key (also label) and let content to be empty + */ + private List> items; + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public List> getItems() { + return items; + } + + public void setItems(List> items) { + this.items = items; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/HttpExtension.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/HttpExtension.java new file mode 100644 index 0000000000..8a7a64efa1 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/HttpExtension.java @@ -0,0 +1,162 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.invocation; + +import okhttp3.HttpUrl; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * HTTP Extension class. + * This class is only needed if the app you are calling is listening on HTTP. + * It contains properties that represent data that may be populated for an HTTP receiver. + */ +public final class HttpExtension { + + /** + * Convenience HttpExtension object for {@link HttpMethods#NONE} with empty queryString. + */ + public static final HttpExtension NONE = new HttpExtension(HttpMethods.NONE); + /** + * Convenience HttpExtension object for the {@link HttpMethods#GET} Verb with empty queryString. + */ + public static final HttpExtension GET = new HttpExtension(HttpMethods.GET); + /** + * Convenience HttpExtension object for the {@link HttpMethods#PUT} Verb with empty queryString. + */ + public static final HttpExtension PUT = new HttpExtension(HttpMethods.PUT); + /** + * Convenience HttpExtension object for the {@link HttpMethods#POST} Verb with empty queryString. + */ + public static final HttpExtension POST = new HttpExtension(HttpMethods.POST); + /** + * Convenience HttpExtension object for the {@link HttpMethods#DELETE} Verb with empty queryString. + */ + public static final HttpExtension DELETE = new HttpExtension(HttpMethods.DELETE); + /** + * Convenience HttpExtension object for the {@link HttpMethods#HEAD} Verb with empty queryString. + */ + public static final HttpExtension HEAD = new HttpExtension(HttpMethods.HEAD); + /** + * Convenience HttpExtension object for the {@link HttpMethods#CONNECT} Verb with empty queryString. + */ + public static final HttpExtension CONNECT = new HttpExtension(HttpMethods.CONNECT); + /** + * Convenience HttpExtension object for the {@link HttpMethods#OPTIONS} Verb with empty queryString. + */ + public static final HttpExtension OPTIONS = new HttpExtension(HttpMethods.OPTIONS); + /** + * Convenience HttpExtension object for the {@link HttpMethods#TRACE} Verb with empty queryString. + */ + public static final HttpExtension TRACE = new HttpExtension(HttpMethods.TRACE); + + /** + * HTTP verb. + */ + private HttpMethods method; + + /** + * HTTP query params. + */ + private Map> queryParams; + + /** + * HTTP headers. + */ + private Map headers; + + /** + * Construct a HttpExtension object. + * + * @param method Required value denoting the HttpMethod. + * @param queryParams map for the query parameters the HTTP call. + * @param headers map to set HTTP headers. + * @throws IllegalArgumentException on null method or queryString. + * @see HttpMethods for supported methods. + */ + public HttpExtension(HttpMethods method, + Map> queryParams, + Map headers) { + if (method == null) { + throw new IllegalArgumentException("HttpExtension method cannot be null"); + } + + this.method = method; + this.queryParams = Collections.unmodifiableMap(queryParams == null ? Collections.emptyMap() : queryParams); + this.headers = Collections.unmodifiableMap(headers == null ? Collections.emptyMap() : headers); + } + + /** + * Construct a HttpExtension object. + * + * @param method Required value denoting the HttpMethod. + * @throws IllegalArgumentException on null method or queryString. + * @see HttpMethods for supported methods. + */ + public HttpExtension(HttpMethods method) { + this(method, null, null); + } + + public HttpMethods getMethod() { + return method; + } + + public Map> getQueryParams() { + return queryParams; + } + + public Map getHeaders() { + return headers; + } + + /** + * Encodes the query string for the HTTP request. + * + * @return Encoded HTTP query string. + */ + public String encodeQueryString() { + if ((this.queryParams == null) || (this.queryParams.isEmpty())) { + return ""; + } + + HttpUrl.Builder urlBuilder = new HttpUrl.Builder(); + // Setting required values but we only need query params in the end. + urlBuilder.scheme("http").host("localhost"); + Optional.ofNullable(this.queryParams).orElse(Collections.emptyMap()).entrySet().stream() + .forEach(urlParameter -> + Optional.ofNullable(urlParameter.getValue()).orElse(Collections.emptyList()).stream() + .forEach(urlParameterValue -> + urlBuilder.addQueryParameter(urlParameter.getKey(), urlParameterValue))); + return urlBuilder.build().encodedQuery(); + } + + /** + * HTTP Methods supported. + */ + public enum HttpMethods { + NONE, + GET, + PUT, + POST, + DELETE, + HEAD, + CONNECT, + OPTIONS, + TRACE + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/InvokeMethodRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/InvokeMethodRequest.java new file mode 100644 index 0000000000..696f3a54a0 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/InvokeMethodRequest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.invocation; + +import java.util.Map; + +/** + * A request to invoke a service. + */ +public class InvokeMethodRequest { + + private final String appId; + + private final String method; + + private Object body; + + private HttpExtension httpExtension; + + private String contentType; + + private Map metadata; + + public InvokeMethodRequest(String appId, String method) { + this.appId = appId; + this.method = method; + } + + public String getAppId() { + return appId; + } + + public String getMethod() { + return method; + } + + public Object getBody() { + return body; + } + + public InvokeMethodRequest setBody(Object body) { + this.body = body; + return this; + } + + public HttpExtension getHttpExtension() { + return httpExtension; + } + + public InvokeMethodRequest setHttpExtension(HttpExtension httpExtension) { + this.httpExtension = httpExtension; + return this; + } + + public String getContentType() { + return contentType; + } + + public InvokeMethodRequest setContentType(String contentType) { + this.contentType = contentType; + return this; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/Metadata.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/Metadata.java new file mode 100644 index 0000000000..19c00a23ae --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/invocation/Metadata.java @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.invocation; + +/** + * Enumerates commonly used metadata attributes. + */ +public final class Metadata { + + public static final String CONTENT_TYPE = "content-type"; + + public static final String TTL_IN_SECONDS = "ttlInSeconds"; + + private Metadata() { + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/pubsub/PublishEventRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/pubsub/PublishEventRequest.java new file mode 100644 index 0000000000..23ed0ab0f4 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/pubsub/PublishEventRequest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.pubsub; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A request to publish an event. + */ +public class PublishEventRequest { + + private final String pubsubName; + + private final String topic; + + private final Object data; + + private String contentType; + + private Map metadata = new HashMap<>(); + + /** + * Constructor for PublishEventRequest. + * + * @param pubsubName name of the pubsub + * @param topic name of the topic in the pubsub + * @param data data to published + */ + public PublishEventRequest(String pubsubName, String topic, Object data) { + this.pubsubName = pubsubName; + this.topic = topic; + this.data = data; + } + + public String getPubsubName() { + return pubsubName; + } + + public String getTopic() { + return topic; + } + + public Object getData() { + return data; + } + + public String getContentType() { + return this.contentType; + } + + public PublishEventRequest setContentType(String contentType) { + this.contentType = contentType; + return this; + } + + public Map getMetadata() { + return metadata; + } + + public PublishEventRequest setMetadata(Map metadata) { + this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); + return this; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/DeleteStateRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/DeleteStateRequest.java new file mode 100644 index 0000000000..2e36361b71 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/DeleteStateRequest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Collections; +import java.util.Map; + +/** + * A request to delete a state by key. + */ +public class DeleteStateRequest { + + private final String stateStoreName; + + private final String key; + + private Map metadata; + + private String etag; + + private StateOptions stateOptions; + + public DeleteStateRequest(String storeName, String key) { + this.stateStoreName = storeName; + this.key = key; + } + + public String getStateStoreName() { + return stateStoreName; + } + + public String getKey() { + return key; + } + + public String getEtag() { + return etag; + } + + public DeleteStateRequest setEtag(String etag) { + this.etag = etag; + return this; + } + + public StateOptions getStateOptions() { + return stateOptions; + } + + public DeleteStateRequest setStateOptions(StateOptions stateOptions) { + this.stateOptions = stateOptions; + return this; + } + + public Map getMetadata() { + return metadata; + } + + public DeleteStateRequest setMetadata(Map metadata) { + this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); + return this; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/ExecuteStateTransactionRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/ExecuteStateTransactionRequest.java new file mode 100644 index 0000000000..8bed077580 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/ExecuteStateTransactionRequest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class ExecuteStateTransactionRequest { + + /** + * Name of the state store. + */ + private final String stateStoreName; + + /** + * Transactional operations list. + */ + private List> operations; + + /** + * Metadata used for transactional operations. + */ + private Map metadata; + + public ExecuteStateTransactionRequest(String stateStoreName) { + this.stateStoreName = stateStoreName; + } + + public String getStateStoreName() { + return stateStoreName; + } + + public ExecuteStateTransactionRequest setOperations(List> operations) { + this.operations = operations == null ? null : Collections.unmodifiableList(operations); + return this; + } + + public List> getOperations() { + return operations; + } + + public ExecuteStateTransactionRequest setMetadata(Map metadata) { + this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); + return this; + } + + public Map getMetadata() { + return metadata; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/GetBulkStateRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/GetBulkStateRequest.java new file mode 100644 index 0000000000..11c5f5ae13 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/GetBulkStateRequest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * A request to get bulk state by keys. + */ +public class GetBulkStateRequest { + + private final String storeName; + + private final List keys; + + private Map metadata; + + private int parallelism = 1; + + public GetBulkStateRequest(String storeName, List keys) { + this.storeName = storeName; + this.keys = keys == null ? null : Collections.unmodifiableList(keys); + } + + public GetBulkStateRequest(String storeName, String... keys) { + this.storeName = storeName; + this.keys = keys == null ? null : Collections.unmodifiableList(Arrays.asList(keys)); + } + + public String getStoreName() { + return storeName; + } + + public List getKeys() { + return keys; + } + + public int getParallelism() { + return parallelism; + } + + public GetBulkStateRequest setParallelism(int parallelism) { + this.parallelism = parallelism; + return this; + } + + public Map getMetadata() { + return metadata; + } + + public GetBulkStateRequest setMetadata(Map metadata) { + this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); + return this; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/GetStateRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/GetStateRequest.java new file mode 100644 index 0000000000..141ef0eae3 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/GetStateRequest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Collections; +import java.util.Map; + +/** + * A request to get a state by key. + */ +public class GetStateRequest { + + private final String storeName; + + private final String key; + + private Map metadata; + + private StateOptions stateOptions; + + public GetStateRequest(String storeName, String key) { + this.storeName = storeName; + this.key = key; + } + + public String getStoreName() { + return storeName; + } + + public String getKey() { + return key; + } + + public StateOptions getStateOptions() { + return stateOptions; + } + + public GetStateRequest setStateOptions(StateOptions stateOptions) { + this.stateOptions = stateOptions; + return this; + } + + public Map getMetadata() { + return metadata; + } + + public GetStateRequest setMetadata(Map metadata) { + this.metadata = metadata == null ? null : Collections.unmodifiableMap(metadata); + return this; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/SaveStateRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/SaveStateRequest.java new file mode 100644 index 0000000000..da6aca2887 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/SaveStateRequest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * A request to save states to state store. + */ +public class SaveStateRequest { + + private final String storeName; + + private List> states; + + public SaveStateRequest(String storeName) { + this.storeName = storeName; + } + + public String getStoreName() { + return storeName; + } + + public List> getStates() { + return states; + } + + public SaveStateRequest setStates(List> states) { + this.states = states == null ? null : Collections.unmodifiableList(states); + return this; + } + + public SaveStateRequest setStates(State... states) { + this.states = Collections.unmodifiableList(Arrays.asList(states)); + return this; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/State.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/State.java new file mode 100644 index 0000000000..c25f733af7 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/State.java @@ -0,0 +1,276 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Map; + +/** + * This class reprent what a State is. + * + * @param The type of the value of the sate + */ +public class State { + + /** + * The value of the state. + */ + private final T value; + + /** + * The key of the state. + */ + private final String key; + + /** + * The ETag to be used + * Keep in mind that for some state stores (like redis) only numbers are supported. + */ + private final String etag; + + /** + * The metadata which will be passed to state store component. + */ + private final Map metadata; + + /** + * The error in case the key could not be retrieved. + */ + private final String error; + + /** + * The options used for saving the state. + */ + private final StateOptions options; + + /** + * Create an immutable state reference to be retrieved or deleted. + * This Constructor CAN be used anytime you need to retrieve or delete a state. + * + * @param key - The key of the state + */ + public State(String key) { + this.key = key; + this.value = null; + this.etag = null; + this.metadata = null; + this.options = null; + this.error = null; + } + + /** + * Create an immutable state reference to be retrieved or deleted. + * This Constructor CAN be used anytime you need to retrieve or delete a state. + * + * @param key - The key of the state + * @param etag - The etag of the state - Keep in mind that for some state stores (like redis) only numbers + * are supported. + * @param options - REQUIRED when saving a state. + */ + public State(String key, String etag, StateOptions options) { + this.value = null; + this.key = key; + this.etag = etag; + this.metadata = null; + this.options = options; + this.error = null; + } + + /** + * Create an immutable state. + * This Constructor CAN be used anytime you want the state to be saved. + * + * @param key - The key of the state. + * @param value - The value of the state. + * @param etag - The etag of the state - for some state stores (like redis) only numbers are supported. + * @param options - REQUIRED when saving a state. + */ + public State(String key, T value, String etag, StateOptions options) { + this.value = value; + this.key = key; + this.etag = etag; + this.metadata = null; + this.options = options; + this.error = null; + } + + /** + * Create an immutable state. + * This Constructor CAN be used anytime you want the state to be saved. + * + * @param key - The key of the state. + * @param value - The value of the state. + * @param etag - The etag of the state - for some state stores (like redis) only numbers are supported. + * @param metadata - The metadata of the state. + * @param options - REQUIRED when saving a state. + */ + public State(String key, T value, String etag, Map metadata, StateOptions options) { + this.value = value; + this.key = key; + this.etag = etag; + this.metadata = metadata; + this.options = options; + this.error = null; + } + + /** + * Create an immutable state. + * This Constructor CAN be used anytime you want the state to be saved. + * + * @param key - The key of the state. + * @param value - The value of the state. + * @param etag - The etag of the state - some state stores (like redis) only numbers are supported. + */ + public State(String key, T value, String etag) { + this.value = value; + this.key = key; + this.etag = etag; + this.metadata = null; + this.options = null; + this.error = null; + } + + /** + * Create an immutable state. + * This Constructor MUST be used anytime the key could not be retrieved and contains an error. + * + * @param key - The key of the state. + * @param error - Error when fetching the state. + */ + public State(String key, String error) { + this.value = null; + this.key = key; + this.etag = null; + this.metadata = null; + this.options = null; + this.error = error; + } + + /** + * Retrieves the Value of the state. + * + * @return The value of the state + */ + public T getValue() { + return value; + } + + /** + * Retrieves the Key of the state. + * + * @return The key of the state + */ + public String getKey() { + return key; + } + + /** + * Retrieve the ETag of this state. + * + * @return The etag of the state + */ + public String getEtag() { + return etag; + } + + /** + * Retrieve the metadata of this state. + * + * @return the metadata of this state + */ + public Map getMetadata() { + return metadata; + } + + /** + * Retrieve the error for this state. + * + * @return The error for this state. + */ + + public String getError() { + return error; + } + + /** + * Retrieve the Options used for saving the state. + * + * @return The options to save the state + */ + public StateOptions getOptions() { + return options; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof State)) { + return false; + } + + State that = (State) o; + + if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) { + return false; + } + + if (getKey() != null ? !getKey().equals(that.getKey()) : that.getKey() != null) { + return false; + } + + if (getEtag() != null ? !getEtag().equals(that.getEtag()) : that.getEtag() != null) { + return false; + } + + if (getError() != null ? !getError().equals(that.getError()) : that.getError() != null) { + return false; + } + + if (getMetadata() != null ? !getMetadata().equals(that.getMetadata()) : that.getMetadata() != null) { + return false; + } + + if (getOptions() != null ? !getOptions().equals(that.getOptions()) : that.getOptions() != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = getValue() != null ? getValue().hashCode() : 0; + result = 31 * result + (getKey() != null ? getKey().hashCode() : 0); + result = 31 * result + (getEtag() != null ? getEtag().hashCode() : 0); + result = 31 * result + (getMetadata() != null ? getMetadata().hashCode() : 0); + result = 31 * result + (getError() != null ? getError().hashCode() : 0); + result = 31 * result + (getOptions() != null ? options.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "StateKeyValue{" + + "key='" + key + "'" + + ", value=" + value + + ", etag='" + etag + "'" + + ", metadata={'" + (metadata != null ? metadata.toString() : null) + "'}" + + ", error='" + error + "'" + + ", options={'" + (options != null ? options.toString() : null) + "'}" + + "}"; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/StateOptions.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/StateOptions.java new file mode 100644 index 0000000000..2874b4299d --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/StateOptions.java @@ -0,0 +1,101 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class StateOptions { + + private final Consistency consistency; + private final Concurrency concurrency; + + /** + * Represents options for a CloudRuntimes state API call. + * + * @param consistency The consistency mode. + * @param concurrency The concurrency mode. + */ + public StateOptions(Consistency consistency, Concurrency concurrency) { + this.consistency = consistency; + this.concurrency = concurrency; + } + + public Concurrency getConcurrency() { + return concurrency; + } + + public Consistency getConsistency() { + return consistency; + } + + /** + * Returns state options as a Map of option name to value. + * + * @return A map of state options. + */ + public Map getStateOptionsAsMap() { + Map mapOptions = new HashMap<>(); + if (this.getConsistency() != null) { + mapOptions.put("consistency", this.getConsistency().getValue()); + } + if (this.getConcurrency() != null) { + mapOptions.put("concurrency", this.getConcurrency().getValue()); + } + return Collections.unmodifiableMap(Optional.ofNullable(mapOptions).orElse(Collections.EMPTY_MAP)); + } + + public enum Consistency { + + EVENTUAL("eventual"), + STRONG("strong"); + + private final String value; + + Consistency(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + public static Consistency fromValue(String value) { + return Consistency.valueOf(value); + } + } + + public enum Concurrency { + + FIRST_WRITE("first-write"), + LAST_WRITE("last-write"); + + private final String value; + + Concurrency(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + public static Concurrency fromValue(String value) { + return Concurrency.valueOf(value); + } + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/TransactionalStateOperation.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/TransactionalStateOperation.java new file mode 100644 index 0000000000..81f8d17990 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/TransactionalStateOperation.java @@ -0,0 +1,80 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Objects; + +public class TransactionalStateOperation { + + /** + * The type of operation to be executed. + */ + private final OperationType operation; + + /** + * State values to be operated on. + */ + private final State request; + + /** + * Construct an immutable transactional state operation object. + * + * @param operationType The type of operation done. + * @param state The required state. + */ + public TransactionalStateOperation(OperationType operationType, State state) { + this.operation = operationType; + this.request = state; + } + + public OperationType getOperation() { + return operation; + } + + public State getRequest() { + return request; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TransactionalStateOperation that = (TransactionalStateOperation) o; + return operation.equals(that.operation) + && request.equals(that.request); + } + + @Override + public int hashCode() { + return Objects.hash(operation, request); + } + + @Override + public String toString() { + return "TransactionalStateOperation{" + + "operationType='" + operation + '\'' + + ", state=" + request + + '}'; + } + + public enum OperationType { + UPSERT, + DELETE + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/TransactionalStateRequest.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/TransactionalStateRequest.java new file mode 100644 index 0000000000..620b306976 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/core/state/TransactionalStateRequest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.core.state; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class TransactionalStateRequest { + + /** + * Transactional operations list. + */ + private final List> operations; + + /** + * Metadata used for transactional operations. + */ + private final Map metadata; + + /** + * Constructor to create immutable transactional state request object. + * + * @param operations List of operations to be performed. + * @param metadata Metadata used for transactional operations. + */ + public TransactionalStateRequest(List> operations, Map metadata) { + this.operations = operations; + this.metadata = metadata; + } + + public List> getOperations() { + return Collections.unmodifiableList(operations); + } + + public Map getMetadata() { + return metadata; + } +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/enhanced/MetricsRuntimes.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/enhanced/MetricsRuntimes.java new file mode 100644 index 0000000000..db5069b642 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/enhanced/MetricsRuntimes.java @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.domain.enhanced; + +/** + * Metrics Runtimes standard API defined. + */ +public interface MetricsRuntimes { + + // TODO: 2021/8/31 API + // see https://github.com/reactivegroup/cloud-runtimes-jvm/issues/2 +} diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/package-info.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/package-info.java new file mode 100644 index 0000000000..c046d9eacf --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/domain/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +/** + * Building blocks address common challenges in building resilient, microservices applications and codify best practices and patterns. + * CloudRuntimes consists of a set of building blocks, with extensibility to add new building blocks. + */ +package spec.sdk.reactor.v1.domain; \ No newline at end of file diff --git a/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/utils/TypeRef.java b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/utils/TypeRef.java new file mode 100644 index 0000000000..7f6ded6914 --- /dev/null +++ b/sdk/java-sdk/sdk-reactor/src/main/java/spec/sdk/reactor/v1/utils/TypeRef.java @@ -0,0 +1,162 @@ +/* + * Copyright 2021 Layotto Authors + * Licensed 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. + */ +package spec.sdk.reactor.v1.utils; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * Used to reference a type. + * + *

Usage: new TypeRef<MyClass>(){}

+ * + * @param Type to be deserialized. + */ +public abstract class TypeRef { + + public static final TypeRef STRING = new TypeRef() { + }; + + public static final TypeRef BOOLEAN = new TypeRef(boolean.class) { + }; + + public static final TypeRef INT = new TypeRef(int.class) { + }; + + public static final TypeRef LONG = new TypeRef(long.class) { + }; + + public static final TypeRef CHAR = new TypeRef(char.class) { + }; + + public static final TypeRef BYTE = new TypeRef(byte.class) { + }; + + public static final TypeRef VOID = new TypeRef(void.class) { + }; + + public static final TypeRef FLOAT = new TypeRef(float.class) { + }; + + public static final TypeRef DOUBLE = new TypeRef(double.class) { + }; + + public static final TypeRef BYTE_ARRAY = new TypeRef() { + }; + + public static final TypeRef INT_ARRAY = new TypeRef() { + }; + + public static final TypeRef STRING_ARRAY = new TypeRef() { + }; + + private final Type type; + + /** + * Constructor. + */ + public TypeRef() { + Type superClass = this.getClass().getGenericSuperclass(); + if (superClass instanceof Class) { + throw new IllegalArgumentException("TypeReference requires type."); + } + + this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; + } + + /** + * Constructor for reflection. + * + * @param type Type to be referenced. + */ + private TypeRef(Type type) { + this.type = type; + } + + /** + * Gets the type referenced. + * + * @return type referenced. + */ + public Type getType() { + return this.type; + } + + /** + * Creates a reference to a given class type. + * + * @param clazz Class type to be referenced. + * @param Type to be referenced. + * @return Class type reference. + */ + public static TypeRef get(Class clazz) { + if (clazz == String.class) { + return (TypeRef) STRING; + } + if (clazz == boolean.class) { + return (TypeRef) BOOLEAN; + } + if (clazz == int.class) { + return (TypeRef) INT; + } + if (clazz == long.class) { + return (TypeRef) LONG; + } + if (clazz == char.class) { + return (TypeRef) CHAR; + } + if (clazz == byte.class) { + return (TypeRef) BYTE; + } + if (clazz == void.class) { + return (TypeRef) VOID; + } + if (clazz == float.class) { + return (TypeRef) FLOAT; + } + if (clazz == double.class) { + return (TypeRef) DOUBLE; + } + if (clazz == byte[].class) { + return (TypeRef) BYTE_ARRAY; + } + if (clazz == int[].class) { + return (TypeRef) INT_ARRAY; + } + if (clazz == String[].class) { + return (TypeRef) STRING_ARRAY; + } + + return new TypeRef(clazz) { + }; + } + + /** + * Creates a reference to a given class type. + * + * @param type Type to be referenced. + * @param Type to be referenced. + * @return Class type reference. + */ + public static TypeRef get(Type type) { + if (type instanceof Class) { + Class clazz = (Class) type; + return get(clazz); + } + + return new TypeRef(type) { + }; + } +} diff --git a/sdk/java-sdk/sdk/pom.xml b/sdk/java-sdk/sdk/pom.xml index 57e8d51182..792b2e794f 100644 --- a/sdk/java-sdk/sdk/pom.xml +++ b/sdk/java-sdk/sdk/pom.xml @@ -15,6 +15,12 @@ jar + + + io.mosn.layotto + runtime-spec-pb + + com.alibaba fastjson @@ -81,29 +87,6 @@ - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.6.1 - - com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier} - - grpc-java - io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} - - false - ${basedir}/../../../spec - src/main/java - - - - - compile - compile-custom - - - - org.apache.maven.plugins maven-source-plugin diff --git a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/AbstractRuntimeClient.java b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/AbstractRuntimeClient.java index c538971386..16ca30c2d5 100644 --- a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/AbstractRuntimeClient.java +++ b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/AbstractRuntimeClient.java @@ -20,7 +20,14 @@ import org.slf4j.Logger; import spec.sdk.runtime.v1.client.RuntimeClient; import spec.sdk.runtime.v1.domain.invocation.InvokeResponse; -import spec.sdk.runtime.v1.domain.state.*; +import spec.sdk.runtime.v1.domain.state.DeleteStateRequest; +import spec.sdk.runtime.v1.domain.state.ExecuteStateTransactionRequest; +import spec.sdk.runtime.v1.domain.state.GetBulkStateRequest; +import spec.sdk.runtime.v1.domain.state.GetStateRequest; +import spec.sdk.runtime.v1.domain.state.SaveStateRequest; +import spec.sdk.runtime.v1.domain.state.State; +import spec.sdk.runtime.v1.domain.state.StateOptions; +import spec.sdk.runtime.v1.domain.state.TransactionalStateOperation; import java.util.ArrayList; import java.util.Collections; diff --git a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeClientGrpc.java b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeClientGrpc.java index fdc14dda2b..21bf4a8f53 100644 --- a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeClientGrpc.java +++ b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeClientGrpc.java @@ -30,36 +30,35 @@ import org.slf4j.Logger; import spec.proto.runtime.v1.RuntimeGrpc; import spec.proto.runtime.v1.RuntimeProto; -import spec.sdk.runtime.v1.domain.file.GetFileRequest; -import spec.sdk.runtime.v1.domain.file.PutFileRequest; import spec.sdk.runtime.v1.domain.file.DelFileRequest; -import spec.sdk.runtime.v1.domain.file.GetFileResponse; -import spec.sdk.runtime.v1.domain.file.PutFileResponse; import spec.sdk.runtime.v1.domain.file.DelFileResponse; -import spec.sdk.runtime.v1.domain.file.ListFileResponse; -import spec.sdk.runtime.v1.domain.file.ListFileRequest; -import spec.sdk.runtime.v1.domain.file.GetMeteResponse; -import spec.sdk.runtime.v1.domain.file.GetMetaRequest; import spec.sdk.runtime.v1.domain.file.FileInfo; +import spec.sdk.runtime.v1.domain.file.GetFileRequest; +import spec.sdk.runtime.v1.domain.file.GetFileResponse; +import spec.sdk.runtime.v1.domain.file.GetMetaRequest; +import spec.sdk.runtime.v1.domain.file.GetMeteResponse; +import spec.sdk.runtime.v1.domain.file.ListFileRequest; +import spec.sdk.runtime.v1.domain.file.ListFileResponse; +import spec.sdk.runtime.v1.domain.file.PutFileRequest; +import spec.sdk.runtime.v1.domain.file.PutFileResponse; import spec.sdk.runtime.v1.domain.invocation.InvokeResponse; import spec.sdk.runtime.v1.domain.state.DeleteStateRequest; +import spec.sdk.runtime.v1.domain.state.ExecuteStateTransactionRequest; +import spec.sdk.runtime.v1.domain.state.GetBulkStateRequest; +import spec.sdk.runtime.v1.domain.state.GetStateRequest; import spec.sdk.runtime.v1.domain.state.SaveStateRequest; import spec.sdk.runtime.v1.domain.state.State; import spec.sdk.runtime.v1.domain.state.StateOptions; -import spec.sdk.runtime.v1.domain.state.ExecuteStateTransactionRequest; import spec.sdk.runtime.v1.domain.state.TransactionalStateOperation; -import spec.sdk.runtime.v1.domain.state.GetStateRequest; -import spec.sdk.runtime.v1.domain.state.GetBulkStateRequest; import java.io.IOException; -import java.io.PipedOutputStream; -import java.io.PipedInputStream; import java.io.InputStream; -import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeServerGrpc.java b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeServerGrpc.java index 4b7685e0d8..6409d1035c 100644 --- a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeServerGrpc.java +++ b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/RuntimeServerGrpc.java @@ -18,8 +18,8 @@ import io.grpc.ServerBuilder; import io.mosn.layotto.v1.callback.GrpcAppCallbackImpl; import io.mosn.layotto.v1.callback.component.pubsub.Subscriber; -import io.mosn.layotto.v1.callback.component.pubsub.SubscriberRegistryImpl; import io.mosn.layotto.v1.callback.component.pubsub.SubscriberRegistry; +import io.mosn.layotto.v1.callback.component.pubsub.SubscriberRegistryImpl; import io.mosn.layotto.v1.grpc.ExceptionHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/config/RuntimeProperties.java b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/config/RuntimeProperties.java index 224cb353e4..4f09bad204 100644 --- a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/config/RuntimeProperties.java +++ b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/config/RuntimeProperties.java @@ -16,8 +16,6 @@ import io.mosn.layotto.v1.domain.ApiProtocol; -import java.util.function.Supplier; - public class RuntimeProperties { /** diff --git a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/GrpcRuntimeClient.java b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/GrpcRuntimeClient.java index 3a6e136a28..38c3d7e713 100644 --- a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/GrpcRuntimeClient.java +++ b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/GrpcRuntimeClient.java @@ -14,7 +14,6 @@ */ package io.mosn.layotto.v1.grpc; -import io.grpc.ManagedChannel; import io.mosn.layotto.v1.grpc.stub.StubManager; import spec.proto.runtime.v1.RuntimeGrpc; import spec.sdk.runtime.v1.client.RuntimeClient; diff --git a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/stub/RRPool.java b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/stub/RRPool.java index 2b9843bb9e..d0fea1be9a 100644 --- a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/stub/RRPool.java +++ b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/grpc/stub/RRPool.java @@ -15,7 +15,6 @@ package io.mosn.layotto.v1.grpc.stub; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; /** diff --git a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/serializer/AbstractSerializer.java b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/serializer/AbstractSerializer.java index 104fd4f4eb..ad1da68a61 100644 --- a/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/serializer/AbstractSerializer.java +++ b/sdk/java-sdk/sdk/src/main/java/io/mosn/layotto/v1/serializer/AbstractSerializer.java @@ -14,8 +14,6 @@ */ package io.mosn.layotto.v1.serializer; -import com.alibaba.fastjson.JSONObject; - import java.io.IOException; public abstract class AbstractSerializer implements ObjectSerializer { diff --git a/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/client/RuntimeClient.java b/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/client/RuntimeClient.java index d940a7815b..f19f7d50f6 100644 --- a/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/client/RuntimeClient.java +++ b/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/client/RuntimeClient.java @@ -14,7 +14,14 @@ */ package spec.sdk.runtime.v1.client; -import spec.sdk.runtime.v1.domain.*; +import spec.sdk.runtime.v1.domain.ConfigurationRuntime; +import spec.sdk.runtime.v1.domain.FileRuntime; +import spec.sdk.runtime.v1.domain.HelloRuntime; +import spec.sdk.runtime.v1.domain.InvocationRuntime; +import spec.sdk.runtime.v1.domain.LockRuntime; +import spec.sdk.runtime.v1.domain.PubSubRuntime; +import spec.sdk.runtime.v1.domain.SequencerRuntime; +import spec.sdk.runtime.v1.domain.StateRuntime; public interface RuntimeClient extends HelloRuntime, diff --git a/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/FileRuntime.java b/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/FileRuntime.java index ac502ad981..b4c77db984 100644 --- a/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/FileRuntime.java +++ b/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/FileRuntime.java @@ -14,16 +14,16 @@ */ package spec.sdk.runtime.v1.domain; -import spec.sdk.runtime.v1.domain.file.GetFileRequest; -import spec.sdk.runtime.v1.domain.file.PutFileRequest; import spec.sdk.runtime.v1.domain.file.DelFileRequest; -import spec.sdk.runtime.v1.domain.file.ListFileResponse; -import spec.sdk.runtime.v1.domain.file.ListFileRequest; +import spec.sdk.runtime.v1.domain.file.DelFileResponse; +import spec.sdk.runtime.v1.domain.file.GetFileRequest; +import spec.sdk.runtime.v1.domain.file.GetFileResponse; import spec.sdk.runtime.v1.domain.file.GetMetaRequest; import spec.sdk.runtime.v1.domain.file.GetMeteResponse; +import spec.sdk.runtime.v1.domain.file.ListFileRequest; +import spec.sdk.runtime.v1.domain.file.ListFileResponse; +import spec.sdk.runtime.v1.domain.file.PutFileRequest; import spec.sdk.runtime.v1.domain.file.PutFileResponse; -import spec.sdk.runtime.v1.domain.file.GetFileResponse; -import spec.sdk.runtime.v1.domain.file.DelFileResponse; public interface FileRuntime { diff --git a/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/StateRuntime.java b/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/StateRuntime.java index 82cbceea58..0480c99529 100644 --- a/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/StateRuntime.java +++ b/sdk/java-sdk/sdk/src/main/java/spec/sdk/runtime/v1/domain/StateRuntime.java @@ -14,7 +14,14 @@ */ package spec.sdk.runtime.v1.domain; -import spec.sdk.runtime.v1.domain.state.*; +import spec.sdk.runtime.v1.domain.state.DeleteStateRequest; +import spec.sdk.runtime.v1.domain.state.ExecuteStateTransactionRequest; +import spec.sdk.runtime.v1.domain.state.GetBulkStateRequest; +import spec.sdk.runtime.v1.domain.state.GetStateRequest; +import spec.sdk.runtime.v1.domain.state.SaveStateRequest; +import spec.sdk.runtime.v1.domain.state.State; +import spec.sdk.runtime.v1.domain.state.StateOptions; +import spec.sdk.runtime.v1.domain.state.TransactionalStateOperation; import java.util.List; import java.util.Map; diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTest.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTest.java index 0af7c573c9..e25b9d3ef4 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTest.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTest.java @@ -27,15 +27,15 @@ import org.junit.runners.JUnit4; import spec.proto.runtime.v1.RuntimeGrpc; import spec.sdk.runtime.v1.client.RuntimeClient; -import spec.sdk.runtime.v1.domain.file.GetFileRequest; -import spec.sdk.runtime.v1.domain.file.PutFileRequest; import spec.sdk.runtime.v1.domain.file.DelFileRequest; -import spec.sdk.runtime.v1.domain.file.ListFileRequest; +import spec.sdk.runtime.v1.domain.file.FileInfo; +import spec.sdk.runtime.v1.domain.file.GetFileRequest; +import spec.sdk.runtime.v1.domain.file.GetFileResponse; import spec.sdk.runtime.v1.domain.file.GetMetaRequest; import spec.sdk.runtime.v1.domain.file.GetMeteResponse; -import spec.sdk.runtime.v1.domain.file.GetFileResponse; +import spec.sdk.runtime.v1.domain.file.ListFileRequest; import spec.sdk.runtime.v1.domain.file.ListFileResponse; -import spec.sdk.runtime.v1.domain.file.FileInfo; +import spec.sdk.runtime.v1.domain.file.PutFileRequest; import java.io.ByteArrayInputStream; import java.util.HashMap; diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTestWithRealServer.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTestWithRealServer.java index 15402b2fb5..4803adb6fc 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTestWithRealServer.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/FileTestWithRealServer.java @@ -26,15 +26,15 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import spec.proto.runtime.v1.RuntimeGrpc; -import spec.sdk.runtime.v1.domain.file.GetFileRequest; -import spec.sdk.runtime.v1.domain.file.PutFileRequest; import spec.sdk.runtime.v1.domain.file.DelFileRequest; -import spec.sdk.runtime.v1.domain.file.ListFileRequest; +import spec.sdk.runtime.v1.domain.file.FileInfo; +import spec.sdk.runtime.v1.domain.file.GetFileRequest; +import spec.sdk.runtime.v1.domain.file.GetFileResponse; import spec.sdk.runtime.v1.domain.file.GetMetaRequest; import spec.sdk.runtime.v1.domain.file.GetMeteResponse; -import spec.sdk.runtime.v1.domain.file.GetFileResponse; +import spec.sdk.runtime.v1.domain.file.ListFileRequest; import spec.sdk.runtime.v1.domain.file.ListFileResponse; -import spec.sdk.runtime.v1.domain.file.FileInfo; +import spec.sdk.runtime.v1.domain.file.PutFileRequest; import java.io.ByteArrayInputStream; import java.util.HashMap; diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/PublishEventTestWithRealServer.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/PublishEventTestWithRealServer.java index 0cca310c88..f33ac3cba9 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/PublishEventTestWithRealServer.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/PublishEventTestWithRealServer.java @@ -16,23 +16,17 @@ import io.grpc.Server; import io.grpc.ServerBuilder; -import io.grpc.testing.GrpcCleanupRule; import io.mosn.layotto.v1.grpc.ExceptionHandler; import io.mosn.layotto.v1.grpc.GrpcRuntimeClient; import io.mosn.layotto.v1.mock.MyPublishService; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import spec.proto.runtime.v1.RuntimeGrpc; import spec.proto.runtime.v1.RuntimeProto; -import static org.mockito.AdditionalAnswers.delegatesTo; -import static org.mockito.Mockito.mock; - @RunWith(JUnit4.class) public class PublishEventTestWithRealServer { diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTest.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTest.java index 435efae6bf..1c1eeca68c 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTest.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTest.java @@ -18,17 +18,11 @@ import io.grpc.inprocess.InProcessChannelBuilder; import io.grpc.inprocess.InProcessServerBuilder; import io.grpc.testing.GrpcCleanupRule; -import io.mosn.layotto.v1.config.RuntimeProperties; -import io.mosn.layotto.v1.domain.ApiProtocol; -import io.mosn.layotto.v1.serializer.JSONSerializer; -import io.mosn.layotto.v1.serializer.ObjectSerializer; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import spec.proto.runtime.v1.RuntimeGrpc; import spec.proto.runtime.v1.RuntimeProto; import spec.sdk.runtime.v1.client.RuntimeClient; diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTestWithRealServer.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTestWithRealServer.java index 8aee6fd52e..a664f5ae0b 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTestWithRealServer.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/SayHelloTestWithRealServer.java @@ -27,7 +27,6 @@ import spec.proto.runtime.v1.RuntimeGrpc; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; @RunWith(JUnit4.class) public class SayHelloTestWithRealServer { diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/StateTestWithRealServer.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/StateTestWithRealServer.java index f048a34f80..0955f36cea 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/StateTestWithRealServer.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/StateTestWithRealServer.java @@ -36,8 +36,6 @@ import java.util.Arrays; import java.util.List; -import static org.mockito.Mockito.mock; - @RunWith(JUnit4.class) public class StateTestWithRealServer { diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/grpc/stub/RRPoolTest.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/grpc/stub/RRPoolTest.java index 131028a21c..ed786436ac 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/grpc/stub/RRPoolTest.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/grpc/stub/RRPoolTest.java @@ -14,7 +14,6 @@ */ package io.mosn.layotto.v1.grpc.stub; -import io.mosn.layotto.v1.grpc.stub.RRPool; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/mock/MyHelloService.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/mock/MyHelloService.java index 88cdfda630..543b23c79b 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/mock/MyHelloService.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/mock/MyHelloService.java @@ -14,15 +14,10 @@ */ package io.mosn.layotto.v1.mock; -import com.google.protobuf.Empty; import io.grpc.stub.StreamObserver; import spec.proto.runtime.v1.RuntimeGrpc; import spec.proto.runtime.v1.RuntimeProto; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class MyHelloService extends RuntimeGrpc.RuntimeImplBase { @Override diff --git a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/serializer/JSONSerializerTest.java b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/serializer/JSONSerializerTest.java index b1d6dca8d3..4a1b555580 100644 --- a/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/serializer/JSONSerializerTest.java +++ b/sdk/java-sdk/sdk/src/test/java/io/mosn/layotto/v1/serializer/JSONSerializerTest.java @@ -18,12 +18,9 @@ import org.junit.Assert; import org.junit.Test; -import spec.proto.runtime.v1.RuntimeProto; import java.io.IOException; import java.io.Serializable; -import java.util.Base64; -import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; diff --git a/sdk/java-sdk/spec/pom.xml b/sdk/java-sdk/spec/pom.xml new file mode 100644 index 0000000000..86eda98ac7 --- /dev/null +++ b/sdk/java-sdk/spec/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + + + io.mosn.layotto + runtime-sdk-parent + 1.1.0-SNAPSHOT + + + runtime-spec-pb + runtime-spec-pb + jar + + + + io.grpc + grpc-all + + + + + src/main/java + + + src/main/resources + true + + **/** + + + + proto + true + + **/*.proto + + + + + src/test/java + + + src/test/resources + true + + **/** + + + + + + + kr.motd.maven + os-maven-plugin + 1.4.1.Final + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier} + + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + false + ${basedir}/../../../spec + src/main/java + + + + + compile + compile-custom + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + + + + + + \ No newline at end of file diff --git a/sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/AppCallbackGrpc.java b/sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/AppCallbackGrpc.java similarity index 100% rename from sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/AppCallbackGrpc.java rename to sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/AppCallbackGrpc.java diff --git a/sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/AppCallbackProto.java b/sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/AppCallbackProto.java similarity index 100% rename from sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/AppCallbackProto.java rename to sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/AppCallbackProto.java diff --git a/sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/RuntimeGrpc.java b/sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/RuntimeGrpc.java similarity index 100% rename from sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/RuntimeGrpc.java rename to sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/RuntimeGrpc.java diff --git a/sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/RuntimeProto.java b/sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/RuntimeProto.java similarity index 100% rename from sdk/java-sdk/sdk/src/main/java/spec/proto/runtime/v1/RuntimeProto.java rename to sdk/java-sdk/spec/src/main/java/spec/proto/runtime/v1/RuntimeProto.java