use of io.vertx.proton.streams.Delivery in project vertx-proton by vert-x3.
the class ProtonPublisherImpl method subscribe.
@Override
public void subscribe(Subscriber<? super Delivery> subscriber) {
LOG.trace("Subscribe called");
Objects.requireNonNull(subscriber, "A subscriber must be supplied");
if (subscribed.getAndSet(true)) {
throw new IllegalStateException("Only a single susbcriber supported, and subscribe already called.");
}
subscription = new AmqpSubscription(subscriber);
connCtx.runOnContext(x -> {
conn.addEndHandler(v -> {
if (emitOnConnectionEnd) {
subscription.indicateError(new Exception("Connection closed: " + conn.getContainer()));
}
});
receiver.closeHandler(res -> {
subscription.indicateError(new Exception("Link closed unexpectedly"));
receiver.close();
});
receiver.detachHandler(res -> {
subscription.indicateError(new Exception("Link detached unexpectedly"));
receiver.detach();
});
receiver.openHandler(res -> {
subscription.indicateSubscribed();
});
receiver.handler((delivery, message) -> {
Delivery envelope = new DeliveryImpl(message, delivery, connCtx);
if (!subscription.onNextWrapper(envelope)) {
delivery.disposition(Released.getInstance(), true);
}
});
receiver.open();
});
}
use of io.vertx.proton.streams.Delivery in project vertx-proton by vert-x3.
the class ProtonPublisherIntTest method doSubscriptionConfigTestImpl.
private void doSubscriptionConfigTestImpl(TestContext context, boolean durable, String linkName, boolean shared, boolean global) throws InterruptedException, ExecutionException {
server.close();
final Async clientLinkOpenAsync = context.async();
final Async serverLinkOpenAsync = context.async();
final Async clientLinkCloseAsync = context.async();
ProtonServer protonServer = null;
try {
protonServer = createServer((serverConnection) -> {
serverConnection.openHandler(result -> {
serverConnection.open();
});
serverConnection.sessionOpenHandler(session -> session.open());
serverConnection.senderOpenHandler(serverSender -> {
serverSender.closeHandler(res -> {
context.assertFalse(durable, "unexpected link close for durable sub");
serverSender.close();
});
serverSender.detachHandler(res -> {
context.assertTrue(durable, "unexpected link detach for non-durable sub");
serverSender.detach();
});
LOG.trace("Server sender opened");
serverSender.open();
// Verify the link details used were as expected
context.assertEquals(linkName, serverSender.getName(), "unexpected link name");
context.assertNotNull(serverSender.getRemoteSource(), "source should not be null");
org.apache.qpid.proton.amqp.messaging.Source source = (org.apache.qpid.proton.amqp.messaging.Source) serverSender.getRemoteSource();
if (durable) {
context.assertEquals(TerminusExpiryPolicy.NEVER, source.getExpiryPolicy(), "unexpected expiry");
context.assertEquals(TerminusDurability.UNSETTLED_STATE, source.getDurable(), "unexpected durability");
}
Symbol[] capabilities = source.getCapabilities();
if (shared && global) {
context.assertTrue(Arrays.equals(new Symbol[] { Symbol.valueOf("shared"), Symbol.valueOf("global") }, capabilities), "Unexpected capabilities: " + Arrays.toString(capabilities));
} else if (shared) {
context.assertTrue(Arrays.equals(new Symbol[] { Symbol.valueOf("shared") }, capabilities), "Unexpected capabilities: " + Arrays.toString(capabilities));
}
serverLinkOpenAsync.complete();
});
});
// ===== Client Handling =====
ProtonClient client = ProtonClient.create(vertx);
client.connect("localhost", protonServer.actualPort(), res -> {
context.assertTrue(res.succeeded());
ProtonConnection connection = res.result();
connection.open();
// Create publisher with given link name
ProtonPublisherOptions options = new ProtonPublisherOptions().setLinkName(linkName);
if (durable) {
options.setDurable(true);
}
if (shared) {
options.setShared(true);
}
if (global) {
options.setGlobal(true);
}
ProtonPublisher<Delivery> publisher = ProtonStreams.createDeliveryConsumer(connection, "myAddress", options);
publisher.subscribe(new Subscriber<Delivery>() {
Subscription sub = null;
@Override
public void onSubscribe(Subscription s) {
clientLinkOpenAsync.complete();
sub = s;
s.request(1);
sub.cancel();
}
@Override
public void onNext(Delivery e) {
}
@Override
public void onError(Throwable t) {
if (!clientLinkCloseAsync.isCompleted()) {
context.fail("onError called");
}
}
@Override
public void onComplete() {
clientLinkCloseAsync.complete();
}
});
});
serverLinkOpenAsync.awaitSuccess();
clientLinkOpenAsync.awaitSuccess();
clientLinkCloseAsync.awaitSuccess();
} finally {
if (protonServer != null) {
protonServer.close();
}
}
}
use of io.vertx.proton.streams.Delivery in project vertx-proton by vert-x3.
the class ProtonPublisherIntTest method testMaxOutstandingCredit1.
@Test(timeout = 20000)
public void testMaxOutstandingCredit1(TestContext context) throws Exception {
server.close();
final int maxOutstanding = 1000;
final int amount1 = 15;
final int amount2 = 1100;
final int totalRequests = amount1 + amount2;
final Async receivedCreditAsync = context.async();
final Async verifiedCreditAsync = context.async();
final Async receivedCreditAsync2 = context.async();
final Async receivedMessages = context.async();
List<Integer> credits = new ArrayList<>();
AtomicInteger counter = new AtomicInteger();
ProtonServer protonServer = null;
try {
protonServer = createServer((serverConnection) -> {
serverConnection.openHandler(result -> {
serverConnection.open();
});
serverConnection.sessionOpenHandler(session -> session.open());
serverConnection.senderOpenHandler(serverSender -> {
LOG.trace("Server sender opened");
serverSender.open();
AtomicInteger msgNum = new AtomicInteger();
serverSender.sendQueueDrainHandler(s -> {
int credit = serverSender.getCredit();
LOG.trace("Server credit: " + credit);
credits.add(credit);
if (credit > maxOutstanding) {
context.fail("Received unexpected amount of credit: " + credit);
} else if (credit == maxOutstanding) {
LOG.trace("Server reached max outstanding: " + credit);
receivedCreditAsync.complete();
verifiedCreditAsync.await();
while (!serverSender.sendQueueFull()) {
serverSender.send(message(String.valueOf(msgNum.incrementAndGet())));
}
return;
} else if (receivedCreditAsync.isCompleted()) {
LOG.trace("Server received topup credit, post-max-outstanding: " + credit);
receivedCreditAsync2.complete();
while (!serverSender.sendQueueFull()) {
serverSender.send(message(String.valueOf(msgNum.incrementAndGet())));
}
}
});
});
});
// ===== Client Handling =====
ProtonClient client = ProtonClient.create(vertx);
client.connect("localhost", protonServer.actualPort(), res -> {
context.assertTrue(res.succeeded());
ProtonConnection connection = res.result();
connection.open();
ProtonPublisher<Delivery> publisher = ProtonStreams.createDeliveryConsumer(connection, "myAddress");
publisher.subscribe(new Subscriber<Delivery>() {
Subscription sub = null;
@Override
public void onSubscribe(Subscription s) {
LOG.trace("Flowing initial credit");
sub = s;
sub.request(amount1);
vertx.setTimer(250, x -> {
LOG.trace("Granting additional credit");
sub.request(amount2);
});
}
@Override
public void onNext(Delivery d) {
int count = counter.incrementAndGet();
validateMessage(context, count, String.valueOf(count), d.message());
if (count >= totalRequests) {
receivedMessages.complete();
}
}
@Override
public void onError(Throwable t) {
if (!receivedMessages.isCompleted()) {
context.fail("onError called");
}
}
@Override
public void onComplete() {
context.fail("onComplete called");
}
});
});
receivedCreditAsync.awaitSuccess();
// Verify the requests were all received as expected
context.assertEquals(credits.size(), 2, "Unexpected credits count");
context.assertEquals(credits.get(0), amount1, "Unexpected credit 1");
context.assertEquals(credits.get(1), maxOutstanding, "Unexpected credit 2");
verifiedCreditAsync.complete();
receivedCreditAsync2.awaitSuccess();
// Verify the requests were all received as expected
context.assertEquals(credits.size(), 3, "Unexpected credits count");
context.assertEquals(credits.get(2), amount1 + amount2 - maxOutstanding, "Unexpected credit 3");
receivedMessages.awaitSuccess();
} finally {
if (protonServer != null) {
protonServer.close();
}
}
}
use of io.vertx.proton.streams.Delivery in project vertx-proton by vert-x3.
the class ProtonPublisherIntTest method testManualAccept.
@Test(timeout = 20000)
public void testManualAccept(TestContext context) throws Exception {
server.close();
final Async receivedMessagesAsync = context.async();
final Async ackedMessagesAsync = context.async();
int messageCount = 5;
List<Integer> accepted = Collections.synchronizedList(new ArrayList<>());
List<Delivery> deliveries = Collections.synchronizedList(new ArrayList<>());
AtomicInteger msgNum = new AtomicInteger(1);
ProtonServer protonServer = null;
try {
protonServer = createServer((serverConnection) -> {
serverConnection.openHandler(result -> {
serverConnection.open();
});
serverConnection.sessionOpenHandler(session -> session.open());
serverConnection.senderOpenHandler(serverSender -> {
LOG.trace("Server sender opened");
serverSender.open();
serverSender.sendQueueDrainHandler(s -> {
for (int i = msgNum.get(); i <= messageCount; i = msgNum.incrementAndGet()) {
int j = i;
serverSender.send(message(String.valueOf(i)), del -> {
LOG.trace("Server received disposition for msg: " + j);
if (del.getRemoteState() instanceof Accepted) {
accepted.add(j);
if (accepted.size() == messageCount) {
ackedMessagesAsync.complete();
}
} else {
context.fail("Expected message to be accepted");
}
});
}
});
});
});
// ===== Client Handling =====
AtomicInteger counter = new AtomicInteger(0);
ProtonClient client = ProtonClient.create(vertx);
client.connect("localhost", protonServer.actualPort(), res -> {
context.assertTrue(res.succeeded());
ProtonConnection connection = res.result();
// Create consumer stream of Delivery, which must be manually accepted
ProtonPublisher<Delivery> publisher = ProtonStreams.createDeliveryConsumer(connection, "myAddress");
publisher.subscribe(new Subscriber<Delivery>() {
Subscription sub = null;
@Override
public void onSubscribe(Subscription s) {
sub = s;
LOG.trace("Flowing initial credit");
sub.request(messageCount);
}
@Override
public void onNext(Delivery d) {
int count = counter.incrementAndGet();
deliveries.add(d);
if (count == messageCount) {
LOG.trace("Got all messages, completing async");
receivedMessagesAsync.complete();
}
}
@Override
public void onError(Throwable t) {
if (!receivedMessagesAsync.isCompleted()) {
context.fail("onError called");
}
}
@Override
public void onComplete() {
context.fail("onComplete called");
}
});
connection.open();
});
receivedMessagesAsync.awaitSuccess();
// Small delay to ensure there is a window for any
// unexpected automatic accept to occur
Thread.sleep(50);
// Verify no messages accepted yet
context.assertTrue(accepted.isEmpty(), "Unexpected accepted count");
// Accept them all
for (Delivery d : deliveries) {
d.accept();
}
ackedMessagesAsync.awaitSuccess();
} finally {
if (protonServer != null) {
protonServer.close();
}
}
// Verify the messages were all accepted
context.assertEquals(accepted.size(), messageCount, "Unexpected accepted count");
for (int i = 1; i <= messageCount; i++) {
// Verify each accepted number, establish correct order etc.
context.assertEquals(accepted.remove(0), i, "Unexpected msgNum");
}
}
use of io.vertx.proton.streams.Delivery in project vertx-proton by vert-x3.
the class ProtonPublisherIntTest method testConfigureSubscriptionDynamic.
@Test(timeout = 20000)
public void testConfigureSubscriptionDynamic(TestContext context) throws Exception {
server.close();
final Async clientLinkOpenAsync = context.async();
final Async serverLinkOpenAsync = context.async();
final Async clientLinkCloseAsync = context.async();
final String dynamicAddress = "testConfigureSubscriptionDynamic:" + UUID.randomUUID();
ProtonServer protonServer = null;
try {
protonServer = createServer((serverConnection) -> {
serverConnection.openHandler(result -> {
serverConnection.open();
});
serverConnection.sessionOpenHandler(session -> session.open());
serverConnection.senderOpenHandler(serverSender -> {
serverSender.closeHandler(res -> {
serverSender.close();
});
// Verify the remote terminus details used were as expected
context.assertNotNull(serverSender.getRemoteSource(), "source should not be null");
org.apache.qpid.proton.amqp.messaging.Source remoteSource = (org.apache.qpid.proton.amqp.messaging.Source) serverSender.getRemoteSource();
context.assertTrue(remoteSource.getDynamic(), "expected dynamic source");
context.assertNull(remoteSource.getAddress(), "expected no source address");
// Set the local terminus details
org.apache.qpid.proton.amqp.messaging.Source source = (org.apache.qpid.proton.amqp.messaging.Source) remoteSource.copy();
source.setAddress(dynamicAddress);
serverSender.setSource(source);
LOG.trace("Server sender opened");
serverSender.open();
serverLinkOpenAsync.complete();
});
});
// ===== Client Handling =====
ProtonClient client = ProtonClient.create(vertx);
client.connect("localhost", protonServer.actualPort(), res -> {
context.assertTrue(res.succeeded());
ProtonConnection connection = res.result();
connection.open();
// Create publisher with dynamic option
ProtonPublisherOptions options = new ProtonPublisherOptions().setDynamic(true);
ProtonPublisher<Delivery> publisher = ProtonStreams.createDeliveryConsumer(connection, null, options);
publisher.subscribe(new Subscriber<Delivery>() {
Subscription sub = null;
@Override
public void onSubscribe(Subscription s) {
// Verify the remote address detail
context.assertEquals(dynamicAddress, publisher.getRemoteAddress(), "unexpected remote address");
// Grab and verify the source details
org.apache.qpid.proton.amqp.messaging.Source remoteSource = (org.apache.qpid.proton.amqp.messaging.Source) publisher.getRemoteSource();
context.assertTrue(remoteSource.getDynamic(), "expected dynamic source");
context.assertEquals(dynamicAddress, remoteSource.getAddress(), "unexpected source address");
clientLinkOpenAsync.complete();
sub = s;
s.request(1);
sub.cancel();
}
@Override
public void onNext(Delivery e) {
}
@Override
public void onError(Throwable t) {
if (!clientLinkCloseAsync.isCompleted()) {
context.fail("onError called");
}
}
@Override
public void onComplete() {
clientLinkCloseAsync.complete();
}
});
});
serverLinkOpenAsync.awaitSuccess();
clientLinkOpenAsync.awaitSuccess();
clientLinkCloseAsync.awaitSuccess();
} finally {
if (protonServer != null) {
protonServer.close();
}
}
}
Aggregations