com.impetus.client.mongodb.schemamanager.MongoDBSchemaManager.java Source code

Java tutorial

Introduction

Here is the source code for com.impetus.client.mongodb.schemamanager.MongoDBSchemaManager.java

Source

/*******************************************************************************
 * * Copyright 2012 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.mongodb.schemamanager;

import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.client.mongodb.MongoDBConstants;
import com.impetus.client.mongodb.config.MongoDBPropertyReader;
import com.impetus.client.mongodb.index.IndexType;
import com.impetus.client.mongodb.utils.MongoDBUtils;
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.IndexInfo;
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.loader.ClientLoaderException;
import com.impetus.kundera.loader.KunderaAuthenticationException;
import com.impetus.kundera.persistence.EntityManagerFactoryImpl.KunderaMetadata;
import com.impetus.kundera.utils.KunderaCoreUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;

/**
 * The Class MongoDBSchemaManager manages auto schema operation
 * {@code ScheamOperationType} for mongoDb database.
 * 
 * @author Kuldeep.kumar
 * 
 */
public class MongoDBSchemaManager extends AbstractSchemaManager implements SchemaManager {

    /** The m. */
    private MongoClient mongo;

    /** The db. */
    private DB db;

    /** The coll. */
    private DBCollection coll;

    /** The Constant logger. */
    private static final Logger logger = LoggerFactory.getLogger(MongoDBSchemaManager.class);

    Logger mongoLogger = LoggerFactory.getLogger(com.mongodb.DB.class);

    public MongoDBSchemaManager(String clientFactory, Map<String, Object> externalProperties,
            final KunderaMetadata kunderaMetadata) {
        super(clientFactory, externalProperties, kunderaMetadata);
    }

    @Override
    /**
     * Export schema handles the handleOperation method.
     */
    public void exportSchema(final String persistenceUnit, List<TableInfo> schemas) {
        super.exportSchema(persistenceUnit, schemas);
    }

    /**
     * drop schema method drop the table
     */
    public void dropSchema() {
        if (operation != null && operation.equalsIgnoreCase("create-drop")) {
            for (TableInfo tableInfo : tableInfos) {
                if (tableInfo.getLobColumnInfo().isEmpty()) {
                    coll = db.getCollection(tableInfo.getTableName());
                    coll.drop();
                    KunderaCoreUtils.printQuery("Drop collection:" + tableInfo.getTableName(), showQuery);
                } else {
                    coll = db.getCollection(tableInfo.getTableName() + MongoDBUtils.FILES);
                    coll.drop();
                    KunderaCoreUtils.printQuery("Drop collection:" + tableInfo.getTableName() + MongoDBUtils.FILES,
                            showQuery);
                    coll = db.getCollection(tableInfo.getTableName() + MongoDBUtils.CHUNKS);
                    coll.drop();
                    KunderaCoreUtils.printQuery("Drop collection:" + tableInfo.getTableName() + MongoDBUtils.CHUNKS,
                            showQuery);
                }
            }
        }
        db = null;
    }

