com.alibaba.wasp.ipc.WaspRPC.java Source code

Java tutorial

Introduction

Here is the source code for com.alibaba.wasp.ipc.WaspRPC.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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 com.alibaba.wasp.ipc;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.RetriesExhaustedException;
import org.apache.hadoop.net.NetUtils;
import org.apache.hadoop.util.ReflectionUtils;

import javax.net.SocketFactory;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;

public class WaspRPC {

    protected static final Log LOG = LogFactory.getLog("com.alibaba.wasp.ipc.WaspRPC");

    /**
     * Configuration key for the {@link RpcEngine} implementation to load to
     * handle connection protocols. Handlers for individual protocols can be
     * configured using {@code "wasp.rpc.engine." + protocol.class.name}.
     */
    public static final String RPC_ENGINE_PROP = "wasp.rpc.engine";

    // track what RpcEngine is used by a proxy class, for stopProxy()
    private static final Map<Class, RpcEngine> PROXY_ENGINES = new HashMap<Class, RpcEngine>();

    // cache of RpcEngines by protocol
    private static final Map<Class, RpcEngine> PROTOCOL_ENGINES = new HashMap<Class, RpcEngine>();

    /** Construct a server for a protocol implementation instance. */
    public static RpcServer getServer(Class protocol, final Object instance, final Class<?>[] ifaces,
            String bindAddress, int port, Configuration conf) throws IOException {
        return getProtocolEngine(protocol, conf).getServer(protocol, instance, ifaces, bindAddress, port, conf);
    }

    // return the RpcEngine configured to handle a protocol
    private static synchronized RpcEngine getProtocolEngine(Class protocol, Configuration conf) {
        RpcEngine engine = PROTOCOL_ENGINES.get(protocol);
        if (engine == null) {
            // check for a configured default engine
            Class<?> defaultEngine = conf.getClass(RPC_ENGINE_PROP, ProtobufRpcEngine.class);

            // check for a per interface override
            Class<?> impl = conf.getClass(RPC_ENGINE_PROP + "." + protocol.getName(), defaultEngine);
            LOG.debug("Using " + impl.getName() + " for " + protocol.getName());
            engine = (RpcEngine) ReflectionUtils.newInstance(impl, conf);
            if (protocol.isInterface())
                PROXY_ENGINES.put(Proxy.getProxyClass(protocol.getClassLoader(), protocol), engine);
            PROTOCOL_ENGINES.put(protocol, engine);
        }
        return engine;
    }

    /**
     * Construct a client-side proxy object that implements the named protocol,
     * talking to a server at the named address.
     *
     * @param protocol
     *          interface
     * @param clientVersion
     *          version we are expecting
     * @param addr
     *          remote address
     * @param conf
     *          configuration
     * @param factory
     *          socket factory
     * @param rpcTimeout
     *          timeout for each RPC
     * @return proxy
     * @throws java.io.IOException
     *           e
     */
    public static VersionedProtocol getProxy(Class<? extends VersionedProtocol> protocol, long clientVersion,
            InetSocketAddress addr, Configuration conf, SocketFactory factory, int rpcTimeout) throws IOException {
        RpcEngine engine = getProtocolEngine(protocol, conf);
        VersionedProtocol proxy = engine.getProxy(protocol, clientVersion, addr, conf, factory, rpcTimeout);
        return proxy;
    }

    /**
     * Construct a client-side proxy object with the default SocketFactory
     *
     * @param protocol
     *          interface
     * @param clientVersion
     *          version we are expecting
     * @param addr
     *          remote address
     * @param conf
     *          configuration
     * @param rpcTimeout
     *          timeout for each RPC
     * @return a proxy instance
     * @throws java.io.IOException
     *           e
     */
    public static VersionedProtocol getProxy(Class<? extends VersionedProtocol> protocol, long clientVersion,
            InetSocketAddress addr, Configuration conf, int rpcTimeout) throws IOException {

        return getProxy(protocol, clientVersion, addr, conf, NetUtils.getDefaultSocketFactory(conf), rpcTimeout);
    }

    static long getProtocolVersion(Class<? extends VersionedProtocol> protocol)
            throws NoSuchFieldException, IllegalAccessException {
        Field versionField = protocol.getField("VERSION");
        versionField.setAccessible(true);
        return versionField.getLong(protocol);
    }

    /**
     * @param protocol
     *          protocol interface
     * @param clientVersion
     *          which client version we expect
     * @param addr
     *          address of remote service
     * @param conf
     *          configuration
     * @param maxAttempts
     *          max attempts
     * @param rpcTimeout
     *          timeout for each RPC
     * @param timeout
     *          timeout in milliseconds
     * @return proxy
     * @throws java.io.IOException
     *           e
     */
    @SuppressWarnings("unchecked")
    public static VersionedProtocol waitForProxy(Class protocol, long clientVersion, InetSocketAddress addr,
            Configuration conf, int maxAttempts, int rpcTimeout, long timeout) throws IOException {
        long startTime = System.currentTimeMillis();
        IOException ioe;
        int reconnectAttempts = 0;
        while (true) {
            try {
                return getProxy(protocol, clientVersion, addr, conf, rpcTimeout);
            } catch (SocketTimeoutException te) { // namenode is busy
                LOG.info("Problem connecting to server: " + addr);
                ioe = te;
            } catch (IOException ioex) {
                // We only handle the ConnectException.
                ConnectException ce = null;
                if (ioex instanceof ConnectException) {
                    ce = (ConnectException) ioex;
                    ioe = ce;
                } else if (ioex.getCause() != null && ioex.getCause() instanceof ConnectException) {
                    ce = (ConnectException) ioex.getCause();
                    ioe = ce;
                } else if (ioex.getMessage().toLowerCase().contains("connection refused")) {
                    ce = new ConnectException(ioex.getMessage());
                    ioe = ce;
                } else {
                    // This is the exception we can't handle.
                    ioe = ioex;
                }
                if (ce != null) {
                    handleConnectionException(++reconnectAttempts, maxAttempts, protocol, addr, ce);
                }
            }
            // check if timed out
            if (System.currentTimeMillis() - timeout >= startTime) {
                throw ioe;
            }

            // wait for retry
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
                // IGNORE
            }
        }
    }

    /**
     * @param retries
     *          current retried times.
     * @param maxAttmpts
     *          max attempts
     * @param protocol
     *          protocol interface
     * @param addr
     *          address of remote service
     * @param ce
     *          ConnectException
     * @throws org.apache.hadoop.hbase.client.RetriesExhaustedException
     */
    private static void handleConnectionException(int retries, int maxAttmpts, Class<?> protocol,
            InetSocketAddress addr, ConnectException ce) throws RetriesExhaustedException {
        if (maxAttmpts >= 0 && retries >= maxAttmpts) {
            LOG.info("Server at " + addr + " could not be reached after " + maxAttmpts + " tries, giving up.");
            throw new RetriesExhaustedException("Failed setting up proxy " + protocol + " to " + addr.toString()
                    + " after attempts=" + maxAttmpts, ce);
        }
    }

    public static void stopProxy(VersionedProtocol proxy) {
        if (proxy != null) {
            getProxyEngine(proxy).stopProxy(proxy);
        }
    }

    // return the RpcEngine that handles a proxy object
    private static synchronized RpcEngine getProxyEngine(Object proxy) {
        return PROXY_ENGINES.get(proxy.getClass());
    }
}