Package org.eclipselabs.mongoemf.builders

Source Code of org.eclipselabs.mongoemf.builders.DBObjectBuilderImpl

/*******************************************************************************
* Copyright (c) 2012 Bryan Hunt & Ed Merks.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Bryan Hunt & Ed Merks - initial API and implementation
*******************************************************************************/

package org.eclipselabs.mongoemf.builders;

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

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipselabs.mongoemf.ConverterService;
import org.eclipselabs.mongoemf.DBObjectBuilder;
import org.eclipselabs.mongoemf.Keywords;
import org.eclipselabs.mongoemf.MongoUtils;

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

/**
* This class builds a DBObject from an EMFObject. This builder is designed to be extensible,
* but you must be aware of the assumptions made by each of the functions in the builder.
*
* This class is thread safe.
*
* @author bhunt
*/
public class DBObjectBuilderImpl implements DBObjectBuilder
{
  /**
   * @param converterService the service to use when converting attribute values
   * @param uriHandler the handler for creating proxy URIs
   * @param serializeDefaultAttributeValues true causes default attribute values to be written to the DBObject;
   *          false causes default attribute values to be skipped
   */
  public DBObjectBuilderImpl(ConverterService converterService, XMLResource.URIHandler uriHandler, boolean serializeDefaultAttributeValues)
  {
    this.converterService = converterService;
    this.uriHandler = uriHandler;
    this.serializeDefaultAttributeValues = serializeDefaultAttributeValues;
  }

  /**
   * Build a DBObject from the supplied EMF object.
   *
   * @param eObject the EMF object to serialize
   * @return the newly created DBObject
   */
  @Override
  public DBObject buildDBObject(EObject eObject)
  {
    // Build a MongoDB object from the EMF object.

    BasicDBObject dbObject = new BasicDBObject();
    EClass eClass = eObject.eClass();

    // We have to add the URI of the class to the object so that we can
    // reconstruct the EMF object when we read it back out of MongoDB.

    dbObject.put(Keywords.ECLASS_KEY, EcoreUtil.getURI(eClass).toString());

    // Save the XML extrinsic id if necessary

    buildExtrensicID(eObject, dbObject);

    // All attributes are mapped as key / value pairs with the key being the attribute name.

    for (EAttribute attribute : eClass.getEAllAttributes())
    {
      if (!attribute.isTransient() && (eObject.eIsSet(attribute) || (!attribute.isUnsettable() && serializeDefaultAttributeValues)))
        buildAttribute(eObject, dbObject, attribute);
    }

    // All references are mapped as key / value pairs with the key being the reference name.

    for (EReference reference : eClass.getEAllReferences())
    {
      if (!reference.isTransient() && eObject.eIsSet(reference))
        buildReference(eObject, dbObject, reference);
    }

    return dbObject;
  }

  /**
   * Serializes the attribute from the EMF object into the DBObject
   * Feature maps are delegated to buildFeatureMap() and non-native arrays to
   * buildAttributeArray(). The converter service is used for value conversion.
   * Attribute values are mapped in the DBObject using the attribute
   * name as the key.
   *
   * @param eObject the EMF object to serialize
   * @param dbObject the MongoDB object being built
   * @param attribute the attribute to serialize from the EMF object
   */
  protected void buildAttribute(EObject eObject, DBObject dbObject, EAttribute attribute)
  {
    Object value = eObject.eGet(attribute);

    if (FeatureMapUtil.isFeatureMap(attribute))
      buildFeatureMap(dbObject, attribute, value);
    else if (attribute.isMany())
      buildAttributeArray(dbObject, attribute, value);
    else
      buildAttributeValue(dbObject, attribute, value);
  }

  /**
   * Serializes an attribute as a java.util.ArrayList. Each value is
   * converted using the converter service.
   *
   * @param dbObject the MongoDB object being built
   * @param attribute the attribute to serialize from the EMF object
   * @param values the attribute values to serialize
   */
  protected void buildAttributeArray(DBObject dbObject, EAttribute attribute, Object values)
  {
    EDataType eDataType = attribute.getEAttributeType();

    if (!MongoUtils.isNativeType(eDataType))
    {
      EList<?> eValues = (EList<?>) values;
      ArrayList<Object> convertedValues = new ArrayList<Object>(eValues.size());

      for (Object rawValue : eValues)
        convertedValues.add(convertEMFValueToMongoDBValue(attribute.getEAttributeType(), rawValue));

      dbObject.put(attribute.getName(), convertedValues);
    }
    else
      dbObject.put(attribute.getName(), values);
  }

  /**
   * Converts the attribute value if needed
   *
   * @param dbObject the MongoDB object being built
   * @param attribute the attribute to serialize from the EMF object
   * @param value the value of the attribute from the EMF object
   */
  protected void buildAttributeValue(DBObject dbObject, EAttribute attribute, Object value)
  {
    EDataType eDataType = attribute.getEAttributeType();

    if (!MongoUtils.isNativeType(eDataType))
      dbObject.put(attribute.getName(), convertEMFValueToMongoDBValue(eDataType, value));
    else
      dbObject.put(attribute.getName(), value);
  }

