public class

ThriftConverter

extends Object
/*******************************************************************************
 * Copyright 2011 Netflix
 * 
 * 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 com.netflix.astyanax.thrift;

import com.netflix.astyanax.Serializer;
import com.netflix.astyanax.connectionpool.exceptions.BadRequestException;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionAbortedException;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.connectionpool.exceptions.OperationTimeoutException;
import com.netflix.astyanax.connectionpool.exceptions.ThriftStateException;
import com.netflix.astyanax.connectionpool.exceptions.TimeoutException;
import com.netflix.astyanax.connectionpool.exceptions.TokenRangeOfflineException;
import com.netflix.astyanax.connectionpool.exceptions.TransportException;
import com.netflix.astyanax.connectionpool.exceptions.UnknownException;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.ColumnPath;
import com.netflix.astyanax.model.ColumnSlice;
import com.netflix.astyanax.model.ColumnType;
import com.netflix.astyanax.model.ConsistencyLevel;

import org.apache.cassandra.thrift.AuthenticationException;
import org.apache.cassandra.thrift.AuthorizationException;
import org.apache.cassandra.thrift.ColumnParent;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.thrift.NotFoundException;
import org.apache.cassandra.thrift.SchemaDisagreementException;
import org.apache.cassandra.thrift.SlicePredicate;
import org.apache.cassandra.thrift.SliceRange;
import org.apache.cassandra.thrift.TimedOutException;
import org.apache.cassandra.thrift.UnavailableException;
import org.apache.thrift.TApplicationException;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TProtocolException;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.Iterator;

public class ThriftConverter {
    private static final Logger LOGGER = LoggerFactory.getLogger(ThriftConverter.class);

    /**
     * Construct a Hector ColumnParent based on the information in the query and
     * the type of column family being queried.
     * 
     * @param <K>
     * @param columnFamily
     * @param path
     * @return
     * @throws BadRequestException
     */
    public static <K> ColumnParent getColumnParent(ColumnFamily<?, ?> columnFamily, ColumnPath<?> path)
            throws BadRequestException {
        ColumnParent cp = new ColumnParent();
        cp.setColumn_family(columnFamily.getName());
        if (path != null) {
            Iterator<ByteBuffer> columns = path.iterator();
            if (columnFamily.getType() == ColumnType.SUPER && columns.hasNext()) {
                cp.setSuper_column(columns.next());
            }
        }
        return cp;
    }

    /**
     * Construct a Thrift ColumnPath based on the information in the query and
     * the type of column family being queried.
     * 
     * @param <K>
     * @param columnFamily
     * @param path
     * @return
     * @throws NotFoundException
     * @throws InvalidRequestException
     * @throws TException
     */
    public static <K> org.apache.cassandra.thrift.ColumnPath getColumnPath(ColumnFamily<?, ?> columnFamily,
            ColumnPath<?> path) throws BadRequestException {
        org.apache.cassandra.thrift.ColumnPath cp = new org.apache.cassandra.thrift.ColumnPath();
        cp.setColumn_family(columnFamily.getName());
        if (path != null) {
            Iterator<ByteBuffer> columns = path.iterator();
            if (columnFamily.getType() == ColumnType.SUPER && columns.hasNext()) {
                cp.setSuper_column(columns.next());
            }

            if (columns.hasNext()) {
                cp.setColumn(columns.next());
            }
            if (columns.hasNext()) {
                throw new BadRequestException("Path depth of " + path.length() + " not supported for column family \'"
                        + columnFamily.getName() + "\'");
            }
        }
        return cp;
    }

    /**
     * Return a Hector SlicePredicate based on the provided column slice
     * 
     * @param <C>
     * @param columns
     * @param colSer
     * @return
     */
    public static <C> SlicePredicate getPredicate(ColumnSlice<C> columns, Serializer<C> colSer) {
        // Get all the columns
        if (columns == null) {
            SlicePredicate predicate = new SlicePredicate();
            predicate.setSlice_range(new SliceRange(ByteBuffer.wrap(new byte[0]), ByteBuffer.wrap(new byte[0]), false,
                    Integer.MAX_VALUE));
            return predicate;
        }
        // Get a specific list of columns
        if (columns.getColumns() != null) {
            SlicePredicate predicate = new SlicePredicate();
            predicate.setColumn_namesIsSet(true);
            predicate.column_names = colSer.toBytesList(columns.getColumns());
            return predicate;
        }
        else {
            SlicePredicate predicate = new SlicePredicate();
            predicate.setSlice_range(new SliceRange((columns.getStartColumn() == null) ? ByteBuffer.wrap(new byte[0])
                    : ByteBuffer.wrap(colSer.toBytes(columns.getStartColumn())),
                    (columns.getEndColumn() == null) ? ByteBuffer.wrap(new byte[0]) : ByteBuffer.wrap(colSer
                            .toBytes(columns.getEndColumn())), columns.getReversed(), columns.getLimit()));
            return predicate;
        }
    }

    /**
     * Convert from Thrift exceptions to an internal ConnectionPoolException
     * 
     * @param e
     * @return
     */
    public static ConnectionException ToConnectionPoolException(Exception e) {
        if (e instanceof ConnectionException) {
            return (ConnectionException) e;
        }
        LOGGER.debug(e.getMessage());
        if (e instanceof InvalidRequestException) {
            return new com.netflix.astyanax.connectionpool.exceptions.BadRequestException(e);
        }
        else if (e instanceof TProtocolException) {
            return new com.netflix.astyanax.connectionpool.exceptions.BadRequestException(e);
        }
        else if (e instanceof UnavailableException) {
            return new TokenRangeOfflineException(e);
        }
        else if (e instanceof SocketTimeoutException) {
            return new TimeoutException(e);
        }
        else if (e instanceof TimedOutException) {
            return new OperationTimeoutException(e);
        }
        else if (e instanceof NotFoundException) {
            return new com.netflix.astyanax.connectionpool.exceptions.NotFoundException(e);
        }
        else if (e instanceof TApplicationException) {
            return new ThriftStateException(e);
        }
        else if (e instanceof AuthenticationException || e instanceof AuthorizationException) {
            return new com.netflix.astyanax.connectionpool.exceptions.AuthenticationException(e);
        }
        else if (e instanceof SchemaDisagreementException) {
            return new com.netflix.astyanax.connectionpool.exceptions.SchemaDisagreementException(e);
        }
        else if (e instanceof TTransportException) {
            if (e.getCause() != null) {
                if (e.getCause() instanceof SocketTimeoutException) {
                    return new TimeoutException(e);
                }
                if (e.getCause().getMessage() != null) {
                    if (e.getCause().getMessage().toLowerCase().contains("connection abort")
                            || e.getCause().getMessage().toLowerCase().contains("connection reset")) {
                        return new ConnectionAbortedException(e);
                    }
                }
            }
            return new TransportException(e);
        }
        else {
            // e.getCause().printStackTrace();
            return new UnknownException(e);
        }
    }

    public static org.apache.cassandra.thrift.ConsistencyLevel ToThriftConsistencyLevel(ConsistencyLevel cl) {
        switch (cl) {
        case CL_ONE:
            return org.apache.cassandra.thrift.ConsistencyLevel.ONE;
        case CL_QUORUM:
            return org.apache.cassandra.thrift.ConsistencyLevel.QUORUM;
        case CL_EACH_QUORUM:
            return org.apache.cassandra.thrift.ConsistencyLevel.EACH_QUORUM;
        case CL_LOCAL_QUORUM:
            return org.apache.cassandra.thrift.ConsistencyLevel.LOCAL_QUORUM;
	case CL_TWO:
	    return org.apache.cassandra.thrift.ConsistencyLevel.TWO;
	case CL_THREE:
	    return org.apache.cassandra.thrift.ConsistencyLevel.THREE;
        case CL_ALL:
            return org.apache.cassandra.thrift.ConsistencyLevel.ALL;
        case CL_ANY:
            return org.apache.cassandra.thrift.ConsistencyLevel.ANY;
        default:
            return org.apache.cassandra.thrift.ConsistencyLevel.QUORUM;
        }
    }
}