    /**
     * create method creates schema and table for the list of tableInfos.
     * 
     * @param tableInfos
     *            list of TableInfos.
     */
    protected void create(List<TableInfo> tableInfos) {
        for (TableInfo tableInfo : tableInfos) {
            DBObject options = setCollectionProperties(tableInfo);
            DB db = mongo.getDB(databaseName);

            if (tableInfo.getLobColumnInfo().isEmpty()) {
                if (db.collectionExists(tableInfo.getTableName())) {
                    db.getCollection(tableInfo.getTableName()).drop();

                    KunderaCoreUtils.printQuery("Drop existing collection: " + tableInfo.getTableName(), showQuery);
                }
                DBCollection collection = db.createCollection(tableInfo.getTableName(), options);
                KunderaCoreUtils.printQuery("Create collection: " + tableInfo.getTableName(), showQuery);

                boolean isCappedCollection = isCappedCollection(tableInfo);
                if (!isCappedCollection) {
                    createIndexes(tableInfo, collection);
                }
            } else {
                /*
                 * In GridFS we have 2 collections. TABLE_NAME.chunks for
                 * storing chunks of data and TABLE_NAME.MongoDBUtils.FILES for
                 * storing it's metadata.
                 */
                checkMultipleLobs(tableInfo);
                if (db.collectionExists(tableInfo.getTableName() + MongoDBUtils.FILES)) {
                    db.getCollection(tableInfo.getTableName() + MongoDBUtils.FILES).drop();
                    KunderaCoreUtils.printQuery("Drop existing Grid FS Metadata collection: "
                            + tableInfo.getTableName() + MongoDBUtils.FILES, showQuery);
                }

                if (db.collectionExists(tableInfo.getTableName() + MongoDBUtils.CHUNKS)) {
                    db.getCollection(tableInfo.getTableName() + MongoDBUtils.CHUNKS).drop();
                    KunderaCoreUtils.printQuery("Drop existing Grid FS data collection: " + tableInfo.getTableName()
                            + MongoDBUtils.CHUNKS, showQuery);
                }
                coll = db.createCollection(tableInfo.getTableName() + MongoDBUtils.FILES, options);
                createUniqueIndexGFS(coll, tableInfo.getIdColumnName());
                KunderaCoreUtils.printQuery("Create collection: " + tableInfo.getTableName() + MongoDBUtils.FILES,
                        showQuery);
                db.createCollection(tableInfo.getTableName() + MongoDBUtils.CHUNKS, options);
                KunderaCoreUtils.printQuery("Create collection: " + tableInfo.getTableName() + MongoDBUtils.CHUNKS,
                        showQuery);

            }
        }
    }

    /**
     * create_drop method creates schema and table for the list of tableInfos.
     * 
     * @param tableInfos
     *            list of TableInfos.
     */
    protected void create_drop(List<TableInfo> tableInfos) {
        create(tableInfos);
    }

    /**
     * update method update schema and table for the list of tableInfos
     * 
     * @param tableInfos
     *            list of TableInfos.
     */
    protected void update(List<TableInfo> tableInfos) {
        for (TableInfo tableInfo : tableInfos) {
            DBObject options = setCollectionProperties(tableInfo);
            DB db = mongo.getDB(databaseName);
            DBCollection collection = null;
            if (tableInfo.getLobColumnInfo().isEmpty()) {
                if (!db.collectionExists(tableInfo.getTableName())) {
                    collection = db.createCollection(tableInfo.getTableName(), options);
                    KunderaCoreUtils.printQuery("Create collection: " + tableInfo.getTableName(), showQuery);
                }

                collection = collection != null ? collection : db.getCollection(tableInfo.getTableName());

                boolean isCappedCollection = isCappedCollection(tableInfo);
                if (!isCappedCollection) {
                    createIndexes(tableInfo, collection);
                }
            } else {
                checkMultipleLobs(tableInfo);
                if (!db.collectionExists(tableInfo.getTableName() + MongoDBUtils.FILES)) {
                    coll = db.createCollection(tableInfo.getTableName() + MongoDBUtils.FILES, options);
                    createUniqueIndexGFS(coll, tableInfo.getIdColumnName());
                    KunderaCoreUtils.printQuery(
                            "Create collection: " + tableInfo.getTableName() + MongoDBUtils.FILES, showQuery);
                }

                if (!db.collectionExists(tableInfo.getTableName() + MongoDBUtils.CHUNKS)) {
                    db.createCollection(tableInfo.getTableName() + MongoDBUtils.CHUNKS, options);
                    KunderaCoreUtils.printQuery(
                            "Create collection: " + tableInfo.getTableName() + MongoDBUtils.CHUNKS, showQuery);
                }
            }
        }
    }

