Search in sources :

Example 6 with ProtonMessageHandler

use of io.vertx.proton.ProtonMessageHandler in project hono by eclipse.

the class AuthenticationServerClient method getToken.

private Future<HonoUser> getToken(final ProtonConnection openCon) {
    final Promise<HonoUser> result = Promise.promise();
    final ProtonMessageHandler messageHandler = (delivery, message) -> {
        final String type = MessageHelper.getApplicationProperty(message.getApplicationProperties(), AuthenticationConstants.APPLICATION_PROPERTY_TYPE, String.class);
        if (AuthenticationConstants.TYPE_AMQP_JWT.equals(type)) {
            final String payload = MessageHelper.getPayloadAsString(message);
            if (payload != null) {
                final HonoUser user = new HonoUserAdapter() {

                    @Override
                    public String getToken() {
                        return payload;
                    }
                };
                LOG.debug("successfully retrieved token from Authentication service");
                result.complete(user);
            } else {
                result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, "message from Authentication service contains no body"));
            }
        } else {
            result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, "Authentication service issued unsupported token [type: " + type + "]"));
        }
    };
    openReceiver(openCon, messageHandler).onComplete(attempt -> {
        if (attempt.succeeded()) {
            vertx.setTimer(5000, tid -> {
                result.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "time out reached while waiting for token from Authentication service"));
            });
            LOG.debug("opened receiver link to Authentication service, waiting for token ...");
        } else {
            result.fail(attempt.cause());
        }
    });
    return result.future();
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) HonoUserAdapter(org.eclipse.hono.auth.HonoUserAdapter) Logger(org.slf4j.Logger) Promise(io.vertx.core.Promise) MechanismMismatchException(io.vertx.proton.sasl.MechanismMismatchException) LoggerFactory(org.slf4j.LoggerFactory) Vertx(io.vertx.core.Vertx) HonoUser(org.eclipse.hono.auth.HonoUser) MessageHelper(org.eclipse.hono.util.MessageHelper) Future(io.vertx.core.Future) AuthenticationConstants(org.eclipse.hono.util.AuthenticationConstants) Objects(java.util.Objects) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Optional(java.util.Optional) AuthenticationException(javax.security.sasl.AuthenticationException) AsyncResult(io.vertx.core.AsyncResult) Handler(io.vertx.core.Handler) HonoUser(org.eclipse.hono.auth.HonoUser) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) HonoUserAdapter(org.eclipse.hono.auth.HonoUserAdapter)

Example 7 with ProtonMessageHandler

use of io.vertx.proton.ProtonMessageHandler in project hono by eclipse.

the class HonoConnectionImpl method createReceiver.

