com.impetus.client.hbase.schemamanager.HBaseSchemaManager.java Source code

Java tutorial

Introduction

Here is the source code for com.impetus.client.hbase.schemamanager.HBaseSchemaManager.java

Source

/*******************************************************************************
 * * Copyright 2015 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.hbase.schemamanager;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.persistence.metamodel.EntityType;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.util.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.client.hbase.config.HBasePropertyReader;
import com.impetus.client.hbase.utils.HBaseUtils;
import com.impetus.kundera.configure.ClientProperties.DataStore.Schema;
import com.impetus.kundera.configure.ClientProperties.DataStore.Schema.Table;
import com.impetus.kundera.configure.schema.CollectionColumnInfo;
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.KunderaMetadataManager;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.metadata.model.Relation;
import com.impetus.kundera.metadata.model.Relation.ForeignKey;
import com.impetus.kundera.metadata.model.annotation.DefaultEntityAnnotationProcessor;
import com.impetus.kundera.metadata.model.type.AbstractManagedType;
import com.impetus.kundera.persistence.EntityManagerFactoryImpl.KunderaMetadata;

/**
 * The Class HBaseSchemaManager.
 * 
 * @author Pragalbh Garg
 */
public class HBaseSchemaManager extends AbstractSchemaManager implements SchemaManager {

    /** The Constant DEFAULT_ZOOKEEPER_PORT. */
    private static final String DEFAULT_ZOOKEEPER_PORT = "2181";

    /**
     * Hbase admin variable holds the admin authorities.
     */
    private static HBaseAdmin admin;

    /**
     * logger used for logging statement.
     */
    private static final Logger logger = LoggerFactory.getLogger(HBaseSchemaManager.class);

    /** The Constant WILDCARD. */
    private static final String WILDCARD = ".*";

    /** The external properties. */
    private Map<String, Properties> externalProperties = new HashMap<String, Properties>();

