diff --git a/src/main/java/io/eigr/spawn/api/ActorRef.java b/src/main/java/io/eigr/spawn/api/ActorRef.java index 2609eec..bf72788 100644 --- a/src/main/java/io/eigr/spawn/api/ActorRef.java +++ b/src/main/java/io/eigr/spawn/api/ActorRef.java @@ -7,8 +7,10 @@ import com.google.protobuf.GeneratedMessageV3; import io.eigr.functions.protocol.Protocol; import io.eigr.functions.protocol.actors.ActorOuterClass; -import io.eigr.spawn.api.exceptions.ActorInvokeException; +import io.eigr.spawn.api.exceptions.ActorCreationException; +import io.eigr.spawn.api.exceptions.ActorInvocationException; import io.eigr.spawn.api.exceptions.ActorNotFoundException; +import io.eigr.spawn.api.exceptions.SpawnException; import io.eigr.spawn.internal.transport.client.SpawnClient; import java.time.Duration; @@ -49,7 +51,7 @@ private ActorRef(ActorOuterClass.ActorId actorId, SpawnClient client) { * @return the ActorRef instance * @since 0.0.1 */ - protected static ActorRef of(SpawnClient client, String system, String name) throws Exception { + protected static ActorRef of(SpawnClient client, String system, String name) throws ActorCreationException { ActorOuterClass.ActorId actorId = buildActorId(system, name); ActorRef ref = ACTOR_REF_CACHE.getIfPresent(actorId); if (Objects.nonNull(ref)) { @@ -72,7 +74,7 @@ protected static ActorRef of(SpawnClient client, String system, String name) thr * @return the ActorRef instance * @since 0.0.1 */ - protected static ActorRef of(SpawnClient client, String system, String name, String parent) throws Exception { + protected static ActorRef of(SpawnClient client, String system, String name, String parent) throws ActorCreationException { ActorOuterClass.ActorId actorId = buildActorId(system, name, parent); ActorRef ref = ACTOR_REF_CACHE.getIfPresent(actorId); if (Objects.nonNull(ref)) { @@ -101,7 +103,7 @@ private static ActorOuterClass.ActorId buildActorId(String system, String name, .build(); } - private static void spawnActor(ActorOuterClass.ActorId actorId, SpawnClient client) throws Exception { + private static void spawnActor(ActorOuterClass.ActorId actorId, SpawnClient client) throws ActorCreationException { Protocol.SpawnRequest req = Protocol.SpawnRequest.newBuilder() .addActors(actorId) .build(); @@ -118,13 +120,10 @@ private static void spawnActor(ActorOuterClass.ActorId actorId, SpawnClient clie * @return an Optional containing, or not, the response object to the Action call * @since 0.0.1 */ - public Optional invoke(String action, Class outputType) throws Exception { + public Optional invoke(String action, Class outputType) throws ActorInvocationException { Optional res = invokeActor(action, Empty.getDefaultInstance(), outputType, Optional.empty()); - if (res.isPresent()) { - return Optional.of(outputType.cast(res.get())); - } + return res.map(outputType::cast); - return res; } /** @@ -139,13 +138,10 @@ public Optional invoke(String action, Class * @return an Optional containing, or not, the response object to the Action call * @since 0.0.1 */ - public Optional invoke(String action, Class outputType, InvocationOpts opts) throws Exception { + public Optional invoke(String action, Class outputType, InvocationOpts opts) throws ActorInvocationException { Optional res = invokeActor(action, Empty.getDefaultInstance(), outputType, Optional.ofNullable(opts)); - if (res.isPresent()) { - return Optional.of(outputType.cast(res.get())); - } + return res.map(outputType::cast); - return res; } /** @@ -159,13 +155,10 @@ public Optional invoke(String action, Class * @return an Optional containing, or not, the response object to the Action call * @since 0.0.1 */ - public Optional invoke(String action, S value, Class outputType) throws Exception { + public Optional invoke(String action, S value, Class outputType) throws ActorInvocationException { Optional res = invokeActor(action, value, outputType, Optional.empty()); - if (res.isPresent()) { - return Optional.of(outputType.cast(res.get())); - } + return res.map(outputType::cast); - return res; } /** @@ -181,13 +174,10 @@ public Optional * @return an Optional containing, or not, the response object to the Action call * @since 0.0.1 */ - public Optional invoke(String action, S value, Class outputType, InvocationOpts opts) throws Exception { + public Optional invoke(String action, S value, Class outputType, InvocationOpts opts) throws ActorInvocationException { Optional res = invokeActor(action, value, outputType, Optional.ofNullable(opts)); - if (res.isPresent()) { - return Optional.of(outputType.cast(res.get())); - } + return res.map(outputType::cast); - return res; } /** @@ -198,7 +188,7 @@ public Optional * @param action name of the action to be called. * @since 0.0.1 */ - public void invokeAsync(String action) throws Exception { + public void invokeAsync(String action) throws ActorInvocationException { InvocationOpts opts = InvocationOpts.builder().async(true).build(); invokeActor(action, Empty.getDefaultInstance(), null, Optional.of(opts)); } @@ -213,10 +203,10 @@ public void invokeAsync(String action) throws Exc * Please see the {@link io.eigr.spawn.api.InvocationOpts} class for more information * @since 0.0.1 */ - public void invokeAsync(String action, InvocationOpts opts) throws Exception { + public void invokeAsync(String action, InvocationOpts opts) throws ActorInvocationException { InvocationOpts mergedOpts = InvocationOpts.builder() .async(true) - .delay(opts.getDelay()) + .delaySeconds(opts.getDelaySeconds()) .scheduledTo(opts.getScheduledTo()) .timeoutSeconds(opts.getTimeoutSeconds()) .build(); @@ -233,7 +223,7 @@ public void invokeAsync(String action, Invocation * @param value the action argument object. * @since 0.0.1 */ - public void invokeAsync(String action, S value) throws Exception { + public void invokeAsync(String action, S value) throws ActorInvocationException { InvocationOpts opts = InvocationOpts.builder().async(true).build(); invokeActor(action, value, null, Optional.of(opts)); } @@ -249,10 +239,10 @@ public void invokeA * Please see the {@link io.eigr.spawn.api.InvocationOpts} class for more information * @since 0.0.1 */ - public void invokeAsync(String action, S value, InvocationOpts opts) throws Exception { + public void invokeAsync(String action, S value, InvocationOpts opts) throws ActorInvocationException { InvocationOpts mergedOpts = InvocationOpts.builder() .async(true) - .delay(opts.getDelay()) + .delaySeconds(opts.getDelaySeconds()) .scheduledTo(opts.getScheduledTo()) .timeoutSeconds(opts.getTimeoutSeconds()) .build(); @@ -285,24 +275,20 @@ public boolean isUnNamedActor() { } private Optional invokeActor( - String cmd, S argument, Class outputType, Optional options) throws Exception { + String cmd, S argument, Class outputType, Optional options) throws ActorInvocationException { Objects.requireNonNull(this.actorId, "ActorId cannot be null"); Protocol.InvocationRequest.Builder invocationRequestBuilder = Protocol.InvocationRequest.newBuilder(); Map metadata = new HashMap<>(); - if (options.isPresent()) { - InvocationOpts opts = options.get(); + options.ifPresent(opts -> { invocationRequestBuilder.setAsync(opts.isAsync()); - - if (opts.getDelay().isPresent() && !opts.getScheduledTo().isPresent()) { - invocationRequestBuilder.setScheduledTo(opts.getDelay().get()); - } else if (opts.getScheduledTo().isPresent()) { - invocationRequestBuilder.setScheduledTo(opts.getScheduleTimeInLong()); - } - metadata.put("request-timeout", String.valueOf(opts.getTimeout())); - } + opts.getDelaySeconds().ifPresent(invocationRequestBuilder::setScheduledTo); + // 'scheduledTo' override 'delay' if both is set. + opts.getScheduledTo() + .ifPresent(scheduleTo -> invocationRequestBuilder.setScheduledTo(opts.getScheduleTimeInLong())); + }); final ActorOuterClass.Actor actorRef = ActorOuterClass.Actor.newBuilder() .setId(this.actorId) @@ -310,8 +296,6 @@ private Optional Any commandArg = Any.pack(argument); - - invocationRequestBuilder .setSystem(ActorOuterClass.ActorSystem.newBuilder().setName(this.actorId.getSystem()).build()) .setActor(actorRef) @@ -328,13 +312,16 @@ private Optional case UNRECOGNIZED: String msg = String.format("Error when trying to invoke Actor %s. Details: %s", this.getActorName(), status.getMessage()); - - throw new ActorInvokeException(msg); + throw new ActorInvocationException(msg); case ACTOR_NOT_FOUND: - throw new ActorNotFoundException(); + throw new ActorNotFoundException("Actor not found."); case OK: if (resp.hasValue() && Objects.nonNull(outputType)) { - return Optional.of(resp.getValue().unpack(outputType)); + try { + return Optional.of(resp.getValue().unpack(outputType)); + } catch (Exception e) { + throw new ActorInvocationException("Error handling response.", e); + } } return Optional.empty(); } diff --git a/src/main/java/io/eigr/spawn/api/InvocationOpts.java b/src/main/java/io/eigr/spawn/api/InvocationOpts.java index 6b92c09..575d29f 100644 --- a/src/main/java/io/eigr/spawn/api/InvocationOpts.java +++ b/src/main/java/io/eigr/spawn/api/InvocationOpts.java @@ -23,7 +23,7 @@ public class InvocationOpts { private Duration timeoutSeconds = Duration.ofSeconds(10); @Builder.Default - private Optional delay = Optional.empty(); + private Optional delaySeconds = Optional.empty(); @Builder.Default private Optional scheduledTo = Optional.empty(); diff --git a/src/main/java/io/eigr/spawn/api/actors/workflows/SideEffect.java b/src/main/java/io/eigr/spawn/api/actors/workflows/SideEffect.java index a2a46c4..4514294 100644 --- a/src/main/java/io/eigr/spawn/api/actors/workflows/SideEffect.java +++ b/src/main/java/io/eigr/spawn/api/actors/workflows/SideEffect.java @@ -43,14 +43,12 @@ public static SideEffect to(ActorRef actor, Strin public Protocol.SideEffect build() { Protocol.InvocationRequest.Builder requestBuilder = Protocol.InvocationRequest.newBuilder(); - if (this.opts.isPresent()) { - InvocationOpts options = this.opts.get(); - if (options.getDelay().isPresent() && !options.getScheduledTo().isPresent()) { - requestBuilder.setScheduledTo(options.getDelay().get()); - } else if (options.getScheduledTo().isPresent()) { - requestBuilder.setScheduledTo(options.getScheduleTimeInLong()); - } - } + opts.ifPresent(invocationOpts -> { + invocationOpts.getDelaySeconds().ifPresent(requestBuilder::setScheduledTo); + // 'scheduledTo' override 'delay' if both is set. + invocationOpts.getScheduledTo() + .ifPresent(scheduleTo -> requestBuilder.setScheduledTo(invocationOpts.getScheduleTimeInLong())); + }); requestBuilder.setSystem(ActorOuterClass.ActorSystem.newBuilder() .setName(this.actor.getActorSystem()) diff --git a/src/main/java/io/eigr/spawn/api/exceptions/ActorCreationException.java b/src/main/java/io/eigr/spawn/api/exceptions/ActorCreationException.java new file mode 100644 index 0000000..28ac7c0 --- /dev/null +++ b/src/main/java/io/eigr/spawn/api/exceptions/ActorCreationException.java @@ -0,0 +1,25 @@ +package io.eigr.spawn.api.exceptions; + +/** + * Actor Creation Exception. + * + * @author Paulo H3nrique Alves + */ +public class ActorCreationException extends SpawnException { + + public ActorCreationException() { + super(); + } + + public ActorCreationException(String s) { + super(s); + } + + public ActorCreationException(String message, Throwable cause) { + super(message, cause); + } + + public ActorCreationException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/io/eigr/spawn/api/exceptions/ActorInvocationException.java b/src/main/java/io/eigr/spawn/api/exceptions/ActorInvocationException.java new file mode 100644 index 0000000..b98c311 --- /dev/null +++ b/src/main/java/io/eigr/spawn/api/exceptions/ActorInvocationException.java @@ -0,0 +1,20 @@ +package io.eigr.spawn.api.exceptions; + +public class ActorInvocationException extends SpawnException { + + public ActorInvocationException() { + super(); + } + + public ActorInvocationException(String message) { + super(message); + } + + public ActorInvocationException(String message, Throwable cause) { + super(message, cause); + } + + public ActorInvocationException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/io/eigr/spawn/api/exceptions/ActorInvokeException.java b/src/main/java/io/eigr/spawn/api/exceptions/ActorInvokeException.java deleted file mode 100644 index 736b01b..0000000 --- a/src/main/java/io/eigr/spawn/api/exceptions/ActorInvokeException.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.eigr.spawn.api.exceptions; - -public final class ActorInvokeException extends IllegalStateException { - - public ActorInvokeException() {} - public ActorInvokeException(String message) { - super(message); - } -} diff --git a/src/main/java/io/eigr/spawn/api/exceptions/ActorNotFoundException.java b/src/main/java/io/eigr/spawn/api/exceptions/ActorNotFoundException.java index 2606a39..58acaa6 100644 --- a/src/main/java/io/eigr/spawn/api/exceptions/ActorNotFoundException.java +++ b/src/main/java/io/eigr/spawn/api/exceptions/ActorNotFoundException.java @@ -1,4 +1,24 @@ package io.eigr.spawn.api.exceptions; -public final class ActorNotFoundException extends IllegalArgumentException{ +/** + * Actor Registration Exception. + * + * @author Paulo H3nrique Alves + */ +public class ActorNotFoundException extends ActorInvocationException { + + public ActorNotFoundException() { + super(); + } + public ActorNotFoundException(String s) { + super(s); + } + + public ActorNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public ActorNotFoundException(Throwable cause) { + super(cause); + } } diff --git a/src/main/java/io/eigr/spawn/api/exceptions/ActorRegistrationException.java b/src/main/java/io/eigr/spawn/api/exceptions/ActorRegistrationException.java new file mode 100644 index 0000000..c662c9f --- /dev/null +++ b/src/main/java/io/eigr/spawn/api/exceptions/ActorRegistrationException.java @@ -0,0 +1,24 @@ +package io.eigr.spawn.api.exceptions; + +/** + * Actor Registration Exception. + * + * @author Paulo H3nrique Alves + */ +public class ActorRegistrationException extends SpawnException { + + public ActorRegistrationException() { + super(); + } + public ActorRegistrationException(String s) { + super(s); + } + + public ActorRegistrationException(String message, Throwable cause) { + super(message, cause); + } + + public ActorRegistrationException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/io/eigr/spawn/api/exceptions/SpawnException.java b/src/main/java/io/eigr/spawn/api/exceptions/SpawnException.java new file mode 100644 index 0000000..07c0f36 --- /dev/null +++ b/src/main/java/io/eigr/spawn/api/exceptions/SpawnException.java @@ -0,0 +1,25 @@ +package io.eigr.spawn.api.exceptions; + +/** + * Generic Spawn exception. + * + * @author Paulo H3nrique Alves + */ +public class SpawnException extends Exception { + + protected SpawnException() { + super(); + } + + public SpawnException(String s) { + super(s); + } + + public SpawnException(String message, Throwable cause) { + super(message, cause); + } + + public SpawnException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/io/eigr/spawn/internal/transport/client/OkHttpSpawnClient.java b/src/main/java/io/eigr/spawn/internal/transport/client/OkHttpSpawnClient.java index c134b49..3567823 100644 --- a/src/main/java/io/eigr/spawn/internal/transport/client/OkHttpSpawnClient.java +++ b/src/main/java/io/eigr/spawn/internal/transport/client/OkHttpSpawnClient.java @@ -1,6 +1,9 @@ package io.eigr.spawn.internal.transport.client; import io.eigr.functions.protocol.Protocol; +import io.eigr.spawn.api.exceptions.ActorCreationException; +import io.eigr.spawn.api.exceptions.ActorInvocationException; +import io.eigr.spawn.api.exceptions.ActorRegistrationException; import okhttp3.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +28,7 @@ public OkHttpSpawnClient(String system, String proxyHost, int proxyPort) { this.system = system; this.proxyHost = proxyHost; this.proxyPort = proxyPort; - this.client = new OkHttpClient.Builder() + this.client = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) @@ -36,7 +39,7 @@ public OkHttpSpawnClient(String system, String proxyHost, int proxyPort) { } @Override - public Protocol.RegistrationResponse register(Protocol.RegistrationRequest registration) throws Exception { + public Protocol.RegistrationResponse register(Protocol.RegistrationRequest registration) throws ActorRegistrationException { RequestBody body = RequestBody.create(registration.toByteArray(), MediaType.parse(SPAWN_MEDIA_TYPE)); Request request = new Request.Builder().url(makeURLFrom(SPAWN_REGISTER_URI)).post(body).build(); @@ -48,13 +51,12 @@ public Protocol.RegistrationResponse register(Protocol.RegistrationRequest regis Objects.requireNonNull(response.body() ).bytes()); } catch (Exception e) { - log.error("Error registering Actors", e); - throw new Exception(e); + throw new ActorRegistrationException("Error registering Actors", e); } } @Override - public Protocol.SpawnResponse spawn(Protocol.SpawnRequest registration) throws Exception { + public Protocol.SpawnResponse spawn(Protocol.SpawnRequest registration) throws ActorCreationException { RequestBody body = RequestBody.create(registration.toByteArray(), MediaType.parse(SPAWN_MEDIA_TYPE)); Request request = new Request.Builder() @@ -68,13 +70,12 @@ public Protocol.SpawnResponse spawn(Protocol.SpawnRequest registration) throws E Objects.requireNonNull(response.body() ).bytes()); } catch (Exception e) { - log.error("Error registering Actors", e); - throw new Exception(e); + throw new ActorCreationException("Error registering Actors", e); } } @Override - public Protocol.InvocationResponse invoke(Protocol.InvocationRequest request) throws Exception { + public Protocol.InvocationResponse invoke(Protocol.InvocationRequest request) throws ActorInvocationException { RequestBody body = RequestBody.create( request.toByteArray(), MediaType.parse(SPAWN_MEDIA_TYPE)); @@ -84,10 +85,13 @@ public Protocol.InvocationResponse invoke(Protocol.InvocationRequest request) th .build(); Call invocationCall = client.newCall(invocationRequest); - Response callInvocationResponse = invocationCall.execute(); - - return Protocol.InvocationResponse - .parseFrom(Objects.requireNonNull(callInvocationResponse.body()).bytes()); + try (Response callInvocationResponse = invocationCall.execute()){ + assert callInvocationResponse.body() != null; + return Protocol.InvocationResponse + .parseFrom(Objects.requireNonNull(callInvocationResponse.body()).bytes()); + } catch (Exception e) { + throw new ActorInvocationException(e); + } } private String makeURLForSystemAndActor(String systemName, String actorName) { diff --git a/src/main/java/io/eigr/spawn/internal/transport/client/SpawnClient.java b/src/main/java/io/eigr/spawn/internal/transport/client/SpawnClient.java index 02c1999..b273f6d 100644 --- a/src/main/java/io/eigr/spawn/internal/transport/client/SpawnClient.java +++ b/src/main/java/io/eigr/spawn/internal/transport/client/SpawnClient.java @@ -1,12 +1,14 @@ package io.eigr.spawn.internal.transport.client; import io.eigr.functions.protocol.Protocol; +import io.eigr.spawn.api.exceptions.ActorCreationException; +import io.eigr.spawn.api.exceptions.ActorInvocationException; +import io.eigr.spawn.api.exceptions.ActorRegistrationException; public interface SpawnClient { - Protocol.RegistrationResponse register(Protocol.RegistrationRequest registration) throws Exception; - - Protocol.SpawnResponse spawn(Protocol.SpawnRequest registration) throws Exception; - Protocol.InvocationResponse invoke(Protocol.InvocationRequest request) throws Exception; + Protocol.RegistrationResponse register(Protocol.RegistrationRequest registration) throws ActorRegistrationException; + Protocol.SpawnResponse spawn(Protocol.SpawnRequest registration) throws ActorCreationException; + Protocol.InvocationResponse invoke(Protocol.InvocationRequest request) throws ActorInvocationException; } diff --git a/src/main/java/io/eigr/spawn/internal/transport/server/ActorServiceHandler.java b/src/main/java/io/eigr/spawn/internal/transport/server/ActorServiceHandler.java index d21f905..7f2d37b 100644 --- a/src/main/java/io/eigr/spawn/internal/transport/server/ActorServiceHandler.java +++ b/src/main/java/io/eigr/spawn/internal/transport/server/ActorServiceHandler.java @@ -16,7 +16,7 @@ import io.eigr.spawn.api.actors.workflows.Forward; import io.eigr.spawn.api.actors.workflows.Pipe; import io.eigr.spawn.api.actors.workflows.SideEffect; -import io.eigr.spawn.api.exceptions.ActorInvokeException; +import io.eigr.spawn.api.exceptions.ActorInvocationException; import io.eigr.spawn.internal.Entity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,8 +62,8 @@ public void handle(HttpExchange exchange) throws IOException { log.debug("Received Actor Action Request."); if ("POST".equals(exchange.getRequestMethod())) { - Protocol.ActorInvocationResponse response = handleRequest(exchange); try (OutputStream os = exchange.getResponseBody()) { + Protocol.ActorInvocationResponse response = handleRequest(exchange); byte[] bytes = response.toByteArray(); exchange.getResponseHeaders().set("Content-Type", CONTENT_TYPE); exchange.sendResponseHeaders(200, bytes.length); @@ -116,13 +116,13 @@ private Protocol.ActorInvocationResponse handleRequest(HttpExchange exchange) th } } catch (Exception e) { - log.error("Error during handle request. Error: {}", e); + log.error("Error during handle request.", e); } - throw new ActorInvokeException("Action result is null"); + throw new IOException("Action result is null"); } - private Optional callAction(String system, String actor, String parent, String commandName, Any value, Protocol.Context context) { + private Optional callAction(String system, String actor, String parent, String commandName, Any value, Protocol.Context context) throws ActorInvocationException { Optional optionalEntity = getEntityByActor(actor, parent); if (optionalEntity.isPresent()) { Entity entity = optionalEntity.get(); @@ -142,7 +142,7 @@ private Optional callAction(String system, String actor, String parent, S } else if (entity.getTimerActions().containsKey(commandName)) { entityMethod = entity.getTimerActions().get(commandName); } else { - throw new ActorInvokeException( + throw new ActorInvocationException( String.format("The Actor does not have the desired action: %s", commandName)); } @@ -164,12 +164,12 @@ private Optional callAction(String system, String actor, String parent, S final Object unpack = value.unpack(inputType); return Optional.of((Value) actorMethod.invoke(actorRef, unpack, actorContext)); } - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new ActorInvocationException(e); } catch (InvalidProtocolBufferException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException | NoSuchMethodException | InstantiationException e) { - throw new RuntimeException(e); + throw new ActorInvocationException(e); + } catch (NoSuchMethodException | InstantiationException e) { + throw new ActorInvocationException(e); } }