com.impetus.client.kudu.schemamanager.KuduDBSchemaManager Maven / Gradle / Ivy
/*******************************************************************************
* * Copyright 2016 Impetus Infotech.
* *
* * 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.impetus.client.kudu.schemamanager;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.persistence.Embeddable;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import org.apache.commons.lang.StringUtils;
import org.apache.kudu.ColumnSchema;
import org.apache.kudu.ColumnSchema.ColumnSchemaBuilder;
import org.apache.kudu.Schema;
import org.apache.kudu.client.AlterTableOptions;
import org.apache.kudu.client.CreateTableOptions;
import org.apache.kudu.client.KuduClient;
import org.apache.kudu.client.KuduTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.impetus.client.kudu.KuduDBDataHandler;
import com.impetus.client.kudu.KuduDBValidationClassMapper;
import com.impetus.kundera.KunderaException;
import com.impetus.kundera.configure.schema.ColumnInfo;
import com.impetus.kundera.configure.schema.EmbeddedColumnInfo;
import com.impetus.kundera.configure.schema.SchemaGenerationException;
import com.impetus.kundera.configure.schema.TableInfo;
import com.impetus.kundera.configure.schema.api.AbstractSchemaManager;
import com.impetus.kundera.configure.schema.api.SchemaManager;
import com.impetus.kundera.metadata.model.MetamodelImpl;
import com.impetus.kundera.metadata.model.attributes.AbstractAttribute;
import com.impetus.kundera.persistence.EntityManagerFactoryImpl.KunderaMetadata;
import com.impetus.kundera.utils.ReflectUtils;
/**
* The Class KuduDBSchemaManager.
*
* @author karthikp.manchala
*/
public class KuduDBSchemaManager extends AbstractSchemaManager implements SchemaManager
{
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(KuduDBSchemaManager.class);
/** The client. */
private KuduClient client;
/**
* Instantiates a new kudu db schema manager.
*
* @param clientFactory
* the client factory
* @param externalProperties
* the external properties
* @param kunderaMetadata
* the kundera metadata
*/
public KuduDBSchemaManager(String clientFactory, Map externalProperties,
KunderaMetadata kunderaMetadata)
{
super(clientFactory, externalProperties, kunderaMetadata);
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.configure.schema.api.AbstractSchemaManager#
* exportSchema(java.lang.String, java.util.List)
*/
public void exportSchema(final String persistenceUnit, List schemas)
{
super.exportSchema(persistenceUnit, schemas);
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.configure.schema.api.SchemaManager#dropSchema()
*/
@Override
public void dropSchema()
{
for (TableInfo tableInfo : tableInfos)
{
try
{
client.deleteTable(tableInfo.getTableName());
}
catch (Exception ex)
{
logger.error("Error during deleting tables in kudu, Caused by: ", ex);
throw new SchemaGenerationException(ex, "Kudu");
}
}
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.configure.schema.api.SchemaManager#validateEntity(
* java.lang.Class)
*/
@Override
public boolean validateEntity(Class clazz)
{
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.configure.schema.api.AbstractSchemaManager#
* initiateClient()
*/
@Override
protected boolean initiateClient()
{
for (String host : hosts)
{
if (host == null || !StringUtils.isNumeric(port) || port.isEmpty())
{
logger.error("Host or port should not be null / port should be numeric");
throw new IllegalArgumentException("Host or port should not be null / port should be numeric");
}
try
{
client = new KuduClient.KuduClientBuilder(host + ":" + port).build();
}
catch (Exception e)
{
logger.error("Database host cannot be resolved, Caused by: " + e.getMessage());
throw new SchemaGenerationException("Database host cannot be resolved, Caused by: " + e.getMessage());
}
}
return true;
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.configure.schema.api.AbstractSchemaManager#validate(
* java.util.List)
*/
@Override
protected void validate(List tableInfos)
{
for (TableInfo tableInfo : tableInfos)
{
try
{
if (!client.tableExists(tableInfo.getTableName()))
{
throw new SchemaGenerationException("Table: " + tableInfo.getTableName() + " does not exist ");
}
}
catch (Exception e)
{
logger.error("Error while validating tables, Caused by: " + e.getMessage());
throw new KunderaException("Error while validating tables, Caused by: " + e.getMessage());
}
}
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.configure.schema.api.AbstractSchemaManager#update(
* java.util.List)
*/
@Override
protected void update(List tableInfos)
{
for (TableInfo tableInfo : tableInfos)
{
try
{
if (!client.tableExists(tableInfo.getTableName()))
{
createKuduTable(tableInfo);
}
else
{
List entityColumns = new ArrayList();
KuduTable table = client.openTable(tableInfo.getTableName());
AlterTableOptions alterTableOptions = new AlterTableOptions();
AtomicBoolean updated = new AtomicBoolean(false);
Schema schema = table.getSchema();
// add modify columns
for (ColumnInfo columnInfo : tableInfo.getColumnMetadatas())
{
entityColumns.add(columnInfo.getColumnName());
alterColumn(alterTableOptions, schema, columnInfo, updated);
}
// update for embeddables logic
for (EmbeddedColumnInfo embColumnInfo : tableInfo.getEmbeddedColumnMetadatas())
{
for (ColumnInfo columnInfo : embColumnInfo.getColumns())
{
entityColumns.add(columnInfo.getColumnName());
alterColumn(alterTableOptions, schema, columnInfo, updated);
}
}
// delete columns
for (ColumnSchema columnSchema : schema.getColumns())
{
// if not in tableInfo and not a key then delete
if (!entityColumns.contains(columnSchema.getName()) && !columnSchema.isKey())
{
alterTableOptions.dropColumn(columnSchema.getName());
updated.set(true);
}
}
if (updated.get())
{
client.alterTable(tableInfo.getTableName(), alterTableOptions);
}
}
}
catch (Exception e)
{
logger.error("Error while updating tables, Caused by: " + e.getMessage());
throw new KunderaException("Error while updating tables, Caused by: " + e.getMessage());
}
}
}
/**
* Alter column.
*
* @param alterTableOptions
* the alter table options
* @param schema
* the schema
* @param columnInfo
* the column info
* @param updated
* the updated
*/
private void alterColumn(AlterTableOptions alterTableOptions, Schema schema, ColumnInfo columnInfo,
AtomicBoolean updated)
{
if (!KuduDBDataHandler.hasColumn(schema, columnInfo.getColumnName()))
{
// add if column is not in schema
alterTableOptions.addNullableColumn(columnInfo.getColumnName(),
KuduDBValidationClassMapper.getValidTypeForClass(columnInfo.getType()));
updated.set(true);
}
else
{
// check for type, drop and add if not consistent TODO: throw
// exception or override?
if (!schema.getColumn(columnInfo.getColumnName()).getType()
.equals(KuduDBValidationClassMapper.getValidTypeForClass(columnInfo.getType())))
{
alterTableOptions.dropColumn(columnInfo.getColumnName());
alterTableOptions.addNullableColumn(columnInfo.getColumnName(),
KuduDBValidationClassMapper.getValidTypeForClass(columnInfo.getType()));
updated.set(true);
}
}
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.configure.schema.api.AbstractSchemaManager#create(
* java.util.List)
*/
@Override
protected void create(List tableInfos)
{
for (TableInfo tableInfo : tableInfos)
{
try
{
if (client.tableExists(tableInfo.getTableName()))
{
client.deleteTable(tableInfo.getTableName());
}
}
catch (Exception e)
{
logger.error("Cannot check table existence for table " + tableInfo.getTableName() + ". Caused By: " + e);
throw new KunderaException("Cannot check table existence for table " + tableInfo.getTableName()
+ ". Caused By: " + e);
}
createKuduTable(tableInfo);
}
}
/**
* Creates the kudu table.
*
* @param tableInfo
* the table info
*/
private void createKuduTable(TableInfo tableInfo)
{
List columns = new ArrayList();
// add key
if (tableInfo.getTableIdType().isAnnotationPresent(Embeddable.class))
{
// composite keys
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
puMetadata.getPersistenceUnitName());
EmbeddableType embeddableIdType = metaModel.embeddable(tableInfo.getTableIdType());
Field[] fields = tableInfo.getTableIdType().getDeclaredFields();
addPrimaryKeyColumnsFromEmbeddable(columns, embeddableIdType, fields, metaModel);
}
else
{
// simple key
columns.add(new ColumnSchema.ColumnSchemaBuilder(tableInfo.getIdColumnName(), KuduDBValidationClassMapper
.getValidTypeForClass(tableInfo.getTableIdType())).key(true).build());
}
// add other columns
for (ColumnInfo columnInfo : tableInfo.getColumnMetadatas())
{
ColumnSchemaBuilder columnSchemaBuilder = new ColumnSchema.ColumnSchemaBuilder(columnInfo.getColumnName(),
KuduDBValidationClassMapper.getValidTypeForClass(columnInfo.getType()));
columns.add(columnSchemaBuilder.build());
}
// add embedded columns
for (EmbeddedColumnInfo embColumnInfo : tableInfo.getEmbeddedColumnMetadatas())
{
if (embColumnInfo.getEmbeddedColumnName().equals(tableInfo.getIdColumnName()))
{
// skip for embeddable ids
continue;
}
buildColumnsFromEmbeddableColumn(embColumnInfo, columns);
}
Schema schema = new Schema(columns);
try
{
CreateTableOptions builder = new CreateTableOptions();
List rangeKeys = new ArrayList<>();
// handle for composite Id
if (tableInfo.getTableIdType().isAnnotationPresent(Embeddable.class))
{
Iterator colIter = columns.iterator();
while (colIter.hasNext())
{
ColumnSchema col = colIter.next();
if (col.isKey())
{
rangeKeys.add(col.getName());
}
}
}
else
{
rangeKeys.add(tableInfo.getIdColumnName());
}
// TODO: Hard Coded Range Partitioning
builder.setRangePartitionColumns(rangeKeys);
client.createTable(tableInfo.getTableName(), schema, builder);
logger.debug("Table: " + tableInfo.getTableName() + " created successfully");
}
catch (Exception e)
{
logger.error("Table: " + tableInfo.getTableName() + " cannot be created, Caused by: " + e.getMessage(), e);
throw new SchemaGenerationException("Table: " + tableInfo.getTableName()
+ " cannot be created, Caused by: " + e.getMessage(), e, "Kudu");
}
}
private void addPrimaryKeyColumnsFromEmbeddable(List columns, EmbeddableType embeddable,
Field[] fields, MetamodelImpl metaModel)
{
for (Field f : fields)
{
if (!ReflectUtils.isTransientOrStatic(f))
{
if (f.getType().isAnnotationPresent(Embeddable.class))
{
// nested
addPrimaryKeyColumnsFromEmbeddable(columns, (EmbeddableType) metaModel.embeddable(f.getType()), f
.getType().getDeclaredFields(), metaModel);
}
else
{
Attribute attribute = embeddable.getAttribute(f.getName());
columns.add(new ColumnSchema.ColumnSchemaBuilder(
((AbstractAttribute) attribute).getJPAColumnName(), KuduDBValidationClassMapper
.getValidTypeForClass(f.getType())).key(true).build());
}
}
}
}
private void buildColumnsFromEmbeddableColumn(EmbeddedColumnInfo embColumnInfo, List columns)
{
for (ColumnInfo columnInfo : embColumnInfo.getColumns())
{
ColumnSchemaBuilder columnSchemaBuilder = new ColumnSchema.ColumnSchemaBuilder(columnInfo.getColumnName(),
KuduDBValidationClassMapper.getValidTypeForClass(columnInfo.getType()));
columns.add(columnSchemaBuilder.build());
}
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.configure.schema.api.AbstractSchemaManager#
* create_drop(java.util.List)
*/
@Override
protected void create_drop(List tableInfos)
{
create(tableInfos);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy