com.googlecode.objectify.Objectify Maven / Gradle / Ivy
Show all versions of objectify Show documentation
package com.googlecode.objectify;
import com.google.appengine.api.datastore.ReadPolicy.Consistency;
import com.google.appengine.api.datastore.Transaction;
import com.googlecode.objectify.cmd.Deferred;
import com.googlecode.objectify.cmd.Deleter;
import com.googlecode.objectify.cmd.Loader;
import com.googlecode.objectify.cmd.Saver;
/**
* This is the main "business end" of Objectify. It lets you load, save, and delete your typed POJO entities.
*
* {@code Objectify} instances are obtained by calling the static method {@code ObjectifyService.ofy()}. This method
* will always provide the correct {@code Objectify} instance for a given transactional context. You can run
* transactions by calling {@code Objectify.transact()} or {@code Objectify.transactNew()}; calling {@code ObjectifyService.ofy()}
* within {@code Work.run()} will produce the correct {@code Objectify} instance associated with the correct transaction.
*
* Objectify instances are immutable but they are NOT thread-safe. The instance contains
* a session cache of entities that have been loaded from the instance. You should never access an Objectify
* from more than one thread simultaneously.
*
* @author Jeff Schnitzer
*/
public interface Objectify
{
/**
* Start a load command chain. This is where you begin for any request that fetches data from
* the datastore: gets and queries.
*
* A quick example:
* {@code Map, Thing> things = ofy().load().type(Thing.class).parent(par).ids(123L, 456L);}
*
* All command objects are immutable; this method returns a new object rather than modifying the
* current command object.
*
* @return the next step in the immutable command chain.
*/
Loader load();
/**
* Start a save command chain. Allows you to save (or re-save) entity objects. Note that all command
* chain objects are immutable.
*
* Saves do NOT cascade; if you wish to save an object graph, you must save each individual entity.
*
* A quick example:
* {@code ofy().save().entities(e1, e2, e3).now();}
*
* All command objects are immutable; this method returns a new object rather than modifying the
* current command object.
*
* @return the next step in the immutable command chain.
*/
Saver save();
/**
* Start a delete command chain. Lets you delete entities or keys.
*
* Deletes do NOT cascade; if you wish to delete an object graph, you must delete each individual entity.
*
* A quick example:
* {@code ofy().delete().entities(e1, e2, e3).now();}
*
* All command objects are immutable; this method returns a new object rather than modifying the
* current command object.
*
* @return the next step in the immutable command chain.
*/
Deleter delete();
/**
* Start a deferred command chain, which lets you make multiple save or delete calls on a single
* entity without incurring multiple datastore operations. Deferred operations are executed at the
* end of a unit-of-work (transaction, or http request if not in a transaction).
*
* Deferred operations are reflected in the session cache immediately. However query operations
* may not reflect these changes. For example, newly indexed entities may not show up, even with
* an otherwise strongly consistent ancestor query. This should not be surprising since the actual
* save operation has not occurred yet.
*
* In the case of deferred save() and delete() operations on the same entity, the last one wins.
*
* @return the next step in the immutable command chain.
*/
Deferred defer();
/**
* Obtain the ObjectifyFactory from which this Objectify instance was created.
*
* @return the ObjectifyFactory associated with this Objectify instance.
*/
ObjectifyFactory factory();
/**
* Provides a new Objectify instance with the specified Consistency. Generally speaking, STRONG consistency
* provides more consistent results more slowly; EVENTUAL consistency produces results quickly but they
* might be out of date. See the
* Appengine Docs
* for more explanation.
*
* The new instance will inherit all other characteristics (transaction, cache policy, session cache contents, etc)
* from this instance.
*
* All command objects are immutable; this method returns a new object rather than modifying the
* current command object.
*
* @param policy the consistency policy to use. STRONG load()s are more consistent but EVENTUAL load()s
* are faster.
* @return a new immutable Objectify instance with the consistency policy replaced
*/
Objectify consistency(Consistency policy);
/**
* Provides a new Objectify instance with a limit, in seconds, for datastore calls. If datastore calls take longer
* than this amount, a timeout exception will be thrown.
*
* The new instance will inherit all other characteristics (transaction, cache policy, session cache contents, etc)
* from this instance.
*
* All command objects are immutable; this method returns a new object rather than modifying the
* current command object.
*
* @param value - limit in seconds, or null to indicate no deadline (other than the standard whole request deadline of 30s/10m).
* @return a new immutable Objectify instance with the specified deadline
*/
Objectify deadline(Double value);
/**
* Provides a new Objectify instance which uses (or doesn't use) a 2nd-level memcache.
* If true, Objectify will obey the @Cache annotation on entity classes,
* saving entity data to the GAE memcache service. Fetches from the datastore
* for @Cache entities will look in the memcache service first. This cache
* is shared across all versions of your application across the entire GAE
* cluster.
*
* Objectify instances are cache(true) by default.
*
* All command objects are immutable; this method returns a new object rather than modifying the
* current command object.
*
* @return a new immutable Objectify instance which will (or won't) use the global cache
*/
Objectify cache(boolean value);
/**
* Get the underlying transaction object associated with this Objectify instance. You typically
* do not need to use this; use transact() instead.
*
* Note that this is *not* the same as {@code DatastoreService.getCurrentTransaction()},
* which uses the Low-Level API's implicit transaction management. Every transactional {@code Objectify}
* instance is associated with a specific {@code Transaction} object.
*
* @return the low-level transaction associated with this Objectify instance,
* or null if no transaction is associated with this instance.
*/
Transaction getTransaction();
/**
* If you are in a transaction, this provides you an objectify instance which is outside of the
* current transaction and works with the session prior to the transaction start. Inherits any
* settings (consistency, deadline, etc) from the present Objectify instance.
*
* If you are not in a transaction, this simply returns "this".
*
* This allows code to quickly "escape" a transactional context for the purpose of loading
* manipulating data without creating or affecting XG transactions.
*
* All command objects are immutable; this method returns a new object instead of modifying the
* current command object.
*
* @return an immutable Objectify instance outside of a transaction, with the session as it was before txn start.
*/
Objectify transactionless();
/**
* Executes work in a transaction. If there is already a transaction context, that context will be inherited.
* If there is not already a transaction context, a new transaction will be started.
*
* Within {@code Work.run()}, obtain the correct transactional {@code Objectify} instance by calling
* {@code ObjectifyService.ofy()}
*
* ConcurrentModificationExceptions will cause the transaction to repeat as many times as necessary to
* finish the job. Work MUST idempotent.
*
* @param work defines the work to be done in a transaction. If this method started a new transaction, it
* will be committed when work is complete. If transactional context was inherited, no commit is issued
* until the full transaction completes normally.
* @return the result of the work
*/
R transact(Work work);
/**
* Executes work in a new transaction. Note that this is equivalent to {@code transactNew(Integer.MAX_VALUE, work);}
*
* ConcurrentModificationExceptions will cause the transaction to repeat as many times as necessary to
* finish the job. Work MUST idempotent.
*
* Within {@code Work.run()}, obtain the new transactional {@code Objectify} instance by calling {@code ObjectifyService.ofy()}
*
* @param work defines the work to be done in a transaction. After the method exits, the transaction will commit.
* @return the result of the work
*/
R transactNew(Work work);
/**
* Executes the work in a new transaction, repeating up to limitTries times when a ConcurrentModificationException
* is thrown. This requires your Work to be idempotent; otherwise limit tries to 1.
*
*
Within {@code Work.run()}, obtain the new transactional {@code Objectify} instance by calling {@code ObjectifyService.ofy()}
*
* @param work defines the work to be done in a transaction. After the method exits, the transaction will commit.
* @return the result of the work
*/
R transactNew(int limitTries, Work work);
/**
* Executes the work with the transactional behavior defined by the parameter txnType. This is very similar
* to EJB semantics. The work can inherit a transaction, create a new transaction, prevent transactions, etc.
*
* This method principally exists to facilitate implementation of AOP interceptors that provide EJB-like behavior.
* Usually you will call {@code transact()} or {@code transactNew()} when writing code.
*
* Note that ConcurrentModificationExceptions will cause the transaction to repeat as many times as necessary to
* finish the job. Work MUST idempotent.
*
* Within {@code Work.run()}, obtain the correct {@code Objectify} instance by calling {@code ObjectifyService.ofy()}
*
* @param txnType defines what kind of transaction context the work should be executed in.
* @param work defines the work to be done; possibly in a transaction, possibly not as defined by txnType
* @return the result of the work
*/
R execute(TxnType txnType, Work work);
/**
* Synchronously flushes any deferred operations to the datastore. Objectify does this for you at the end
* of transactions and requests, but if you need data to be written immediately - say, you're about to perform
* a strongly-consistent ancestor query and you need to see the updated indexes immediately - you can call this
* method. If there are no deferred operations, this does nothing.
*/
void flush();
/**
* Clears the session; all subsequent requests (or Ref.get() calls) will go to the datastore/memcache
* to repopulate the session. This should rarely, if ever be necessary. Note that if you iterate query results
* you should only perform this action on chunk boundaries, otherwise performance will suffer. This is a "use
* only if you really know what you are doing" feature.
*/
void clear();
/**
* @return true if the key has been loaded into the session; false if loading the key would result in a datastore
* (or memcache) fetch.
*/
boolean isLoaded(Key key);
}