  /**
   * Sets the extrensic ID if it exists and the resource is of type XMLResource. The
   * extrensic ID is mapped to the key EXTRINSIC_ID_KEY.
   *
   * @param eObject the EMF object to serialize
   * @param dbObject the MongoDB object being built
   */
  protected void buildExtrensicID(EObject eObject, DBObject dbObject)
  {
    Resource resource = eObject.eResource();

    if (resource instanceof XMLResource)
    {
      String id = ((XMLResource) resource).getID(eObject);

      if (id != null)
        dbObject.put(Keywords.EXTRINSIC_ID_KEY, id);
    }
  }

  /**
   * Serializes a feature map from the attribute value. Feature maps
   * of references are delegated to buildReferencedObject to build
   * the referenced object.
   *
   * @param dbObject the MongoDB object being built
   * @param attribute the emf attribute being serialized
   * @param value the feature map
   */
  protected void buildFeatureMap(DBObject dbObject, EAttribute attribute, Object value)
  {
    FeatureMap.Internal featureMap = (FeatureMap.Internal) value;
    Iterator<FeatureMap.Entry> iterator = featureMap.basicIterator();
    ArrayList<DBObject> dbFeatureMap = new ArrayList<DBObject>();

    while (iterator.hasNext())
    {
      DBObject dbEntry = new BasicDBObject();
      FeatureMap.Entry entry = iterator.next();
      EStructuralFeature feature = entry.getEStructuralFeature();
      dbEntry.put("key", EcoreUtil.getURI(feature).toString());

      if (feature instanceof EAttribute)
      {
        EDataType eDataType = ((EAttribute) feature).getEAttributeType();

        if (!MongoUtils.isNativeType(eDataType))
          dbEntry.put("value", convertEMFValueToMongoDBValue(eDataType, entry.getValue()));
        else
          dbEntry.put("value", entry.getValue());
      }
      else
        dbEntry.put("value", buildReferencedObject((EReference) feature, (EObject) entry.getValue()));

      dbFeatureMap.add(dbEntry);
    }

    dbObject.put(attribute.getName(), dbFeatureMap);
  }

  /**
   * Serializes a reference value from the EMF object. References with cardinality greater
   * than one are stored as a java.util.ArrayList. Reference values are mapped in the
   * DBObject using the reference name as the key. Building of the referenced object is
   * delegated to buildReferencedObject().
   *
   * @param eObject the EMF object to serialize
   * @param dbObject the MongoDB object being built
   * @param reference
   */
  protected void buildReference(EObject eObject, DBObject dbObject, EReference reference)
  {
    Object value = eObject.eGet(reference, false);

    if (reference.isMany())
    {
      // One to many reference

      @SuppressWarnings("unchecked")
      List<EObject> targetObjects = ((InternalEList<EObject>) value).basicList();
      ArrayList<Object> dbReferences = new ArrayList<Object>(targetObjects.size());

      for (EObject targetObject : targetObjects)
        dbReferences.add(buildReferencedObject(reference, targetObject));

      value = dbReferences;
    }
    else if (value != null)
    {
      // One to one reference

      EObject targetObject = (EObject) value;
      value = buildReferencedObject(reference, targetObject);
    }

    dbObject.put(reference.getName(), value);
  }

  /**
   * Serializes a reference as an embedded object or a proxy as appropriate
   *
   * @param eReference the reference to serialize
   * @param targetObject to referenced object
   * @return the serialized object / proxy
   */
  protected DBObject buildReferencedObject(EReference eReference, EObject targetObject)
  {
    InternalEObject internalEObject = (InternalEObject) targetObject;
    URI eProxyURI = internalEObject.eProxyURI();

    if (eProxyURI != null)
    {
      BasicDBObject dbObject = new BasicDBObject(2);
      dbObject.put(Keywords.PROXY_KEY, uriHandler.deresolve(eProxyURI).toString());
      dbObject.put(Keywords.ECLASS_KEY, EcoreUtil.getURI(targetObject.eClass()).toString());
      return dbObject;
    }
    else if (!eReference.isContainment() || (eReference.isResolveProxies() && internalEObject.eDirectResource() != null))
    {
      // Cross-document containment, or non-containment reference - build a proxy

      BasicDBObject dbObject = new BasicDBObject(2);
      dbObject.put(Keywords.PROXY_KEY, uriHandler.deresolve(EcoreUtil.getURI(targetObject)).toString());
      dbObject.put(Keywords.ECLASS_KEY, EcoreUtil.getURI(targetObject.eClass()).toString());
      return dbObject;
    }
    else
    {
      // Non cross-document containment reference - build a MongoDB embedded object

      return buildDBObject(targetObject);
    }
  }

  /**
   * Converts the EMF value into a MongoDB value using the converter service
   *
   * @param eDataType the value type
   * @param emfValue the value
   * @return the converted value
   */
  protected Object convertEMFValueToMongoDBValue(EDataType eDataType, Object emfValue)
  {
    return converterService.getConverter(eDataType).convertEMFValueToMongoDBValue(eDataType, emfValue);
  }

  private ConverterService converterService;
  private XMLResource.URIHandler uriHandler;
  private boolean serializeDefaultAttributeValues;
}
TOP

Related Classes of org.eclipselabs.mongoemf.builders.DBObjectBuilderImpl

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.