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

org.jgroups.ping.common.OpenshiftPing Maven / Gradle / Ivy

/**
 *  Copyright 2014 Red Hat, Inc.
 *
 *  Red Hat licenses this file to you 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.jgroups.ping.common;

import static org.jgroups.ping.common.Utils.getSystemEnvInt;
import static org.jgroups.ping.common.Utils.trimToNull;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.jgroups.Event;
import org.jgroups.Message;
import org.jgroups.annotations.Property;
import org.jgroups.ping.common.server.Server;
import org.jgroups.ping.common.server.ServerFactory;
import org.jgroups.ping.common.server.Servers;
import org.jgroups.protocols.PING;
import org.openshift.ping.common.compatibility.CompatibilityException;
import org.openshift.ping.common.compatibility.CompatibilityUtils;

public abstract class OpenshiftPing extends PING {

    private String clusterName;

    private final String _systemEnvPrefix;

    @Property
    private int connectTimeout = 5000;
    private int _connectTimeout;

    @Property
    private int readTimeout = 30000;
    private int _readTimeout;

    @Property
    private int operationAttempts = 3;
    private int _operationAttempts;

    @Property
    private long operationSleep = 1000;
    private long _operationSleep;

    private ServerFactory _serverFactory;
    private Server _server;
    private String _serverName;

    private static Method sendMethod; //handled via reflection due to JGroups 3/4 incompatibility

    public OpenshiftPing(String systemEnvPrefix) {
        super();
        _systemEnvPrefix = trimToNull(systemEnvPrefix);
        try {
            if(CompatibilityUtils.isJGroups4()) {
                sendMethod = this.getClass().getMethod("up", Message.class);
            } else {
                sendMethod = this.getClass().getMethod("up", Event.class);
            }
        } catch (Exception e) {
            throw new CompatibilityException("Could not find suitable 'up' method.", e);
        }
    }

    protected final String getSystemEnvName(String systemEnvSuffix) {
        StringBuilder sb = new StringBuilder();
        String suffix = trimToNull(systemEnvSuffix);
        if (suffix != null) {
            if (_systemEnvPrefix != null) {
                sb.append(_systemEnvPrefix);
            }
            sb.append(suffix);
        }
        return sb.length() > 0 ? sb.toString() : null;
    }

    protected final int getConnectTimeout() {
        return _connectTimeout;
    }

    protected final int getReadTimeout() {
        return _readTimeout;
    }

    protected final int getOperationAttempts() {
        return _operationAttempts;
    }

    protected final long getOperationSleep() {
        return _operationSleep;
    }

    protected abstract boolean isClusteringEnabled();

    protected abstract int getServerPort();

    public final void setServerFactory(ServerFactory serverFactory) {
        _serverFactory = serverFactory;
    }

    @Override
    public void init() throws Exception {
        super.init();
        _connectTimeout = getSystemEnvInt(getSystemEnvName("CONNECT_TIMEOUT"), connectTimeout);
        _readTimeout = getSystemEnvInt(getSystemEnvName("READ_TIMEOUT"), readTimeout);
        _operationAttempts = getSystemEnvInt(getSystemEnvName("OPERATION_ATTEMPTS"), operationAttempts);
        _operationSleep = (long) getSystemEnvInt(getSystemEnvName("OPERATION_SLEEP"), (int) operationSleep);
    }

    @Override
    public void destroy() {
        _connectTimeout = 0;
        _readTimeout = 0;
        _operationAttempts = 0;
        _operationSleep = 0l;
        super.destroy();
    }

    @Override
    public void start() throws Exception {
        if (isClusteringEnabled()) {
            int serverPort = getServerPort();
            if (_serverFactory != null) {
                _server = _serverFactory.getServer(serverPort);
            } else {
                _server = Servers.getServer(serverPort);
            }
            _serverName = _server.getClass().getSimpleName();
            if (log.isInfoEnabled()) {
                log.info(String.format("Starting %s on port %s for channel address: %s", _serverName, serverPort, stack
                        .getChannel().getAddress()));
            }
            boolean started = _server.start(stack.getChannel());
            if (log.isInfoEnabled()) {
                log.info(String.format("%s %s.", _serverName, started ? "started" : "reused (pre-existing)"));
            }
        }
        super.start();
    }

    @Override
    public void stop() {
        try {
            if (_server != null) {
                if (log.isInfoEnabled()) {
                    log.info(String.format("Stopping server: %s", _serverName));
                }
                boolean stopped = _server.stop(stack.getChannel());
                if (log.isInfoEnabled()) {
                    log.info(String.format("%s %s.", _serverName, stopped ? "stopped" : "not stopped (still in use)"));
                }
            }
        } finally {
            super.stop();
        }
    }

    public Object down(Event evt) {
        switch (evt.getType()) {
        case Event.CONNECT:
        case Event.CONNECT_WITH_STATE_TRANSFER:
        case Event.CONNECT_USE_FLUSH:
        case Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH:
            clusterName = (String) evt.getArg();
            break;
        }
        return super.down(evt);
    }

    @Override
    protected void sendMcastDiscoveryRequest(Message msg) {
        List nodes = readAll();
        if (nodes == null) {
            return;
        }
        if (msg.getSrc() == null) {
            msg.setSrc(local_addr);
        }
        for (InetSocketAddress node : nodes) {
            // forward the request to each node
            timer.execute(new SendDiscoveryRequest(node, msg));
        }
    }

    public void handlePingRequest(InputStream stream) throws Exception {
        DataInputStream dataInput = new DataInputStream(stream);
        Message msg = new Message();
        msg.readFrom(dataInput);
        try {
            sendUp(msg);
        } catch (Exception e) {
            log.error("Error processing GET_MBRS_REQ.", e);
        }
    }

    private void sendUp(Message msg) {
        try {
            if(CompatibilityUtils.isJGroups4()) {
                sendMethod.invoke(this, msg);
            } else {
                sendMethod.invoke(this, new Event(1, msg));
            }
        } catch (Exception e) {
            throw new CompatibilityException("Could not invoke 'up' method.", e);
        }
    }

    private List readAll() {
        if (isClusteringEnabled()) {
            return doReadAll(clusterName);
        } else {
            return Collections.emptyList();
        }
    }

    protected abstract List doReadAll(String clusterName);

    private final class SendDiscoveryRequest implements Runnable {
        private final InetSocketAddress node;
        private final Message msg;
        private int attempts;

        private SendDiscoveryRequest(InetSocketAddress node, Message msg) {
            this.node = node;
            this.msg = msg;
        }

        @Override
        public void run() {
            ++attempts;
            final String url = String.format("http://%s:%s", node.getHostString(), node.getPort());
            if (log.isTraceEnabled()) {
                log.trace(String.format(
                        "%s opening connection: url [%s], clusterName [%s], connectTimeout [%s], readTimeout [%s]",
                        getClass().getSimpleName(), url, clusterName, _connectTimeout, _readTimeout));
            }
            HttpURLConnection connection = null;
            try {
                connection = (HttpURLConnection) new URL(url).openConnection();
                connection.addRequestProperty(Server.CLUSTER_NAME, clusterName);
                if (_connectTimeout < 0 || _readTimeout < 0) {
                    throw new IllegalArgumentException(String.format(
                            "Neither connectTimeout [%s] nor readTimeout [%s] can be less than 0 for URLConnection.",
                            _connectTimeout, _readTimeout));
                }
                connection.setConnectTimeout(_connectTimeout);
                connection.setReadTimeout(_readTimeout);
                connection.setDoOutput(true);
                connection.setRequestMethod("POST");
                DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                msg.writeTo(out);
                out.flush();
                String responseMessage = connection.getResponseMessage();
                if (log.isTraceEnabled()) {
                    log.trace(String.format(
                            "%s received response from server: url [%s], clusterName [%s], response [%s]", getClass()
                                    .getSimpleName(), url, clusterName, responseMessage));
                }
            } catch (Exception e) {
                log.warn(String.format("Error sending ping request: url [%s], clusterName [%s], attempts[%d]: %s", url,
                        clusterName, attempts, e.getLocalizedMessage()));
                if (attempts < _operationAttempts) {
                    timer.schedule(this, _operationSleep, TimeUnit.MILLISECONDS);
                }
            } finally {
                try {
                    connection.disconnect();
                } catch (Exception e) {
                }
            }
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy