Package org.datanucleus.store.mongodb.fieldmanager

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

/**********************************************************************
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.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Array;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import com.mongodb.DBObject;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusDataStoreException;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.identity.IdentityUtils;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.EmbeddedMetaData;
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;
import org.datanucleus.store.types.sco.SCOUtils;

/**
* Field Manager for retrieving values from MongoDB.
*/
public class FetchFieldManager extends AbstractFieldManager
{
    protected ExecutionContext ec;

    protected ObjectProvider sm;

    protected DBObject dbObject;

    protected AbstractClassMetaData cmd;

    boolean embedded = false;

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

    public FetchFieldManager(ObjectProvider sm, DBObject dbObject, AbstractClassMetaData acmd)
    {
        this.sm = sm;
        this.ec = sm.getExecutionContext();
        this.dbObject = dbObject;
        this.cmd = acmd;
        if (sm.getEmbeddedOwners() != null)
        {
            embedded = true;
        }
    }

    public FetchFieldManager(ExecutionContext ec, DBObject dbObject, AbstractClassMetaData acmd)
    {
        this.ec = ec;
        this.dbObject = dbObject;
        this.cmd = acmd;
    }

    @Override
    public boolean fetchBooleanField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Boolean)dbObject.get(fieldName)).booleanValue();
    }

    @Override
    public char fetchCharField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Character)dbObject.get(fieldName)).charValue();
    }

    @Override
    public byte fetchByteField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Byte)dbObject.get(fieldName)).byteValue();
    }

    @Override
    public short fetchShortField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Short)dbObject.get(fieldName)).shortValue();
    }

    @Override
    public int fetchIntField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Integer)dbObject.get(fieldName)).intValue();
    }

    @Override
    public long fetchLongField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Long)dbObject.get(fieldName)).longValue();
    }

    @Override
    public float fetchFloatField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Float)dbObject.get(fieldName)).floatValue();
    }

    @Override
    public double fetchDoubleField(int fieldNumber)
    {
        String fieldName = getFieldName(fieldNumber);
        return ((Double)dbObject.get(fieldName)).doubleValue();
    }

    @Override
    public String fetchStringField(int fieldNumber)
    {
        AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        if (mmd.getValueStrategy() == IdentityStrategy.IDENTITY)
        {
            // Return the "_id" value since not using this field as such
            Object id = dbObject.get("_id");
            return (String)(id.toString());
        }
        String fieldName = getFieldName(fieldNumber);
        if (dbObject.containsField(fieldName))
        {
            return (String)(dbObject.get(fieldName));
        }
        else
        {
            return null;
        }
    }

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

    @Override
    public Object fetchObjectField(int fieldNumber)
    {
        AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        int relationType = mmd.getRelationType(clr);

        boolean embedded = false;
        if (this.embedded || ownerMmd != 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 collection 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() +
                        " marked as embedded but no such metadata");
                }

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

                if (nested)
                {
                    // Nested embedding, as nested document
                    if (embedded && 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 return the owner
                            ObjectProvider[] ownerSms = sm.getEmbeddedOwners();
                            if (ownerSms == null)
                            {
                                throw new NucleusException("Processing of " + mmd.getFullFieldName() + " cannot set value to owner since owner StateManager not set");
                            }
                            return ownerSms[0].getObject();
                        }
                    }

                    String fieldName = MongoDBUtils.getFieldName(mmd);
                    if (!dbObject.containsField(fieldName))
                    {
                        return null;
                    }

                    DBObject embeddedValue = (DBObject)dbObject.get(fieldName);
                    ObjectProvider embSM = ec.newObjectProviderForEmbedded(mmd, embcmd, sm, fieldNumber);
                    FetchFieldManager ffm = new FetchFieldManager(embSM, embeddedValue, embcmd);
                    ffm.ownerMmd = mmd;
                    ffm.embedded = true;
                    embSM.replaceFields(embcmd.getAllMemberPositions(), ffm);
                    return embSM.getObject();
                }
                else
                {
                    // Flat embedding as fields of the owning document

                    // TODO Cater for null (use embmd.getNullIndicatorColumn/Value)
                    EmbeddedMetaData embmd = mmd.getEmbeddedMetaData();
                    AbstractMemberMetaData[] embmmds = embmd.getMemberMetaData();
                    boolean isNull = true;
                    for (int i=0;i<embmmds.length;i++)
                    {
                        String embFieldName = MongoDBUtils.getFieldName(mmd, i);
                        if (dbObject.containsField(embFieldName))
                        {
                            isNull = false;
                            break;
                        }
                    }
                    if (isNull)
                    {
                        return null;
                    }

                    ObjectProvider embSM = ec.newObjectProviderForEmbedded(mmd, embcmd, sm, fieldNumber);
                    FieldManager ffm = new FetchEmbeddedFieldManager(embSM, dbObject, mmd);
                    embSM.replaceFields(embcmd.getAllMemberPositions(), ffm);
                    return embSM.getObject();
                }
            }
            else if (Relation.isRelationMultiValued(relationType))
            {
                if (mmd.hasCollection())
                {
                    String fieldName = MongoDBUtils.getFieldName(mmd);
                    if (!dbObject.containsField(fieldName))
                    {
                        return null;
                    }
                    Object value = dbObject.get(fieldName);
                    Collection<Object> coll;
                    AbstractClassMetaData elemCmd = mmd.getCollection().getElementClassMetaData(clr, ec.getMetaDataManager());
                    try
                    {
                        Class instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), mmd.getOrderMetaData() != null);
                        coll = (Collection<Object>) instanceType.newInstance();
                    }
                    catch (Exception e)
                    {
                        throw new NucleusDataStoreException(e.getMessage(), e);
                    }

                    Collection collValue = (Collection)value;
                    Iterator collIter = collValue.iterator();
                    while (collIter.hasNext())
                    {
                        DBObject elementObj = (DBObject)collIter.next();
                        ObjectProvider embSM = ec.newObjectProviderForEmbedded(mmd, elemCmd, sm, fieldNumber);
                        embSM.setPcObjectType(ObjectProvider.EMBEDDED_COLLECTION_ELEMENT_PC);
                        FetchFieldManager ffm = new FetchFieldManager(embSM, elementObj, elemCmd);
                        ffm.ownerMmd = mmd;
                        ffm.embedded = true;
                        embSM.replaceFields(elemCmd.getAllMemberPositions(), ffm);
                        coll.add(embSM.getObject());
                    }

                    if (sm != null)
                    {
                        return sm.wrapSCOField(fieldNumber, coll, false, false, true);
                    }
                    return coll;
                }
                else if (mmd.hasArray())
                {
                    String fieldName = MongoDBUtils.getFieldName(mmd);
                    if (!dbObject.containsField(fieldName))
                    {
                        return null;
                    }

                    AbstractClassMetaData elemCmd = mmd.getArray().getElementClassMetaData(clr, ec.getMetaDataManager());
                    Object value = dbObject.get(fieldName);
                    Object[] array = new Object[Array.getLength(value)];
                    for (int i=0;i<array.length;i++)
                    {
                        DBObject elementObj = (DBObject)Array.get(value, i);
                        ObjectProvider embSM = ec.newObjectProviderForEmbedded(mmd, elemCmd, sm, fieldNumber);
                        embSM.setPcObjectType(ObjectProvider.EMBEDDED_COLLECTION_ELEMENT_PC);
                        FetchFieldManager ffm = new FetchFieldManager(embSM, elementObj, elemCmd);
                        ffm.ownerMmd = mmd;
                        ffm.embedded = true;
                        embSM.replaceFields(elemCmd.getAllMemberPositions(), ffm);
                        array[i] = embSM.getObject();
                    }

                    return array;
                }
                else
                {
                    String fieldName = MongoDBUtils.getFieldName(mmd);
                    if (!dbObject.containsField(fieldName))
                    {
                        return null;
                    }
                    Object value = dbObject.get(fieldName);
                    Map map = null;
                    try
                    {
                        Class instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), null);
                        map = (Map) instanceType.newInstance();
                    }
                    catch (Exception e)
                    {
                        throw new NucleusDataStoreException(e.getMessage(), e);
                    }

                    AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr, ec.getMetaDataManager());
                    AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr, ec.getMetaDataManager());
                    Collection<DBObject> entryColl = (Collection)value;
                    Iterator<DBObject> entryIter = entryColl.iterator();
                    while (entryIter.hasNext())
                    {
                        DBObject entryObj = entryIter.next();
                        Object keyObj = entryObj.get("key");
                        Object valObj = entryObj.get("value");

                        Object mapKey = null;
                        if (keyCmd != null)
                        {
                            // Key is embedded object
                            DBObject keyDbObj = (DBObject)keyObj;
                            ObjectProvider embSM = ec.newObjectProviderForEmbedded(mmd, keyCmd, sm, fieldNumber);
                            embSM.setPcObjectType(ObjectProvider.EMBEDDED_MAP_KEY_PC);
                            FetchFieldManager ffm = new FetchFieldManager(embSM, keyDbObj, keyCmd);
                            ffm.ownerMmd = mmd;
                            ffm.embedded = true;
                            embSM.replaceFields(keyCmd.getAllMemberPositions(), ffm);
                            mapKey = embSM.getObject();
                        }
                        else
                        {
                            mapKey = getMapKeyForReturnValue(mmd, keyObj);
                        }

                        Object mapVal = null;
                        if (valCmd != null)
                        {
                            // Value is embedded object
                            DBObject valDbObj = (DBObject)valObj;
                            ObjectProvider embSM = ec.newObjectProviderForEmbedded(mmd, valCmd, sm, fieldNumber);
                            embSM.setPcObjectType(ObjectProvider.EMBEDDED_MAP_VALUE_PC);
                            FetchFieldManager ffm = new FetchFieldManager(embSM, valDbObj, valCmd);
                            ffm.ownerMmd = mmd;
                            ffm.embedded = true;
                            embSM.replaceFields(valCmd.getAllMemberPositions(), ffm);
                            mapVal = embSM.getObject();
                        }
                        else
                        {
                            mapVal = getMapValueForReturnValue(mmd, valObj);
                        }

                        map.put(mapKey, mapVal);
                    }

                    if (sm != null)
                    {
                        return sm.wrapSCOField(fieldNumber, map, false, false, true);
                    }
                    return map;
                }
            }
        }

        String fieldName = MongoDBUtils.getFieldName(mmd);
        if (!dbObject.containsField(fieldName))
        {
            return null;
        }

        Object value = dbObject.get(fieldName);
        if (mmd.isSerialized())
        {
            return getValueForSerialisedField(mmd, value);
        }
        if (Relation.isRelationSingleValued(relationType))
        {
            return getValueForSingleRelationField(mmd, value, clr);
        }
        else if (Relation.isRelationMultiValued(relationType))
        {
            return getValueForContainerRelationField(mmd, value, clr);
        }
        else
        {
            Object val = getValueForContainerNonRelationField(mmd, value);
            if (sm != null)
            {
                // Wrap if SCO
                return sm.wrapSCOField(mmd.getAbsoluteFieldNumber(), val, false, false, true);
            }
            return val;
        }
    }

    protected Object getValueForSerialisedField(AbstractMemberMetaData mmd, Object value)
    {
        Object returnValue = null;
        try
        {
            if (value != null)
            {
                byte[] bytes = (byte[])value;
                ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
                ObjectInputStream ois = new ObjectInputStream(bis);
                returnValue = ois.readObject();
                ois.close();
                bis.close();

                if (sm != null)
                {
                    // Wrap if SCO
                    returnValue = sm.wrapSCOField(mmd.getAbsoluteFieldNumber(), returnValue, false, false, true);
                }
            }
        }
        catch (Exception e)
        {
            throw new NucleusUserException("Exception thrown deserialising field at " + mmd.getFullFieldName(), e);
        }
        return returnValue;
    }

    protected Object getValueForSingleRelationField(AbstractMemberMetaData mmd, Object value, ClassLoaderResolver clr)
    {
        String idStr = (String)value;
        if (value == null)
        {
            return null;
        }
        AbstractClassMetaData otherCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
        return IdentityUtils.getObjectFromIdString(idStr, otherCmd, ec, true);
    }

    protected Object getValueForContainerRelationField(AbstractMemberMetaData mmd, Object value, ClassLoaderResolver clr)
    {
        if (mmd.hasCollection())
        {
            // "a,b,c,d,..."
            Collection<Object> coll;
            try
            {
                Class instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), mmd.getOrderMetaData() != null);
                coll = (Collection<Object>) instanceType.newInstance();
            }
            catch (Exception e)
            {
                throw new NucleusDataStoreException(e.getMessage(), e);
            }

            AbstractClassMetaData elemCmd = mmd.getCollection().getElementClassMetaData(clr, ec.getMetaDataManager());
            Collection collIds = (Collection)value;
            Iterator idIter = collIds.iterator();
            while (idIter.hasNext())
            {
                String elementIdStr = (String)idIter.next();
                coll.add(IdentityUtils.getObjectFromIdString(elementIdStr, elemCmd, ec, true));
            }

            if (sm != null)
            {
                // Wrap if SCO
                return sm.wrapSCOField(mmd.getAbsoluteFieldNumber(), coll, false, false, true);
            }
            return coll;
        }
        else if (mmd.hasMap())
        {
            // "List<Entry>" where the entry object has "key", "value" fields
            Map map = null;
            try
            {
                Class instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), null);
                map = (Map) instanceType.newInstance();
            }
            catch (Exception e)
            {
                throw new NucleusDataStoreException(e.getMessage(), e);
            }

            AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr, ec.getMetaDataManager());
            AbstractClassMetaData valueCmd = mmd.getMap().getValueClassMetaData(clr, ec.getMetaDataManager());
            Collection<DBObject> collEntries = (Collection)value;
            Iterator<DBObject> entryIter = collEntries.iterator();
            while (entryIter.hasNext())
            {
                DBObject entryObj = entryIter.next();
                Object keyObj = entryObj.get("key");
                Object valueObj = entryObj.get("value");

                Object mapKey = null;
                if (keyCmd != null)
                {
                    mapKey = IdentityUtils.getObjectFromIdString((String)keyObj, keyCmd, ec, true);
                }
                else
                {
                    mapKey = getMapKeyForReturnValue(mmd, keyObj);
                }

                Object mapVal = null;
                if (valueCmd != null)
                {
                    mapVal = IdentityUtils.getObjectFromIdString((String)valueObj, valueCmd, ec, true);
                }
                else
                {
                    mapVal = getMapValueForReturnValue(mmd, valueObj);
                }

                map.put(mapKey, mapVal);
            }

            if (sm != null)
            {
                // Wrap if SCO
                return sm.wrapSCOField(mmd.getAbsoluteFieldNumber(), map, false, false, true);
            }
            return map;
        }
        else if (mmd.hasArray())
        {
            // "a,b,c,d,..."
            AbstractClassMetaData elemCmd = mmd.getArray().getElementClassMetaData(clr, ec.getMetaDataManager());

            Collection collIds = (Collection)value;
            Iterator idIter = collIds.iterator();
            int i = 0;
            Object array = Array.newInstance(mmd.getType().getComponentType(), collIds.size());
            while (idIter.hasNext())
            {
                String elementIdStr = (String)idIter.next();
                Array.set(array, i, IdentityUtils.getObjectFromIdString(elementIdStr, elemCmd, ec, true));
                i++;
            }
            return array;
        }
        else
        {
            return value;
        }
    }

    protected Object getValueForContainerNonRelationField(AbstractMemberMetaData mmd, Object value)
    {
        if (Enum.class.isAssignableFrom(mmd.getType()))
        {
            // TODO Retrieve as number when requested
            return Enum.valueOf(mmd.getType(), (String)value);
        }
        else if (Date.class.isAssignableFrom(mmd.getType()) && value instanceof Date)
        {
            // Date could have been persisted as String (in 3.0m4) so this just handles the Date case
            if (sm != null)
            {
                // Wrap if SCO
                return sm.wrapSCOField(mmd.getAbsoluteFieldNumber(), value, false, false, true);
            }
            return value;
        }
        else if (Calendar.class.isAssignableFrom(mmd.getType()))
        {
            Calendar cal = Calendar.getInstance();
            cal.setTime((Date)value);
            return cal;
        }

        ObjectStringConverter strConv =
            ec.getNucleusContext().getTypeManager().getStringConverter(mmd.getType());
        ObjectLongConverter longConv =
            ec.getNucleusContext().getTypeManager().getLongConverter(mmd.getType());
        Object returnValue = value;
        if (strConv != null)
        {
            // Persisted as a String, so convert back
            String strValue = (String)value;
            returnValue = strConv.toObject(strValue);
        }
        else if (longConv != null)
        {
            // Persisted as a Long, so convert back
            Long longValue = (Long)value;
            returnValue = longConv.toObject(longValue);
        }

        if (sm != null)
        {
            // Wrap if SCO
            return sm.wrapSCOField(mmd.getAbsoluteFieldNumber(), returnValue, false, false, true);
        }
        return returnValue;
    }

    private Object getMapKeyForReturnValue(AbstractMemberMetaData mmd, Object value)
    {
        String keyType = mmd.getMap().getKeyType();
        Class keyCls = ec.getClassLoaderResolver().classForName(keyType);
        if (keyCls == Long.class || keyCls == Double.class || keyCls == Float.class ||
            keyCls == Integer.class || keyCls == Short.class || keyCls == String.class)
        {
            return value;
        }
        else if (Enum.class.isAssignableFrom(keyCls))
        {
            return Enum.valueOf(keyCls, (String)value);
        }
        else
        {
            throw new NucleusException("Dont currently support persistence/retrieval of maps with keys of type " + keyType);
        }
    }

    private Object getMapValueForReturnValue(AbstractMemberMetaData mmd, Object value)
    {
        String valueType = mmd.getMap().getValueType();
        Class valueCls = ec.getClassLoaderResolver().classForName(valueType);
        if (valueCls == Long.class || valueCls == Double.class || valueCls == Float.class ||
                valueCls == Integer.class || valueCls == Short.class || valueCls == String.class)
        {
            return value;
        }
        else if (Enum.class.isAssignableFrom(valueCls))
        {
            return Enum.valueOf(valueCls, (String)value);
        }
        else
        {
            throw new NucleusException("Dont currently support persistence/retrieval of maps with values of type " + valueType);
        }
    }
}
TOP

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

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.