/*
* Password Management Servlets (PWM)
* http://www.pwm-project.org
*
* Copyright (c) 2006-2009 Novell, Inc.
* Copyright (c) 2009-2017 The PWM Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package password.pwm.util.localdb;
import password.pwm.util.java.ClosableIterator;
import java.io.File;
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.Map;
/**
* A lightweight interface for DB interaction. Implementations may be backed by an embedded database, an RDBMS or
* even a simple hashmap in memory.
* <p/>
* Implementations are required to implement a simplistic locking policy, where any method marked with {@link LocalDB.WriteOperation}
* must block until any outstanding write or read methods are completed. That is, concurrency is allowed for reads, but
* writes are gaurenteed to be single threaded.
*
* @author Jason D. Rivard
*/
public interface LocalDB {
// -------------------------- OTHER METHODS --------------------------
int MAX_KEY_LENGTH = 256;
int MAX_VALUE_LENGTH = 1024 * 100;
enum Status {
NEW, OPEN, CLOSED
}
@WriteOperation
void close()
throws LocalDBException;
@ReadOperation
boolean contains(DB db, String key)
throws LocalDBException;
@ReadOperation
String get(DB db, String key)
throws LocalDBException;
LocalDBIterator<String> iterator(DB db)
throws LocalDBException;
@WriteOperation
void putAll(DB db, Map<String, String> keyValueMap)
throws LocalDBException;
Status status();
/**
* Put a key/value into a database. This operation inserts a new key/value pair
* into the specified database. If the key already exists in the database, then
* the value is replaced.
*
* @param db database to perform the operation on
* @param key key value
* @param value string value
* @return true if the key previously existed
* @throws LocalDBException if there is an error writing to the store
* @throws NullPointerException if the db, key or value is null
* @throws IllegalArgumentException if the key is zero length, the key is larger than {@link #MAX_KEY_LENGTH} or the value is larger than {@link #MAX_VALUE_LENGTH}
*/
@WriteOperation
boolean put(DB db, String key, String value)
throws LocalDBException;
@WriteOperation
boolean remove(DB db, String key)
throws LocalDBException;
@WriteOperation
void removeAll(DB db, Collection<String> key)
throws LocalDBException;
@ReadOperation
int size(DB db)
throws LocalDBException;
@WriteOperation
void truncate(DB db)
throws LocalDBException;
File getFileLocation();
Map<String,Serializable> debugInfo();
// -------------------------- ENUMERATIONS --------------------------
enum DB {
/**
* Used for various pwm operational data
*/
PWM_META(true),
SHAREDHISTORY_META(true),
SHAREDHISTORY_WORDS(true),
// WORDLIST_META(true), // @deprecated
WORDLIST_WORDS(true),
// SEEDLIST_META(true), // @deprecated
SEEDLIST_WORDS(true),
PWM_STATS(true),
EVENTLOG_EVENTS(true),
EMAIL_QUEUE(true),
SMS_QUEUE(true),
RESPONSE_STORAGE(true),
OTP_SECRET(true),
TOKENS(true),
INTRUDER(true),
AUDIT_EVENTS(true),
USER_CACHE(true),
TEMP(false),
SYSLOG_QUEUE(true),
CACHE(false),
REPORT_QUEUE(false),
;
private final boolean backup;
DB(final boolean backup) {
this.backup = backup;
}
public boolean isBackup() {
return backup;
}
}
// -------------------------- INNER CLASSES --------------------------
@Retention(RetentionPolicy.RUNTIME)
@interface
ReadOperation {
}
@Retention(RetentionPolicy.RUNTIME)
@interface
WriteOperation {
}
interface LocalDBIterator<K> extends ClosableIterator<String> {
}
class TransactionItem implements Serializable, Comparable {
private final DB db;
private final String key;
private final String value;
public TransactionItem(final DB db, final String key, final String value) {
if (key == null || value == null || db == null) {
throw new IllegalArgumentException("db, key or value can not be null");
}
this.db = db;
this.key = key;
this.value = value;
}
public DB getDb() {
return db;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return "db=" + db + ", key=" + key + ", value=" + value;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final TransactionItem that = (TransactionItem) o;
return db == that.db && key.equals(that.key) && value.equals(that.value);
}
@Override
public int hashCode() {
int result;
result = db.hashCode();
result = 31 * result + key.hashCode();
result = 31 * result + value.hashCode();
return result;
}
@Override
public int compareTo(final Object o) {
if (!(o instanceof TransactionItem)) {
throw new IllegalArgumentException("can only compare same object type");
}
int result = db.compareTo(db);
if (result == 0) {
result = getKey().compareTo(((TransactionItem) o).getKey());
if (result == 0) {
result = getValue().compareTo(((TransactionItem) o).getValue());
}
}
return result;
}
}
}