Package org.springframework.data.cassandra.core

Source Code of org.springframework.data.cassandra.core.CassandraTemplate

/*
* Copyright 2013-2014 the original author or authors
*
* 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 org.springframework.data.cassandra.core;

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

import org.springframework.cassandra.core.AsynchronousQueryListener;
import org.springframework.cassandra.core.CqlOperations;
import org.springframework.cassandra.core.CqlTemplate;
import org.springframework.cassandra.core.Cancellable;
import org.springframework.cassandra.core.QueryForObjectListener;
import org.springframework.cassandra.core.QueryOptions;
import org.springframework.cassandra.core.SessionCallback;
import org.springframework.cassandra.core.WriteOptions;
import org.springframework.cassandra.core.cql.CqlIdentifier;
import org.springframework.cassandra.core.util.CollectionUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.convert.EntityWriter;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.util.Assert;

import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.SimpleStatement;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.Batch;
import com.datastax.driver.core.querybuilder.Clause;
import com.datastax.driver.core.querybuilder.Delete;
import com.datastax.driver.core.querybuilder.Delete.Where;
import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Update;

/**
* The CassandraTemplate is a convenient API for all Cassandra operations using POJOs with their Spring Data Cassandra
* mapping information. For low-level Cassandra operation, see {@link CqlTemplate}.
*
* @author Alex Shvid
* @author David Webb
* @author Matthew T. Adams
* @author Oliver Gierke
* @see CqlTemplate
*/
public class CassandraTemplate extends CqlTemplate implements CassandraOperations {

  protected CassandraConverter cassandraConverter;
  protected CassandraMappingContext mappingContext;

  /**
   * Default Constructor for wiring in the required components later
   */
  public CassandraTemplate() {}

  public CassandraTemplate(Session session) {
    this(session, new MappingCassandraConverter());
  }

  /**
   * Constructor if only session and converter are known at time of Template Creation
   *
   * @param session must not be {@literal null}
   * @param converter must not be {@literal null}.
   */
  public CassandraTemplate(Session session, CassandraConverter converter) {
    setSession(session);
    setConverter(converter);
  }

  public void setConverter(CassandraConverter cassandraConverter) {

    Assert.notNull(cassandraConverter);

    this.cassandraConverter = cassandraConverter;
    mappingContext = cassandraConverter.getMappingContext();
  }

  @Override
  public CassandraConverter getConverter() {
    return cassandraConverter;
  }

  public CassandraMappingContext getCassandraMappingContext() {
    return mappingContext;
  }

  @Override
  public void afterPropertiesSet() {
    super.afterPropertiesSet();

    Assert.notNull(cassandraConverter);
    Assert.notNull(mappingContext);
  }

  @Override
  public boolean exists(Class<?> type, Object id) {

    Assert.notNull(type);
    Assert.notNull(id);

    CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);

    Select select = QueryBuilder.select().countAll().from(entity.getTableName().toCql());
    appendIdCriteria(select.where(), entity, id);

    Long count = queryForObject(select, Long.class);

