com.carmanconsulting.cassidy.pojo.mapper.ColumnMapperPojoDao.java Source code

Java tutorial

Introduction

Here is the source code for com.carmanconsulting.cassidy.pojo.mapper.ColumnMapperPojoDao.java

Source

/*
 * Copyright (c) 2014 Carman Consulting, Inc.
 *
 * 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.carmanconsulting.cassidy.pojo.mapper;

import com.carmanconsulting.cassidy.context.CassidyContext;
import com.carmanconsulting.cassidy.pojo.AbstractPojoDao;
import com.carmanconsulting.cassidy.pojo.PojoCallback;
import com.google.common.collect.Lists;
import me.prettyprint.cassandra.serializers.BytesArraySerializer;
import me.prettyprint.hector.api.Serializer;
import me.prettyprint.hector.api.beans.ColumnSlice;
import me.prettyprint.hector.api.beans.HColumn;
import me.prettyprint.hector.api.beans.Row;
import me.prettyprint.hector.api.beans.Rows;
import me.prettyprint.hector.api.ddl.ColumnFamilyDefinition;
import me.prettyprint.hector.api.factory.HFactory;
import me.prettyprint.hector.api.mutation.Mutator;
import me.prettyprint.hector.api.query.MultigetSliceQuery;
import me.prettyprint.hector.api.query.QueryResult;
import me.prettyprint.hector.api.query.SliceQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ColumnMapperPojoDao<K, N, V> extends AbstractPojoDao<K, V> {
    //----------------------------------------------------------------------------------------------------------------------
    // Fields
    //----------------------------------------------------------------------------------------------------------------------

    public static final BytesArraySerializer BYTE_ARRAY_SERIALIZER = BytesArraySerializer.get();
    public static final int DEFAULT_PAGE_SIZE = 100;
    private static final Logger LOGGER = LoggerFactory.getLogger(ColumnMapperPojoDao.class);

    private final CassidyContext context;

    private final String columnFamily;
    private final Serializer<K> keySerializer;
    private final Serializer<N> nameSerializer;
    private final ColumnMapper<N, V> mapper;

    //----------------------------------------------------------------------------------------------------------------------
    // Constructors
    //----------------------------------------------------------------------------------------------------------------------

    public ColumnMapperPojoDao(CassidyContext context, String columnFamily, Serializer<K> keySerializer,
            Serializer<N> nameSerializer, ColumnMapper<N, V> mapper) {
        this.context = context;
        this.columnFamily = columnFamily;
        this.keySerializer = keySerializer;
        this.nameSerializer = nameSerializer;
        this.mapper = mapper;
        createColumnFamily(context, columnFamily, mapper);
    }

    private static <N, V> void createColumnFamily(CassidyContext context, String columnFamily,
            ColumnMapper<N, V> mapper) {
        ColumnFamilyDefinition definition = context.keyspaceHelper().createColumnFamilyDefinition(columnFamily);

        definition.setComparatorType(mapper.getComparatorType());
        String alias = mapper.getComparatorTypeAlias();
        if (alias != null) {
            definition.setComparatorTypeAlias(mapper.getComparatorTypeAlias());
        }
        context.keyspaceHelper().createColumnFamily(definition);
    }

    public ColumnMapperPojoDao(CassidyContext context, String columnFamily, Class<K> keyType, Class<N> nameType,
            ColumnMapper<N, V> mapper) {
        this(context, columnFamily, context.serializerRegistry().getSerializer(keyType),
                context.serializerRegistry().getSerializer(nameType), mapper);
    }

    //----------------------------------------------------------------------------------------------------------------------
    // PojoDao Implementation
    //----------------------------------------------------------------------------------------------------------------------

    @Override
    @SuppressWarnings("unchecked")
    public boolean contains(K key) {
        SliceQuery<K, N, byte[]> query = HFactory.createSliceQuery(context.keyspaceHelper().keyspace(),
                keySerializer, nameSerializer, BYTE_ARRAY_SERIALIZER);
        final QueryResult<ColumnSlice<N, byte[]>> result = query.setColumnFamily(columnFamily).setKey(key)
                .setRange(null, null, false, Integer.MAX_VALUE).execute();
        final ColumnSlice<N, byte[]> slice = result.get();
        return !slice.getColumns().isEmpty();
    }

    @Override
    public void delete(K key) {
        fireOnBeforeDelete(key);
        mutator().delete(key, columnFamily, null, nameSerializer);
        fireOnDelete(key);
    }

    @Override
    public List<V> find(Iterable<K> keys) {
        return find(keys, DEFAULT_PAGE_SIZE);
    }

    @Override
    public V find(K key) {
        SliceQuery<K, N, byte[]> query = HFactory.createSliceQuery(context.keyspaceHelper().keyspace(),
                keySerializer, nameSerializer, BYTE_ARRAY_SERIALIZER);
        final QueryResult<ColumnSlice<N, byte[]>> result = query.setColumnFamily(columnFamily).setKey(key)
                .setRange(null, null, false, Integer.MAX_VALUE).execute();
        final ColumnSlice<N, byte[]> slice = result.get();
        return mapColumnSlice(slice);
    }

    @Override
    public List<V> find(Iterable<K> keys, int pageSize) {
        CollectingCallback<V> handler = new CollectingCallback<>();
        iterate(keys, pageSize, handler);
        return handler.getValues();
    }

    @Override
    public void iterate(Iterable<K> keys, PojoCallback<V> handler) {
        iterate(keys, DEFAULT_PAGE_SIZE, handler);
    }

    @Override
    public void iterate(Iterable<K> keys, int pageSize, PojoCallback<V> handler) {
        List<List<K>> chunks = breakIntoChunks(getExistingKeys(keys), pageSize);
        for (List<K> chunk : chunks) {
            iterateChunk(handler, chunk);
        }
    }

    @Override
    public void save(K key, V pojo) {
        fireOnBeforeSave(key, pojo);
        Mutator<K> mutator = mutator();
        mutator.addDeletion(key, columnFamily, null, nameSerializer);
        final List<HColumn<N, ?>> columns = mapper.toColumns(pojo);
        LOGGER.debug("Saving {} object requires {} columns.", pojo.getClass().getCanonicalName(), columns.size());
        for (HColumn<?, ?> column : columns) {
            LOGGER.debug("Inserting column {} with value {} for key {} in column family '{}'...", column.getName(),
                    column.getValue(), key, columnFamily);
            mutator.addInsertion(key, columnFamily, column);
        }
        mutator.execute();
        fireOnSave(key, pojo);
    }

    //----------------------------------------------------------------------------------------------------------------------
    // Other Methods
    //----------------------------------------------------------------------------------------------------------------------

    private List<List<K>> breakIntoChunks(List<K> keys, int chunkSize) {
        return Lists.partition(keys, chunkSize);
    }

    @SuppressWarnings("unchecked")
    private List<K> getExistingKeys(Iterable<K> keys) {
        final MultigetSliceQuery<K, N, byte[]> query = HFactory.createMultigetSliceQuery(
                context.keyspaceHelper().keyspace(), keySerializer, nameSerializer, BYTE_ARRAY_SERIALIZER);
        query.setKeys(keys);
        query.setColumnFamily(columnFamily);
        query.setColumnNames();
        final QueryResult<Rows<K, N, byte[]>> result = query.execute();
        List<K> existing = new ArrayList<>(result.get().getCount());
        for (Row<K, N, byte[]> row : result.get()) {
            existing.add(row.getKey());
        }
        return existing;
    }

    private void iterateChunk(PojoCallback<V> handler, List<K> chunk) {
        final MultigetSliceQuery<K, N, byte[]> query = HFactory.createMultigetSliceQuery(
                context.keyspaceHelper().keyspace(), keySerializer, nameSerializer, BYTE_ARRAY_SERIALIZER);
        query.setKeys(chunk);
        query.setColumnFamily(columnFamily);
        query.setRange(null, null, false, Integer.MAX_VALUE);
        final QueryResult<Rows<K, N, byte[]>> result = query.execute();
        for (Row<K, N, byte[]> row : result.get()) {
            V value = mapColumnSlice(row.getColumnSlice());
            if (value != null) {
                handler.onPojo(value);
            }
        }
    }

    private V mapColumnSlice(ColumnSlice<N, byte[]> slice) {
        final List<HColumn<N, byte[]>> columns = slice.getColumns();
        if (columns.isEmpty()) {
            return null;
        }
        return mapper.fromColumns(columns);
    }

    private Mutator<K> mutator() {
        return HFactory.createMutator(context.keyspaceHelper().keyspace(), keySerializer);
    }

    //----------------------------------------------------------------------------------------------------------------------
    // Inner Classes
    //----------------------------------------------------------------------------------------------------------------------

    private static class CollectingCallback<V> implements PojoCallback<V> {
        private final List<V> values = new LinkedList<>();

        public List<V> getValues() {
            return values;
        }

        @Override
        public void onPojo(V pojo) {
            values.add(pojo);
        }
    }
}