    /**
     * validate method validate schema and table for the list of tableInfos.
     * 
     * @param tableInfos
     *            list of TableInfos.
     */
    protected void validate(List<TableInfo> tableInfos) {
        db = mongo.getDB(databaseName);
        if (db == null) {
            logger.error("Database " + databaseName + "does not exist");
            throw new SchemaGenerationException("database " + databaseName + "does not exist", "mongoDb",
                    databaseName);
        } else {
            for (TableInfo tableInfo : tableInfos) {
                if (tableInfo.getLobColumnInfo().isEmpty()) {
                    if (!db.collectionExists(tableInfo.getTableName())) {
                        logger.error(
                                "Collection " + tableInfo.getTableName() + "does not exist in db " + db.getName());
                        throw new SchemaGenerationException(
                                "Collection " + tableInfo.getTableName() + " does not exist in db " + db.getName(),
                                "mongoDb", databaseName, tableInfo.getTableName());
                    }
                } else {
                    checkMultipleLobs(tableInfo);
                    if (!db.collectionExists(tableInfo.getTableName() + MongoDBUtils.FILES)) {
                        logger.error("Collection " + tableInfo.getTableName() + MongoDBUtils.FILES
                                + "does not exist in db " + db.getName());
                        throw new SchemaGenerationException(
                                "Collection " + tableInfo.getTableName() + " does not exist in db " + db.getName(),
                                "mongoDb", databaseName, tableInfo.getTableName());
                    }
                    if (!db.collectionExists(tableInfo.getTableName() + MongoDBUtils.CHUNKS)) {
                        logger.error("Collection " + tableInfo.getTableName() + MongoDBUtils.CHUNKS
                                + "does not exist in db " + db.getName());
                        throw new SchemaGenerationException(
                                "Collection " + tableInfo.getTableName() + " does not exist in db " + db.getName(),
                                "mongoDb", databaseName, tableInfo.getTableName());
                    }

                }
            }
        }
    }

