package AgentProvider.Implementation.Database;
import AgentSystemPluginAPI.Contract.StateAction;
import EnvironmentPluginAPI.Exceptions.TechnicalException;
import ZeroTypes.Exceptions.ErrorMessages;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
/**
* This class implements the connection to the database as an unlimited cache.
*/
public class DatabaseCache extends DatabaseAccessor implements ICache {
private String tableName;
private final PreparedStatement selectStatement;
private ResultSet resultSet;
private int size;
private Map<StateAction, Float> buffer;
private int elemCount;
public DatabaseCache(Connection connection, String tableName, int size) throws TechnicalException {
super(connection);
this.tableName = tableName;
this.size = size;
buffer = new HashMap<StateAction, Float>(size);
elemCount = 0;
createTableIfNotExists(tableName, "(key VARCHAR(255) NOT NULL PRIMARY KEY, value FLOAT)");
try {
selectStatement = connection.prepareStatement("select value from " + tableName + " where key = ?");
} catch (SQLException e) {
throw new TechnicalException(ErrorMessages.get("databaseError") + "\nReason}\n" + e);
}
}
@Override
public void store(StateAction stateAction, float value) throws TechnicalException {
if(elemCount >= size) {
flush();
}
if(!buffer.containsKey(stateAction)) {
elemCount++;
}
buffer.put(stateAction, value);
}
@Override
public float remove(StateAction stateAction) throws ValueNotFoundException, TechnicalException {
Float result;
result = buffer.get(stateAction);
if (result != null) {
buffer.remove(stateAction);
return result;
}
result = readFromDb(stateAction);
if (result != null) {
return result;
} else {
throw new ValueNotFoundException();
}
}
@Override
public boolean hasStored(StateAction stateAction) throws TechnicalException {
return
buffer.containsKey(stateAction)
|| (readFromDb(stateAction) != null);
}
@Override
public float get(StateAction stateAction) throws ValueNotFoundException, TechnicalException {
Float result;
result = buffer.get(stateAction);
if (result != null) {
return result;
}
result = readFromDb(stateAction);
if (result != null) {
store(stateAction, result);
return result;
} else {
throw new ValueNotFoundException();
}
}
private Float readFromDb(StateAction stateAction) throws TechnicalException {
// if that fails read data from db and update caches
try {
selectStatement.setString(1, stateAction.getCompressedRepresentation());
resultSet = selectStatement.executeQuery();
if (resultSet.next()) {
return resultSet.getFloat("value");
} else {
return null;
}
} catch (SQLException e) {
throw new TechnicalException(ErrorMessages.get("databaseError") + "\nReason}\n" + e);
}
}
@Override
public void flush() throws TechnicalException {
try {
Statement statement = activeConnection().createStatement();
for (Map.Entry<StateAction, Float> stateActionFloatEntry : buffer.entrySet()) {
statement.addBatch(String.format("merge into %s (key, value) key(key) values ('%s', %s)", tableName, stateActionFloatEntry.getKey().getCompressedRepresentation(), stateActionFloatEntry.getValue()));
}
statement.executeBatch();
elemCount = 0;
} catch (SQLException e) {
throw new TechnicalException(ErrorMessages.get("databaseError") + "\nReason}\n" + e);
}
}
public void clear() throws TechnicalException {
try {
activeConnection().createStatement().execute("drop table " + tableName);
createTableIfNotExists(tableName, "(key VARCHAR(255) NOT NULL PRIMARY KEY, value FLOAT)");
} catch (SQLException e) {
throw new TechnicalException(ErrorMessages.get("databaseError") + "\nReason}\n" + e);
}
}
}