    /**
     * Instantiates a new h base schema manager.
     * 
     * @param clientFactory
     *            the client factory
     * @param puProperties
     *            the pu properties
     * @param kunderaMetadata
     *            the kundera metadata
     */
    public HBaseSchemaManager(String clientFactory, Map<String, Object> puProperties,
            final KunderaMetadata kunderaMetadata) {
        super(clientFactory, puProperties, kunderaMetadata);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.configure.schema.api.AbstractSchemaManager#exportSchema
     * (java.lang.String, java.util.List)
     */
    @Override
    /**
     * Export schema handles the handleOperation method.
     */
    public void exportSchema(final String persistenceUnit, List<TableInfo> schemas) {
        super.exportSchema(persistenceUnit, schemas);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.configure.schema.api.AbstractSchemaManager#update
     * (java.util.List)
     */
    @Override
    protected void update(List<TableInfo> tableInfos) {
        createOrUpdateSchema(true);

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.configure.schema.api.AbstractSchemaManager#validate
     * (java.util.List)
     */
    @Override
    protected void validate(List<TableInfo> tableInfos) {
        try {
            if (isNamespaceAvailable(databaseName)) {
                for (TableInfo tableInfo : tableInfos) {
                    if (tableInfo != null) {
                        HTableDescriptor hTableDescriptor = admin
                                .getTableDescriptor((databaseName + ":" + tableInfo.getTableName()).getBytes());
                        boolean columnFamilyFound = false;
                        Boolean f = false;
                        for (HColumnDescriptor columnDescriptor : hTableDescriptor.getColumnFamilies()) {

                            if (!columnFamilyFound && columnDescriptor.getNameAsString()
                                    .equalsIgnoreCase(tableInfo.getTableName())) {
                                columnFamilyFound = true;
                            }

                            for (CollectionColumnInfo cci : tableInfo.getCollectionColumnMetadatas()) {
                                if (columnDescriptor.getNameAsString()
                                        .equalsIgnoreCase(cci.getCollectionColumnName())) {
                                    f = true;
                                    break;
                                }

                            }
                            if (!(columnFamilyFound || f)) {
                                throw new SchemaGenerationException(
                                        "column " + tableInfo.getTableName() + " does not exist in table "
                                                + databaseName + "",
                                        "Hbase", databaseName, tableInfo.getTableName());
                            }
                            // TODO make a check for sec table
                        }

                    }
                }
            } else {
                throw new SchemaGenerationException("Namespace" + databaseName + "does not exist", "HBase",
                        databaseName);
            }

        } catch (TableNotFoundException tnfex) {
            throw new SchemaGenerationException("table " + databaseName + " does not exist ", tnfex, "Hbase");
        } catch (IOException ioe) {
            logger.error("Either check for network connection or table isn't in enabled state, Caused by:", ioe);
            throw new SchemaGenerationException(ioe, "Hbase");
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.configure.schema.api.AbstractSchemaManager#create_drop
     * (java.util.List)
     */
    @Override
    protected void create_drop(List<TableInfo> tableInfos) {
        createOrUpdateSchema(false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.configure.schema.api.AbstractSchemaManager#create
     * (java.util.List)
     */
    @Override
    protected void create(List<TableInfo> tableInfos) {
        createOrUpdateSchema(false);
    }

    /**
     * Drop.
     */
    protected void drop() {
        try {
            admin.disableTables(HBaseUtils.getHTableName(databaseName, WILDCARD));
            admin.deleteTables(HBaseUtils.getHTableName(databaseName, WILDCARD));
        } catch (TableNotFoundException tnfe) {
            logger.error("Table doesn't exist, Caused by ", tnfe);
        } catch (IOException ioe) {
            logger.error("Table isn't in enabled state, Caused by", ioe);
            throw new SchemaGenerationException(ioe, "Hbase");
        } finally {
            try {
                admin.deleteNamespace(databaseName);
            } catch (IOException ioe) {
                logger.error("Table isn't in enabled state, Caused by", ioe);
                throw new SchemaGenerationException(ioe, "Hbase");
            }
        }
    }

    /**
     * Creates the or update schema.
     * 
     * @param isUpdate
     *            the is update
     */
    private void createOrUpdateSchema(Boolean isUpdate)

    {
        createNamespace(isUpdate);
        readExternalProperties();
        Map<Class<?>, EntityType<?>> entityMap = kunderaMetadata.getApplicationMetadata()
                .getMetaModelBuilder(puMetadata.getPersistenceUnitName()).getManagedTypes();
        // iterating all classes of pu to generate schema
        for (Class<?> clazz : entityMap.keySet()) {
            EntityMetadata m = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, clazz);
            if (m != null) {
                String tablename = m.getTableName();
                HTableDescriptor hTableDescriptor = getTableDescriptor(clazz, entityMap.get(clazz), tablename);
                String hTableName = HBaseUtils.getHTableName(databaseName, tablename);
                createOrUpdateTable(hTableName, hTableDescriptor);
            }
        }
    }

    /**
     * Gets the table descriptor.
     * 
     * @param clazz
     *            the clazz
     * @param entityType
     *            the entity type
     * @param tableName
     *            the table name
     * @return the table descriptor
     */
    private HTableDescriptor getTableDescriptor(Class<?> clazz, EntityType<?> entityType, String tableName) {
        try {
            AbstractManagedType<?> ent = (AbstractManagedType<?>) entityType;
            HTableDescriptor tableDescriptor = null;
            String hTableName = HBaseUtils.getHTableName(databaseName, tableName);
            tableDescriptor = !admin.tableExists(TableName.valueOf(hTableName))
                    ? new HTableDescriptor(TableName.valueOf(hTableName))
                    : admin.getTableDescriptor(TableName.valueOf(hTableName));
            addColumnFamilyAndSetProperties(tableDescriptor, tableName);

            // Add column families for @SecondaryTable
            List<String> secondaryTables = ((DefaultEntityAnnotationProcessor) ent.getEntityAnnotation())
                    .getSecondaryTablesName();
            for (String secTable : secondaryTables) {
                addColumnFamilyAndSetProperties(tableDescriptor, secTable);
            }

            // handle @JoinTable for @ManyToMany
            List<Relation> relations = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, clazz)
                    .getRelations();
            addJoinTable(relations);

            // @CollectionTable is not handled.
            return tableDescriptor;
        } catch (IOException ex) {
            logger.error("Either table isn't in enabled state or some network problem, Caused by: ", ex);
            throw new SchemaGenerationException(ex, "Hbase");
        }
    }

    /**
     * Adds the join table.
     * 
     * @param relations
     *            the relations
     */
    private void addJoinTable(List<Relation> relations) {
        for (Relation relation : relations) {
            if (relation.getType().equals(ForeignKey.MANY_TO_MANY) && relation.isRelatedViaJoinTable()) {
                String joinTableName = relation.getJoinTableMetadata().getJoinTableName();
                String hTableName = HBaseUtils.getHTableName(databaseName, joinTableName);
                HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(hTableName));
                tableDescriptor.addFamily(new HColumnDescriptor(joinTableName));
                createOrUpdateTable(hTableName, tableDescriptor);
            }
        }
    }

    /**
     * Adds the column family and set properties.
     * 
     * @param tableDescriptor
     *            the table descriptor
     * @param colFamilyName
     *            the sec table
     */
    private void addColumnFamilyAndSetProperties(HTableDescriptor tableDescriptor, String colFamilyName) {
        if (!tableDescriptor.hasFamily(colFamilyName.getBytes())) {
            HColumnDescriptor hColumnDescriptor = getColumnDescriptor(colFamilyName);
            tableDescriptor.addFamily(hColumnDescriptor);
            setExternalProperties(tableDescriptor.getNameAsString(), hColumnDescriptor);
        }
    }

    /**
     * Sets the external properties.
     * 
     * @param name
     *            the name
     * @param hColumnDescriptor
     *            the h column descriptor
     */
    private void setExternalProperties(String name, HColumnDescriptor hColumnDescriptor) {
        Properties properties = externalProperties != null ? externalProperties.get(name) : null;
        if (properties != null && !properties.isEmpty()) {
            for (Object obj : properties.keySet()) {
                hColumnDescriptor.setValue(Bytes.toBytes(obj.toString()),
                        Bytes.toBytes(properties.get(obj).toString()));
            }
        }
    }

    /**
     * Creates the namespace.
     * 
     * @param isUpdate
     *            the is update
     */
    private void createNamespace(boolean isUpdate) {
        boolean isNameSpaceAvailable = isNamespaceAvailable(databaseName);
        if (isNameSpaceAvailable && !isUpdate) {
            drop();
        }
        if (!(isNameSpaceAvailable && isUpdate)) {
            try {
                NamespaceDescriptor descriptor = NamespaceDescriptor.create(databaseName).build();
                admin.createNamespace(descriptor);
            } catch (IOException ioex) {
                logger.error("Either table isn't in enabled state or some network problem, Caused by: ", ioex);
                throw new SchemaGenerationException(ioex, "Hbase");
            }
        }
    }

    /**
     * Checks if is namespace available.
     * 
     * @param databaseName
     *            the database name
     * @return true, if is namespace available
     */
    private boolean isNamespaceAvailable(String databaseName) {
        try {
            for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) {
                if (ns.getName().equals(databaseName)) {
                    return true;
                }
            }
            return false;
        } catch (IOException ioex) {
            logger.error("Either table isn't in enabled state or some network problem, Caused by: ", ioex);
            throw new SchemaGenerationException(ioex,
                    "Either table isn't in enabled state or some network problem.");
        }
    }

    /**
     * Creates the or update table.
     * 
     * @param tablename
     *            the tablename
     * @param hTableDescriptor
     *            the h table descriptor
     */
    private void createOrUpdateTable(String tablename, HTableDescriptor hTableDescriptor) {
        try {
            if (admin.isTableAvailable(tablename)) {
                admin.modifyTable(tablename, hTableDescriptor);
            } else {
                admin.createTable(hTableDescriptor);
            }
        } catch (IOException ioex) {
            logger.error("Either table isn't in enabled state or some network problem, Caused by: ", ioex);
            throw new SchemaGenerationException(ioex,
                    "Either table isn't in enabled state or some network problem.");
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.configure.schema.api.SchemaManager#dropSchema()
     */
    @Override
    public void dropSchema() {
        if (operation != null && operation.equalsIgnoreCase("create-drop")) {
            drop();
        }
        operation = null;
        admin = null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.configure.schema.api.AbstractSchemaManager#initiateClient
     * ()
     */
    @Override
    protected boolean initiateClient() {
        String message = null;
        for (String host : hosts) {
            vaildateHostPort(host, port);
            Configuration hadoopConf = new Configuration();
            hadoopConf.set("hbase.master", host + ":" + port);
            conn = HBasePropertyReader.hsmd.getDataStore() != null
                    ? HBasePropertyReader.hsmd.getDataStore().getConnection()
                    : null;
            if (conn != null && conn.getProperties() != null) {
                String zookeeperHost = conn.getProperties().getProperty("hbase.zookeeper.quorum").trim();
                String zookeeperPort = conn.getProperties().getProperty("hbase.zookeeper.property.clientPort")
                        .trim();
                vaildateHostPort(zookeeperHost, zookeeperPort);
                hadoopConf.set("hbase.zookeeper.quorum", zookeeperHost != null ? zookeeperHost : host);
                hadoopConf.set("hbase.zookeeper.property.clientPort",
                        zookeeperPort != null ? zookeeperPort : DEFAULT_ZOOKEEPER_PORT);
            } else {
                hadoopConf.set("hbase.zookeeper.quorum", host);
                hadoopConf.set("hbase.zookeeper.property.clientPort", DEFAULT_ZOOKEEPER_PORT);
            }
            Configuration conf = HBaseConfiguration.create(hadoopConf);
            try {
                Connection connection = ConnectionFactory.createConnection(conf);
                admin = (HBaseAdmin) connection.getAdmin();
                return true;
            } catch (MasterNotRunningException mnre) {
                message = mnre.getMessage();
                logger.error("Master not running exception, Caused by:", mnre);
            } catch (ZooKeeperConnectionException zkce) {
                message = zkce.getMessage();
                logger.error("Unable to connect to zookeeper, Caused by:", zkce);
            } catch (IOException ioe) {
                message = ioe.getMessage();
                logger.error("I/O exception, Caused by:", ioe);
            }
        }
        throw new SchemaGenerationException("Master not running exception, Caused by:" + message);
    }

    /**
     * Vaildate host port.
     * 
     * @param host
     *            the host
     * @param port
     *            the port
     */
    private void vaildateHostPort(String host, String port) {
        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");
        }
    }

    /**
     * Gets the column descriptor.
     * 
     * @param tableName
     *            the table name
     * @return the column descriptor
     */
    private HColumnDescriptor getColumnDescriptor(String tableName) {
        HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(tableName);
        return hColumnDescriptor;
    }

    /**
     * Read external properties.
     */
    private void readExternalProperties() {
        schemas = HBasePropertyReader.hsmd.getDataStore() != null
                ? HBasePropertyReader.hsmd.getDataStore().getSchemas()
                : null;
        List<Table> tables = null;
        if (schemas != null && !schemas.isEmpty()) {
            for (Schema s : schemas) {
                if (s.getName() != null && s.getName().equalsIgnoreCase(databaseName)) {
                    tables = s.getTables();
                }
            }
        }
        if (tables != null && !tables.isEmpty()) {
            for (Table table : tables) {
                externalProperties.put(HBaseUtils.getHTableName(databaseName, table.getName()),
                        table.getProperties());
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.configure.schema.api.SchemaManager#validateEntity
     * (java.lang.Class)
     */
    @Override
    public boolean validateEntity(Class clazz) {
        return true;
    }

}