Java tutorial
/* * 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); } } }