/**
*
*/
package org.openntf.domino.tests.jpg;
import static java.lang.Math.pow;
import static org.openntf.domino.utils.DominoUtils.checksum;
import java.util.HashMap;
import java.util.Map;
import org.openntf.domino.Database;
import org.openntf.domino.DbDirectory;
import org.openntf.domino.Document;
import org.openntf.domino.Session;
/**
* @author jgallagher
*
*/
public class KeyValueStore {
public interface ServerStrategy {
public String getServerForHashChunk(final String hashChunk);
}
private final Session session_;
private final String server_;
private final ServerStrategy serverStrategy_;
private final String baseName_;
private final Map<String, Database> dbCache_ = new HashMap<String, Database>();
private final Map<String, DbDirectory> dbdirCache_ = new HashMap<String, DbDirectory>();
private final int places_;
public KeyValueStore(final Session session, final String server, final String baseName, final int places) {
if (session == null)
throw new NullPointerException("session cannot be null");
if (baseName == null || baseName.length() == 0)
throw new IllegalArgumentException("baseName cannot be null or zero-length");
if (places < 0)
throw new IllegalArgumentException("places must be nonnegative");
session_ = session;
baseName_ = baseName.toLowerCase().endsWith(".nsf") ? baseName.substring(0, baseName.length() - 4) : baseName;
places_ = places;
server_ = server == null ? "" : server;
dbdirCache_.put("only", session_.getDbDirectory(server_));
serverStrategy_ = null;
}
public KeyValueStore(final Session session, final ServerStrategy serverStrategy, final String baseName, final int places) {
if (session == null)
throw new NullPointerException("session cannot be null");
if (baseName == null || baseName.length() == 0)
throw new IllegalArgumentException("baseName cannot be null or zero-length");
if (places < 1)
throw new IllegalArgumentException("places must be greater than zero");
if (serverStrategy == null)
throw new NullPointerException("serverStrategy cannot be null");
session_ = session;
baseName_ = baseName.toLowerCase().endsWith(".nsf") ? baseName.substring(0, baseName.length() - 4) : baseName;
places_ = places;
server_ = null;
serverStrategy_ = serverStrategy;
}
public void initializeDatabases() {
if (places_ > 0) {
for (int i = 0; i < pow(16, places_); i++) {
String hashChunk = Integer.toString(i, 16).toLowerCase();
while (hashChunk.length() < places_)
hashChunk = "0" + hashChunk;
String server = serverStrategy_ == null ? server_ : serverStrategy_.getServerForHashChunk(hashChunk);
DbDirectory dbdir = getDbDirectoryForHashChunk(hashChunk);
String dbName = baseName_ + "-" + hashChunk + ".nsf";
Database database = session_.getDatabase(server, dbName, true);
if (!database.isOpen()) {
database = createDatabase(dbdir, dbName);
}
dbCache_.put(dbName, database);
}
} else {
Database database = session_.getDatabase(server_, baseName_ + ".nsf");
if (!database.isOpen()) {
database = createDatabase(getDbDirectoryForHashChunk(null), baseName_ + ".nsf");
}
dbCache_.put(baseName_ + ".nsf", database);
}
}
public Object get(final String key) {
String hashKey = checksum(key, "MD5");
Database keyDB = getDatabaseForKey(hashKey);
Document keyDoc = keyDB.getDocumentWithKey(key);
return keyDoc == null ? null : keyDoc.get("Value");
}
public void put(final String key, final Object value) {
String hashKey = checksum(key, "MD5");
Database keyDB = getDatabaseForKey(hashKey);
Document keyDoc = keyDB.getDocumentWithKey(key, true);
keyDoc.replaceItemValue("Value", value);
keyDoc.save();
}
private Database getDatabaseForKey(final String hashKey) {
String hashChunk = hashKey.substring(0, places_);
String dbName = baseName_ + "-" + hashChunk + ".nsf";
if (!dbCache_.containsKey(dbName)) {
String server = serverStrategy_ == null ? server_ : serverStrategy_.getServerForHashChunk(hashChunk);
Database database = session_.getDatabase(server, dbName, true);
if (!database.isOpen()) {
DbDirectory dbdir = getDbDirectoryForHashChunk(hashChunk);
database = createDatabase(dbdir, dbName);
}
dbCache_.put(dbName, database);
}
return dbCache_.get(dbName);
}
private DbDirectory getDbDirectoryForHashChunk(final String hashChunk) {
if (server_ != null) {
return dbdirCache_.get("only");
} else {
if (!dbdirCache_.containsKey(hashChunk)) {
String server = serverStrategy_ == null ? server_ : serverStrategy_.getServerForHashChunk(hashChunk);
dbdirCache_.put(hashChunk, session_.getDbDirectory(server));
}
return dbdirCache_.get(hashChunk);
}
}
private Database createDatabase(final DbDirectory dbdir, final String dbName) {
Database database = dbdir.createDatabase(dbName, true);
database.createView();
database.setOption(Database.DBOption.LZ1, true);
database.setOption(Database.DBOption.COMPRESSDESIGN, true);
database.setOption(Database.DBOption.COMPRESSDOCUMENTS, true);
database.setOption(Database.DBOption.NOUNREAD, true);
return database;
}
}