All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datanucleus.store.mongodb.MongoDBSchemaHandler Maven / Gradle / Ivy

/**********************************************************************
Copyright (c) 2014 Andy Jefferson and others. All rights reserved.
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.

Contributors:
    ...
**********************************************************************/
package org.datanucleus.store.mongodb;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.ClassMetaData;
import org.datanucleus.metadata.ClassPersistenceModifier;
import org.datanucleus.metadata.IdentityType;
import org.datanucleus.metadata.IndexMetaData;
import org.datanucleus.metadata.RelationType;
import org.datanucleus.metadata.UniqueMetaData;
import org.datanucleus.store.StoreData;
import org.datanucleus.store.StoreManager;
import org.datanucleus.store.connection.ManagedConnection;
import org.datanucleus.store.schema.AbstractStoreSchemaHandler;
import org.datanucleus.store.schema.naming.NamingFactory;
import org.datanucleus.store.schema.table.Column;
import org.datanucleus.store.schema.table.CompleteClassTable;
import org.datanucleus.store.schema.table.MemberColumnMapping;
import org.datanucleus.store.schema.table.Table;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;

/**
 * Handler for schema operations with MongoDB datastores.
 */
public class MongoDBSchemaHandler extends AbstractStoreSchemaHandler
{
    public MongoDBSchemaHandler(StoreManager storeMgr)
    {
        super(storeMgr);
    }

