package org.myeslib.util.hazelcast;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.myeslib.util.jdbi.ClobToStringMapper;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.PreparedBatch;
import org.skife.jdbi.v2.TransactionCallback;
import org.skife.jdbi.v2.TransactionIsolationLevel;
import org.skife.jdbi.v2.TransactionStatus;
import org.skife.jdbi.v2.tweak.HandleCallback;
import org.skife.jdbi.v2.util.StringMapper;
import com.hazelcast.core.MapStore;
@Deprecated
@Slf4j
public class HzStringMapStore implements MapStore<UUID, String>{
private final DBI dbi;
private final String tableName;
public HzStringMapStore(DataSource ds, String tableName){
this.dbi = new DBI(ds);
this.tableName = tableName;
}
public void createTableForMap() {
log.warn(String.format("checking if table %s exists for map storage", tableName));
dbi.inTransaction(new TransactionCallback<Integer>() {
@Override
public Integer inTransaction(Handle h, TransactionStatus ts)
throws Exception {
h.execute(String.format("create table if not exists %s(id varchar(36) not null, "
+ "aggregate_root_data clob not null, "
+ "constraint aggregate_pk primary key (id))",
tableName));
return 0;
}
}) ;
}
@Override
public Set<UUID> loadAllKeys() {
// TODO define how many keys will be pre-loaded
log.debug("loading all keys from table {}", tableName);
Set<UUID> result = dbi.withHandle(new HandleCallback<Set<UUID>>() {
@Override
public Set<UUID> withHandle(Handle h) throws Exception {
List<String> strResult = h.createQuery(String.format("select id from %s", tableName))
.map(new StringMapper()).list();
Set<UUID> uResult = new HashSet<>();
for (String uuid : strResult){
uResult.add(UUID.fromString(uuid));
}
return uResult;
}
});
log.debug("{} keys within table {} were loaded", result.size(), tableName);
return result;
}
@Override
public String load(final UUID id) {
String result = null;
try {
log.debug("will load {} from table {}", id.toString(), tableName);
result = dbi.inTransaction(TransactionIsolationLevel.READ_COMMITTED,
new TransactionCallback<String>() {
@Override
public String inTransaction(Handle h, TransactionStatus ts) throws Exception {
String sql = String.format("select aggregate_root_data from %s where id = :id", tableName);
return h.createQuery(sql).bind("id", id.toString()).map(ClobToStringMapper.FIRST).first();
}
});
// http://stackoverflow.com/questions/9779324/program-hangs-after-retrieving-100-rows-containg-clob
if (result == null) {
log.debug("found a null or zero length value for id {}", id.toString());
} else {
log.debug("loaded {} {} from table {}", id.toString(), result.replace("\n", "").substring(0, Math.min(10, result.length()-1)), tableName);
}
} catch (Exception e) {
log.error("error when loading {} from table {}", id.toString(), tableName);
e.printStackTrace();
} finally {
}
return result;
}
@Override
public Map<UUID, String> loadAll(Collection<UUID> ids) {
log.debug("loading {} keys within table {}", ids.size(), tableName);
Map<UUID, String> result = new HashMap<>();
for (UUID id : ids){
result.put(id, load(id));
}
log.debug("{} keys were loaded from table {}", result.size(), tableName);
return result;
}
@Override
public void delete(UUID id) {
deleteAll(Arrays.asList(id));
}
@Override
public void deleteAll(final Collection<UUID> ids) {
log.debug("deleting {} rows within table {}", ids.size(), tableName);
dbi.inTransaction(new TransactionCallback<Integer>() {
@Override
public Integer inTransaction(Handle h, TransactionStatus ts)
throws Exception {
PreparedBatch pb = h.prepareBatch(String.format("delete from %s where id = :id", tableName));
for (UUID id: ids){
pb.add().bind("id", id.toString());
}
return pb.execute().length;
}
}) ;
}
@Override
public void store(UUID id, String value) {
Map<UUID, String> map = new HashMap<>();
map.put(id, value);
storeAll(map);
}
@Override
public void storeAll(final Map<UUID, String> id_value_pairs) {
log.debug("storing {} rows within table {}", id_value_pairs.size(), tableName);
dbi.inTransaction(new TransactionCallback<Integer>() {
@Override
public Integer inTransaction(Handle h, TransactionStatus ts)
throws Exception {
int inserts = 0, updates = 0;
boolean hasInsert = false, hasUpdate = false;
PreparedBatch pbInsert = h.prepareBatch(String.format("append into %s (id, aggregate_root_data) values (:id, :aggregate_root_data)", tableName));
PreparedBatch pbUpdate = h.prepareBatch(String.format("update %s set aggregate_root_data = :aggregate_root_data where id = :id", tableName));
for (Entry<UUID, String> entry : id_value_pairs.entrySet()){
final String id = entry.getKey().toString();
final String value = entry.getValue();
String idOnTable = h.createQuery(String.format("select id from %s where id = :id", tableName)).bind("id", id.toString()).map(StringMapper.FIRST).first();
if (id.toString().equals(idOnTable)) {
hasUpdate = true;
pbUpdate.add().bind("id", id.toString()).bind("aggregate_root_data", value);
log.debug(String.format("updating with id %s into table %s", id, tableName));
} else {
hasInsert = true;
pbInsert.add().bind("id", id.toString()).bind("aggregate_root_data", value); // value.getBytes... testando sem o
log.debug(String.format("inserting with id %s into table %s", id, tableName));
}
}
if (hasInsert) {
inserts = pbInsert.execute().length;
}
if (hasUpdate) {
updates = pbUpdate.execute().length;
}
return inserts + updates;
}
}) ;
}
}