All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.azure.eventhubs.impl.ManagementChannel Maven / Gradle / Ivy

There is a newer version: 3.3.0
Show newest version
/*
 * Copyright (c) Microsoft. All rights reserved.
 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
 */
package com.microsoft.azure.eventhubs.impl;

import org.apache.qpid.proton.Proton;
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
import org.apache.qpid.proton.message.Message;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import com.microsoft.azure.eventhubs.OperationCancelledException;
import com.microsoft.azure.eventhubs.TimeoutException;

final class ManagementChannel {

    final FaultTolerantObject innerChannel;
    final SessionProvider sessionProvider;
    final AmqpConnection connectionEventDispatcher;

    public ManagementChannel(final SessionProvider sessionProvider, final AmqpConnection connection) {
        this.sessionProvider = sessionProvider;
        this.connectionEventDispatcher = connection;

        final RequestResponseCloser closer = new RequestResponseCloser();
        this.innerChannel = new FaultTolerantObject<>(
                new RequestResponseOpener(
                        sessionProvider,
                        "mgmt-session",
                        "mgmt",
                        ClientConstants.MANAGEMENT_ADDRESS,
                        connection),
                closer);
        closer.setInnerChannel(this.innerChannel);
    }

    public CompletableFuture> request(
            final ReactorDispatcher dispatcher,
            final Map request,
            final long timeoutInMillis) {
        // no body required
        final Message requestMessage = Proton.message();
        final ApplicationProperties applicationProperties = new ApplicationProperties(request);
        requestMessage.setApplicationProperties(applicationProperties);
        final CompletableFuture> resultFuture = new CompletableFuture>();
        try {
            // schedule client-timeout on the request
            dispatcher.invoke((int) timeoutInMillis,
                    new DispatchHandler() {
                        @Override
                        public void onEvent() {
                            final RequestResponseChannel channel = innerChannel.unsafeGetIfOpened();
                            final String errorMessage;
                            if (channel != null && channel.getState() == IOObject.IOObjectState.OPENED) {
                                final String remoteContainerId = channel.getSendLink().getSession().getConnection().getRemoteContainer();
                                errorMessage = String.format("Management request timed out (%sms), after not receiving response from service. TrackingId: %s",
                                        timeoutInMillis, StringUtil.isNullOrEmpty(remoteContainerId) ? "n/a" : remoteContainerId);
                            } else {
                                errorMessage = "Management request timed out on the client - enable info level tracing to diagnose.";
                            }

                            resultFuture.completeExceptionally(new TimeoutException(errorMessage));
                        }
                    });
        } catch (final IOException ioException) {
            resultFuture.completeExceptionally(
                    new OperationCancelledException(
                            "Sending request failed while dispatching to Reactor, see cause for more details.",
                            ioException));

            return resultFuture;
        }

        // if there isn't even 5 millis left - request will not make the round-trip
        // to the event hubs service. so don't schedule the request - let it timeout
        if (timeoutInMillis > ClientConstants.MGMT_CHANNEL_MIN_RETRY_IN_MILLIS) {
            this.innerChannel.runOnOpenedObject(dispatcher,
                    new OperationResult() {
                        @Override
                        public void onComplete(final RequestResponseChannel result) {
                            result.request(requestMessage,
                                    new OperationResult() {
                                        @Override
                                        public void onComplete(final Message response) {
                                            final int statusCode = (int) response.getApplicationProperties().getValue()
                                                    .get(ClientConstants.PUT_TOKEN_STATUS_CODE);
                                            final String statusDescription = (String) response.getApplicationProperties().getValue()
                                                    .get(ClientConstants.PUT_TOKEN_STATUS_DESCRIPTION);

                                            if (statusCode == AmqpResponseCode.ACCEPTED.getValue()
                                                    || statusCode == AmqpResponseCode.OK.getValue()) {
                                                if (response.getBody() != null) {
                                                    resultFuture.complete((Map) ((AmqpValue) response.getBody()).getValue());
                                                }
                                            } else {
                                                this.onError(ExceptionUtil.amqpResponseCodeToException(statusCode, statusDescription));
                                            }
                                        }

                                        @Override
                                        public void onError(final Exception error) {
                                            resultFuture.completeExceptionally(error);
                                        }
                                    });
                        }

                        @Override
                        public void onError(Exception error) {
                            resultFuture.completeExceptionally(error);
                        }
                    });
        }

        return resultFuture;
    }

    public void close(final ReactorDispatcher reactorDispatcher, final OperationResult closeCallback) {
        this.innerChannel.close(reactorDispatcher, closeCallback);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy