All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.archinnov.achilles.persistence.AsyncManager Maven / Gradle / Ivy

There is a newer version: 6.1.0
Show newest version
/*
 * Copyright (C) 2012-2014 DuyHai DOAN
 *
 *  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.
 */
package info.archinnov.achilles.persistence;

import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;
import info.archinnov.achilles.async.AchillesFuture;
import info.archinnov.achilles.internal.context.ConfigurationContext;
import info.archinnov.achilles.internal.context.DaoContext;
import info.archinnov.achilles.internal.context.PersistenceContextFactory;
import info.archinnov.achilles.internal.metadata.holder.EntityMeta;
import info.archinnov.achilles.internal.validation.Validator;
import info.archinnov.achilles.query.cql.AsyncNativeQuery;
import info.archinnov.achilles.query.slice.AsyncSliceQueryBuilder;
import info.archinnov.achilles.query.typed.AsyncTypedQuery;
import info.archinnov.achilles.type.IndexCondition;
import info.archinnov.achilles.options.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.datastax.driver.core.BatchStatement.Type.LOGGED;
import static com.datastax.driver.core.BatchStatement.Type.UNLOGGED;
import static info.archinnov.achilles.options.OptionsBuilder.noOptions;

/**
 * 

* Stateless object to manage asynchronous entity persistence. * This class is totally thread-safe and can be shared by many threads. * You should normally have only one instance of PersistenceMananger across the application * *
* An AsyncMananger is very cheap to create from an {@link PersistenceManagerFactory} *

* *

*

I Persist asynchronously transient entity

*

 *      // Insert
 *      AchillesFuture managedEntityFuture = asyncManager.insert(myEntity);
 *  
* *

II Update asynchronously for modifications

*

 *      User managedUser = asyncManager.find(User.class,1L).get();
 *      user.setFirstname("DuyHai");
 *
 *      AchillesFuture userFuture = asyncManager.update(user);
 *  
* *

III Removing asynchronously entities

*

 *      // Simple removed
 *      User managedUser = asyncManager.find(User.class,1L).get();
 *      AchillesFuture userFuture = asyncManager.remove(managedUser);
 *
 *      // Direct remove without read-before-write
 *      AchillesFuture emptyFuture = asyncManager.removeById(User.class,1L);
 *  
* *

IV Loading entities asynchronously

*

 *      // Read data from Cassandra
 *      AchillesFuture managedUserFuture = asyncManager.find(User.class,1L);
 *  
* *

V Direct update

* Please note that proxy creation always return immediately since we do not hit the database *

 *      // No data read from Cassandra
 *      User managedUserProxy = asyncManager.forUpdate(User.class,1L).get();
 *      managedUser.setAge(30);
 *
 *      // Direct update, no read from Cassandra has been done
 *      AchillesFuture userFuture = asyncManager.update(managedUser);
 *  
* *

VI Reloading state asynchronously for managed entities

*

 *      // Read data from Cassandra
 *      User managedUser = asyncManager.find(User.class,1L).get();
 *      ...
 *      // Perform some logic
 *
 *      // Reload data from Cassandra into the managed entity
 *      AchillesFuture userFuture = asyncManager.refresh(managedUser);
 *  
* *

VII Removing proxy from managed entities

*

 *      // Create managed entity
 *      User managedUser = asyncManager.find(User.class,1L);
 *      ...
 *      // Perform some logic
 *
 *      // Removing proxy before passing it to client via serialization
 *      User transientUser = asyncManager.removeProxy(managedUser);
 *  
* *

VIII Accessing native Session object

*

 *      Session session = asyncManager.getNativeSession();
 *      ...
 *
 *      // Issue simple CQL queries
 *      session.execute("UPDATE users SET age=:age WHERE id=:id",30,10);
 *  
* *

IX JSON serialization/deserialization

*

 *      // Serialize an object to JSON using the registered or default object mapper
 *      String json = asyncManager.serializeToJSON(myModel);
 *      ...
 *
 *      // Deserialize a JSON string into an object  the registered or default object mapper
 *      MyModel myModel = asyncManager.deserializeFromJSON(json);
 *  
* *

X Initializing all counter fields

*

 *      // Create managed entity
 *      AchillesFuture@lt;User> futureUser = asyncManager.find(User.class,1L);
 *      ...
 *      // Perform some logic
 *      ...
 *
 *      // Load all lazy counter fields
 *      asyncManager.initialize(futureUser.get());
 *  
*

* * * @see Persistence Manager operations */ public class AsyncManager extends CommonAsyncManager { private static final Logger log = LoggerFactory.getLogger(AsyncManager.class); protected AsyncManager(Map, EntityMeta> entityMetaMap, PersistenceContextFactory contextFactory, DaoContext daoContext, ConfigurationContext configContext) { super(entityMetaMap, contextFactory, daoContext, configContext); } /** * Find an entity, asynchronously. * * @param entityClass * Entity type * @param primaryKey * Primary key (Cassandra row key) of the entity to load * * @return AchillesFuture<T> future managed entity */ public AchillesFuture find(Class entityClass, Object primaryKey) { log.debug("Find entity class '{}' with primary key '{}'", entityClass, primaryKey); return super.asyncFind(entityClass, primaryKey, noOptions()); } /** * Find an entity with the given Consistency Level for read, asynchronously * * @param entityClass * Entity type * @param primaryKey * Primary key (Cassandra row key) of the entity to load * @param options * Options * * @return AchillesFuture<T> future managed entity */ public AchillesFuture find(final Class entityClass, final Object primaryKey, Options options) { log.debug("Find entity class '{}' with primary key '{}' and options '{}'", entityClass, primaryKey, options); return super.asyncFind(entityClass, primaryKey, options); } /** * Create a proxy for the entity update. An new empty entity will be created, * populated with the provided primary key and then proxified. This method * never returns null. Use this method to perform direct update without * read-before-write * *

     *      // No data read from Cassandra
     *      User managedUser = manager.forUpdate(User.class,1L);
     *      managedUser.setAge(33);
     *      manager.update(managedUser);
     *  
* * @param entityClass * Entity type * @param primaryKey * Primary key (Cassandra row key) of the entity to initialize * * @return T proxy */ public T forUpdate(Class entityClass, Object primaryKey) { log.debug("Get reference for entity class '{}' with primary key {}", entityClass, primaryKey); return super.getProxyForUpdateInternal(entityClass, primaryKey); } /** * Initialize all lazy fields of a set of 'managed' entities * *

     *      // Create a managed entity
     *      User userProxy = manager.find(User.class,1L);
     *      ...
     *      // Perform some logic
     *
     *      // Initialize all fields not yet loaded into the managed entity, including counter fields
     *      manager.initialize(userProxy);
     *  
* * Raise an IllegalStateException if an entity is not 'managed' * */ public T initialize(final T entity) { log.debug("Force lazy fields initialization for entity {}", proxifier.removeProxy(entity)); return super.initialize(entity); } /** * Initialize all counter fields of a list of 'managed' entities * *

     *      // Create managed entities
     *      User user1 = manager.find(User.class,1L);
     *      User user2 = manager.find(User.class,2L);
     *      ...
     *      // Perform some logic
     *      ...
     *
     *      // Initialize all counter fields not yet loaded into the managed entity
     *      manager.initialize(Sets.newHashSet(user1, user2));
     *  
* * Raise an IllegalStateException if an entity is not 'managed' * */ public Set initialize(final Set entities) { return super.initialize(entities); } /** * Initialize all counter fields of a list of 'managed' entities * *

     *      // Create managed entities
     *      User user1 = manager.find(User.class,1L);
     *      User user2 = manager.find(User.class,2L);
     *      ...
     *      // Perform some logic
     *      ...
     *
     *      // Initialize all counter fields not yet loaded into the managed entity
     *      manager.initialize(Arrays.asList(user1, user2));
     *  
* * Raise an IllegalStateException if an entity is not 'managed' * */ public List initialize(final List entities) { log.debug("Force lazy fields initialization for entity set {}", entities); return super.initialize(entities); } /** * Shorthand for manager.removeProxy(manager.initialize(T entity)) * */ public T initAndRemoveProxy(T entity) { return super.removeProxy(super.initialize(entity)); } /** * Shorthand for manager.removeProxy(manager.initialize(Set entities)) * */ public Set initAndRemoveProxy(Set entities) { return super.removeProxy(super.initialize(entities)); } /** * Shorthand for manager.removeProxy(manager.initialize(List entities)) * */ public List initAndRemoveProxy(List entities) { return super.removeProxy(super.initialize(entities)); } /** * Remove the proxy of a 'managed' entity and return the underlying "raw" * entity *
*
* If the argument is not a proxy object, return itself
* Else, return the target object behind the proxy * *

     *      // Create managed entity
     *      User managedUser = manager.find(User.class,1L);
     *      ...
     *      // Perform some logic
     *
     *      // Removing proxy before passing it to client via serialization
     *      User transientUser = manager.removeProxy(managedUser);
     *  
* * @param proxy * @return real object */ public T removeProxy(T proxy) { return super.removeProxy(proxy); } /** * Remove the proxy of a list of 'managed' entities and return the * underlying "raw" entities * * See {@link #removeProxy} * * @param proxies * list of proxified entity * @return real object list */ public List removeProxy(List proxies) { log.debug("Removing proxy for a list of entities {}", proxies); return super.removeProxy(proxies); } /** * Remove the proxy of a set of 'managed' entities return the underlying * "raw" entities * * See {@link #removeProxy} * * @param proxies * set of proxified entities * @return real object set */ public Set removeProxy(Set proxies) { log.debug("Removing proxy for a set of entities {}", proxies); return super.removeProxy(proxies); } /** * Create a builder to start an asynchronous slice query DSL. The provided entity class must be: * *
    *
  • a entity type managed by Achilles
  • *
  • a clustered entity, slicing is irrelevant for non-clustered entity
  • *
* * @see Slice query API * * @param entityClass type of the clustered entity * @param : type of the clustered entity * @return AsyncSliceQueryBuilder<T> */ public AsyncSliceQueryBuilder sliceQuery(Class entityClass) { log.debug("Execute slice query for entity class {}", entityClass); final EntityMeta meta = super.validateSliceQueryInternal(entityClass); return new AsyncSliceQueryBuilder<>(sliceQueryExecutor, entityClass, meta); } /** * Return a CQL native query DSL * *
*
* *

Native query without bound values

*

     *      RegularStatement nativeQuery = select("name",age_in_years").from("UserEntity").where(in("id",Arrays.asList(10,11))).limit(20);
     *      AchillesFuture<List<TypedMap>> actual = asyncManager.nativeQuery(nativeQuery).get();
     *  
* *
*
* *

Native query with bound values

*

     *      RegularStatement nativeQuery = select("name",age_in_years").from("UserEntity").where(in("id",bindMarker())).limit(bindMarker());
     *      AchillesFuture<List<TypedMap>> actual = asyncManager.nativeQuery(nativeQuery,Arrays.asList(10,11),20).get();
     *  
* * @see Native query API * * @param statement * native CQL regularStatement, including limit, ttl and consistency * options * * @param boundValues * values to be bind to the parameterized query, if any * * @return AsyncNativeQuery */ public AsyncNativeQuery nativeQuery(Statement statement, Object... boundValues) { log.debug("Execute native query {}", statement); Validator.validateNotNull(statement, "The statement for native query should not be null"); return new AsyncNativeQuery(daoContext, configContext, statement, noOptions(), boundValues); } /** * Return an asynchronous CQL native query * *
*
* *

Native query without bound values

*

     *      RegularStatement nativeQuery = select("name",age_in_years").from("UserEntity").where(in("id",Arrays.asList(10,11))).limit(20);
     *      AchillesFuture<List<TypedMap>> actual = asyncManager.nativeQuery(nativeQuery).get();
     *  
* *
*
* *

Native query with bound values

*

     *      RegularStatement nativeQuery = select("name",age_in_years").from("UserEntity").where(in("id",bindMarker())).limit(bindMarker());
     *      AchillesFuture<List<TypedMap>> actual = asyncManager.nativeQuery(nativeQuery,Arrays.asList(10,11),20).get();
     *  
* * @see Native query API * * @param statement * native CQL regularStatement, including limit, ttl and consistency * options * * @param options * options for the query. Only LWT Result listener passed as option is taken * into account. For timestamp, TTL and LWT conditions you must specify them * directly in the query string * * @param boundValues * values to be bind to the parameterized query, if any * * @return AsyncNativeQuery */ public AsyncNativeQuery nativeQuery(Statement statement, Options options, Object... boundValues) { log.debug("Execute native query {}", statement); Validator.validateNotNull(statement, "The statement for native query should not be null"); return new AsyncNativeQuery(daoContext, configContext, statement, options, boundValues); } /** * Return an asynchronous CQL typed query * * All found entities will be in managed state * *
*
* *

Typed query without bound values

*

     *      RegularStatement nativeQuery = select().from("MyEntity").where().limit(3);
     *      AchillesFuture<List<MyEntity>> actual = asyncManager.typedQuery(MyEntity.class, nativeQuery).get();
     *  
* *
*
* *

Typed query with bound values

*

     *      RegularStatement statement = select().from("MyEntity").limit(bindMarker());
     *      AchillesFuture<List<MyEntity>> actual = asyncManager.typedQuery(MyEntity.class, statement,3).get();
     *  
* * @see Typed query API * * @param entityClass * type of entity to be returned * * @param statement * native CQL regularStatement, including limit, ttl and consistency * options * * @param boundValues * values to be bind to the parameterized query, if any * * @return AsyncTypedQuery<T> */ public AsyncTypedQuery typedQuery(Class entityClass, Statement statement, Object... boundValues) { final EntityMeta meta = super.typedQueryInternal(entityClass, statement,boundValues); return new AsyncTypedQuery<>(entityClass, daoContext, configContext, statement, meta, contextFactory, boundValues); } /** * Return an asynchronous CQL indexed query * * All found entities will be in 'managed' state * * @param entityClass * type of entity to be returned * * @param indexCondition * index condition * * @return AsyncTypedQuery<T> */ public AsyncTypedQuery indexedQuery(Class entityClass, IndexCondition indexCondition) { log.debug("Execute indexed query for entity class {}", entityClass); final Statement statement = super.indexedQueryInternal(entityClass, indexCondition); final EntityMeta meta = super.typedQueryInternal(entityClass, statement, indexCondition.getColumnValue()); return new AsyncTypedQuery<>(entityClass, daoContext, configContext, statement, meta, contextFactory, new Object[]{indexCondition.getColumnValue()}); } /** * Serialize the entity in JSON using a registered Object Mapper or default Achilles Object Mapper * @param entity * @return serialized entity in JSON * @throws java.io.IOException */ public String serializeToJSON(Object entity) throws IOException { return super.serializeToJSON(entity); } /** * Deserialize the given JSON into entity using a registered Object Mapper or default Achilles Object Mapper * @param type * @param serialized * @param * @return deserialized entity from JSON * @throws java.io.IOException */ public T deserializeFromJSON(Class type, String serialized) throws IOException { return super.deserializeFromJSON(type, serialized); } /** * Return Session object from Java Driver * @return Session */ public Session getNativeSession() { return super.getNativeSession(); } /** * Create a new state-full asynchronous LOGGED Batch
*
*

* WARNING : This Batch is state-full and not * thread-safe. In case of exception, you MUST not re-use it but create * another one * * @return a new state-full AsyncBatch */ public AsyncBatch createLoggedBatch() { log.debug("Spawn new Logged AsyncBatch"); return new AsyncBatch(entityMetaMap, contextFactory, daoContext, configContext, LOGGED, false); } /** * Create a new state-full asynchronous UNLOGGED Batch
*
*

* WARNING : This Batch is state-full and not * thread-safe. In case of exception, you MUST not re-use it but create * another one * * @return a new state-full AsyncBatch */ public AsyncBatch createUnloggedBatch() { log.debug("Spawn new Unlogged AsyncBatch"); return new AsyncBatch(entityMetaMap, contextFactory, daoContext, configContext, UNLOGGED, false); } /** * Create a new state-full asynchronous ordered and LOGGED Batch
*
*

* This Batch respect insertion order by generating increasing timestamp with micro second resolution. * If you use ordered Batch in multiple clients, do not forget to synchronize the clock between those clients * to avoid statements interleaving *

* WARNING : This Batch is state-full and not * thread-safe. In case of exception, you MUST not re-use it but create * another one * * @return a new state-full AsyncBatch */ public AsyncBatch createOrderedLoggedBatch() { log.debug("Spawn new ordered Logged AsyncBatch"); return new AsyncBatch(entityMetaMap, contextFactory, daoContext, configContext, LOGGED, true); } /** * Create a new state-full asynchronous ordered and UNLOGGED Batch
*
*

* This Batch respect insertion order by generating increasing timestamp with micro second resolution. * If you use ordered Batch in multiple clients, do not forget to synchronize the clock between those clients * to avoid statements interleaving *

* WARNING : This Batch is state-full and not * thread-safe. In case of exception, you MUST not re-use it but create * another one * * @return a new state-full AsyncBatch */ public AsyncBatch createOrderedUnloggedBatch() { log.debug("Spawn new ordered Unlogged AsyncBatch"); return new AsyncBatch(entityMetaMap, contextFactory, daoContext, configContext, UNLOGGED, true); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy