org.diqube.connection.DefaultConnectionFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.diqube.connection.DefaultConnectionFactory.java

Source

/**
 * diqube: Distributed Query Base.
 *
 * Copyright (C) 2015 Bastian Gloeckle
 *
 * This file is part of diqube.
 *
 * diqube is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.diqube.connection;

import java.lang.reflect.InvocationTargetException;

import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TMultiplexedProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.THttpClient;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.diqube.connection.integrity.IntegrityCheckingProtocol;
import org.diqube.connection.integrity.IntegritySecretHelper;
import org.diqube.thrift.base.services.DiqubeThriftServiceInfoManager.DiqubeThriftServiceInfo;
import org.diqube.thrift.base.thrift.RNodeAddress;
import org.diqube.thrift.util.RememberingTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Default implementation for {@link ConnectionFactory}.
 *
 * @author Bastian Gloeckle
 */
/* package */class DefaultConnectionFactory implements ConnectionFactory {
    private static final Logger logger = LoggerFactory.getLogger(DefaultConnectionFactory.class);

    private final ConnectionPool connectionPool;
    private int socketTimeout;
    private byte[][] macKeys;

    /**
     * @param connectionPool
     *          The pool this factory belongs to.
     */
    /* package */ DefaultConnectionFactory(ConnectionPool connectionPool,
            IntegritySecretHelper integritySecretHelper, int socketTimeout) {
        this.connectionPool = connectionPool;
        this.socketTimeout = socketTimeout;

        macKeys = integritySecretHelper.provideMessageIntegritySecrets();
    }

    private TTransport openTransport(RNodeAddress addr, SocketListener socketListener) throws ConnectionException {
        if (addr.isSetHttpAddr()) {
            try {
                // TODO #32: Integrate SocketListener into HTTP connections.
                return new THttpClient(addr.getHttpAddr().getUrl());
            } catch (TTransportException e) {
                throw new ConnectionException("Could not open connection to " + addr, e);
            }
        }

        TTransport transport = new DiqubeClientSocket(addr.getDefaultAddr().getHost(),
                addr.getDefaultAddr().getPort(), socketTimeout, socketListener);
        return new TFramedTransport(transport);
    }

    @Override
    public <T> Connection<T> createConnection(DiqubeThriftServiceInfo<T> serviceInfo, RNodeAddress addr,
            SocketListener socketListener) throws ConnectionException {

        TTransport transport = openTransport(addr, socketListener);

        T queryResultClient = createProtocolAndClient(serviceInfo, transport);
        try {
            transport.open();
        } catch (TTransportException e) {
            throw new ConnectionException("Could not open connection to " + addr, e);
        }

        return new Connection<>(connectionPool, serviceInfo, queryResultClient, transport, addr);
    }

    @Override
    public <T, U> Connection<U> createConnection(Connection<T> oldConnection,
            DiqubeThriftServiceInfo<U> serviceInfo) throws ConnectionException {
        U client = createProtocolAndClient(serviceInfo, oldConnection.getTransport());

        oldConnection.setWasReplaced(true);

        Connection<U> res = new Connection<>(connectionPool, serviceInfo, client, oldConnection.getTransport(),
                oldConnection.getAddress());
        res.setTimeout(oldConnection.getTimeout());
        res.setExecutionUuid(oldConnection.getExecutionUuid());

        logger.trace("Connection {}: Replacing object {} with {}", System.identityHashCode(res.getTransport()),
                System.identityHashCode(oldConnection), System.identityHashCode(res));

        return res;
    }

    private <T> T createProtocolAndClient(DiqubeThriftServiceInfo<T> serviceInfo, TTransport transport)
            throws ConnectionException {

        TProtocol innerProtocol;
        if (serviceInfo.isIntegrityChecked()) {
            if (!(transport instanceof RememberingTransport))
                transport = new RememberingTransport(transport);
            innerProtocol = new IntegrityCheckingProtocol(new TCompactProtocol(transport), macKeys);
        } else
            innerProtocol = new TCompactProtocol(transport);

        TProtocol queryProtocol = new TMultiplexedProtocol(innerProtocol, serviceInfo.getServiceName());

        try {
            @SuppressWarnings("unchecked")
            T queryResultClient = (T) serviceInfo.getClientClass().getConstructor(TProtocol.class)
                    .newInstance(queryProtocol);
            return queryResultClient;
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | NoSuchMethodException | SecurityException e) {
            ConnectionPool.logger.error("Error while constructing a client", e);
            throw new ConnectionException("Error while constructing a client", e);
        }
    }
}