|
@@ -1,140 +1,58 @@
|
|
|
package io.connector.core;
|
|
package io.connector.core;
|
|
|
|
|
|
|
|
import io.connector.core.module.ModuleType;
|
|
import io.connector.core.module.ModuleType;
|
|
|
-import io.vertx.core.MultiMap;
|
|
|
|
|
import io.vertx.core.eventbus.DeliveryOptions;
|
|
import io.vertx.core.eventbus.DeliveryOptions;
|
|
|
import io.vertx.core.eventbus.EventBus;
|
|
import io.vertx.core.eventbus.EventBus;
|
|
|
-import io.vertx.core.eventbus.ReplyException;
|
|
|
|
|
import io.vertx.ext.web.Router;
|
|
import io.vertx.ext.web.Router;
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
import org.apache.logging.log4j.Logger;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
|
|
+import java.util.HashSet;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
+import java.util.Set;
|
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Consumer;
|
|
|
|
|
|
|
|
import static io.connector.core.AddressPath.*;
|
|
import static io.connector.core.AddressPath.*;
|
|
|
import static io.connector.core.AddressPath.Creator.create;
|
|
import static io.connector.core.AddressPath.Creator.create;
|
|
|
import static io.connector.core.MessageHeader.*;
|
|
import static io.connector.core.MessageHeader.*;
|
|
|
-import static io.vertx.core.eventbus.ReplyFailure.NO_HANDLERS;
|
|
|
|
|
|
|
+import static java.lang.String.format;
|
|
|
|
|
|
|
|
public abstract class AbstractGateway {
|
|
public abstract class AbstractGateway {
|
|
|
|
|
|
|
|
private final static Logger logger = LogManager.getLogger(AbstractGateway.class);
|
|
private final static Logger logger = LogManager.getLogger(AbstractGateway.class);
|
|
|
|
|
|
|
|
- protected static class Message<T> {
|
|
|
|
|
- private final io.vertx.core.eventbus.Message<T> message;
|
|
|
|
|
- private Reply<Object> reply;
|
|
|
|
|
-
|
|
|
|
|
- private Fail fail;
|
|
|
|
|
-
|
|
|
|
|
- private Message(io.vertx.core.eventbus.Message<T> message) {
|
|
|
|
|
- this.message= message;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private Message(Throwable throwable) {
|
|
|
|
|
- this.message = null;
|
|
|
|
|
-
|
|
|
|
|
- if (throwable instanceof ReplyException) {
|
|
|
|
|
- this.fail = new Fail(((ReplyException)throwable).failureCode(), throwable.getMessage());
|
|
|
|
|
- } else {
|
|
|
|
|
- this.fail = new Fail(400, throwable.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public T body() {
|
|
|
|
|
- return message.body();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public MultiMap headers() {
|
|
|
|
|
- return message.headers();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public String address() {
|
|
|
|
|
- return message.address();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public void fail(int code, String message) {
|
|
|
|
|
- fail = new Fail(code, message);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public boolean success() {
|
|
|
|
|
- return fail == null;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public boolean isFail() {
|
|
|
|
|
- return !success();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public Fail cause() {
|
|
|
|
|
- return fail;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public Reply<Object> reply(Object data) {
|
|
|
|
|
- reply = new Reply<>(data);
|
|
|
|
|
- return reply;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- protected static class Fail {
|
|
|
|
|
- private final int code;
|
|
|
|
|
- private final String message;
|
|
|
|
|
-
|
|
|
|
|
- Fail(int code, String message) {
|
|
|
|
|
- this.code = code;
|
|
|
|
|
- this.message = message;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public int getCode() {
|
|
|
|
|
- return code;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public String getMessage() {
|
|
|
|
|
- return message;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- protected static class Reply<T> {
|
|
|
|
|
- private final T data;
|
|
|
|
|
- private final DeliveryOptions options;
|
|
|
|
|
-
|
|
|
|
|
- private Reply(T data) {
|
|
|
|
|
- this.data = data;
|
|
|
|
|
- this.options = new DeliveryOptions();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public DeliveryOptions options() {
|
|
|
|
|
- return options;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
private final EventBus eventBus;
|
|
private final EventBus eventBus;
|
|
|
|
|
+ private final Event event;
|
|
|
private final Router router;
|
|
private final Router router;
|
|
|
private final ModuleType moduleType;
|
|
private final ModuleType moduleType;
|
|
|
protected final ModuleType gatewayType;
|
|
protected final ModuleType gatewayType;
|
|
|
- private final Map<String, String> registeredConsumers;
|
|
|
|
|
|
|
+ private final Set<String> registeredConsumers;
|
|
|
private final Map<String, String> schedulerMapping;
|
|
private final Map<String, String> schedulerMapping;
|
|
|
- private final Map<String, Consumer<Message<Object>>> consumerHandlers;
|
|
|
|
|
|
|
|
|
|
protected AbstractGateway(EventBus eventBus, Router router, ModuleType moduleType, ModuleType gatewayType) {
|
|
protected AbstractGateway(EventBus eventBus, Router router, ModuleType moduleType, ModuleType gatewayType) {
|
|
|
this.eventBus = eventBus;
|
|
this.eventBus = eventBus;
|
|
|
|
|
+ this.event = new EventImpl(eventBus);
|
|
|
this.router = router;
|
|
this.router = router;
|
|
|
this.moduleType = moduleType;
|
|
this.moduleType = moduleType;
|
|
|
this.gatewayType = gatewayType;
|
|
this.gatewayType = gatewayType;
|
|
|
- this.registeredConsumers = new HashMap<>();
|
|
|
|
|
|
|
+ this.registeredConsumers = new HashSet<>();
|
|
|
this.schedulerMapping = new HashMap<>();
|
|
this.schedulerMapping = new HashMap<>();
|
|
|
- this.consumerHandlers = new HashMap<>();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ protected abstract void run();
|
|
|
|
|
+
|
|
|
public String id() {
|
|
public String id() {
|
|
|
return gatewayType.name().toLowerCase();
|
|
return gatewayType.name().toLowerCase();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public Router router() {
|
|
|
|
|
|
|
+ public final Router router() {
|
|
|
return router;
|
|
return router;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- protected abstract void run();
|
|
|
|
|
|
|
+ public final Event event() {
|
|
|
|
|
+ return event;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
public final void start() {
|
|
public final void start() {
|
|
|
run();
|
|
run();
|
|
@@ -142,83 +60,14 @@ public abstract class AbstractGateway {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private String createAddress(String consumerName) {
|
|
private String createAddress(String consumerName) {
|
|
|
- if (!registeredConsumers.containsKey(consumerName)) {
|
|
|
|
|
|
|
+ if (!registeredConsumers.contains(consumerName)) {
|
|
|
throw logger.throwing(new RuntimeException(
|
|
throw logger.throwing(new RuntimeException(
|
|
|
- String.format("Consumer '%s' in module %s and gateway %s is not registered.",
|
|
|
|
|
|
|
+ format("Consumer '%s' in module %s and gateway %s is not registered.",
|
|
|
consumerName, moduleType.name().toLowerCase(), gatewayType.name().toLowerCase()
|
|
consumerName, moduleType.name().toLowerCase(), gatewayType.name().toLowerCase()
|
|
|
)
|
|
)
|
|
|
));
|
|
));
|
|
|
}
|
|
}
|
|
|
- String encapsulation = registeredConsumers.get(consumerName);
|
|
|
|
|
- return create(encapsulation, moduleType, gatewayType, consumerName);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private <T> void privateRequest(String address, Object body, DeliveryOptions options, Consumer<Message<T>> handler) {
|
|
|
|
|
- // TODO request in the same gateway
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private <T> void publicRequest(String address, Object body, DeliveryOptions options, Consumer<Message<T>> handler) {
|
|
|
|
|
- // TODO request to another module
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- protected final <T> void request(String address, Object body, DeliveryOptions options, Consumer<Message<T>> handler) {
|
|
|
|
|
- if (!registeredConsumers.containsKey(address)) {
|
|
|
|
|
- handler.accept(new Message<>(new ReplyException(NO_HANDLERS, "no handler " + address))); return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- String encapsulation = registeredConsumers.get(address);
|
|
|
|
|
- if (encapsulation.equals(PUBLIC_CONSUMER)) {
|
|
|
|
|
- eventBus.<T>request(createAddress(address), body, options, reply -> {
|
|
|
|
|
- Message<T> message;
|
|
|
|
|
- if (reply.succeeded()) {
|
|
|
|
|
- message = new Message<>(reply.result());
|
|
|
|
|
- } else {
|
|
|
|
|
- message = new Message<>(reply.cause());
|
|
|
|
|
- }
|
|
|
|
|
- handler.accept(message);
|
|
|
|
|
- });
|
|
|
|
|
- } else if (encapsulation.equals(PRIVATE_CONSUMER)) {
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- protected final <T> void publicConsumer(String address, Consumer<Message<T>> handler) {
|
|
|
|
|
- registerConsumer(address, PUBLIC_CONSUMER, handler);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // TODO change handler to map of handlers without eventBus
|
|
|
|
|
- protected final <T> void privateConsumer(String address, Consumer<Message<T>> handler) {
|
|
|
|
|
- registerConsumer(address, PRIVATE_CONSUMER, handler);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private <T> void registerConsumer(String address, String encapsulation, Consumer<Message<T>> handler) {
|
|
|
|
|
- if (registeredConsumers.containsKey(address)) {
|
|
|
|
|
- logger.throwing(new RuntimeException(
|
|
|
|
|
- String.format("Address '%s' is already registered as '%s'.", address, registeredConsumers.get(address))
|
|
|
|
|
- ));
|
|
|
|
|
- }
|
|
|
|
|
- registeredConsumers.put(address, encapsulation);
|
|
|
|
|
- eventBus.<T>consumer(createAddress(address), message -> {
|
|
|
|
|
- Message<T> msg = new Message<>(message);
|
|
|
|
|
- handler.accept(msg);
|
|
|
|
|
- if (msg.isFail()) {
|
|
|
|
|
- Fail fail = msg.fail;
|
|
|
|
|
- message.fail(fail.code, fail.message);
|
|
|
|
|
- } else {
|
|
|
|
|
- Reply<Object> reply = msg.reply;
|
|
|
|
|
- if (reply != null) {
|
|
|
|
|
- reply.options
|
|
|
|
|
- .addHeader(MODULE_TYPE, moduleType.name())
|
|
|
|
|
- .addHeader(GATEWAY_TYPE, gatewayType.name())
|
|
|
|
|
- .addHeader(ADDRESS, address);
|
|
|
|
|
- message.reply(reply.data, reply.options);
|
|
|
|
|
- } else {
|
|
|
|
|
- message.fail(204, "no content");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ return create(moduleType, gatewayType, consumerName);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public interface SchedulerMapping {
|
|
public interface SchedulerMapping {
|
|
@@ -236,34 +85,19 @@ public abstract class AbstractGateway {
|
|
|
|
|
|
|
|
private void registerSchedulerConsumers() {
|
|
private void registerSchedulerConsumers() {
|
|
|
final boolean isDefault = moduleType.equals(gatewayType);
|
|
final boolean isDefault = moduleType.equals(gatewayType);
|
|
|
-
|
|
|
|
|
for (Map.Entry<String, String> mappingEntry : schedulerMapping.entrySet()) {
|
|
for (Map.Entry<String, String> mappingEntry : schedulerMapping.entrySet()) {
|
|
|
if (isDefault) {
|
|
if (isDefault) {
|
|
|
- String privateConsumer = registeredConsumers.get(mappingEntry.getKey());
|
|
|
|
|
- if (privateConsumer == null) {
|
|
|
|
|
- throw logger.throwing(new RuntimeException(
|
|
|
|
|
- String.format("Consumer '%s' in module %s and gateway %s is not registered.",
|
|
|
|
|
- mappingEntry.getKey(),
|
|
|
|
|
- moduleType.name().toLowerCase(),
|
|
|
|
|
- gatewayType.name().toLowerCase()
|
|
|
|
|
- )
|
|
|
|
|
- ));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!privateConsumer.equalsIgnoreCase(PRIVATE_CONSUMER)) {
|
|
|
|
|
- logger.warn("Consumer '{}' in module {} and gateway {} is not private and could be dangerous.",
|
|
|
|
|
- mappingEntry.getKey(), moduleType.name().toLowerCase(), gatewayType.name().toLowerCase());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!registeredConsumers.containsKey(mappingEntry.getValue())) {
|
|
|
|
|
- throw logger.throwing(new RuntimeException(
|
|
|
|
|
- String.format("Consumer '%s' in module %s and gateway %s is not registered.",
|
|
|
|
|
- mappingEntry.getValue(),
|
|
|
|
|
- moduleType.name().toLowerCase(),
|
|
|
|
|
- gatewayType.name().toLowerCase()
|
|
|
|
|
- )
|
|
|
|
|
- ));
|
|
|
|
|
|
|
+ Consumer<String> check = name -> {
|
|
|
|
|
+ if (!registeredConsumers.contains(name)) {
|
|
|
|
|
+ throw logger.throwing(new RuntimeException(
|
|
|
|
|
+ format("Consumer '%s' in module %s and gateway %s is not registered.",
|
|
|
|
|
+ name, moduleType.name().toLowerCase(), gatewayType.name().toLowerCase()
|
|
|
|
|
+ )
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ check.accept(mappingEntry.getKey());
|
|
|
|
|
+ check.accept(mappingEntry.getValue());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -318,4 +152,56 @@ public abstract class AbstractGateway {
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ protected interface Event {
|
|
|
|
|
+ <T> void consume(String address, Consumer<Message<T>> handler);
|
|
|
|
|
+ <T> void send(String address, Object body, DeliveryOptions options, Consumer<Message<T>> handler);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private class EventImpl implements Event {
|
|
|
|
|
+
|
|
|
|
|
+ private final EventBus eventBus;
|
|
|
|
|
+
|
|
|
|
|
+ private EventImpl(EventBus eventBus) {
|
|
|
|
|
+ this.eventBus = eventBus;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public <T> void consume(String address, Consumer<Message<T>> handler) {
|
|
|
|
|
+ registeredConsumers.add(address);
|
|
|
|
|
+ eventBus.<T>consumer(createAddress(address), message -> {
|
|
|
|
|
+ Message<T> msg = new Message<>(message);
|
|
|
|
|
+ handler.accept(msg);
|
|
|
|
|
+ if (msg.isFail()) {
|
|
|
|
|
+ Fail fail = msg.cause();
|
|
|
|
|
+ message.fail(fail.getCode(), fail.getMessage());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Reply<Object> reply = msg.reply;
|
|
|
|
|
+ if (reply != null) {
|
|
|
|
|
+ reply.options()
|
|
|
|
|
+ .addHeader(MODULE_TYPE, moduleType.name())
|
|
|
|
|
+ .addHeader(GATEWAY_TYPE, gatewayType.name())
|
|
|
|
|
+ .addHeader(ADDRESS, address);
|
|
|
|
|
+ message.reply(reply.data, reply.options());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ message.fail(204, "no content");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public <T> void send(String address, Object body, DeliveryOptions options, Consumer<Message<T>> handler) {
|
|
|
|
|
+ eventBus.<T>request(createAddress(address), body, options, reply -> {
|
|
|
|
|
+ Message<T> message;
|
|
|
|
|
+ if (reply.succeeded()) {
|
|
|
|
|
+ message = new Message<>(reply.result());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ message = new Message<>(reply.cause());
|
|
|
|
|
+ }
|
|
|
|
|
+ handler.accept(message);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|