Package org.datanucleus.store.mongodb.fieldmanager

Source Code of org.datanucleus.store.mongodb.fieldmanager.StoreFieldManager

/**********************************************************************
Copyright (c) 2011 Andy Jefferson. 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.fieldmanager;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.IdentityStrategy;
import org.datanucleus.metadata.Relation;
import org.datanucleus.store.ExecutionContext;
import org.datanucleus.store.ObjectProvider;
import org.datanucleus.store.fieldmanager.AbstractFieldManager;
import org.datanucleus.store.fieldmanager.FieldManager;
import org.datanucleus.store.mongodb.MongoDBUtils;
import org.datanucleus.store.types.ObjectLongConverter;
import org.datanucleus.store.types.ObjectStringConverter;

/**
* Field Manager for putting values into MongoDB.
*/
public class StoreFieldManager extends AbstractFieldManager
{
    protected ObjectProvider sm;

    protected DBObject dbObject;

    protected AbstractClassMetaData cmd;

    /** Metadata of the owner field if this is for an embedded object. */
    protected AbstractMemberMetaData ownerMmd = null;

    public StoreFieldManager(ObjectProvider sm, DBObject dbObject, AbstractClassMetaData cmd)
    {
        super();
        this.sm = sm;
        this.dbObject = dbObject;
        this.cmd = cmd;
    }

