DatabaseList.java
/*
* Copyright 2021 Gregory Graham.
*
* Commercial licenses are available, please contact info@gregs.co.nz for details.
*
* This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
* or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
*
* You are free to:
* Share - copy and redistribute the material in any medium or format
* Adapt - remix, transform, and build upon the material
*
* The licensor cannot revoke these freedoms as long as you follow the license terms.
* Under the following terms:
*
* Attribution -
* You must give appropriate credit, provide a link to the license, and indicate if changes were made.
* You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
* NonCommercial -
* You may not use the material for commercial purposes.
* ShareAlike -
* If you remix, transform, or build upon the material,
* you must distribute your contributions under the same license as the original.
* No additional restrictions -
* You may not apply legal terms or technological measures that legally restrict others from doing anything the
* license permits.
*
* Check the Creative Commons website for any details, legalese, and updates.
*/
package nz.co.gregs.dbvolution.internal.database;
import java.io.Serializable;
import java.util.*;
import nz.co.gregs.dbvolution.databases.DBDatabase;
import nz.co.gregs.dbvolution.databases.DBDatabaseCluster;
import static nz.co.gregs.dbvolution.databases.DBDatabaseCluster.Status.*;
/**
*
* @author gregorygraham
*/
public class DatabaseList implements Serializable {
private static final long serialVersionUID = 1L;
/* TODO combine these into one list of a data object */
private final Map<String, DBDatabase> databaseMap = Collections.synchronizedMap(new HashMap<String, DBDatabase>());
private final Map<String, DBDatabaseCluster.Status> statusMap = Collections.synchronizedMap(new HashMap<String, DBDatabaseCluster.Status>(0));
private final Map<String, Integer> quarantineCountMap = Collections.synchronizedMap(new HashMap<String, Integer>(0));
public synchronized int size() {
return databaseMap.size();
}
public synchronized boolean isEmpty() {
return databaseMap.isEmpty();
}
public synchronized boolean contains(Object o) {
if (o instanceof DBDatabase) {
DBDatabase db = (DBDatabase) o;
return databaseMap.containsKey(getKey(db));
} else {
return false;
}
}
public synchronized Iterator<DBDatabase> iterator() {
return databaseMap.values().iterator();
}
public synchronized DBDatabase[] toArray() {
return toArray(new DBDatabase[]{});
}
public synchronized DBDatabase[] toArray(DBDatabase[] a) {
return databaseMap.values().toArray(a);
}
public synchronized final boolean add(DBDatabase e) {
databaseMap.put(getKey(e), e);
statusMap.put(getKey(e), UNSYNCHRONISED);
return true;
}
public synchronized boolean remove(DBDatabase e) {
databaseMap.remove(getKey(e));
statusMap.remove(getKey(e));
return true;
}
public boolean containsAll(Collection<DBDatabase> c) {
boolean allAreInTheMap = c
.stream()
.allMatch(t -> databaseMap.containsKey(getKey(t))
);
return allAreInTheMap;
}
public boolean addAll(Collection<? extends DBDatabase> collectionOfDatabases) {
for (DBDatabase dBDatabase : collectionOfDatabases) {
this.add(dBDatabase);
}
return true;
}
public boolean addAll(int index, Collection<? extends DBDatabase> c) {
return addAll(c);
}
public boolean removeAll(Collection<DBDatabase> collectionOfDatabases) {
for (DBDatabase db : collectionOfDatabases) {
remove(db);
}
return true;
}
private String getKey(DBDatabase db) {
return db.getSettings().encode();
}
public DatabaseList() {
}
public DatabaseList(DBDatabase firstDB, DBDatabase... databases) {
add(firstDB);
for (var db : databases) {
add(db);
}
}
private synchronized void set(DBDatabase db, DBDatabaseCluster.Status status) {
if (statusMap.containsKey(getKey(db))) {
statusMap.put(getKey(db), status);
if (QUARANTINED.equals(status)) {
incrementQuarantineCount(db);
}
if (READY.equals(status)) {
clearQuarantineCount(db);
}
}
}
public void setReady(DBDatabase db) {
set(db, READY);
}
public void setUnsynchronised(DBDatabase db) {
set(db, UNSYNCHRONISED);
}
public void setPaused(DBDatabase db) {
set(db, PAUSED);
}
public void setDead(DBDatabase db) {
set(db, DEAD);
}
public void setQuarantined(DBDatabase db) {
set(db, QUARANTINED);
}
public void setUnknown(DBDatabase db) {
set(db, UNKNOWN);
}
public void setProcessing(DBDatabase db) {
set(db, PROCESSING);
}
public void setSynchronising(DBDatabase db) {
set(db, SYNCHRONIZING);
}
public synchronized DBDatabase[] getDatabases() {
return databaseMap.values().toArray(new DBDatabase[0]);
}
public synchronized DBDatabaseCluster.Status getStatusOf(DBDatabase statusOfThisDatabase) {
return statusMap.getOrDefault(getKey(statusOfThisDatabase), UNKNOWN);
}
public synchronized boolean isReady(DBDatabase database) {
return statusMap.getOrDefault(getKey(database), UNKNOWN).equals(READY);
}
public synchronized DBDatabase[] getDatabases(DBDatabaseCluster.Status... statuses) {
List<DBDatabase> found = new ArrayList<>(0);
for (Map.Entry<String, DBDatabaseCluster.Status> entry : statusMap.entrySet()) {
String key = entry.getKey();
DBDatabaseCluster.Status val = entry.getValue();
for (DBDatabaseCluster.Status status : statuses) {
if (val.equals(status)) {
DBDatabase db = databaseMap.get(key);
found.add(db);
}
}
}
DBDatabase[] array = found.toArray(new DBDatabase[]{});
return array;
}
public synchronized long countReadyDatabases() {
return countDatabases(READY);
}
public synchronized long countPausedDatabases() {
return statusMap.values().stream().filter(t -> t.equals(PAUSED)).count();
}
public synchronized long countDatabases(DBDatabaseCluster.Status... statuses) {
return getDatabases(statuses).length;
}
public void clear() {
statusMap.clear();
databaseMap.clear();
}
public synchronized boolean areAllReady() {
return countDatabases(DBDatabaseCluster.Status.READY) == databaseMap.size();
}
private void incrementQuarantineCount(DBDatabase db) {
String key = getKey(db);
Integer currentValue = quarantineCountMap.get(key);
quarantineCountMap.put(key, currentValue + 1);
}
private void clearQuarantineCount(DBDatabase db) {
String key = getKey(db);
quarantineCountMap.put(key, 0);
}
public boolean isDead(DBDatabase db) {
if (DEAD.equals(getStatusOf(db))) {
return true;
}
String key = getKey(db);
Integer currentValue = quarantineCountMap.get(key);
if(currentValue >= 3){
setDead(db);
return true;
}
return false;
}
}