    return count != 0;
  }

  @Override
  public long count(Class<?> type) {
    return count(getTableName(type).toCql());
  }

  @Override
  public <T> void delete(List<T> entities) {
    delete(entities, null);
  }

  @Override
  public <T> void delete(List<T> entities, QueryOptions options) {
    doBatchDelete(entities, options);
  }

  @Override
  public void deleteById(Class<?> type, Object id) {

    Assert.notNull(type);
    Assert.notNull(id);

    CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);

    Delete delete = QueryBuilder.delete().from(entity.getTableName().toCql());
    appendIdCriteria(delete.where(), entity, id);

    execute(delete);
  }

  @Override
  public <T> void delete(T entity) {
    delete(entity, null);
  }

  @Override
  public <T> void delete(T entity, QueryOptions options) {
    doDelete(entity, options);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(List<T> entities) {
    return doBatchDeleteAsync(entities, null, null);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(List<T> entities, QueryOptions options) {
    return doBatchDeleteAsync(entities, null, options);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(List<T> entities, DeletionListener<T> listener) {
    return doBatchDeleteAsync(entities, listener, null);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(List<T> entities, DeletionListener<T> listener, QueryOptions options) {
    return doBatchDeleteAsync(entities, listener, options);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(T entity) {
    return doDeleteAsync(entity, null, null);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(T entity, QueryOptions options) {
    return doDeleteAsync(entity, null, options);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(T entity, DeletionListener<T> listener) {
    return doDeleteAsync(entity, listener, null);
  }

  @Override
  public <T> Cancellable deleteAsynchronously(T entity, DeletionListener<T> listener, QueryOptions options) {
    return doDeleteAsync(entity, listener, options);
  }

  @Override
  public CqlIdentifier getTableName(Class<?> type) {
    return mappingContext.getPersistentEntity(type).getTableName();
  }

  @Override
  public <T> List<T> insert(List<T> entities) {
    return insert(entities, null);
  }

  @Override
  public <T> List<T> insert(List<T> entities, WriteOptions options) {
    return doBatchInsert(entities, options);
  }

  @Override
  public <T> T insert(T entity) {
    return insert(entity, null);
  }

  @Override
  public <T> T insert(T entity, WriteOptions options) {
    return doInsert(entity, options);
  }

  /**
   * @deprecated See {@link CassandraTemplate#insertAsynchronously(List)}
   */
  @Deprecated
  @Override
  public <T> List<T> insertAsynchronously(List<T> entities) {
    insertAsynchronously(entities, (WriteOptions) null);
    return entities;
  }

  /**
   * @deprecated See {@link CassandraTemplate#insertAsynchronously(List, WriteOptions)}
   */
  @Deprecated
  @Override
  public <T> List<T> insertAsynchronously(List<T> entities, WriteOptions options) {
    doInsertAsynchronously(entities, null, options);
    return entities;
  }

  @Override
  public <T> Cancellable insertAsynchronously(List<T> entities, WriteListener<T> listener) {
    return doInsertAsynchronously(entities, listener, null);
  }

  @Override
  public <T> Cancellable insertAsynchronously(List<T> entities, WriteListener<T> listener, WriteOptions options) {
    return doInsertAsynchronously(entities, listener, options);
  }

  /**
   * This method resolves ambiguity the compiler sees as a result of type erasure between
   * {@link #insertAsynchronously(Object, WriteListener, WriteOptions)} and {@link #insertAsynchronously(List<T>,
   * WriteListener<T>, WriteOptions)}.
   */
  protected <T> Cancellable doInsertAsynchronously(List<T> entities, WriteListener<T> listener, WriteOptions options) {
    return doBatchInsertAsync(entities, listener, options);
  }

  /**
   * @deprecated See {@link CqlOperations#insert(Object)}
   */
  @Deprecated
  @Override
  public <T> T insertAsynchronously(T entity) {
    insertAsynchronously(entity, null, null);
    return entity;
  }

  /**
   * @deprecated See {@link CqlOperations#insert(Object,WriteOptions)}
   */
  @Deprecated
  @Override
  public <T> T insertAsynchronously(T entity, WriteOptions options) {
    insertAsynchronously(entity, null, options);
    return entity;
  }

  @Override
  public <T> Cancellable insertAsynchronously(T entity, WriteListener<T> listener) {
    return insertAsynchronously(entity, listener, null);
  }

  @Override
  public <T> Cancellable insertAsynchronously(T entity, WriteListener<T> listener, WriteOptions options) {
    return doInsertAsync(entity, listener, options);
  }

  @Override
  public <T> List<T> selectAll(Class<T> type) {
    return select(QueryBuilder.select().all().from(getTableName(type).toCql()), type);
  }

  @Override
  public <T> List<T> select(String cql, Class<T> type) {

    Assert.hasText(cql);
    Assert.notNull(type);

    return select(cql, new CassandraConverterRowCallback<T>(cassandraConverter, type));
  }

  @Override
  public <T> List<T> select(Select select, Class<T> type) {

    Assert.notNull(select);

    return select(select, new CassandraConverterRowCallback<T>(cassandraConverter, type));
  }

  @Override
  public <T> List<T> selectBySimpleIds(Class<T> type, Iterable<?> ids) {

    CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);

    if (entity.getIdProperty().isCompositePrimaryKey()) {
      throw new IllegalArgumentException(String.format(
          "entity class [%s] uses a composite primary key class [%s] which this method can't support", type.getName(),
          entity.getIdProperty().getCompositePrimaryKeyEntity().getType().getName()));
    }

    Select select = QueryBuilder.select().all().from(entity.getTableName().toCql());
    select.where(QueryBuilder.in(entity.getIdProperty().getColumnName().toCql(), CollectionUtils.toArray(ids)));

    return select(select, type);
  }

  @Override
  public <T> T selectOneById(Class<T> type, Object id) {

    Assert.notNull(type);
    Assert.notNull(id);

    CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
    if (entity == null) {
      throw new IllegalArgumentException(String.format("unknown entity class [%s]", type.getName()));
    }

    Select select = QueryBuilder.select().all().from(entity.getTableName().toCql());
    appendIdCriteria(select.where(), entity, id);

    return selectOne(select, type);
  }

  protected interface ClauseCallback {
    void doWithClause(Clause clause);
  }

  protected void appendIdCriteria(final ClauseCallback clauseCallback, CassandraPersistentEntity<?> entity,
      final Map<?, ?> id) {

    for (Map.Entry<?, ?> entry : id.entrySet()) {

      CassandraPersistentProperty property = entity.getPersistentProperty(entry.getKey().toString());
      clauseCallback.doWithClause(QueryBuilder.eq(property.getColumnName().toCql(), entry.getValue()));
    }
  }

  protected void appendIdCriteria(final ClauseCallback clauseCallback, CassandraPersistentEntity<?> entity, Object id) {

    if (id instanceof Map<?, ?>) {

      appendIdCriteria(clauseCallback, entity, (Map<?, ?>) id);
      return;
    }

    CassandraPersistentProperty idProperty = entity.getIdProperty();

    if (idProperty.isCompositePrimaryKey()) {

      CassandraPersistentEntity<?> idEntity = idProperty.getCompositePrimaryKeyEntity();

      final BeanWrapper<Object> idWrapper = BeanWrapper.create(id, cassandraConverter.getConversionService());

      idEntity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {

        @Override
        public void doWithPersistentProperty(CassandraPersistentProperty p) {

          clauseCallback.doWithClause(QueryBuilder.eq(p.getColumnName().toCql(),
              idWrapper.getProperty(p, p.getActualType())));
        }
      });

      return;
    }

    clauseCallback.doWithClause(QueryBuilder.eq(idProperty.getColumnName().toCql(), id));
  }

  protected void appendIdCriteria(final com.datastax.driver.core.querybuilder.Select.Where where,
      CassandraPersistentEntity<?> entity, Object id) {

    appendIdCriteria(new ClauseCallback() {

      @Override
      public void doWithClause(Clause clause) {
        where.and(clause);
      }
    }, entity, id);
  }

  protected void appendIdCriteria(final Where where, CassandraPersistentEntity<?> entity, Object id) {

    appendIdCriteria(new ClauseCallback() {

      @Override
      public void doWithClause(Clause clause) {
        where.and(clause);
      }
    }, entity, id);
  }

  @Override
  public <T> T selectOne(String cql, Class<T> type) {
    return selectOne(cql, new CassandraConverterRowCallback<T>(cassandraConverter, type));
  }

  @Override
  public <T> T selectOne(Select select, Class<T> type) {
    return selectOne(select, new CassandraConverterRowCallback<T>(cassandraConverter, type));
  }

  @Override
  public <T> List<T> update(List<T> entities) {
    return update(entities, null);
  }

  @Override
  public <T> List<T> update(List<T> entities, WriteOptions options) {
    return doBatchUpdate(entities, options);
  }

  @Override
  public <T> T update(T entity) {
    return update(entity, null);
  }

  @Override
  public <T> T update(T entity, WriteOptions options) {
    return doUpdate(entity, options);
  }

  @Override
  public <T> List<T> updateAsynchronously(List<T> entities) {
    doUpdateAsynchronously(entities, null, null);
    return entities;
  }

  @Override
  public <T> List<T> updateAsynchronously(List<T> entities, WriteOptions options) {
    doUpdateAsynchronously(entities, null, options);
    return entities;
  }

  @Override
  public <T> Cancellable updateAsynchronously(List<T> entities, WriteListener<T> listener) {
    return doUpdateAsynchronously(entities, listener, null);
  }

  @Override
  public <T> Cancellable updateAsynchronously(List<T> entities, WriteListener<T> listener, WriteOptions options) {
    return doUpdateAsynchronously(entities, listener, options);
  }

  /**
   * This method resolves ambiguity the compiler sees as a result of type erasure between
   * {@link #updateAsynchronously(Object, WriteListener, WriteOptions)} and {@link #updateAsynchronously(List<T>,
   * WriteListener<T>, WriteOptions)}.
   */
  protected <T> Cancellable doUpdateAsynchronously(List<T> entities, WriteListener<T> listener, WriteOptions options) {
    return doBatchUpdateAsync(entities, listener, options);
  }

  @Override
  public <T> T updateAsynchronously(T entity) {
    updateAsynchronously(entity, null, null);
    return entity;
  }

  @Override
  public <T> T updateAsynchronously(T entity, WriteOptions options) {
    updateAsynchronously(entity, null, options);
    return entity;
  }

  @Override
  public <T> Cancellable updateAsynchronously(T entity, WriteListener<T> listener) {
    return updateAsynchronously(entity, listener, null);
  }

  @Override
  public <T> Cancellable updateAsynchronously(T entity, WriteListener<T> listener, WriteOptions options) {
    return doUpdateAsync(entity, listener, options);
  }

  protected <T> CqlIdentifier determineTableName(T obj) {
    return obj == null ? null : determineTableName(obj.getClass());
  }

  protected <T> List<T> select(final String query, CassandraConverterRowCallback<T> readRowCallback) {

    ResultSet resultSet = doExecute(new SessionCallback<ResultSet>() {

      @Override
      public ResultSet doInSession(Session s) throws DataAccessException {
        return s.execute(query);
      }
    });

    if (resultSet == null) {
      return null;
    }

    List<T> result = new ArrayList<T>();
    Iterator<Row> iterator = resultSet.iterator();
    while (iterator.hasNext()) {
      Row row = iterator.next();
      result.add(readRowCallback.doWith(row));
    }

    return result;
  }

  protected <T> List<T> select(final Select query, CassandraConverterRowCallback<T> readRowCallback) {

    ResultSet resultSet = doExecute(new SessionCallback<ResultSet>() {

      @Override
      public ResultSet doInSession(Session s) throws DataAccessException {
        return s.execute(query);
      }
    });

    if (resultSet == null) {
      return null;
    }

    List<T> result = new ArrayList<T>();
    Iterator<Row> iterator = resultSet.iterator();
    while (iterator.hasNext()) {
      Row row = iterator.next();
      result.add(readRowCallback.doWith(row));
    }

    return result;
  }

  /**
   * @param query
   * @param readRowCallback
   * @return
   */
  protected <T> T selectOne(String query, CassandraConverterRowCallback<T> readRowCallback) {

    logger.debug(query);

    ResultSet resultSet = query(query);

    Iterator<Row> iterator = resultSet.iterator();
    if (iterator.hasNext()) {
      Row row = iterator.next();
      T result = readRowCallback.doWith(row);
      if (iterator.hasNext()) {
        throw new DuplicateKeyException("found two or more results in query " + query);
      }
      return result;
    }

    return null;
  }

  protected <T> T selectOne(Select query, CassandraConverterRowCallback<T> readRowCallback) {

    ResultSet resultSet = query(query);

    Iterator<Row> iterator = resultSet.iterator();
    if (iterator.hasNext()) {
      Row row = iterator.next();
      T result = readRowCallback.doWith(row);
      if (iterator.hasNext()) {
        throw new DuplicateKeyException("found two or more results in query " + query);
      }
      return result;
    }

    return null;
  }

  protected <T> void doBatchDelete(List<T> entities, QueryOptions options) {
    execute(createDeleteBatchQuery(getTableName(entities.get(0).getClass()).toCql(), entities, options,
        cassandraConverter));
  }

  protected <T> Cancellable doBatchDeleteAsync(final List<T> entities, final DeletionListener listener,
      QueryOptions options) {

    AsynchronousQueryListener aql = listener == null ? null : new AsynchronousQueryListener() {

      @Override
      public void onQueryComplete(ResultSetFuture rsf) {
        try {
          rsf.getUninterruptibly();
          listener.onDeletionComplete(entities);
        } catch (Exception e) {
          listener.onException(translateExceptionIfPossible(e));
        }
      }
    };

    return executeAsynchronously(
        createDeleteBatchQuery(getTableName(entities.get(0).getClass()).toCql(), entities, options, cassandraConverter),
        aql);
  }

  protected <T> T doInsert(T entity, WriteOptions options) {

    Assert.notNull(entity);
    Insert insert = createInsertQuery(getTableName(entity.getClass()).toCql(), entity, options, cassandraConverter);
    execute(insert);
    return entity;
  }

  protected <T> Cancellable doInsertAsync(final T entity, final WriteListener<T> listener, WriteOptions options) {

    Assert.notNull(entity);

    Insert insert = createInsertQuery(getTableName(entity.getClass()).toCql(), entity, options, cassandraConverter);

    AsynchronousQueryListener aql = listener == null ? null : new AsynchronousQueryListener() {

      @SuppressWarnings("unchecked")
      @Override
      public void onQueryComplete(ResultSetFuture rsf) {
        try {
          rsf.getUninterruptibly();
          listener.onWriteComplete((Collection<T>) CollectionUtils.toList(entity));
        } catch (Exception x) {
          listener.onException(translateExceptionIfPossible(x));
        }
      }
    };

    return executeAsynchronously(insert, aql);
  }

  protected <T> List<T> doBatchInsert(List<T> entities, WriteOptions options) {
    return doBatchWrite(entities, options, true);
  }

  protected <T> List<T> doBatchUpdate(List<T> entities, WriteOptions options) {
    return doBatchWrite(entities, options, false);
  }

  protected <T> List<T> doBatchWrite(List<T> entities, WriteOptions options, boolean insert) {

    if (entities == null || entities.size() == 0) {
      if (logger.isWarnEnabled()) {
        logger.warn("no-op due to given null or empty list");
      }
      return entities;
    }

    String tableName = getTableName(entities.get(0).getClass()).toCql();
    Batch b = insert ? createInsertBatchQuery(tableName, entities, options, cassandraConverter)
        : createUpdateBatchQuery(tableName, entities, options, cassandraConverter);
    execute(b);

    return entities;
  }

  /**
   * Asynchronously performs a batch insert or update.
   *
   * @param entities The entities to insert or update.
   * @param listener The listener that will receive notification of the completion of the batch insert or update. May be
   *          <code>null</code>.
   * @param options The {@link WriteOptions} to use. May be <code>null</code>.
   * @return A {@link Cancellable} that can be used to cancel the query if necessary.
   */
  protected <T> Cancellable doBatchInsertAsync(final List<T> entities, final WriteListener<T> listener,
      WriteOptions options) {
    return doBatchWriteAsync(entities, listener, options, true);
  }

  /**
   * Asynchronously performs a batch insert or update.
   *
   * @param entities The entities to insert or update.
   * @param listener The listener that will receive notification of the completion of the batch insert or update. May be
   *          <code>null</code>.
   * @param options The {@link WriteOptions} to use. May be <code>null</code>.
   * @return A {@link Cancellable} that can be used to cancel the query if necessary.
   */
  protected <T> Cancellable doBatchUpdateAsync(final List<T> entities, final WriteListener<T> listener,
      WriteOptions options) {
    return doBatchWriteAsync(entities, listener, options, false);
  }

  /**
   * Asynchronously performs a batch insert or update.
   *
   * @param entities The entities to insert or update.
   * @param listener The listener that will receive notification of the completion of the batch insert or update. May be
   *          <code>null</code>.
   * @param options The {@link WriteOptions} to use. May be <code>null</code>.
   * @param insert If <code>true</code>, then an insert is performed, else an update is performed.
   * @return A {@link Cancellable} that can be used to cancel the query if necessary.
   */
  protected <T> Cancellable doBatchWriteAsync(final List<T> entities, final WriteListener<T> listener,
      WriteOptions options, boolean insert) {

    if (entities == null || entities.size() == 0) {
      if (logger.isWarnEnabled()) {
        logger.warn("no-op due to given null or empty list");
      }
      return new Cancellable() {

        @Override
        public void cancel() {
          if (logger.isWarnEnabled()) {
            logger.warn("no-op query cancellation due to given null or empty list");
          }
        }
      };
    }

    String tableName = getTableName(entities.get(0).getClass()).toCql();
    Batch b = insert ? createInsertBatchQuery(tableName, entities, options, cassandraConverter)
        : createUpdateBatchQuery(tableName, entities, options, cassandraConverter);

    AsynchronousQueryListener aql = listener == null ? null : new AsynchronousQueryListener() {

      @Override
      public void onQueryComplete(ResultSetFuture rsf) {
        try {
          rsf.getUninterruptibly();
          listener.onWriteComplete(entities);
        } catch (Exception e) {
          listener.onException(translateExceptionIfPossible(e));
        }
      }
    };

    return executeAsynchronously(b, aql);
  }

  protected <T> void doDelete(T entity, QueryOptions options) {

    Assert.notNull(entity);
    Delete delete = createDeleteQuery(getTableName(entity.getClass()).toCql(), entity, options, cassandraConverter);
    execute(delete);
  }

  protected <T> Cancellable doDeleteAsync(final T entity, final DeletionListener listener, QueryOptions options) {

    Assert.notNull(entity);

    Delete delete = createDeleteQuery(getTableName(entity.getClass()).toCql(), entity, options, cassandraConverter);

    AsynchronousQueryListener aql = listener == null ? null : new AsynchronousQueryListener() {
      @Override
      public void onQueryComplete(ResultSetFuture rsf) {
        try {
          rsf.getUninterruptibly();
          listener.onDeletionComplete(CollectionUtils.toList(entity));
        } catch (Exception x) {
          listener.onException(translateExceptionIfPossible(x));
        }
      }
    };

    return executeAsynchronously(delete, aql);
  }

  protected <T> T doUpdate(T entity, WriteOptions options) {

    Assert.notNull(entity);
    Update update = createUpdateQuery(getTableName(entity.getClass()).toCql(), entity, options, cassandraConverter);
    execute(update);
    return entity;
  }

  protected <T> Cancellable doUpdateAsync(final T entity, final WriteListener<T> listener, WriteOptions options) {

    Assert.notNull(entity);

    Update update = createUpdateQuery(getTableName(entity.getClass()).toCql(), entity, options, cassandraConverter);

    AsynchronousQueryListener aql = listener == null ? null : new AsynchronousQueryListener() {

      @SuppressWarnings("unchecked")
      @Override
      public void onQueryComplete(ResultSetFuture rsf) {
        try {
          rsf.getUninterruptibly();
          listener.onWriteComplete((Collection<T>) CollectionUtils.toList(entity));
        } catch (Exception x) {
          listener.onException(translateExceptionIfPossible(x));
        }
      }
    };

    return executeAsynchronously(update, aql);
  }

  /**
   * Generates a Query Object for an insert
   *
   * @param tableName
   * @param objectToSave
   * @param entity
   * @param optionsByName
   * @return The Query object to run with session.execute();
   */
  public static Insert createInsertQuery(String tableName, Object objectToSave, WriteOptions options,
      EntityWriter<Object, Object> entityWriter) {

    Insert insert = QueryBuilder.insertInto(tableName);
    entityWriter.write(objectToSave, insert);
    CqlTemplate.addWriteOptions(insert, options);
    return insert;
  }

  /**
   * @deprecated Method renamed. Use {@link #createUpdateQuery(String, Object, WriteOptions, EntityWriter)}
   * @see #createUpdateQuery(String, Object, WriteOptions, EntityWriter)
   */
  @Deprecated
  public static Update toUpdateQueryX(String tableName, Object objectToSave, WriteOptions options,
      EntityWriter<Object, Object> entityWriter) {
    return createUpdateQuery(tableName, objectToSave, options, entityWriter);
  }

  /**
   * Generates a Query Object for an Update
   *
   * @param tableName
   * @param objectToSave
   * @param entity
   * @param optionsByName
   * @return The Query object to run with session.execute();
   */
  public static Update createUpdateQuery(String tableName, Object objectToSave, WriteOptions options,
      EntityWriter<Object, Object> entityWriter) {

    Update update = QueryBuilder.update(tableName);
    entityWriter.write(objectToSave, update);
    CqlTemplate.addWriteOptions(update, options);
    return update;
  }

  /**
   * @deprecated Method renamed. Use {@link #createUpdateBatchQuery(String, List, WriteOptions, EntityWriter)}
   * @see #createUpdateBatchQuery(String, List, WriteOptions, EntityWriter)
   */
  @Deprecated
  public static <T> Batch toUpdateBatchQuery(String tableName, List<T> objectsToSave, WriteOptions options,
      EntityWriter<Object, Object> entityWriter) {
    return createUpdateBatchQuery(tableName, objectsToSave, options, entityWriter);
  }

  /**
   * Generates a Batch Object for multiple Updates
   *
   * @param tableName
   * @param objectsToSave
   * @param entity
   * @param optionsByName
   * @return The Query object to run with session.execute();
   */
  public static <T> Batch createUpdateBatchQuery(String tableName, List<T> objectsToSave, WriteOptions options,
      EntityWriter<Object, Object> entityWriter) {

    Batch b = QueryBuilder.batch();

    for (T objectToSave : objectsToSave) {
      b.add(createUpdateQuery(tableName, objectToSave, options, entityWriter));
    }

    CqlTemplate.addQueryOptions(b, options);

    return b;
  }

  /**
   * Generates a Batch Object for multiple inserts
   *
   * @param tableName
   * @param entities
   * @param entity
   * @param optionsByName
   * @return The Query object to run with session.execute();
   */
  public static <T> Batch createInsertBatchQuery(String tableName, List<T> entities, WriteOptions options,
      EntityWriter<Object, Object> entityWriter) {

    Batch batch = QueryBuilder.batch();

    for (T entity : entities) {
      batch.add(createInsertQuery(tableName, entity, options, entityWriter));
    }

    CqlTemplate.addQueryOptions(batch, options);

    return batch;
  }

  /**
   * Create a Delete Query Object from an annotated POJO
   *
   * @param tableName
   * @param object
   * @param entity
   * @param optionsByName
   * @return
   */
  public static Delete createDeleteQuery(String tableName, Object object, QueryOptions options,
      EntityWriter<Object, Object> entityWriter) {

    Delete.Selection ds = QueryBuilder.delete();
    Delete delete = ds.from(tableName);
    Where w = delete.where();
    entityWriter.write(object, w);
    CqlTemplate.addQueryOptions(delete, options);
    return delete;
  }

  /**
   * Create a Batch Query object for multiple deletes.
   *
   * @param tableName
   * @param entities
   * @param entity
   * @param optionsByName
   * @return
   */
  public static <T> Batch createDeleteBatchQuery(String tableName, List<T> entities, QueryOptions options,
      EntityWriter<Object, Object> entityWriter) {

    Assert.notEmpty(entities);
    Assert.hasText(tableName);

    Batch batch = QueryBuilder.batch();

    for (T entity : entities) {
      batch.add(createDeleteQuery(tableName, entity, options, entityWriter));
    }

    CqlTemplate.addQueryOptions(batch, options);

    return batch;
  }

  @Override
  public <T> void deleteAll(Class<T> clazz) {

    if (!mappingContext.contains(clazz)) {
      throw new IllegalArgumentException(String.format("unknown persistent entity class [%s]", clazz.getName()));
    }

    truncate(mappingContext.getPersistentEntity(clazz).getTableName());
  }

  @Override
  public <T> Cancellable selectOneAsynchronously(Select select, Class<T> type, QueryForObjectListener<T> listener) {
    return selectOneAsynchronously(select, type, listener, null);
  }

  @Override
  public <T> Cancellable selectOneAsynchronously(String cql, Class<T> type, QueryForObjectListener<T> listener) {
    return selectOneAsynchronously(cql, type, listener, null);
  }

  @Override
  public <T> Cancellable selectOneAsynchronously(Select select, Class<T> type, QueryForObjectListener<T> listener,
      QueryOptions options) {
    return doSelectOneAsync(select, type, listener, options);
  }

  @Override
  public <T> Cancellable selectOneAsynchronously(String cql, Class<T> type, QueryForObjectListener<T> listener,
      QueryOptions options) {
    return doSelectOneAsync(cql, type, listener, options);
  }

  protected <T> Cancellable doSelectOneAsync(final Object query, final Class<T> type,
      final QueryForObjectListener<T> listener, QueryOptions options) {

    AsynchronousQueryListener aql = new AsynchronousQueryListener() {

      @Override
      public void onQueryComplete(ResultSetFuture rsf) {
        try {
          ResultSet rs = rsf.getUninterruptibly();
          Iterator<Row> iterator = rs.iterator();
          if (iterator.hasNext()) {
            Row row = iterator.next();
            T result = new CassandraConverterRowCallback<T>(cassandraConverter, type).doWith(row);
            if (iterator.hasNext()) {
              throw new DuplicateKeyException("found two or more results in query " + query);
            }
            listener.onQueryComplete(result);
          }
        } catch (Exception e) {
          listener.onException(translateExceptionIfPossible(e));
        }
      }
    };
    if (query instanceof String) {
      return queryAsynchronously((String) query, aql, options);
    }
    if (query instanceof Select) {
      return queryAsynchronously((Select) query, aql);
    }
    throw new IllegalArgumentException(String.format("Expected type String or Select; got type [%s] with value [%s]",
        query.getClass(), query));
  }
}
TOP

Related Classes of org.springframework.data.cassandra.core.CassandraTemplate

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.