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

org.yamcs.api.artemis.YamcsConnector Maven / Gradle / Ivy

There is a newer version: 4.10.9
Show newest version
package org.yamcs.api.artemis;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
import org.apache.activemq.artemis.api.core.client.SessionFailureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yamcs.YamcsException;
import org.yamcs.api.YamcsConnectionProperties;
import org.yamcs.protobuf.YamcsInstance;
import org.yamcs.protobuf.YamcsInstances;

/**
 * this is like a yamcssession but performs reconnection and implements some callbacks to announce the state. to be used
 * by all the gui data receivers (event viewer, archive browser, etc)
 * 
 * @author nm
 *
 */
public class YamcsConnector implements SessionFailureListener {
    public int getMaxAttempts() {
        return maxAttempts;
    }

    public void setMaxAttempts(int maxAttempts) {
        this.maxAttempts = maxAttempts;
    }

    CopyOnWriteArrayList connectionListeners = new CopyOnWriteArrayList<>();
    volatile boolean connected, connecting;
    protected YamcsSession yamcsSession;
    protected YamcsConnectionProperties connectionParams;
    static Logger log = LoggerFactory.getLogger(YamcsConnector.class);
    private boolean retry = true;
    private boolean reconnecting = false;
    final private ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    int maxAttempts = 10;

    public YamcsConnector() {
    }

    public YamcsConnector(boolean retry) {
        this.retry = retry;
    }

    public void addConnectionListener(ConnectionListener connectionListener) {
        this.connectionListeners.add(connectionListener);
    }

    public List getYamcsInstances() {
        try {
            YamcsSession ys = YamcsSession.newBuilder().setConnectionParams(connectionParams).build();
            YamcsClient mc = ys.newClientBuilder().setRpc(true).build();
            YamcsInstances ainst = (YamcsInstances) mc.executeRpc(Protocol.YAMCS_SERVER_CONTROL_ADDRESS,
                    "getYamcsInstances", null, YamcsInstances.newBuilder());
            mc.close();
            List instances = new ArrayList<>(ainst.getInstanceCount());
            for (YamcsInstance ai : ainst.getInstanceList()) {
                instances.add(ai.getName());
            }
            ys.close();
            return instances;
        } catch (ActiveMQException hqe) {
            // If we don't have permissions, treat as a failed connection
            if (hqe.getType() == ActiveMQExceptionType.SECURITY_EXCEPTION
                    || hqe.getType() == ActiveMQExceptionType.SESSION_CREATION_REJECTED) {
                String message = "Connection failed with security exception: " + hqe.getMessage();
                log.warn(message);
                if (connected) {
                    disconnect();
                }
                for (ConnectionListener cl : connectionListeners) {
                    cl.connectionFailed(connectionParams.getUrl(), new YamcsException(message));
                }
            } else {
                // Other errors may not be fatal
                for (ConnectionListener cl : connectionListeners) {
                    cl.log("failed to retrieve instances: " + hqe);
                }
            }
        } catch (Exception e) {
            for (ConnectionListener cl : connectionListeners) {
                cl.log("failed to retrieve instances: " + e);
            }
        }
        return null;
    }

    public Future connect(YamcsConnectionProperties cp) {
        this.connectionParams = cp;
        return doConnect();
    }

    private FutureTask doConnect() {
        if (connected) {
            disconnect();
        }
        final String url = connectionParams.getUrl();

        FutureTask future = new FutureTask<>(() -> {

            // connect to yamcs
            try {
                if (reconnecting && !retry) {
                    log.warn("Retries are disabled, cancelling reconnection");
                    reconnecting = false;
                    return;
                }

                connecting = true;
                for (ConnectionListener cl1 : connectionListeners) {
                    cl1.connecting(url);
                }
                for (int i = 0; i < maxAttempts; i++) {
                    try {
                        log.debug("Connecting to {} attempt {}", url, i);
                        yamcsSession = YamcsSession.newBuilder().setConnectionParams(connectionParams).build();
                        log.debug("Connection successful");
                        yamcsSession.session.addFailureListener(YamcsConnector.this);
                        connected = true;
                        for (ConnectionListener cl2 : connectionListeners) {
                            cl2.connected(url);
                        }
                        return;
                    } catch (ArtemisApiException e1) {
                        // If we don't have permissions, treat as a failed connection and don't re-try
                        Throwable cause = e1.getCause();
                        if (cause != null && cause instanceof ActiveMQException
                                && ((ActiveMQException) cause).getType() == ActiveMQExceptionType.SECURITY_EXCEPTION) {
                            String message = "Connection failed with security exception: " + e1.getMessage();
                            log.warn(message);
                            if (connected) {
                                disconnect();
                            }
                            for (ConnectionListener cl3 : connectionListeners) {
                                cl3.connectionFailed(url, new YamcsException(message));
                            }
                            return;
                        }

                        // For anything other than a security exception, re-try
                        for (ConnectionListener cl4 : connectionListeners) {
                            cl4.log("Connection to " + url + " failed :" + e1.getMessage());
                        }
                        log.warn("Connection to " + url + " failed :!", e1);
                        Thread.sleep(5000);
                    }
                }
                connecting = false;
                for (ConnectionListener cl5 : connectionListeners) {
                    cl5.log(maxAttempts + " connection attempts failed, giving up.");
                    cl5.connectionFailed(url,
                            new YamcsException(maxAttempts + " connection attempts failed, giving up."));
                }
                log.warn(maxAttempts + " connection attempts failed, giving up.");
            } catch (InterruptedException e2) {
                Thread.currentThread().interrupt();
                for (ConnectionListener cl6 : connectionListeners) {
                    cl6.connectionFailed(url, new YamcsException("Thread interrupted", e2));
                }
            }
        }, url);
        executor.submit(future);
        return future;
    }

    public void disconnect() {
        log.warn("Disconnection requested");
        if (!connected) {
            return;
        }

        try {
            yamcsSession.close();
            connected = false;
        } catch (ActiveMQException e) {
            for (ConnectionListener cl : connectionListeners) {
                cl.log(e.toString());
            }
        }
    }

    public String getUrl() {
        return connectionParams.getUrl();
    }

    public boolean isConnected() {
        return connected;
    }

    public boolean isConnecting() {
        return connecting;
    }

    @Override
    public void connectionFailed(ActiveMQException e, boolean failedOver, String scaleDownTargetNodeID) {
        connectionFailed(e, failedOver);
    }

    @Override
    public void connectionFailed(ActiveMQException e, boolean failedOver) {
        connected = false;
        for (ConnectionListener cl : connectionListeners) {
            cl.disconnected();
        }
        log.warn("Connection to Yamcs lost: ", e);
        doConnect();

    }

    @Override
    public void beforeReconnect(ActiveMQException e) {
        // should not be called because reconnection is not configured in the factory
        // log.warn("Before reconnect: ", creatorContext);
        log.warn("Before reconnect: ", e);
        reconnecting = true;
    }

    public YamcsSession getSession() {
        return yamcsSession;
    }

    public YamcsConnectionProperties getConnectionParams() {
        return connectionParams;
    }

    public void close() throws ActiveMQException {
        yamcsSession.close();
    }

    public ExecutorService getExecutor() {
        return executor;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy