org.datanucleus.store.mongodb.fieldmanager.FetchFieldManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of datanucleus-mongodb Show documentation
Show all versions of datanucleus-mongodb Show documentation
Plugin providing persistence to MongoDB datastores.
/**********************************************************************
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.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ExecutionContext;
import org.datanucleus.exceptions.NucleusDataStoreException;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusObjectNotFoundException;
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.FieldPersistenceModifier;
import org.datanucleus.metadata.FieldRole;
import org.datanucleus.metadata.ValueGenerationStrategy;
import org.datanucleus.metadata.MetaDataUtils;
import org.datanucleus.metadata.RelationType;
import org.datanucleus.query.QueryUtils;
import org.datanucleus.state.ObjectProvider;
import org.datanucleus.store.StoreData;
import org.datanucleus.store.StoreManager;
import org.datanucleus.store.fieldmanager.AbstractFetchFieldManager;
import org.datanucleus.store.fieldmanager.FieldManager;
import org.datanucleus.store.mongodb.MongoDBUtils;
import org.datanucleus.store.schema.naming.ColumnType;
import org.datanucleus.store.schema.table.MemberColumnMapping;
import org.datanucleus.store.schema.table.Table;
import org.datanucleus.store.types.SCOUtils;
import org.datanucleus.store.types.converters.MultiColumnConverter;
import org.datanucleus.store.types.converters.TypeConverter;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.TypeConversionHelper;
/**
* Field Manager for retrieving values from MongoDB.
*/
public class FetchFieldManager extends AbstractFetchFieldManager
{
protected Table table;
protected DBObject dbObject;
/** Metadata for the owner field if this is embedded. TODO Is this needed now that we have "mmds" in EmbeddedFetchFieldManager? */
protected AbstractMemberMetaData ownerMmd = null;
public FetchFieldManager(ObjectProvider op, DBObject dbObject, Table table)
{
super(op);
this.table = table;
this.dbObject = dbObject;
}
public FetchFieldManager(ExecutionContext ec, DBObject dbObject, AbstractClassMetaData cmd, Table table)
{
super(ec, cmd);
this.table = table;
this.dbObject = dbObject;
}
protected MemberColumnMapping getColumnMapping(int fieldNumber)
{
return table.getMemberColumnMappingForMember(cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber));
}
@Override
public boolean fetchBooleanField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null)
{
return Boolean.valueOf(dflt);
}
return false;
}
Object value = dbObject.get(fieldName);
return ((Boolean)value).booleanValue();
}
@Override
public byte fetchByteField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null)
{
return Byte.valueOf(dflt);
}
return 0;
}
Object value = dbObject.get(fieldName);
return ((Number)value).byteValue();
}
@Override
public char fetchCharField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null && dflt.length() > 0)
{
return dflt.charAt(0);
}
return 0;
}
Object value = dbObject.get(fieldName);
return ((String)value).charAt(0);
}
@Override
public double fetchDoubleField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null)
{
return Double.valueOf(dflt);
}
return 0;
}
Object value = dbObject.get(fieldName);
return ((Number)value).doubleValue();
}
@Override
public float fetchFloatField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null)
{
return Float.valueOf(dflt);
}
return 0;
}
Object value = dbObject.get(fieldName);
return ((Number)value).floatValue();
}
@Override
public int fetchIntField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null)
{
return Integer.valueOf(dflt);
}
return 0;
}
Object value = dbObject.get(fieldName);
return ((Number)value).intValue();
}
@Override
public long fetchLongField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null)
{
return Long.valueOf(dflt);
}
return 0;
}
Object value = dbObject.get(fieldName);
return ((Number)value).longValue();
}
@Override
public short fetchShortField(int fieldNumber)
{
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String dflt = MongoDBUtils.getDefaultValueForMember(mmd);
if (dflt != null)
{
return Short.valueOf(dflt);
}
return 0;
}
Object value = dbObject.get(fieldName);
return ((Number)value).shortValue();
}
@Override
public String fetchStringField(int fieldNumber)
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
if (mmd.getValueStrategy() == ValueGenerationStrategy.IDENTITY)
{
// Return the "_id" value since not using this field as such
Object id = dbObject.get("_id");
return id.toString();
}
String fieldName = getColumnMapping(fieldNumber).getColumn(0).getName();
if (dbObject.containsField(fieldName))
{
return (String)(dbObject.get(fieldName));
}
return null;
}
@Override
public Object fetchObjectField(int fieldNumber)
{
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
if (mmd.getPersistenceModifier() != FieldPersistenceModifier.PERSISTENT)
{
return op != null ? op.provideField(fieldNumber) : null;
}
StoreManager storeMgr = ec.getStoreManager();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RelationType relationType = mmd.getRelationType(clr);
if (relationType != RelationType.NONE && MetaDataUtils.getInstance().isMemberEmbedded(ec.getMetaDataManager(), clr, mmd, relationType, ownerMmd))
{
// Embedded field
if (RelationType.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");
}
if (MongoDBUtils.isMemberNested(mmd))
{
// Nested embedding, as nested document
if (ownerMmd != null)
{
if (RelationType.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[] ownerOps = ec.getOwnersForEmbeddedObjectProvider(op);
return (ownerOps != null && ownerOps.length > 0 ? ownerOps[0].getObject() : null);
}
}
else
{
// mapped-by not set but could have owner-field
if (ownerMmd.hasCollection())
{
if (ownerMmd.getElementMetaData().getEmbeddedMetaData() != null &&
ownerMmd.getElementMetaData().getEmbeddedMetaData().getOwnerMember() != null &&
ownerMmd.getElementMetaData().getEmbeddedMetaData().getOwnerMember().equals(mmd.getName()))
{
// This is the owner-field linking back to the owning object so return the owner
ObjectProvider[] ownerOps = ec.getOwnersForEmbeddedObjectProvider(op);
return (ownerOps != null && ownerOps.length > 0 ? ownerOps[0].getObject() : null);
}
}
else if (ownerMmd.getEmbeddedMetaData() != null &&
ownerMmd.getEmbeddedMetaData().getOwnerMember() != null &&
ownerMmd.getEmbeddedMetaData().getOwnerMember().equals(mmd.getName()))
{
// This is the owner-field linking back to the owning object so return the owner
ObjectProvider[] ownerOps = ec.getOwnersForEmbeddedObjectProvider(op);
return (ownerOps != null && ownerOps.length > 0 ? ownerOps[0].getObject() : null);
}
}
}
MemberColumnMapping mapping = getColumnMapping(fieldNumber);
String fieldName = mapping.getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
return null;
}
DBObject embeddedValue = (DBObject)dbObject.get(fieldName);
if (embcmd.hasDiscriminatorStrategy())
{
// Set embcmd based on the discriminator value of this element
String discPropName = null;
if (mmd.getEmbeddedMetaData() != null && mmd.getEmbeddedMetaData().getDiscriminatorMetaData() != null)
{
discPropName = mmd.getEmbeddedMetaData().getDiscriminatorMetaData().getColumnName();
}
else
{
discPropName = storeMgr.getNamingFactory().getColumnName(embcmd, ColumnType.DISCRIMINATOR_COLUMN); // TODO Use Table
}
String discVal = (String)embeddedValue.get(discPropName);
String elemClassName = ec.getMetaDataManager().getClassNameFromDiscriminatorValue(discVal, embcmd.getDiscriminatorMetaData());
if (!elemClassName.equals(embcmd.getFullClassName()))
{
embcmd = ec.getMetaDataManager().getMetaDataForClass(elemClassName, clr);
}
}
List embMmds = new ArrayList<>();
embMmds.add(mmd);
ObjectProvider embOP = ec.getNucleusContext().getObjectProviderFactory().newForEmbedded(ec, embcmd, op, fieldNumber);
FetchFieldManager ffm = new FetchEmbeddedFieldManager(embOP, embeddedValue, embMmds, table);
embOP.replaceFields(embcmd.getAllMemberPositions(), ffm);
return embOP.getObject();
}
// Flat embedding as fields of the owning document
if (embcmd.hasDiscriminatorStrategy())
{
// Set embcmd based on the discriminator value of this element
String discPropName = null;
if (mmd.getEmbeddedMetaData() != null && mmd.getEmbeddedMetaData().getDiscriminatorMetaData() != null)
{
discPropName = mmd.getEmbeddedMetaData().getDiscriminatorMetaData().getColumnName();
}
else
{
discPropName = storeMgr.getNamingFactory().getColumnName(embcmd, ColumnType.DISCRIMINATOR_COLUMN); // TODO Use Table
}
String discVal = (String)dbObject.get(discPropName);
String elemClassName = ec.getMetaDataManager().getClassNameFromDiscriminatorValue(discVal, embcmd.getDiscriminatorMetaData());
if (!elemClassName.equals(embcmd.getFullClassName()))
{
embcmd = ec.getMetaDataManager().getMetaDataForClass(elemClassName, clr);
}
}
// 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 = new ArrayList<>();
embMmds.add(mmd);
ObjectProvider embOP = ec.getNucleusContext().getObjectProviderFactory().newForEmbedded(ec, embcmd, op, fieldNumber);
FieldManager ffm = new FetchEmbeddedFieldManager(embOP, dbObject, embMmds, table);
embOP.replaceFields(embcmd.getAllMemberPositions(), ffm);
return embOP.getObject();
}
else if (RelationType.isRelationMultiValued(relationType))
{
if (mmd.hasCollection())
{
// Embedded Collection, stored nested
MemberColumnMapping mapping = getColumnMapping(fieldNumber);
String fieldName = mapping.getColumn(0).getName();
if (!dbObject.containsField(fieldName))
{
return null;
}
Object value = dbObject.get(fieldName);
Collection