Package com.googlecode.objectify.impl

Source Code of com.googlecode.objectify.impl.ObjectifyImpl

package com.googlecode.objectify.impl;

import com.google.appengine.api.datastore.AsyncDatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceConfig;
import com.google.appengine.api.datastore.ReadPolicy;
import com.google.appengine.api.datastore.ReadPolicy.Consistency;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.TxnType;
import com.googlecode.objectify.Work;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.cmd.Deferred;
import com.googlecode.objectify.cmd.Deleter;
import com.googlecode.objectify.cmd.Loader;
import com.googlecode.objectify.cmd.Saver;
import com.googlecode.objectify.impl.translate.CreateContext;
import com.googlecode.objectify.impl.translate.SaveContext;
import com.googlecode.objectify.impl.translate.Translator;
import com.googlecode.objectify.impl.translate.TypeKey;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

/**
* <p>Implementation of the Objectify interface. This is also suitable for subclassing; you
* can return your own subclass by overriding ObjectifyFactory.begin().</p>
*
* <p>Note we *always* use the AsyncDatastoreService
* methods that use transactions to avoid the confusion of implicit transactions.</p>
*
* @author Jeff Schnitzer <jeff@infohazard.org>
*/
public class ObjectifyImpl<O extends Objectify> implements Objectify, Cloneable
{
  /** The factory that produced us */
  protected ObjectifyFactory factory;

  /** Our options */
  protected boolean cache = true;
  protected Consistency consistency = Consistency.STRONG;
  protected Double deadline;

  /** */
  protected Transactor<O> transactor = new TransactorNo<>(this);

  /**
   */
  public ObjectifyImpl(ObjectifyFactory fact) {
    this.factory = fact;
  }

