@Override public final boolean isOpen() { return sender.isOpen(); }
/** * Checks if this client's sender and receiver links are open. * * @return {@code true} if a request can be sent to and a response can be received * from the peer. */ @Override public final boolean isOpen() { return sender != null && sender.isOpen() && receiver != null && receiver.isOpen(); }
/** * Close the endpoint, detaching the link */ public void close() { if (this.sender.isOpen()) { // detach link this.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(); } }
/** * Creates a new sender. * * @param config The configuration properties to use. * @param sender The sender link to send messages over. * @param tenantId The identifier of the tenant that the * devices belong to which have published the messages * that this sender is used to send downstream. * @param targetAddress The target address to send the messages to. * @param context The vert.x context to use for sending the messages. * @param tracer The tracer to use. */ protected AbstractSender( final ClientConfigProperties config, final ProtonSender sender, final String tenantId, final String targetAddress, final Context context, final Tracer tracer) { super(context, config, tracer); this.sender = Objects.requireNonNull(sender); this.tenantId = Objects.requireNonNull(tenantId); this.targetAddress = targetAddress; if (sender.isOpen()) { this.offeredCapabilities = Optional.ofNullable(sender.getRemoteOfferedCapabilities()) .map(caps -> Collections.unmodifiableList(Arrays.asList(caps))) .orElse(Collections.emptyList()); this.registrationAssertionRequired = supportsCapability(Constants.CAP_REG_ASSERTION_VALIDATION); } }
/** * 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(); }
/** * 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(); } }
@Override public final void onClientAttach(final UpstreamReceiver client, final Handler<AsyncResult<Void>> resultHandler) { if (!running) { throw new IllegalStateException("adapter must be started first"); } Objects.requireNonNull(client); Objects.requireNonNull(resultHandler); ProtonSender sender = activeSenders.get(client); if (sender != null && sender.isOpen()) { logger.info("reusing existing downstream sender [con: {}, link: {}]", client.getConnectionId(), client.getLinkId()); resultHandler.handle(Future.succeededFuture()); } else { createSender( client.getTargetAddress(), replenishedSender -> handleFlow(replenishedSender, client), creationAttempt -> { if (creationAttempt.succeeded()) { logger.info("created downstream sender [con: {}, link: {}]", client.getConnectionId(), client.getLinkId()); addSender(client, creationAttempt.result()); resultHandler.handle(Future.succeededFuture()); } else { logger.warn("can't create downstream sender [con: {}, link: {}]", client.getConnectionId(), client.getLinkId(), creationAttempt.cause()); removeSender(client); resultHandler.handle(Future.failedFuture(creationAttempt.cause())); } }); } }
private void partitionsAssignedHandler(Set<TopicPartition> partitions) { if (partitions.isEmpty()) { sendAmqpError(AmqpBridge.newError(AmqpBridge.AMQP_ERROR_NO_PARTITIONS, "All partitions already have a receiver")); } else { if (!this.sender.isOpen()) { this.sender .setSource(this.sender.getRemoteSource()) .open(); } } }
/** * 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(); } } }
/** * Send the AMQP_PUBREL to the related client pubrel address * * @param amqpPubrelMessage AMQP_PUBREL message */ public void publish(AmqpPubrelMessage amqpPubrelMessage, Handler<AsyncResult<ProtonDelivery>> handler) { // send AMQP_PUBREL message if (!this.senderPubrel.isOpen()) { this.senderPubrel .setQoS(ProtonQoS.AT_LEAST_ONCE) .open(); // TODO: think about starting a timer for inactivity on this link for detaching ? } this.senderPubrel.send(amqpPubrelMessage.toAmqp(), delivery -> { if (delivery.getRemoteState() == Accepted.getInstance()) { LOG.info("AMQP pubrel delivery {}", delivery.getRemoteState()); handler.handle(Future.succeededFuture(delivery)); } else { handler.handle(Future.failedFuture(String.format("AMQP pubrel delivery %s", delivery.getRemoteState()))); } }); }
@Override @Deprecated public final Future<ProtonDelivery> send(final Message rawMessage, final Handler<Void> capacityAvailableHandler) { Objects.requireNonNull(rawMessage); return executeOrRunOnContext(result -> { if (capacityAvailableHandler == null) { final Span currentSpan = startSpan(rawMessage); sendMessage(rawMessage, currentSpan).setHandler(result.completer()); } else if (this.drainHandler != null) { result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "cannot send message while waiting for replenishment with credit")); } else if (sender.isOpen()) { final Span currentSpan = startSpan(rawMessage); sendMessage(rawMessage, currentSpan).setHandler(result.completer()); if (sender.sendQueueFull()) { sendQueueDrainHandler(capacityAvailableHandler); } else { capacityAvailableHandler.handle(null); } } else { result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "send link to peer is closed")); } }); }
logger.info("no downstream sender for link [{}] available, discarding message and closing link with client", client.getLinkId()); client.close(ErrorConditions.ERROR_NO_DOWNSTREAM_CONSUMER); } else if (sender.isOpen()) { if (sender.getCredit() <= 0) { if (delivery.remotelySettled()) {
/** * {@inheritDoc} */ @Override public Future<Void> sendOneWayCommand(final String command, final String contentType, final Buffer data, final Map<String, Object> properties) { Objects.requireNonNull(command); final Span currentSpan = newChildSpan(null, command); if (sender.isOpen()) { final Future<BufferResult> responseTracker = Future.future(); final Message request = ProtonHelper.message(); AbstractHonoClient.setApplicationProperties(request, properties); final String messageId = createMessageId(); request.setMessageId(messageId); request.setSubject(command); MessageHelper.setPayload(request, contentType, data); sendRequest(request, responseTracker.completer(), null, currentSpan); return responseTracker.map(ignore -> null); } else { TracingHelper.logError(currentSpan, "sender link is not open"); return Future.failedFuture(new ServerErrorException( HttpURLConnection.HTTP_UNAVAILABLE, "sender link is not open")); } }
private Future<MessageConsumer> createCommandConsumer( final ProtonSender sender, final ResourceIdentifier sourceAddress) { return getCommandConnection().createCommandConsumer( sourceAddress.getTenantId(), sourceAddress.getResourceId(), commandContext -> { Tags.COMPONENT.set(commandContext.getCurrentSpan(), getTypeName()); final Command command = commandContext.getCommand(); if (!command.isValid()) { final Exception ex = new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed command message"); commandContext.reject(AmqpContext.getErrorCondition(ex), 1); } else if (!sender.isOpen()) { commandContext.release(1); } else { onCommandReceived(sender, commandContext); } }, closeHandler -> {}, DEFAULT_COMMAND_CONSUMER_CHECK_INTERVAL_MILLIS); }