package eu.ttbox.androgister.repository;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.persistence.PersistenceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Repository;
import com.google.common.base.Function;
import com.netflix.astyanax.ColumnListMutation;
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.MutationBatch;
import com.netflix.astyanax.connectionpool.OperationResult;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.entitystore.DefaultEntityManager;
import com.netflix.astyanax.entitystore.MyEntityMapper;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.ColumnList;
import com.netflix.astyanax.model.Row;
import com.netflix.astyanax.model.Rows;
import com.netflix.astyanax.query.IndexQuery;
import com.netflix.astyanax.serializers.StringSerializer;
import com.netflix.astyanax.serializers.UUIDSerializer;
import eu.ttbox.androgister.model.Product;
@Repository
public class ProductRepository {
private static final Logger LOG = LoggerFactory.getLogger(ProductRepository.class);
public static ColumnFamily<UUID, String> CF_PRODUCT = ColumnFamily.newColumnFamily("Product", UUIDSerializer.get(), StringSerializer.get());
public static ColumnFamily<String, UUID> CF_SALESPOINT_PRODUCT = ColumnFamily.newColumnFamily("SalepointProduct", StringSerializer.get(), UUIDSerializer.get());
@Autowired
public Keyspace keyspace;
public DefaultEntityManager<Product, UUID> entityManager;
public MyEntityMapper<Product, UUID> entityMapper;
public enum ProductColumn {
uuid, salepointId, versionDate, creationDate, name, description, priceHT;
}
@PostConstruct
public void init() {
entityManager = new DefaultEntityManager.Builder<Product, UUID>() //
.withEntityType(Product.class) //
.withKeyspace(keyspace) //
.withColumnFamily(CF_PRODUCT) //
.build();
entityMapper = new MyEntityMapper<Product, UUID>(Product.class);
}
public Product findById(UUID uuid) {
return entityManager.get(uuid);
}
public List<Product> findAll() {
return entityManager.getAll();
}
public void findEntityUpdatedFrom(String salespointId, long timestamp, Function<Product, Boolean> callback) throws ConnectionException {
IndexQuery<UUID, String> query = keyspace.prepareQuery(CF_PRODUCT) //
.searchWithIndex() //
.setRowLimit(20) // This is the page size
.autoPaginateRows(true)//
.withColumnSlice("versionDate")//
.addExpression().whereColumn("salepointId").equals().value(salespointId) //
.addExpression().whereColumn("versionDate").greaterThanEquals().value(timestamp) //
;
int pageCount = 0;
int rowCount = 0;
OperationResult<Rows<UUID, String>> result;
while (!(result = query.execute()).getResult().isEmpty()) {
pageCount++;
rowCount += result.getResult().size();
for (Row<UUID, String> row : result.getResult()) {
// TODO
// Product entity = entityManager.get(row.getKey());
// TODO
UUID id = row.getKey();
ColumnList<String> cl = row.getColumns();
if (cl.isEmpty())
continue;
Product entity = entityMapper.constructEntity(id, cl);
callback.apply(entity);
}
}
}
public void persist(Product product) {
long now = System.currentTimeMillis();
persist(product, Long.valueOf( now));
}
public void persist(Product product, Long updateTime) {
LOG.debug("Creating product : {}", product);
// validateEntity(product);
if (product.serverId == null) {
product.serverId = UUID.randomUUID();
product.creationDate = updateTime;
}
product.versionDate = updateTime;
entityManager.put(product);
// Deps
try {
// addProductToSalespointline(product.salepointId, product.uuid, updateTime);
} catch (Exception e) {
throw new PersistenceException("failed to put entity ", e);
}
LOG.debug("Creating End product : {}", product);
}
private void addProductToSalespointline(String salespointId, UUID uuid, long updateTime) throws ConnectionException {
MutationBatch mb = keyspace.prepareMutationBatch();
mb.withRow(CF_SALESPOINT_PRODUCT, salespointId).putColumn(uuid, updateTime);
mb.execute();
}
private void removeProductToSalespointline(String salespointId, UUID uuid) throws ConnectionException {
MutationBatch mb = keyspace.prepareMutationBatch();
mb.withRow(CF_SALESPOINT_PRODUCT, salespointId).deleteColumn(uuid);
mb.execute();
}
public void persist(Map<String, Object> entity) {
long updateTime = System.currentTimeMillis();
// Define Id
UUID uuid = (UUID) entity.get(ProductColumn.uuid.name());
String salepointId = (String) entity.get(ProductColumn.salepointId.name());
if (uuid == null) {
uuid = UUID.randomUUID();// TimeUUIDUtils.getUniqueTimeUUIDinMillis();
entity.put(ProductColumn.uuid.name(), uuid);
entity.put(ProductColumn.creationDate.name(), updateTime);
} else {
// Get Previous
// getById(uuid);
}
entity.put(ProductColumn.versionDate.name(), updateTime);
// Save It
MutationBatch m = keyspace.prepareMutationBatch();
ColumnListMutation<String> updaterEntity = m.withRow(CF_PRODUCT, uuid); //
for (Entry<String, Object> entry : entity.entrySet()) {
String colName = entry.getKey();
if (!colName.equals(ProductColumn.uuid.name())) {
Object value = entry.getValue();
setColumnListMutation(updaterEntity, colName, value);
}
}
try {
OperationResult<Void> result = m.execute();
// Deps
addProductToSalespointline(salepointId, uuid, updateTime);
} catch (Exception e) {
throw new PersistenceException("failed to put entity ", e);
}
}
public void setColumnListMutation(ColumnListMutation<String> updaterEntity, String columnName, Object value) {
if (value == null) {
updaterEntity.putColumn(columnName, (byte[]) value);
} else if (value instanceof String) {
updaterEntity.putColumn(columnName, (String) value);
} else if (value instanceof UUID) {
updaterEntity.putColumn(columnName, (UUID) value);
} else if (value instanceof Date) {
updaterEntity.putColumn(columnName, (Date) value);
} else if (value instanceof Integer) {
updaterEntity.putColumn(columnName, (Integer) value);
} else if (value instanceof Long) {
updaterEntity.putColumn(columnName, (Long) value);
}
}
@CacheEvict(value = "product-cache", key = "#product.uuid")
public void remove(Product product) {
LOG.debug("Deleting product : {} ", product);
remove(product.serverId, product.salepointId);
}
@CacheEvict(value = "product-cache", key = "#uuid")
public void remove(UUID uuid, String salepointId) {
LOG.debug("Deleting product : {} ", uuid);
// entityManager.delete(uuid);
// removeProductToSalespointline(salepointId, uuid);
// Deps
try {
MutationBatch mb = keyspace.prepareMutationBatch();// public
// entityManager.newMutationBatch()
mb.withRow(CF_PRODUCT, uuid).delete();
mb.withRow(CF_SALESPOINT_PRODUCT, salepointId).deleteColumn(uuid);
mb.execute();
} catch (Exception e) {
throw new PersistenceException("failed to put entity ", e);
}
}
}