    /* (non-Javadoc)
     * @see org.datanucleus.store.schema.AbstractStoreSchemaHandler#createSchemaForClasses(java.util.Set, java.util.Properties, java.lang.Object)
     */
    @Override
    public void createSchemaForClasses(Set classNames, Properties props, Object connection)
    {
        DB db = (DB)connection;
        ManagedConnection mconn = null;
        try
        {
            if (db == null)
            {
                mconn = storeMgr.getConnection(-1);
                db = (DB)mconn.getConnection();
            }

            Iterator classIter = classNames.iterator();
            ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null);
            while (classIter.hasNext())
            {
                String className = classIter.next();
                AbstractClassMetaData cmd = storeMgr.getMetaDataManager().getMetaDataForClass(className, clr);
                if (cmd != null)
                {
                    createSchemaForClass(cmd, db);
                }
            }
        }
        finally
        {
            if (mconn != null)
            {
                mconn.release();
            }
        }
    }

    protected void createSchemaForClass(AbstractClassMetaData cmd, DB db)
    {
        if (cmd.isEmbeddedOnly() || cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_CAPABLE)
        {
            // No table required here
            return;
        }
        if (cmd instanceof ClassMetaData && ((ClassMetaData) cmd).isAbstract())
        {
            // No table required here
            return;
        }

        StoreData storeData = storeMgr.getStoreDataForClass(cmd.getFullClassName());
        Table table = null;
        if (storeData != null)
        {
            table = storeData.getTable();
        }
        else
        {
            table = new CompleteClassTable(storeMgr, cmd, null);
        }

        String collectionName = table.getName();
        DBCollection collection = null;
        if (isAutoCreateTables() && !db.collectionExists(collectionName))
        {
            // Create collection (if not existing)
            if (cmd.hasExtension(MongoDBStoreManager.CAPPED_SIZE_EXTENSION_NAME))
            {
                Set collNames = db.getCollectionNames();
                if (!collNames.contains(collectionName))
                {
                    // Collection specified as "capped" with a size and doesn't exist so create it
                    DBObject options = new BasicDBObject();
                    options.put("capped", "true");
                    Long size = Long.valueOf(cmd.getValueForExtension(MongoDBStoreManager.CAPPED_SIZE_EXTENSION_NAME));
                    options.put("size", size);
                    if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled())
                    {
                        NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("MongoDB.Schema.CreateClass", cmd.getFullClassName(), collectionName));
                    }
                    db.createCollection(collectionName, options);
                }
                else
                {
                    DBObject options = new BasicDBObject();
                    if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled())
                    {
                        NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("MongoDB.Schema.CreateClass", cmd.getFullClassName(), collectionName));
                    }
                    collection = db.createCollection(collectionName, options);
                }
            }
            else
            {
                DBObject options = new BasicDBObject();
                if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled())
                {
                    NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("MongoDB.Schema.CreateClass", cmd.getFullClassName(), collectionName));
                }
                collection = db.createCollection(collectionName, options);
            }
        }

        ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null);
        if (autoCreateConstraints)
        {
            // Create indexes
            if (collection == null && !db.getCollectionNames().contains(collectionName))
            {
                NucleusLogger.DATASTORE_SCHEMA.warn("Cannot create constraints for " + cmd.getFullClassName() +
                    " since collection of name " + collectionName + " doesn't exist (enable autoCreateTables?)");
                return;
            }
            else if (collection == null)
            {
                collection = db.getCollection(collectionName);
            }


            // Class-level indexes
            NamingFactory namingFactory = storeMgr.getNamingFactory();
            AbstractClassMetaData theCmd = cmd;
            while (theCmd != null)
            {
                IndexMetaData[] clsIdxMds = theCmd.getIndexMetaData();
                if (clsIdxMds != null)
                {
                    for (int i=0;i mappings = table.getMemberColumnMappings();
            for (MemberColumnMapping mapping : mappings)
            {
                Column column = mapping.getColumn(0);
                RelationType relType = mapping.getMemberMetaData().getRelationType(clr);
                UniqueMetaData unimd = mapping.getMemberMetaData().getUniqueMetaData();
                if (relType == RelationType.NONE && unimd != null) // Don't allow on relation fields since MongoDB would equate two null rows as breaking the constraint (on a String field)
                {
                    BasicDBObject query = new BasicDBObject();
                    query.append(column.getName(), 1);
                    if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled())
                    {
                        NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("MongoDB.Schema.CreateClassIndex", unimd.getName(), collectionName, query));
                    }
                    String idxName = unimd.getName();
                    if (idxName == null)
                    {
                        idxName = namingFactory.getConstraintName(cmd.getName(), mapping.getMemberMetaData(), unimd);
                    }
                    collection.createIndex(query, idxName, true);
                }
                else
                {
                    IndexMetaData idxmd = mapping.getMemberMetaData().getIndexMetaData();
                    if (idxmd != null)
                    {
                        BasicDBObject query = new BasicDBObject();
                        query.append(column.getName(), 1);
                        String idxName = namingFactory.getConstraintName(cmd.getName(), mapping.getMemberMetaData(), idxmd);
                        if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled())
                        {
                            NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("MongoDB.Schema.CreateClassIndex", idxName, collectionName, query));
                        }
                        collection.createIndex(query, idxName, idxmd.isUnique());
                    }
                }
            }
        }
    }

    private DBObject getDBObjectForIndex(AbstractClassMetaData cmd, IndexMetaData idxmd, Table table)
    {
        BasicDBObject idxObj = new BasicDBObject();
        if (idxmd.getNumberOfColumns() > 0)
        {
            String[] idxcolNames = idxmd.getColumnNames();
            for (int j=0;j 0)
        {
            String[] idxMemberNames = idxmd.getMemberNames();
            for (int i=0;i 0)
        {
            String[] unicolNames = unimd.getColumnNames();
            for (int j=0;j classNames, Properties props, Object connection)
    {
        DB db = (DB)connection;
        ManagedConnection mconn = null;
        try
        {
            if (db == null)
            {
                mconn = storeMgr.getConnection(-1);
                db = (DB)mconn.getConnection();
            }

            Iterator classIter = classNames.iterator();
            ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null);
            while (classIter.hasNext())
            {
                String className = classIter.next();
                AbstractClassMetaData cmd = storeMgr.getMetaDataManager().getMetaDataForClass(className, clr);
                if (cmd != null)
                {
                    StoreData storeData = storeMgr.getStoreDataForClass(cmd.getFullClassName());
                    Table table = null;
                    if (storeData != null)
                    {
                        table = storeData.getTable();
                    }
                    else
                    {
                        table = new CompleteClassTable(storeMgr, cmd, null);
                    }
                    DBCollection collection = db.getCollection(table.getName());
                    collection.dropIndexes();
                    if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled())
                    {
                        NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("MongoDB.SchemaDelete.Class", cmd.getFullClassName(), table.getName()));
                    }
                    collection.drop();
                }
            }
        }
        finally
        {
            if (mconn != null)
            {
                mconn.release();
            }
        }
    }

    /* (non-Javadoc)
     * @see org.datanucleus.store.schema.AbstractStoreSchemaHandler#validateSchema(java.util.Set, java.util.Properties, java.lang.Object)
     */
    @Override
    public void validateSchema(Set classNames, Properties props, Object connection)
    {
        boolean success = true;
        DB db = (DB)connection;
        ManagedConnection mconn = null;
        try
        {
            if (db == null)
            {
                mconn = storeMgr.getConnection(-1);
                db = (DB)mconn.getConnection();
            }

            Iterator classIter = classNames.iterator();
            ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null);
            while (classIter.hasNext())
            {
                String className = classIter.next();
                AbstractClassMetaData cmd = storeMgr.getMetaDataManager().getMetaDataForClass(className, clr);
                if (cmd != null)
                {
                    // Validate the schema for the class
                    StoreData storeData = storeMgr.getStoreDataForClass(cmd.getFullClassName());
                    Table table = null;
                    if (storeData != null)
                    {
                        table = storeData.getTable();
                    }
                    else
                    {
                        table = new CompleteClassTable(storeMgr, cmd, null);
                    }

                    String tableName = table.getName();
                    if (!db.collectionExists(tableName))
                    {
                        success = false;
                        String msg = Localiser.msg("MongoDB.SchemaValidate.Class", cmd.getFullClassName(), tableName);
                        System.out.println(msg);
                        NucleusLogger.DATASTORE_SCHEMA.error(msg);
                        continue;
                    }

                    String msg = "Table for class="+cmd.getFullClassName() + " with name="+tableName + " validated";
                    NucleusLogger.DATASTORE_SCHEMA.info(msg);

                    DBCollection dbColl = db.getCollection(tableName);
                    List indices = new ArrayList(dbColl.getIndexInfo());

                    IndexMetaData[] idxmds = cmd.getIndexMetaData();
                    if (idxmds != null && idxmds.length > 0)
                    {
                        for (int i=0;i indices, String idxName, DBObject idxObj, boolean unique)
    {
        if (indices == null || indices.isEmpty())
        {
            return null;
        }

        Iterator idxIter = indices.iterator();
        while (idxIter.hasNext())
        {
            DBObject index = idxIter.next();
            DBObject obj = null;
            String name = (String) index.get("name");
            if (name.equals(idxName))
            {
                obj = index;
                if (unique)
                {
                    boolean flag = (Boolean) index.get("unique");
                    if (!flag)
                    {
                        continue;
                    }
                }

                boolean equal = true;
                DBObject key = (DBObject)index.get("key");
                if (key.toMap().size() != idxObj.toMap().size())
                {
                    equal = false;
                }
                else
                {
                    Iterator indicKeyIter = key.keySet().iterator();
                    while (indicKeyIter.hasNext())
                    {
                        String fieldKey = indicKeyIter.next();
                        Object fieldValue = key.get(fieldKey);
                        if (!idxObj.containsField(fieldKey))
                        {
                            equal = false;
                        }
                        else
                        {
                            Object idxObjValue = idxObj.get(fieldKey);
                            if (!idxObjValue.equals(fieldValue))
                            {
                                equal = false;
                            }
                        }
                    }
                }
                if (equal)
                {
                    return obj;
                }
            }
        }
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy