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

org.jivesoftware.smack.websocket.WebSocketConnectionAttemptState Maven / Gradle / Ivy

The newest version!
/**
 *
 * Copyright 2020 Aditya Borikar, 2020-2021 Florian Schmaus.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jivesoftware.smack.websocket;

import java.util.ArrayList;
import java.util.List;

import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.SmackFuture;
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
import org.jivesoftware.smack.fsm.StateTransitionResult;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.websocket.impl.AbstractWebSocket;
import org.jivesoftware.smack.websocket.impl.WebSocketFactory;
import org.jivesoftware.smack.websocket.rce.WebSocketRemoteConnectionEndpoint;
import org.jivesoftware.smack.websocket.rce.WebSocketRemoteConnectionEndpointLookup;

public final class WebSocketConnectionAttemptState {

    private final ModularXmppClientToServerConnectionInternal connectionInternal;
    private final XmppWebSocketTransportModule.XmppWebSocketTransport.DiscoveredWebSocketEndpoints discoveredEndpoints;
    private final WebSocketFactory webSocketFactory;

    private AbstractWebSocket webSocket;

    WebSocketConnectionAttemptState(ModularXmppClientToServerConnectionInternal connectionInternal,
                    XmppWebSocketTransportModule.XmppWebSocketTransport.DiscoveredWebSocketEndpoints discoveredWebSocketEndpoints,
                    WebSocketFactory webSocketFactory) {
        assert discoveredWebSocketEndpoints != null;
        assert !discoveredWebSocketEndpoints.result.isEmpty();

        this.connectionInternal = connectionInternal;
        this.discoveredEndpoints = discoveredWebSocketEndpoints;
        this.webSocketFactory = webSocketFactory;
    }

    /**
     * Establish  a websocket connection with one of the discoveredRemoteConnectionEndpoints.
* * @return {@link AbstractWebSocket} with which connection is established * @throws InterruptedException if the calling thread was interrupted */ @SuppressWarnings({"incomplete-switch", "MissingCasesInEnumSwitch"}) StateTransitionResult.Failure establishWebSocketConnection() throws InterruptedException { final WebSocketRemoteConnectionEndpointLookup.Result endpointLookupResult = discoveredEndpoints.result; final List failures = new ArrayList<>(endpointLookupResult.discoveredEndpointCount()); webSocket = null; SecurityMode securityMode = connectionInternal.connection.getConfiguration().getSecurityMode(); switch (securityMode) { case required: case ifpossible: establishWebSocketConnection(endpointLookupResult.discoveredSecureEndpoints, failures); if (webSocket != null) { return null; } } establishWebSocketConnection(endpointLookupResult.discoveredInsecureEndpoints, failures); if (webSocket != null) { return null; } StateTransitionResult.Failure failure = FailedToConnectToAnyWebSocketEndpoint.create(failures); return failure; } private void establishWebSocketConnection(List webSocketEndpoints, List failures) throws InterruptedException { final int endpointCount = webSocketEndpoints.size(); List> futures = new ArrayList<>(endpointCount); { List webSockets = new ArrayList<>(endpointCount); // First only create the AbstractWebSocket instances, in case a constructor throws. for (WebSocketRemoteConnectionEndpoint endpoint : webSocketEndpoints) { AbstractWebSocket webSocket = webSocketFactory.create(endpoint, connectionInternal); webSockets.add(webSocket); } for (AbstractWebSocket webSocket : webSockets) { SmackFuture future = webSocket.getFuture(); futures.add(future); } } SmackFuture.await(futures, connectionInternal.connection.getReplyTimeout()); for (SmackFuture future : futures) { AbstractWebSocket connectedWebSocket = future.getIfAvailable(); if (connectedWebSocket == null) { Exception exception = future.getExceptionIfAvailable(); assert exception != null; failures.add(exception); continue; } if (webSocket == null) { webSocket = connectedWebSocket; // Continue here since we still need to read out the failure exceptions from potential further remaining // futures and close remaining successfully connected ones. continue; } connectedWebSocket.disconnect(1000, "Using other connection endpoint at " + webSocket.getEndpoint()); } } public AbstractWebSocket getConnectedWebSocket() { return webSocket; } public static final class FailedToConnectToAnyWebSocketEndpoint extends StateTransitionResult.Failure { private final List failures; private FailedToConnectToAnyWebSocketEndpoint(String failureMessage, List failures) { super(failureMessage); this.failures = failures; } public List getFailures() { return failures; } private static FailedToConnectToAnyWebSocketEndpoint create(List failures) { StringBuilder sb = new StringBuilder(256); StringUtils.appendTo(failures, sb, e -> sb.append(e.getMessage())); String message = sb.toString(); return new FailedToConnectToAnyWebSocketEndpoint(message, failures); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy