vertx.effect.VerticleRef Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vertx-effect Show documentation
Show all versions of vertx-effect Show documentation
When actors meet Functional Programming
package vertx.effect;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.core.eventbus.Message;
import vertx.effect.core.EventPublisher;
import vertx.effect.exp.Cons;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static java.util.Objects.requireNonNull;
/**
It represents a reference to a Verticle, the unit of computation. It allows to send messages
to the Verticle with the method {@link #tell(DeliveryOptions)}, or establish conversations with the
method {@link #ask(DeliveryOptions)}.
@param the type of the input message sent to this verticle
@param the type of the output message returned by this verticle */
public class VerticleRef {
private final Vertx vertx;
/**
the default delivery options that will be used if not specified
*/
private static final DeliveryOptions DEFAULT = new DeliveryOptions();
/**
address where a verticle is listening on
*/
public final String address;
/**
the identifiers assigned to the different instances of this verticle after being deployed.
To undeploy a verticle, its identifier is needed.
*/
public final Set ids;
private static final Supplier EMPTY_HEADERS = MultiMap::caseInsensitiveMultiMap;
public VerticleRef(final Vertx vertx,
final String address) {
this.vertx = requireNonNull(vertx);
this.address = requireNonNull(address);
ids = Set.of();
}
VerticleRef(final Vertx vertx,
final Set ids,
final String address
) {
this.vertx = requireNonNull(vertx);
this.ids = requireNonNull(ids);
this.address = requireNonNull(address);
if (ids.isEmpty()) throw new IllegalArgumentException("ids is empty");
}
/**
Method to establish a conversation with this verticle: a message is sent and then a message is
received.
@param options the delivery options
@return a function that takes an object of type I and returns an object of type O wrapped in a
future
*/
public λ ask(final DeliveryOptions options) {
requireNonNull(options);
return body -> Cons.of(() -> {
try {
MessageEvent messageEvent = new MessageEvent();
messageEvent.address = address;
messageEvent.begin();
EventPublisher.PUBLISHER.sentMessage(address,
body
)
.accept(vertx);
return vertx.eventBus().request(address,
body,
options
)
.onComplete(event -> {
if (event.succeeded()) {
EventPublisher.PUBLISHER.receivedResp(address,
EMPTY_HEADERS.get(),
messageEvent
)
.accept(vertx);
}
else {
EventPublisher.PUBLISHER.receivedError(address,
event.cause(),
messageEvent
)
.accept(vertx);
}
})
.map(Message::body);
} catch (Exception e) {
return Future.failedFuture(e);
}
}
);
}
public λc trace(final DeliveryOptions options) {
requireNonNull(options);
return (context, body) -> Cons.of(() -> {
try {
MessageEvent messageEvent = new MessageEvent();
messageEvent.address = address;
messageEvent.begin();
EventPublisher.PUBLISHER.sentMessage(address,
body,
context
)
.accept(vertx);
return vertx.eventBus().request(address,
body,
options.setHeaders(context)
)
.onComplete(event -> {
if (event.succeeded()) {
EventPublisher.PUBLISHER.receivedResp(address,
context,
messageEvent
)
.accept(vertx);
}
else {
EventPublisher.PUBLISHER.receivedError(address,
event.cause(),
context,
messageEvent
)
.accept(vertx);
}
})
.map(Message::body);
} catch (Exception e) {
return Future.failedFuture(e);
}
}
);
}
/**
Method to establish a conversation with this verticle: a message is sent and then a message is
received.
@return a function that takes an object of type I and returns an object of type O wrapped in a
future
*/
public λ ask() {
return ask(DEFAULT);
}
public λc trace() {
return trace(DEFAULT);
}
/**
Method to send a message to this verticle.
@param options the delivery options
@return a consumer that takes an object of type I
*/
public Consumer tell(final DeliveryOptions options) {
requireNonNull(options);
return body -> vertx.eventBus()
.send(address,
body,
options
);
}
/**
Method to send a message to this verticle.
@return a consumer that takes an object of type I
*/
public Consumer tell() {
return tell(DEFAULT);
}
/**
Undeploy all the instances of this verticle
@return a future that will be completed when all the instances are undeployed
*/
@SuppressWarnings({"rawtypes", "squid:S3740"})//vertx api doesn't use type parameter
public Future undeploy() {
if (ids.isEmpty()) return Future.succeededFuture();
List futures = new ArrayList<>();
for (final String id : ids) {
final Future future = vertx.undeploy(id);
futures.add(future);
}
return CompositeFuture.all(futures)
.flatMap(it ->
{
if (it.succeeded()) return Future.succeededFuture();
else return Future.failedFuture(it.cause());
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy