/* * Licensed to STRATIO (C) under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. The STRATIO (C) licenses this file * to you 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.stratio.cassandra.lucene.column; import com.stratio.cassandra.lucene.IndexException; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.CollectionType; import org.apache.cassandra.db.marshal.TupleType; import org.apache.cassandra.db.marshal.UserType; import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.db.rows.ComplexColumnData; import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.serializers.CollectionSerializer; import org.apache.cassandra.serializers.MapSerializer; import org.apache.cassandra.transport.Server; import org.apache.cassandra.utils.ByteBufferUtil; import java.nio.ByteBuffer; /** * Class for several regular column mappings between Cassandra and Lucene. * * @author Andres de la Pena {@literal <adelapena@stratio.com>} */ public final class ColumnsMapper { /** * Adds to the specified {@link Column} to the {@link Column}s contained in the specified {@link Row}. * * @param columns The {@link Columns} in which the {@link Column}s are going to be added. * @param row A {@link Row}. */ public void addColumns(Columns columns, Row row) { for (ColumnDefinition columnDefinition : row.columns()) { if (columnDefinition.isComplex()) { addColumns(columns, row.getComplexColumnData(columnDefinition)); } else { addColumns(columns, row.getCell(columnDefinition)); } } } private void addColumns(Columns columns, ComplexColumnData complexColumnData) { if (complexColumnData != null) { for (Cell cell : complexColumnData) { addColumns(columns, cell); } } } private void addColumns(Columns columns, Cell cell) { if (cell != null) { ColumnDefinition columnDefinition = cell.column(); String name = columnDefinition.name.toString(); AbstractType<?> type = cell.column().type; ByteBuffer value = cell.value(); ColumnBuilder builder = Column.builder(name); if (type.isCollection() && !type.isFrozenCollection()) { CollectionType<?> collectionType = (CollectionType<?>) type; switch (collectionType.kind) { case SET: { type = collectionType.nameComparator(); value = cell.path().get(0); addColumns(columns, builder, type, value); break; } case LIST: { type = collectionType.valueComparator(); addColumns(columns, builder, type, value); break; } case MAP: { type = collectionType.valueComparator(); ByteBuffer keyValue = cell.path().get(0); AbstractType<?> keyType = collectionType.nameComparator(); String nameSuffix = keyType.compose(keyValue).toString(); addColumns(columns, builder.withMapName(nameSuffix), type, value); break; } default: { throw new IndexException("Unknown collection type %s", collectionType.kind); } } } else { addColumns(columns, Column.builder(name), type, value); } } } private void addColumns(Columns columns, ColumnBuilder builder, AbstractType type, ByteBuffer value) { if (type.isCollection()) { value = ByteBufferUtil.clone(value); CollectionType<?> collectionType = (CollectionType<?>) type; switch (collectionType.kind) { case SET: { AbstractType<?> nameType = collectionType.nameComparator(); int colSize = CollectionSerializer.readCollectionSize(value, Server.CURRENT_VERSION); for (int j = 0; j < colSize; j++) { ByteBuffer itemValue = CollectionSerializer.readValue(value, Server.CURRENT_VERSION); addColumns(columns, builder, nameType, itemValue); } break; } case LIST: { AbstractType<?> valueType = collectionType.valueComparator(); int colSize = CollectionSerializer.readCollectionSize(value, Server.CURRENT_VERSION); for (int j = 0; j < colSize; j++) { ByteBuffer itemValue = CollectionSerializer.readValue(value, Server.CURRENT_VERSION); addColumns(columns, builder, valueType, itemValue); } break; } case MAP: { AbstractType<?> keyType = collectionType.nameComparator(); AbstractType<?> valueType = collectionType.valueComparator(); int colSize = MapSerializer.readCollectionSize(value, Server.CURRENT_VERSION); for (int j = 0; j < colSize; j++) { ByteBuffer mapKey = MapSerializer.readValue(value, Server.CURRENT_VERSION); ByteBuffer mapValue = MapSerializer.readValue(value, Server.CURRENT_VERSION); String itemName = keyType.compose(mapKey).toString(); collectionType.nameComparator(); addColumns(columns, builder.withMapName(itemName), valueType, mapValue); } break; } default: { throw new IndexException("Unknown collection type %s", collectionType.kind); } } } else if (type instanceof UserType) { UserType userType = (UserType) type; ByteBuffer[] values = userType.split(value); for (int i = 0; i < userType.fieldNames().size(); i++) { String itemName = userType.fieldNameAsString(i); AbstractType<?> itemType = userType.fieldType(i); // This only occurs in UDT not fully composed if (values[i] != null) { addColumns(columns, builder.withUDTName(itemName), itemType, values[i]); } } } else if (type instanceof TupleType) { TupleType tupleType = (TupleType) type; ByteBuffer[] values = tupleType.split(value); for (Integer i = 0; i < tupleType.size(); i++) { String itemName = i.toString(); AbstractType<?> itemType = tupleType.type(i); addColumns(columns, builder.withUDTName(itemName), itemType, values[i]); } } else { if (value != null) { columns.add(builder.buildWithDecomposed(value, type)); } } } }