@Override
public Future<ProtonReceiver> createReceiver(final String sourceAddress, final ProtonQoS qos, final ProtonMessageHandler messageHandler, final int preFetchSize, final boolean autoAccept, final Handler<String> remoteCloseHook) {
    Objects.requireNonNull(sourceAddress);
    Objects.requireNonNull(qos);
    Objects.requireNonNull(messageHandler);
    if (preFetchSize < 0) {
        throw new IllegalArgumentException("pre-fetch size must be >= 0");
    }
    return executeOnContext(result -> {
        checkConnected().compose(v -> {
            final Promise<ProtonReceiver> receiverPromise = Promise.promise();
            final ProtonReceiver receiver = session.createReceiver(sourceAddress);
            if (clientConfigProperties.getMaxMessageSize() > ClientConfigProperties.MAX_MESSAGE_SIZE_UNLIMITED) {
                receiver.setMaxMessageSize(new UnsignedLong(clientConfigProperties.getMaxMessageSize()));
            }
            receiver.setAutoAccept(autoAccept);
            receiver.setQoS(qos);
            receiver.setPrefetch(preFetchSize);
            receiver.handler((delivery, message) -> {
                HonoProtonHelper.onReceivedMessageDeliveryUpdatedFromRemote(delivery, d -> log.debug("got unexpected disposition update for received message [remote state: {}]", delivery.getRemoteState()));
                try {
                    messageHandler.handle(delivery, message);
                    if (log.isTraceEnabled()) {
                        final int remainingCredits = receiver.getCredit() - receiver.getQueued();
                        log.trace("handling message [remotely settled: {}, queued messages: {}, remaining credit: {}]", delivery.remotelySettled(), receiver.getQueued(), remainingCredits);
                    }
                } catch (final Exception ex) {
                    log.warn("error handling message", ex);
                    ProtonHelper.released(delivery, true);
                }
            });
            final DisconnectListener<HonoConnection> disconnectBeforeOpenListener = (con) -> {
                log.debug("opening receiver [{}] failed: got disconnected", sourceAddress);
                receiverPromise.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "not connected"));
            };
            oneTimeDisconnectListeners.add(disconnectBeforeOpenListener);
            receiver.openHandler(recvOpen -> {
                oneTimeDisconnectListeners.remove(disconnectBeforeOpenListener);
                // the result future may have already been completed here in case of a link establishment timeout
                if (receiverPromise.future().isComplete()) {
                    log.debug("ignoring server response for opening receiver [{}]: receiver creation already timed out", sourceAddress);
                } else if (recvOpen.failed()) {
                    // this means that we have received the peer's attach
                    // and the subsequent detach frame in one TCP read
                    final ErrorCondition error = receiver.getRemoteCondition();
                    if (error == null) {
                        log.debug("opening receiver [{}] failed", sourceAddress, recvOpen.cause());
                        receiverPromise.tryFail(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND, "cannot open receiver", recvOpen.cause()));
                    } else {
                        log.debug("opening receiver [{}] failed: {} - {}", sourceAddress, error.getCondition(), error.getDescription());
                        receiverPromise.tryFail(StatusCodeMapper.fromAttachError(error));
                    }
                } else if (HonoProtonHelper.isLinkEstablished(receiver)) {
                    log.debug("receiver open [source: {}]", sourceAddress);
                    receiverPromise.tryComplete(recvOpen.result());
                } else {
                    // this means that the peer did not create a local terminus for the link
                    // and will send a detach frame for closing the link very shortly
                    // see AMQP 1.0 spec section 2.6.3
                    log.debug("peer did not create terminus for source [{}] and will detach the link", sourceAddress);
                    receiverPromise.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE));
                }
            });
            HonoProtonHelper.setDetachHandler(receiver, remoteDetached -> onRemoteDetach(receiver, connection.getRemoteContainer(), false, remoteCloseHook));
            HonoProtonHelper.setCloseHandler(receiver, remoteClosed -> onRemoteDetach(receiver, connection.getRemoteContainer(), true, remoteCloseHook));
            receiver.open();
            vertx.setTimer(clientConfigProperties.getLinkEstablishmentTimeout(), tid -> {
                final boolean notOpenedAndNotDisconnectedYet = oneTimeDisconnectListeners.remove(disconnectBeforeOpenListener);
                if (notOpenedAndNotDisconnectedYet) {
                    onLinkEstablishmentTimeout(receiver, clientConfigProperties, receiverPromise);
                }
            });
            return receiverPromise.future();
        }).onComplete(result);
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) Arrays(java.util.Arrays) LoggerFactory(org.slf4j.LoggerFactory) Context(io.vertx.core.Context) HonoProtonHelper(org.eclipse.hono.util.HonoProtonHelper) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) SaslSystemException(io.vertx.proton.sasl.SaslSystemException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) DisconnectListener(org.eclipse.hono.client.DisconnectListener) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) MechanismMismatchException(io.vertx.proton.sasl.MechanismMismatchException) ProtonQoS(io.vertx.proton.ProtonQoS) UUID(java.util.UUID) Future(io.vertx.core.Future) Objects(java.util.Objects) CountDownLatch(java.util.concurrent.CountDownLatch) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ReconnectListener(org.eclipse.hono.client.ReconnectListener) List(java.util.List) SSLException(javax.net.ssl.SSLException) Optional(java.util.Optional) ProtonSender(io.vertx.proton.ProtonSender) AuthenticationException(javax.security.sasl.AuthenticationException) ProtonLink(io.vertx.proton.ProtonLink) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) AtomicReference(java.util.concurrent.atomic.AtomicReference) Constants(org.eclipse.hono.util.Constants) ArrayList(java.util.ArrayList) ProtonSession(io.vertx.proton.ProtonSession) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) Symbol(org.apache.qpid.proton.amqp.Symbol) StatusCodeMapper(org.eclipse.hono.client.StatusCodeMapper) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) AsyncResult(io.vertx.core.AsyncResult) HonoConnection(org.eclipse.hono.client.HonoConnection) Logger(org.slf4j.Logger) VertxInternal(io.vertx.core.impl.VertxInternal) Iterator(java.util.Iterator) Tracer(io.opentracing.Tracer) NoopTracerFactory(io.opentracing.noop.NoopTracerFactory) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) TimeUnit(java.util.concurrent.TimeUnit) Handler(io.vertx.core.Handler) Collections(java.util.Collections) ProtonReceiver(io.vertx.proton.ProtonReceiver) Promise(io.vertx.core.Promise) DisconnectListener(org.eclipse.hono.client.DisconnectListener) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServerErrorException(org.eclipse.hono.client.ServerErrorException) SaslSystemException(io.vertx.proton.sasl.SaslSystemException) MechanismMismatchException(io.vertx.proton.sasl.MechanismMismatchException) SSLException(javax.net.ssl.SSLException) AuthenticationException(javax.security.sasl.AuthenticationException) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 8 with ProtonMessageHandler