    /**
     * initiate client method initiates the client.
     * 
     * @return boolean value ie client started or not.
     * 
     */
    protected boolean initiateClient() {
        String message = null;
        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 {
                mongo = new MongoClient(host, Integer.parseInt(port));
                db = mongo.getDB(databaseName);

                try {
                    MongoDBUtils.authenticate(puMetadata.getProperties(), externalProperties, db);
                } catch (ClientLoaderException e) {
                    throw new SchemaGenerationException(e);
                } catch (KunderaAuthenticationException e) {
                    throw new SchemaGenerationException(e);
                }

                return true;
            } catch (UnknownHostException e) {
                message = e.getMessage();
                logger.error("Database host cannot be resolved, Caused by", e);
            }
        }
        throw new SchemaGenerationException("Database host cannot be resolved, Caused by" + message);
    }

    /**
     * @param tableInfo
     * @return
     */
    private DBObject setCollectionProperties(TableInfo tableInfo) {
        boolean isCappedCollection = isCappedCollection(tableInfo);
        DBObject options = new BasicDBObject();
        if ((tableInfo.getLobColumnInfo().isEmpty() || tableInfo.getLobColumnInfo() == null)
                && isCappedCollection) {
            int collectionSize = MongoDBPropertyReader.msmd != null
                    ? MongoDBPropertyReader.msmd.getCollectionSize(databaseName, tableInfo.getTableName())
                    : 100000;
            int max = MongoDBPropertyReader.msmd != null
                    ? MongoDBPropertyReader.msmd.getMaxSize(databaseName, tableInfo.getTableName())
                    : 100;
            options.put(MongoDBConstants.CAPPED, isCappedCollection);
            options.put(MongoDBConstants.SIZE, collectionSize);
            options.put(MongoDBConstants.MAX, max);
        }
        return options;
    }

    /**
     * Checks whether the given table is a capped collection
     */
    protected boolean isCappedCollection(TableInfo tableInfo) {
        return MongoDBPropertyReader.msmd != null
                ? MongoDBPropertyReader.msmd.isCappedCollection(databaseName, tableInfo.getTableName())
                : false;
    }

    /**
     * @param tableInfo
     * @param collection
     */
    private void createIndexes(TableInfo tableInfo, DBCollection collection) {
        // index normal column
        for (ColumnInfo columnInfo : tableInfo.getColumnMetadatas()) {
            if (columnInfo.isIndexable()) {
                IndexInfo indexInfo = tableInfo.getColumnToBeIndexed(columnInfo.getColumnName());
                indexColumn(indexInfo, collection);
            }
        }

        // index embedded column.
        for (EmbeddedColumnInfo info : tableInfo.getEmbeddedColumnMetadatas()) {
            for (ColumnInfo columnInfo : info.getColumns()) {
                if (columnInfo.isIndexable()) {
                    IndexInfo indexInfo = tableInfo.getColumnToBeIndexed(columnInfo.getColumnName());
                    indexEmbeddedColumn(indexInfo, info.getEmbeddedColumnName(), collection);
                }
            }
        }
    }

    private void indexColumn(IndexInfo indexInfo, DBCollection collection) {
        DBObject keys = new BasicDBObject();
        getIndexType(indexInfo.getIndexType(), keys, indexInfo.getColumnName());
        DBObject options = new BasicDBObject();
        if (indexInfo.getMinValue() != null) {
            options.put(MongoDBConstants.MIN, indexInfo.getMinValue());
        }
        if (indexInfo.getMaxValue() != null) {
            options.put(MongoDBConstants.MAX, indexInfo.getMaxValue());
        }

        if (indexInfo.getIndexType() != null && (indexInfo.getIndexType().toLowerCase()).equals("unique")) {
            options.put("unique", true);
        }
        collection.createIndex(keys, options);
        KunderaCoreUtils.printQuery("Create indexes on:" + keys, showQuery);
    }

    private void indexEmbeddedColumn(IndexInfo indexInfo, String embeddedColumnName, DBCollection collection) {
        DBObject keys = new BasicDBObject();
        getIndexType(indexInfo.getIndexType(), keys, embeddedColumnName + "." + indexInfo.getColumnName());
        DBObject options = new BasicDBObject();
        if (indexInfo.getMinValue() != null) {
            options.put(MongoDBConstants.MIN, indexInfo.getMinValue());
        }
        if (indexInfo.getMaxValue() != null) {
            options.put(MongoDBConstants.MAX, indexInfo.getMaxValue());
        }
        collection.createIndex(keys, options);
        KunderaCoreUtils.printQuery("Create indexes on:" + keys, showQuery);
    }

    /**
     * @param indexType
     * @param clazz
     * @return
     */
    private void getIndexType(String indexType, DBObject keys, String columnName) {
        // TODO validation for indexType and attribute type

        if (indexType != null) {
            if (indexType.equals(IndexType.ASC.name())) {
                keys.put(columnName, 1);
                return;
            } else if (indexType.equals(IndexType.DSC.name())) {
                keys.put(columnName, -1);
                return;
            } else if (indexType.equals(IndexType.GEO2D.name())) {
                keys.put(columnName, "2d");
                return;
            }
        }
        keys.put(columnName, 1);
        return;
    }

    private void checkMultipleLobs(TableInfo tableInfo) {
        if (tableInfo.getLobColumnInfo().size() > 1)
            throw new KunderaException("Multiple Lob fields in a single Entity are not supported in Kundera");
    }

    private void createUniqueIndexGFS(DBCollection coll, String id) {
        try {
            coll.createIndex(new BasicDBObject("metadata." + id, 1), new BasicDBObject("unique", true));
        } catch (MongoException ex) {
            throw new KunderaException("Error in creating unique indexes in " + coll.getFullName()
                    + " collection on " + id + " field");
        }
    }

    @Override
    public boolean validateEntity(Class clazz) {
        return true;
    }

}