zipkin.storage.cassandra3.DefaultSessionFactory.java Source code

Java tutorial

Introduction

Here is the source code for zipkin.storage.cassandra3.DefaultSessionFactory.java

Source

/**
 * Copyright 2015-2016 The OpenZipkin Authors
 *
 * 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 zipkin.storage.cassandra3;

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.HostDistance;
import com.datastax.driver.core.KeyspaceMetadata;
import com.datastax.driver.core.PoolingOptions;
import com.datastax.driver.core.QueryLogger;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.policies.DCAwareRoundRobinPolicy;
import com.datastax.driver.core.policies.LatencyAwarePolicy;
import com.datastax.driver.core.policies.RoundRobinPolicy;
import com.datastax.driver.core.policies.TokenAwarePolicy;
import com.datastax.driver.mapping.MappingManager;
import com.google.common.collect.Sets;
import com.google.common.io.Closer;
import com.google.common.net.HostAndPort;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import zipkin.storage.cassandra3.Schema.AnnotationUDT;
import zipkin.storage.cassandra3.Schema.BinaryAnnotationUDT;
import zipkin.storage.cassandra3.Schema.EndpointUDT;
import zipkin.storage.cassandra3.Schema.TraceIdUDT;
import zipkin.storage.cassandra3.Schema.TypeCodecImpl;

import static zipkin.storage.cassandra3.Schema.DEFAULT_KEYSPACE;

/**
 * Creates a session and ensures schema if configured. Closes the cluster and session if any
 * exception occurred.
 */
final class DefaultSessionFactory implements Cassandra3Storage.SessionFactory {

    /**
     * Creates a session and ensures schema if configured. Closes the cluster and session if any
     * exception occurred.
     */
    @Override
    public Session create(Cassandra3Storage cassandra) {
        Closer closer = Closer.create();
        try {
            Cluster cluster = closer.register(buildCluster(cassandra));
            cluster.register(new QueryLogger.Builder().build());
            Session session;
            if (cassandra.ensureSchema) {
                session = closer.register(cluster.connect());
                Schema.ensureExists(cassandra.keyspace, session);
                session.execute("USE " + cassandra.keyspace);
            } else {
                session = cluster.connect(cassandra.keyspace);
            }

            initializeUDTs(session);

            return session;
        } catch (RuntimeException e) {
            try {
                closer.close();
            } catch (IOException ignored) {
            }
            throw e;
        }
    }

    private static void initializeUDTs(Session session) {
        Schema.ensureExists(DEFAULT_KEYSPACE + "_udts", session);
        MappingManager mapping = new MappingManager(session);

        // The UDTs are hardcoded against the zipkin keyspace.
        // If a different keyspace is being used the codecs must be re-applied to this different keyspace
        TypeCodec<TraceIdUDT> traceIdCodec = mapping.udtCodec(TraceIdUDT.class);
        TypeCodec<EndpointUDT> endpointCodec = mapping.udtCodec(EndpointUDT.class);
        TypeCodec<AnnotationUDT> annoCodec = mapping.udtCodec(AnnotationUDT.class);
        TypeCodec<BinaryAnnotationUDT> bAnnoCodec = mapping.udtCodec(BinaryAnnotationUDT.class);

        KeyspaceMetadata keyspace = session.getCluster().getMetadata().getKeyspace(session.getLoggedKeyspace());

        session.getCluster().getConfiguration().getCodecRegistry()
                .register(new TypeCodecImpl(keyspace.getUserType("trace_id"), TraceIdUDT.class, traceIdCodec))
                .register(new TypeCodecImpl(keyspace.getUserType("endpoint"), EndpointUDT.class, endpointCodec))
                .register(new TypeCodecImpl(keyspace.getUserType("annotation"), AnnotationUDT.class, annoCodec))
                .register(new TypeCodecImpl(keyspace.getUserType("binary_annotation"), BinaryAnnotationUDT.class,
                        bAnnoCodec));
    }

    // Visible for testing
    static Cluster buildCluster(Cassandra3Storage cassandra) {
        Cluster.Builder builder = Cluster.builder();
        List<InetSocketAddress> contactPoints = parseContactPoints(cassandra);
        int defaultPort = findConnectPort(contactPoints);
        builder.addContactPointsWithPorts(contactPoints);
        builder.withPort(defaultPort); // This ends up protocolOptions.port
        if (cassandra.username != null && cassandra.password != null) {
            builder.withCredentials(cassandra.username, cassandra.password);
        }
        builder.withRetryPolicy(ZipkinRetryPolicy.INSTANCE);
        builder.withLoadBalancingPolicy(new TokenAwarePolicy(new LatencyAwarePolicy.Builder(
                cassandra.localDc != null ? DCAwareRoundRobinPolicy.builder().withLocalDc(cassandra.localDc).build()
                        : new RoundRobinPolicy()
        // This can select remote, but LatencyAwarePolicy will prefer local
        ).build()));
        builder.withPoolingOptions(
                new PoolingOptions().setMaxConnectionsPerHost(HostDistance.LOCAL, cassandra.maxConnections));
        if (cassandra.useSsl) {
            builder = builder.withSSL();
        }

        return builder.build();
    }

    static List<InetSocketAddress> parseContactPoints(Cassandra3Storage cassandra) {
        List<InetSocketAddress> result = new LinkedList<>();
        for (String contactPoint : cassandra.contactPoints.split(",")) {
            HostAndPort parsed = HostAndPort.fromString(contactPoint);
            result.add(new InetSocketAddress(parsed.getHostText(), parsed.getPortOrDefault(9042)));
        }
        return result;
    }

    /** Returns the consistent port across all contact points or 9042 */
    static int findConnectPort(List<InetSocketAddress> contactPoints) {
        Set<Integer> ports = Sets.newLinkedHashSet();
        for (InetSocketAddress contactPoint : contactPoints) {
            ports.add(contactPoint.getPort());
        }
        return ports.size() == 1 ? ports.iterator().next() : 9042;
    }
}