/** * Close the endpoint, detaching the link */ public void close() { if (this.sender.isOpen()) { // detach link this.sender.close(); } } }
@Override public void onComplete() { if(!completed.getAndSet(true)) { connCtx.runOnContext(x-> { // clear the handlers, we are done sender.sendQueueDrainHandler(null); sender.detachHandler(null); sender.closeHandler(null); sender.close(); }); } }
/** * Close the endpoint, detaching the links */ public void close() { // detach links for (Map.Entry<String, AmqpPublisher> entry: this.publishers.entrySet()) { AmqpPublisher publisher = entry.getValue(); if (publisher.isOpen()) { publisher.close(); } } if (this.senderPubrel.isOpen()) { this.senderPubrel.close(); } this.publishers.clear(); this.deliveries.clear(); }
@Override public void onError(Throwable t) { Objects.requireNonNull(t, "An error must be supplied when calling onError"); if(!completed.getAndSet(true)) { connCtx.runOnContext(x-> { // clear the handlers, we are done sender.sendQueueDrainHandler(null); sender.detachHandler(null); sender.closeHandler(null); sender.close(); }); } }
private void closeSender(final UpstreamReceiver link) { ProtonSender sender = activeSenders.remove(link); if (sender != null && sender.isOpen()) { logger.info("closing downstream sender [con: {}, link: {}]", link.getConnectionId(), link.getLinkId()); sender.close(); } }
@Override public void onLinkAttach(final ProtonSender sender, final ResourceIdentifier targetResource) { /* note: we "misuse" deviceId part of the resource as reply address here */ if (targetResource.getResourceId() == null) { logger.debug("link target provided in client's link ATTACH does not match pattern \"registration/<tenant>/<reply-address>\""); sender.setCondition(condition(AmqpError.INVALID_FIELD.toString(), "link target must have the following format registration/<tenant>/<reply-address>")); sender.close(); } else { logger.debug("establishing sender link with client [{}]", MessageHelper.getLinkName(sender)); final MessageConsumer<JsonObject> replyConsumer = vertx.eventBus().consumer(targetResource.toString(), message -> { // TODO check for correct session here...? logger.trace("forwarding reply to client: {}", message.body()); final Message amqpReply = RegistrationConstants.getAmqpReply(message); sender.send(amqpReply); }); sender.closeHandler(senderClosed -> { replyConsumer.unregister(); senderClosed.result().close(); final String linkName = MessageHelper.getLinkName(sender); logger.debug("receiver closed link [{}], removing associated event bus consumer [{}]", linkName, replyConsumer.address()); }); sender.setQoS(ProtonQoS.AT_LEAST_ONCE).open(); } }
@Override public void onLinkAttach(final ProtonConnection con, final ProtonSender sender, final ResourceIdentifier targetResource) { logger.info("Endpoint [{}] does not support data retrieval, closing link.", getName()); sender.setCondition(ProtonHelper.condition(AmqpError.NOT_IMPLEMENTED, "resource cannot be read from")); sender.close(); }
serverSender.close(); });
@Override public void onLinkAttach(final ProtonConnection con, final ProtonSender sender, final ResourceIdentifier targetResource) { logger.info("Endpoint [{}] does not support data retrieval, closing link.", getName()); sender.setCondition(ProtonHelper.condition(AmqpError.NOT_IMPLEMENTED, "resource cannot be read from")); sender.close(); }
@Override public void onLinkAttach(final ProtonSender sender, final ResourceIdentifier targetResource) { logger.info("Endpoint [{}] does not support data retrieval, closing link.", getName()); sender.setCondition(ProtonHelper.condition(AmqpError.NOT_IMPLEMENTED, "resource cannot be read from")); sender.close(); }
/** * Removes all state kept for an upstream client. * <p> * Any downstream sender associated with the client is closed. * * @param link The upstream client. */ public final void removeSender(final UpstreamReceiver link) { List<UpstreamReceiver> senders = sendersPerConnection.get(link.getConnectionId()); if (senders != null) { senders.remove(link); } ProtonSender downstreamSender = activeSenders.remove(link); if (downstreamSender != null && downstreamSender.isOpen()) { logger.info("closing downstream sender [con: {}, link: {}]", link.getConnectionId(), link.getLinkId()); downstreamSender.close(); } }
@Override public void close() { // close Kafka related stuff super.close(); if (this.offsetTracker != null) this.offsetTracker.clear(); if (this.sender.isOpen()) { this.sender.close(); } }
/** * Close the endpoint, detaching the link * * @param isDetachForced if link should be detached with error */ public void close(boolean isDetachForced) { if (this.sender.isOpen()) { if (isDetachForced) { ErrorCondition errorCondition = new ErrorCondition(LinkError.DETACH_FORCED, "Link detached due to a brute MQTT client disconnection"); this.sender.setCondition(errorCondition); } // detach link this.sender.close(); } } }
@Override public void close() throws Exception { if (context != null) { CompletableFuture.allOf( runOnContext(context, () -> { if (sender != null) { sender.close(); } }), runOnContext(context, () -> { if (receiver != null) { receiver.close(); } }), runOnContext(context, () -> { if (connection != null) { connection.close(); } })).get(1, TimeUnit.MINUTES); } sender = null; receiver = null; connection = null; replies.clear(); replyTo = null; context = null; }
/** * Verifies that the endpoint closes a sender that does not contain a source address * that is not suitable as a reply-to-address. */ @Test public void testOnLinkAttachClosesSenderWithoutAppropriateReplyAddress() { final RequestResponseEndpoint<ServiceConfigProperties> endpoint = getEndpoint(true); endpoint.onLinkAttach(connection, sender, resource); verify(sender).setCondition(any()); verify(sender).close(); }
@Override public final void onLinkAttach(final ProtonConnection con, final ProtonSender sender, final ResourceIdentifier targetResource) { if (ProtonQoS.AT_LEAST_ONCE.equals(sender.getRemoteQoS())) { final HonoUser user = Constants.getClientPrincipal(con); sender.setQoS(ProtonQoS.AT_LEAST_ONCE).open(); logger.debug("transferring token to client..."); final Message tokenMsg = ProtonHelper.message(user.getToken()); MessageHelper.addProperty(tokenMsg, AuthenticationConstants.APPLICATION_PROPERTY_TYPE, AuthenticationConstants.TYPE_AMQP_JWT); sender.send(tokenMsg, disposition -> { if (disposition.remotelySettled()) { logger.debug("successfully transferred auth token to client"); } else { logger.debug("failed to transfer auth token to client"); } sender.close(); }); } else { onLinkDetach(sender, ProtonHelper.condition(AmqpError.INVALID_FIELD, "supports AT_LEAST_ONCE delivery mode only")); } }
/** * Verify that a second response link to the same address is being rejected. */ @Test public void testDuplicateSubscription() { final ProtonConnection con1 = mock(ProtonConnection.class); final ProtonConnection con2 = mock(ProtonConnection.class); final ProtonSender sender1 = mock(ProtonSender.class); final ProtonSender sender2 = mock(ProtonSender.class); final Future<Void> processingTracker = Future.future(); final RequestResponseEndpoint<ServiceConfigProperties> endpoint = getEndpoint(true, processingTracker); // WHEN a first sender attaches endpoint.onLinkAttach(con1, sender1, REPLY_RESOURCE); // THEN open has to be called verify(sender1).open(); // WHEN a second sender attaches endpoint.onLinkAttach(con2, sender2, REPLY_RESOURCE); // THEN close has to be called verify(sender2).close(); }
LOG.debug("subject [{}] is not authorized to READ from [{}]", user.getName(), targetResource); sender.setCondition(ProtonHelper.condition(AmqpError.UNAUTHORIZED_ACCESS.toString(), "unauthorized")); sender.close(); LOG.debug("client has provided invalid resource identifier as target address", e); sender.setCondition(ProtonHelper.condition(AmqpError.NOT_FOUND, "no such address")); sender.close();