use of io.vertx.proton.ProtonMessageHandler in project hono by eclipse.

the class ProtonBasedNotificationReceiverTest method assertReceiverLinkCreated.

private static Map<String, ProtonMessageHandler> assertReceiverLinkCreated(final HonoConnection connection) {
    final Map<String, ProtonMessageHandler> resultMap = new HashMap<>();
    final ArgumentCaptor<ProtonMessageHandler> messageHandlerCaptor = ArgumentCaptor.forClass(ProtonMessageHandler.class);
    final ArgumentCaptor<String> addressCaptor = ArgumentCaptor.forClass(String.class);
    verify(connection, atLeastOnce()).createReceiver(addressCaptor.capture(), any(ProtonQoS.class), messageHandlerCaptor.capture(), VertxMockSupport.anyHandler());
    final List<ProtonMessageHandler> handlers = messageHandlerCaptor.getAllValues();
    final List<String> addresses = addressCaptor.getAllValues();
    for (int i = 0; i < handlers.size(); i++) {
        resultMap.put(addresses.get(i), handlers.get(i));
    }
    return resultMap;
}
Also used : ProtonQoS(io.vertx.proton.ProtonQoS) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) HashMap(java.util.HashMap) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Checkpoint(io.vertx.junit5.Checkpoint)

Example 9 with ProtonMessageHandler

use of io.vertx.proton.ProtonMessageHandler in project hono by eclipse.

the class AuthenticationServerClient method getToken.

private void getToken(final ProtonConnection openCon, final Future<HonoUser> authResult) {
    final ProtonMessageHandler messageHandler = (delivery, message) -> {
        String type = MessageHelper.getApplicationProperty(message.getApplicationProperties(), AuthenticationConstants.APPLICATION_PROPERTY_TYPE, String.class);
        if (AuthenticationConstants.TYPE_AMQP_JWT.equals(type)) {
            Section body = message.getBody();
            if (body instanceof AmqpValue) {
                final String token = ((AmqpValue) body).getValue().toString();
                HonoUser user = new HonoUserAdapter() {

                    @Override
                    public String getToken() {
                        return token;
                    }
                };
                LOG.debug("successfully retrieved token from Authentication service");
                authResult.complete(user);
            } else {
                authResult.fail("message from Authentication service contains no body");
            }
        } else {
            authResult.fail("Authentication service issued unsupported token [type: " + type + "]");
        }
    };
    openReceiver(openCon, messageHandler).compose(openReceiver -> {
        LOG.debug("opened receiver link to Authentication service, waiting for token ...");
    }, authResult);
}
Also used : ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) HonoUserAdapter(org.eclipse.hono.auth.HonoUserAdapter) Logger(org.slf4j.Logger) LoggerFactory(org.slf4j.LoggerFactory) Vertx(io.vertx.core.Vertx) Autowired(org.springframework.beans.factory.annotation.Autowired) HonoUser(org.eclipse.hono.auth.HonoUser) MessageHelper(org.eclipse.hono.util.MessageHelper) Future(io.vertx.core.Future) AuthenticationConstants(org.eclipse.hono.service.auth.AuthenticationConstants) Objects(java.util.Objects) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) Section(org.apache.qpid.proton.amqp.messaging.Section) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) AmqpValue(org.apache.qpid.proton.amqp.messaging.AmqpValue) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Qualifier(org.springframework.beans.factory.annotation.Qualifier) AsyncResult(io.vertx.core.AsyncResult) Handler(io.vertx.core.Handler) HonoUser(org.eclipse.hono.auth.HonoUser) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) HonoUserAdapter(org.eclipse.hono.auth.HonoUserAdapter) Section(org.apache.qpid.proton.amqp.messaging.Section) AmqpValue(org.apache.qpid.proton.amqp.messaging.AmqpValue)

Example 10 with ProtonMessageHandler

use of io.vertx.proton.ProtonMessageHandler in project hono by eclipse.

the class RequestResponseClientTest method testCreateAndSendRequestReturnsCorrespondingResponseMessage.

