/**********************************************************************
Copyright (c) 2011 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.fieldmanager;
import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.Relation;
import org.datanucleus.store.ExecutionContext;
import org.datanucleus.store.ObjectProvider;
import org.datanucleus.store.fieldmanager.FieldManager;
import org.datanucleus.store.mongodb.MongoDBUtils;
import com.mongodb.DBObject;
/**
* FieldManager for the persistence of a related embedded object (1-1/N-1 relation).
* This handles flat embedding of related embedded objects, where the field of the embedded object become
* a field in the owner document.
*/
public class StoreEmbeddedFieldManager extends StoreFieldManager
{
private final AbstractMemberMetaData ownerMmd;
public StoreEmbeddedFieldManager(ObjectProvider sm, DBObject dbObject, AbstractMemberMetaData ownerMmd)
{
super(sm, dbObject, null);
this.ownerMmd = ownerMmd;
}
protected String getFieldName(int fieldNumber)
{
return MongoDBUtils.getFieldName(ownerMmd, fieldNumber);
}
@Override
public void storeObjectField(int fieldNumber, Object value)
{
AbstractMemberMetaData embMmd = ownerMmd.getEmbeddedMetaData().getMemberMetaData()[fieldNumber];
ExecutionContext ec = sm.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
int relationType = embMmd.getRelationType(clr);
if (embMmd.isEmbedded() && Relation.isRelationSingleValued(relationType))
{
// Embedded PC object - This performs "flat embedding" as fields in the same document
AbstractClassMetaData embcmd = ec.getMetaDataManager().getMetaDataForClass(embMmd.getType(), clr);
if (embcmd == null)
{
throw new NucleusUserException("Field " + embMmd.getFullFieldName() +
" specified as embedded but metadata not found for the class of type " + embMmd.getTypeName());
}
if (value == null)
{
// TODO Delete any fields for the embedded object
return;
}
if (relationType == Relation.ONE_TO_ONE_BI || relationType == Relation.MANY_TO_ONE_BI)
{
if ((ownerMmd.getMappedBy() != null && embMmd.getName().equals(ownerMmd.getMappedBy())) ||
(embMmd.getMappedBy() != null && ownerMmd.getName().equals(embMmd.getMappedBy())))
{
// Other side of owner bidirectional, so omit
return;
}
}
// Process all fields of the embedded object
ObjectProvider embSM = ec.findObjectProviderForEmbedded(value, sm, embMmd);
FieldManager ffm = new StoreEmbeddedFieldManager(embSM, dbObject, embMmd);
embSM.provideFields(embcmd.getAllMemberPositions(), ffm);
return;
}
String fieldName = MongoDBUtils.getFieldName(ownerMmd, fieldNumber);
if (value == null)
{
if (dbObject.containsField(fieldName))
{
dbObject.removeField(fieldName);
}
return;
}
if (embMmd.isSerialized())
{
processSerialisedField(fieldName, value, dbObject);
}
else if (Relation.isRelationSingleValued(relationType))
{
// PC object
processSingleRelationField(value, ec, fieldName);
}
else if (Relation.isRelationMultiValued(relationType))
{
// Collection/Map/Array
processContainerRelationField(embMmd, value, ec, fieldName);
}
else
{
processContainerNonRelationField(fieldName, ec, value, dbObject);
}
}
}