  /** Copy constructor */
  public ObjectifyImpl(ObjectifyImpl<O> other) {
    this.factory = other.factory;
    this.cache = other.cache;
    this.consistency = other.consistency;
    this.deadline = other.deadline;
    this.transactor = other.transactor;
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#getFactory()
   */
  public ObjectifyFactory factory() {
    return this.factory;
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#find()
   */
  @Override
  public Loader load() {
    return new LoaderImpl<>(this);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#put()
   */
  @Override
  public Saver save() {
    return new SaverImpl(this);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#delete()
   */
  @Override
  public Deleter delete() {
    return new DeleterImpl(this);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#defer()
   */
  @Override
  public Deferred defer() {
    return new DeferredImpl(this);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#consistency(com.google.appengine.api.datastore.ReadPolicy.Consistency)
   */
  @Override
  @SuppressWarnings("unchecked")
  public O consistency(Consistency value) {
    if (value == null)
      throw new IllegalArgumentException("Consistency cannot be null");

    ObjectifyImpl<O> clone = this.clone();
    clone.consistency = value;
    return (O)clone;
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#deadline(java.lang.Double)
   */
  @Override
  @SuppressWarnings("unchecked")
  public O deadline(Double value) {
    ObjectifyImpl<O> clone = this.clone();
    clone.deadline = value;
    return (O)clone;
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#cache(boolean)
   */
  @Override
  @SuppressWarnings("unchecked")
  public O cache(boolean value) {
    ObjectifyImpl<O> clone = this.clone();
    clone.cache = value;
    return (O)clone;
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#transactionless()
   */
  @Override
  @SuppressWarnings("unchecked")
  public O transactionless() {
    return (O)transactor.transactionless(this);
  }

  /* (non-Javadoc)
   * @see java.lang.Object#clone()
   */
  @SuppressWarnings("unchecked")
  protected ObjectifyImpl<O> clone() {
    try {
      return (ObjectifyImpl<O>)super.clone();
    } catch (CloneNotSupportedException e) {
      throw new RuntimeException(e); // impossible
    }
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#getTxn()
   */
  public TransactionImpl getTransaction() {
    return transactor.getTransaction();
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#execute(com.googlecode.objectify.TxnType, com.googlecode.objectify.Work)
   */
  @Override
  public <R> R execute(TxnType txnType, Work<R> work) {
    return transactor.execute(this, txnType, work);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#transact(com.googlecode.objectify.Work)
   */
  @Override
  public <R> R transact(Work<R> work) {
    return transactor.transact(this, work);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#transact(com.googlecode.objectify.Work)
   */
  @Override
  public <R> R transactNew(Work<R> work) {
    return this.transactNew(Integer.MAX_VALUE, work);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#transactNew(com.googlecode.objectify.Work)
   */
  @Override
  public <R> R transactNew(int limitTries, Work<R> work) {
    return transactor.transactNew(this, limitTries, work);
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#clear()
   */
  @Override
  public void clear() {
    transactor.getSession().clear();
  }

  /**
   * Make a datastore service config that corresponds to our options.
   */
  protected DatastoreServiceConfig createDatastoreServiceConfig() {
    DatastoreServiceConfig cfg = DatastoreServiceConfig.Builder.withReadPolicy(new ReadPolicy(consistency));

    if (deadline != null)
      cfg.deadline(deadline);

    return cfg;
  }

  /**
   * Make a datastore service config that corresponds to our options.
   */
  protected AsyncDatastoreService createAsyncDatastoreService() {
    return factory.createAsyncDatastoreService(this.createDatastoreServiceConfig(), cache);
  }

  /**
   * Use this once for one operation and then throw it away
   * @return a fresh engine that handles fundamental datastore operations for saving and deleting
   */
  protected WriteEngine createWriteEngine() {
    return new WriteEngine(this, createAsyncDatastoreService(), transactor.getSession());
  }

  /**
   * <p>Translates the value of a filter clause into something the datastore understands.  Key<?> goes to native Key,
   * entities go to native Key, java.sql.Date goes to java.util.Date, etc.  It uses the same translation system
   * that is used for standard entity fields, but does no checking to see if the value is appropriate for the field.</p>
   *
   * <p>Unrecognized types are returned as-is.</p>
   *
   * <p>A future version of this method might check for type validity.</p>
   *
   * @return whatever can be put into a filter clause.
   */
  protected Object makeFilterable(Object value) {
    if (value == null)
      return null;

    // This is really quite a dilemma.  We need to convert that value into something we can filter by, but we don't
    // really have a lot of information about it.  We could use type information from the matched field, but there's
    // no guarantee that there is a field to check - it could be a typeless query or a query on an old property value.
    // The only real solution is to create a (non root!) translator on the fly.  Even that is not straightforward,
    // because erasure wipes out any component type information in a collection. We don't know what the collection
    // contains.
    //
    // The answer:  Check for collections explicitly.  Create a separate translator for every item in the collection;
    // after all, it could be a heterogeneous list.  This is not especially efficient but GAE only allows a handful of
    // items in a IN operation and at any rate processing will still be negligible compared to the cost of a query.

    // If this is an array, make life easier by turning it into a list first.  Because of primitive
    // mismatching we can't trust Arrays.asList().
    if (value.getClass().isArray()) {
      int len = Array.getLength(value);
      List<Object> asList = new ArrayList<>(len);
      for (int i=0; i<len; i++)
        asList.add(Array.get(value, i));

      value = asList;
    }

    if (value instanceof Iterable) {
      List<Object> result = new ArrayList<>(50)// hard limit is 30, but wth
      for (Object obj: (Iterable<?>)value)
        result.add(makeFilterable(obj));

      return result;
    } else {
      // Special case entity pojos that become keys
      if (value.getClass().isAnnotationPresent(Entity.class)) {
        return factory().keys().getMetadataSafe(value).getRawKey(value);
      } else {
        // Run it through a translator
        Translator<Object, Object> translator = factory().getTranslators().get(new TypeKey<>(value.getClass()), new CreateContext(factory()), Path.root());
        return translator.save(value, false, new SaveContext(), Path.root());
      }
    }
  }

  /** */
  protected Session getSession() {
    return this.transactor.getSession();
  }

  /** @return true if cache is enabled */
  public boolean getCache() {
    return cache;
  }

  /* (non-Javadoc)
   * @see com.googlecode.objectify.Objectify#isLoaded(com.googlecode.objectify.Key)
   */
  @Override
  public boolean isLoaded(Key<?> key) {
    return transactor.getSession().contains(key);
  }

  @Override
  public void flush() {
    transactor.getDeferrer().flush();
  }

  /**
   * Defer the saving of one entity. Updates the session cache with this new value.
   */
  void deferSave(Object entity) {
    transactor.getDeferrer().deferSave(factory().keys().keyOf(entity), entity);
  }

  /**
   * Defer the deletion of one entity. Updates the session cache with this new value.
   */
  void deferDelete(Key<?> key) {
    transactor.getDeferrer().deferDelete(key);
  }

}
TOP

Related Classes of com.googlecode.objectify.impl.ObjectifyImpl

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.