/**
 * Verifies that the client returns the service's response message that correlates with the request.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testCreateAndSendRequestReturnsCorrespondingResponseMessage(final VertxTestContext ctx) {
    // WHEN sending a request message to the peer
    client.compose(c -> c.createAndSendRequest("request", null, Buffer.buffer("hello"), "text/plain", SimpleRequestResponseResult::from, span)).onComplete(ctx.succeeding(s -> {
        ctx.verify(() -> {
            // THEN the response is passed to the handler registered with the request
            assertEquals(200, s.getStatus());
            assertEquals("payload", s.getPayload().toString());
            verify(sample).completed(isA(Accepted.class));
            // and a timer has been set to time out the request
            final ArgumentCaptor<Handler<Long>> timeoutHandlerCaptor = VertxMockSupport.argumentCaptorHandler();
            verify(vertx).setTimer(eq(clientConfig.getRequestTimeout()), timeoutHandlerCaptor.capture());
            // triggering the timer now that the request has been handled should not invoke the sampler timeout method
            timeoutHandlerCaptor.getValue().handle(1L);
            verify(sample, never()).timeout();
        });
        ctx.completeNow();
    }));
    // WHEN a response is received for the request
    final Message request = verifySenderSendAndUpdateDelivery(new Accepted());
    final ProtonMessageHandler responseHandler = verifyResponseHandlerSet();
    final Message response = ProtonHelper.message("payload");
    response.setCorrelationId(request.getMessageId());
    MessageHelper.addProperty(response, MessageHelper.APP_PROPERTY_STATUS, 200);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    responseHandler.handle(delivery, response);
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) BeforeEach(org.junit.jupiter.api.BeforeEach) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Timeout(io.vertx.junit5.Timeout) EventBus(io.vertx.core.eventbus.EventBus) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Map(java.util.Map) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) TracingMockSupport(org.eclipse.hono.test.TracingMockSupport) JsonObject(io.vertx.core.json.JsonObject) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) Data(org.apache.qpid.proton.amqp.messaging.Data) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) Test(org.junit.jupiter.api.Test) Buffer(io.vertx.core.buffer.Buffer) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) VertxTestContext(io.vertx.junit5.VertxTestContext) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) ProtonDelivery(io.vertx.proton.ProtonDelivery) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) AmqpClientUnitTestHelper(org.eclipse.hono.client.amqp.test.AmqpClientUnitTestHelper) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) ArgumentCaptor(org.mockito.ArgumentCaptor) Symbol(org.apache.qpid.proton.amqp.Symbol) Message(org.apache.qpid.proton.message.Message) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) HonoConnection(org.eclipse.hono.client.HonoConnection) ArgumentMatchers.isA(org.mockito.ArgumentMatchers.isA) RequestResponseClientConfigProperties(org.eclipse.hono.client.RequestResponseClientConfigProperties) Tracer(io.opentracing.Tracer) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) Mockito.never(org.mockito.Mockito.never) ResourceLimitExceededException(org.eclipse.hono.client.ResourceLimitExceededException) SendMessageSampler(org.eclipse.hono.client.SendMessageSampler) Handler(io.vertx.core.Handler) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) ArgumentCaptor(org.mockito.ArgumentCaptor) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) Test(org.junit.jupiter.api.Test)

Aggregations

ProtonMessageHandler (io.vertx.proton.ProtonMessageHandler)14 ProtonReceiver (io.vertx.proton.ProtonReceiver)13 Vertx (io.vertx.core.Vertx)11 Future (io.vertx.core.Future)9 ProtonDelivery (io.vertx.proton.ProtonDelivery)9 Message (org.apache.qpid.proton.message.Message)9 Handler (io.vertx.core.Handler)8 ProtonQoS (io.vertx.proton.ProtonQoS)8 ProtonHelper (io.vertx.proton.ProtonHelper)7 Truth.assertThat (com.google.common.truth.Truth.assertThat)5 Timeout (io.vertx.junit5.Timeout)5 VertxExtension (io.vertx.junit5.VertxExtension)5 VertxTestContext (io.vertx.junit5.VertxTestContext)5 HttpURLConnection (java.net.HttpURLConnection)5 TimeUnit (java.util.concurrent.TimeUnit)5 MessageHelper (org.eclipse.hono.util.MessageHelper)5 Test (org.junit.Test)5 BeforeEach (org.junit.jupiter.api.BeforeEach)5 Test (org.junit.jupiter.api.Test)5 ExtendWith (org.junit.jupiter.api.extension.ExtendWith)5