    @Override
    public void storeBooleanField(int fieldNumber, boolean value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Boolean.valueOf(value));
    }


    @Override
    public void storeCharField(int fieldNumber, char value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Character.valueOf(value));
    }

    @Override
    public void storeByteField(int fieldNumber, byte value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Byte.valueOf(value));
    }

    @Override
    public void storeShortField(int fieldNumber, short value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Short.valueOf(value));
    }

    @Override
    public void storeIntField(int fieldNumber, int value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Integer.valueOf(value));
    }

    @Override
    public void storeLongField(int fieldNumber, long value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Long.valueOf(value));
    }

    @Override
    public void storeFloatField(int fieldNumber, float value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Float.valueOf(value));
    }

    @Override
    public void storeDoubleField(int fieldNumber, double value)
    {
        String fieldName = getFieldName(fieldNumber);
        dbObject.put(fieldName, Double.valueOf(value));
    }

    @Override
    public void storeStringField(int fieldNumber, String value)
    {
        AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        if (mmd.getValueStrategy() == IdentityStrategy.IDENTITY)
        {
            // Using "_id" to represent this field so don't put it
            return;
        }

        String fieldName = getFieldName(fieldNumber);
        if (value == null)
        {
            dbObject.removeField(fieldName);
            return;
        }

        dbObject.put(fieldName, value);
    }

    protected String getFieldName(int fieldNumber)
    {
        return MongoDBUtils.getFieldName(cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber));
    }

    @Override
    public void storeObjectField(int fieldNumber, Object value)
    {
        AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        String fieldName = MongoDBUtils.getFieldName(mmd);
        ExecutionContext ec = sm.getExecutionContext();
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        int relationType = mmd.getRelationType(clr);

        boolean embedded = false;
        if (sm.getEmbeddedOwners() != null)
        {
            embedded = true;
        }
        else if (relationType != Relation.NONE)
        {
            if (mmd.isEmbedded())
            {
                embedded = true;
            }
            else if (mmd.getEmbeddedMetaData() != null)
            {
                embedded = true;
            }
            else if (Relation.isRelationMultiValued(relationType))
            {
                if (mmd.hasCollection() && mmd.getElementMetaData() != null && mmd.getElementMetaData().getEmbeddedMetaData() != null)
                {
                    // Embedded collection element
                    embedded = true;
                }
                else if (mmd.hasArray() && mmd.getElementMetaData() != null && mmd.getElementMetaData().getEmbeddedMetaData() != null)
                {
                    // Embedded array element
                    embedded = true;
                }
                else if (mmd.hasMap() &&
                        ((mmd.getKeyMetaData() != null && mmd.getKeyMetaData().getEmbeddedMetaData() != null) ||
                        (mmd.getValueMetaData() != null && mmd.getValueMetaData().getEmbeddedMetaData() != null)))
                {
                    // Embedded map key/value
                    embedded = true;
                }
            }
        }

        if (embedded)
        {
            if (Relation.isRelationSingleValued(relationType))
            {
                // Embedded PC object
                AbstractClassMetaData embcmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
                if (embcmd == null)
                {
                    throw new NucleusUserException("Field " + mmd.getFullFieldName() +
                        " specified as embedded but metadata not found for the class of type " + mmd.getTypeName());
                }

                boolean nested = true;
                String nestedStr = mmd.getValueForExtension("nested");
                if (nestedStr != null && nestedStr.equalsIgnoreCase("false"))
                {
                    nested = false;
                }

                if (nested && ownerMmd != null && Relation.isBidirectional(relationType))
                {
                    if ((ownerMmd.getMappedBy() != null && mmd.getName().equals(ownerMmd.getMappedBy())) ||
                        (mmd.getMappedBy() != null && ownerMmd.getName().equals(mmd.getMappedBy())))
                    {
                        // Other side of owner bidirectional, so omit
                        return;
                    }
                }

                if (value == null)
                {
                    if (nested)
                    {
                        dbObject.removeField(MongoDBUtils.getFieldName(mmd));
                        return;
                    }
                    else
                    {
                        // TODO Delete any fields for the embedded object
                        return;
                    }
                }

                ObjectProvider embSM = ec.findObjectProviderForEmbedded(value, sm, mmd);

                if (nested)
                {
                    // Nested embedding, as nested document
                    BasicDBObject embeddedObject = new BasicDBObject();
                    StoreFieldManager sfm = new StoreFieldManager(embSM, embeddedObject, embcmd);
                    sfm.ownerMmd = mmd;
                    embSM.provideFields(embcmd.getAllMemberPositions(), sfm);
                    dbObject.put(fieldName, embeddedObject);
                    return;
                }
                else
                {
                    // Flat embedding as fields of the owning document
                    FieldManager ffm = new StoreEmbeddedFieldManager(embSM, dbObject, mmd);
                    embSM.provideFields(embcmd.getAllMemberPositions(), ffm);
                    return;
                }
            }
            else if (Relation.isRelationMultiValued(relationType))
            {
                if (value == null)
                {
                    dbObject.removeField(MongoDBUtils.getFieldName(mmd));
                    return;
                }

                if (ownerMmd != null && Relation.isBidirectional(relationType))
                {
                    if ((ownerMmd.getMappedBy() != null && mmd.getName().equals(ownerMmd.getMappedBy())) ||
                        (mmd.getMappedBy() != null && ownerMmd.getName().equals(mmd.getMappedBy())))
                    {
                        // Other side of owner bidirectional, so omit
                        // TODO Need to store the collection somehow since no way of getting it back after
                        return;
                    }
                }

                if (mmd.hasCollection())
                {
                    AbstractClassMetaData embcmd = mmd.getCollection().getElementClassMetaData(clr, ec.getMetaDataManager());
                    Collection coll = new ArrayList();
                    Collection valueColl = (Collection)value;
                    Iterator collIter = valueColl.iterator();
                    while (collIter.hasNext())
                    {
                        Object element = collIter.next();
                        ObjectProvider embSM = ec.findObjectProviderForEmbedded(element, sm, mmd);
                        embSM.setPcObjectType(ObjectProvider.EMBEDDED_COLLECTION_ELEMENT_PC);
                        BasicDBObject embeddedObject = new BasicDBObject();
                        StoreFieldManager sfm = new StoreFieldManager(embSM, embeddedObject, embcmd);
                        sfm.ownerMmd = mmd;
                        embSM.provideFields(embcmd.getAllMemberPositions(), sfm);
                        coll.add(embeddedObject);
                    }
                    dbObject.put(fieldName, coll); // Store as List<DBObject>
                    return;
                }
                else if (mmd.hasArray())
                {
                    AbstractClassMetaData embcmd = mmd.getArray().getElementClassMetaData(clr, ec.getMetaDataManager());
                    Object[] array = new Object[Array.getLength(value)];
                    for (int i=0;i<array.length;i++)
                    {
                        Object element = Array.get(value, i);
                        ObjectProvider embSM = ec.findObjectProviderForEmbedded(element, sm, mmd);
                        embSM.setPcObjectType(ObjectProvider.EMBEDDED_COLLECTION_ELEMENT_PC);
                        BasicDBObject embeddedObject = new BasicDBObject();
                        StoreFieldManager sfm = new StoreFieldManager(embSM, embeddedObject, embcmd);
                        sfm.ownerMmd = mmd;
                        embSM.provideFields(embcmd.getAllMemberPositions(), sfm);
                        array[i] = embeddedObject;
                    }
                    dbObject.put(fieldName, array); // Store as DBObject[]
                    return;
                }
                else
                {
                    AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr, ec.getMetaDataManager());
                    AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr, ec.getMetaDataManager());

                    Collection entryList = new ArrayList();
                    Map valueMap = (Map)value;
                    Iterator<Map.Entry> mapEntryIter = valueMap.entrySet().iterator();
                    while (mapEntryIter.hasNext())
                    {
                        Map.Entry entry = mapEntryIter.next();
                        BasicDBObject entryObj = new BasicDBObject();

                        if (keyCmd == null)
                        {
                            processContainerNonRelationField("key", ec, entry.getKey(), entryObj);
                        }
                        else
                        {
                            ObjectProvider embSM = ec.findObjectProviderForEmbedded(entry.getKey(), sm, mmd);
                            embSM.setPcObjectType(ObjectProvider.EMBEDDED_MAP_KEY_PC);
                            BasicDBObject embeddedKey = new BasicDBObject();
                            StoreFieldManager sfm = new StoreFieldManager(embSM, embeddedKey, keyCmd);
                            sfm.ownerMmd = mmd;
                            embSM.provideFields(keyCmd.getAllMemberPositions(), sfm);
                            entryObj.append("key", embeddedKey);
                        }

                        if (valCmd == null)
                        {
                            processContainerNonRelationField("value", ec, entry.getValue(), entryObj);
                        }
                        else
                        {
                            ObjectProvider embSM = ec.findObjectProviderForEmbedded(entry.getValue(), sm, mmd);
                            embSM.setPcObjectType(ObjectProvider.EMBEDDED_MAP_VALUE_PC);
                            BasicDBObject embeddedVal = new BasicDBObject();
                            StoreFieldManager sfm = new StoreFieldManager(embSM, embeddedVal, valCmd);
                            sfm.ownerMmd = mmd;
                            embSM.provideFields(valCmd.getAllMemberPositions(), sfm);
                            entryObj.append("value", embeddedVal);
                        }
                        entryList.add(entryObj);
                    }
                    dbObject.put(fieldName, entryList);
                    return;
                }
            }
        }

        if (value == null)
        {
            if (dbObject.containsField(fieldName))
            {
                dbObject.removeField(fieldName);
            }
            return;
        }

        if (mmd.isSerialized())
        {
            processSerialisedField(fieldName, value, dbObject);
            sm.wrapSCOField(fieldNumber, value, false, false, true);
        }
        else if (Relation.isRelationSingleValued(relationType))
        {
            // PC object, so make sure it is persisted
            processSingleRelationField(value, ec, fieldName);
        }
        else if (Relation.isRelationMultiValued(relationType))
        {
            // Collection/Map/Array
            processContainerRelationField(mmd, value, ec, fieldName);
            sm.wrapSCOField(fieldNumber, value, false, false, true);
        }
        else
        {
            processContainerNonRelationField(fieldName, ec, value, dbObject);
            sm.wrapSCOField(fieldNumber, value, false, false, true);
        }
    }

    protected void processSingleRelationField(Object value, ExecutionContext ec, String fieldName)
    {
        Object valuePC = sm.getExecutionContext().persistObjectInternal(value, null, -1, -1);
        Object valueId = ec.getApiAdapter().getIdForObject(valuePC);
        dbObject.put(fieldName, valueId.toString()); // Store the id String form
    }

    protected void processContainerRelationField(AbstractMemberMetaData mmd, Object value, ExecutionContext ec,
            String fieldName)
    {
        // Collection/Map/Array
        if (mmd.hasCollection())
        {
            Collection collIds = new ArrayList();
            Collection coll = (Collection)value;
            Iterator collIter = coll.iterator();
            while (collIter.hasNext())
            {
                Object element = collIter.next();
                Object elementPC = sm.getExecutionContext().persistObjectInternal(element, null, -1, -1);
                Object elementID = sm.getExecutionContext().getApiAdapter().getIdForObject(elementPC);
                collIds.add(elementID.toString());
            }
            dbObject.put(fieldName, collIds); // Store List<String> of ids
        }
        else if (mmd.hasMap())
        {
            Collection<DBObject> collEntries = new HashSet();
            Map map = (Map)value;
            Iterator<Map.Entry> mapIter = map.entrySet().iterator();
            while (mapIter.hasNext())
            {
                Map.Entry entry = mapIter.next();
                Object mapKey = entry.getKey();
                Object mapValue = entry.getValue();

                BasicDBObject entryObj = new BasicDBObject();
                if (ec.getApiAdapter().isPersistable(mapKey))
                {
                    Object pc = ec.persistObjectInternal(mapKey, null, -1, -1);
                    Object keyID = sm.getExecutionContext().getApiAdapter().getIdForObject(pc);
                    entryObj.append("key", keyID.toString());
                }
                else
                {
                    processContainerNonRelationField("key", ec, mapKey, entryObj);
                }

                if (ec.getApiAdapter().isPersistable(mapValue))
                {
                    Object pc = ec.persistObjectInternal(mapValue, null, -1, -1);
                    Object valueID = sm.getExecutionContext().getApiAdapter().getIdForObject(pc);
                    entryObj.append("value", valueID.toString());
                }
                else
                {
                    processContainerNonRelationField("value", ec, mapValue, entryObj);
                }

                collEntries.add(entryObj);
            }
            dbObject.put(fieldName, collEntries); // Store Collection<DBObject> of entries
        }
        else if (mmd.hasArray())
        {
            Collection<String> collIds = new ArrayList();
            for (int i=0;i<Array.getLength(value);i++)
            {
                Object element = Array.get(value, i);
                Object elementPC = ec.persistObjectInternal(element, null, -1, -1);
                Object elementID = ec.getApiAdapter().getIdForObject(elementPC);
                collIds.add(elementID.toString());
            }
            dbObject.put(fieldName, collIds); // Store List<String> of ids
        }
    }

    protected void processSerialisedField(String fieldName, Object value, DBObject dbObject)
    {
        try
        {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(value);
            dbObject.put(fieldName, bos.toByteArray());
            oos.close();
            bos.close();
        }
        catch (IOException e)
        {
            throw new NucleusException("Exception thrown serialising value for field " + fieldName, e);
        }
    }

    protected void processContainerNonRelationField(String fieldName, ExecutionContext ec, Object value, DBObject dbObject)
    {
        if (Enum.class.isAssignableFrom(value.getClass()))
        {
            // TODO Persist as number when requested
            dbObject.put(fieldName, ((Enum)value).name());
            return;
        }
        else if (Date.class.isAssignableFrom(value.getClass()))
        {
            // Persist as Date
            dbObject.put(fieldName, (Date)value);
            return;
        }
        else if (Calendar.class.isAssignableFrom(value.getClass()))
        {
            Date dateValue = ((Calendar)value).getTime();
            dbObject.put(fieldName, dateValue);
            return;
        }

        ObjectStringConverter strConv =
            ec.getNucleusContext().getTypeManager().getStringConverter(value.getClass());
        ObjectLongConverter longConv =
            ec.getNucleusContext().getTypeManager().getLongConverter(value.getClass());
        if (strConv != null)
        {
            // Persist as a String
            String strValue = strConv.toString(value);
            dbObject.put(fieldName, strValue);
        }
        else if (longConv != null)
        {
            // Persist as a Long
            Long longValue = longConv.toLong(value);
            dbObject.put(fieldName, longValue);
        }
        else
        {
            dbObject.put(fieldName, value);
        }
    }
}
TOP

Related Classes of org.datanucleus.store.mongodb.fieldmanager.StoreFieldManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.