Add Data and Sync managers to manage Everest's data and move HistoryManager into SQLiteManager

This commit is contained in:
Rohit Awate 2018-08-15 18:45:36 +05:30
parent 2d0cf380a7
commit 7b631a019b
No known key found for this signature in database
GPG key ID: 1051D7B79CF2EE25
18 changed files with 217 additions and 116 deletions

View file

@ -15,7 +15,6 @@
*/ */
package com.rohitawate.everest; package com.rohitawate.everest;
import com.rohitawate.everest.misc.Services;
import com.rohitawate.everest.misc.ThemeManager; import com.rohitawate.everest.misc.ThemeManager;
import com.rohitawate.everest.settings.SettingsLoader; import com.rohitawate.everest.settings.SettingsLoader;
import javafx.application.Application; import javafx.application.Application;
@ -35,7 +34,6 @@ public class Main extends Application {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HomeWindow.fxml")); FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HomeWindow.fxml"));
Parent homeWindow = loader.load(); Parent homeWindow = loader.load();
Services.homeWindowController = loader.getController();
Stage dashboardStage = new Stage(); Stage dashboardStage = new Stage();
ThemeManager.setTheme(homeWindow); ThemeManager.setTheme(homeWindow);

View file

@ -27,7 +27,6 @@ import com.rohitawate.everest.exceptions.RedirectException;
import com.rohitawate.everest.format.FormatterFactory; import com.rohitawate.everest.format.FormatterFactory;
import com.rohitawate.everest.logging.LoggingService; import com.rohitawate.everest.logging.LoggingService;
import com.rohitawate.everest.misc.EverestUtilities; import com.rohitawate.everest.misc.EverestUtilities;
import com.rohitawate.everest.misc.Services;
import com.rohitawate.everest.misc.ThemeManager; import com.rohitawate.everest.misc.ThemeManager;
import com.rohitawate.everest.models.requests.DELETERequest; import com.rohitawate.everest.models.requests.DELETERequest;
import com.rohitawate.everest.models.requests.DataRequest; import com.rohitawate.everest.models.requests.DataRequest;
@ -39,6 +38,7 @@ import com.rohitawate.everest.requestmanager.RequestManagersPool;
import com.rohitawate.everest.state.ComposerState; import com.rohitawate.everest.state.ComposerState;
import com.rohitawate.everest.state.DashboardState; import com.rohitawate.everest.state.DashboardState;
import com.rohitawate.everest.state.FieldState; import com.rohitawate.everest.state.FieldState;
import com.rohitawate.everest.sync.SyncManager;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
@ -310,7 +310,7 @@ public class DashboardController implements Initializable {
cancelButton.setOnAction(e -> requestManager.cancel()); cancelButton.setOnAction(e -> requestManager.cancel());
requestManager.addHandlers(this::whileRunning, this::onSucceeded, this::onFailed, this::onCancelled); requestManager.addHandlers(this::whileRunning, this::onSucceeded, this::onFailed, this::onCancelled);
requestManager.start(); requestManager.start();
Services.historyManager.saveHistory(getState().composer); SyncManager.saveState(getState().composer);
} catch (MalformedURLException MURLE) { } catch (MalformedURLException MURLE) {
showLayer(ResponseLayer.PROMPT); showLayer(ResponseLayer.PROMPT);
snackbar.show("Invalid address. Please verify and try again.", 3000); snackbar.show("Invalid address. Please verify and try again.", 3000);
@ -589,6 +589,7 @@ public class DashboardController implements Initializable {
previousController.isValueFieldEmpty()) { previousController.isValueFieldEmpty()) {
previousController.setKeyField(key); previousController.setKeyField(key);
previousController.setValueField(value); previousController.setValueField(value);
previousController.setChecked(checked);
/* /*
For when the last field is loaded from setState. For when the last field is loaded from setState.

View file

@ -82,6 +82,7 @@ public class FormDataTabController implements Initializable {
previousController.isFileValueFieldEmpty()) { previousController.isFileValueFieldEmpty()) {
previousController.setFileKeyField(key); previousController.setFileKeyField(key);
previousController.setFileValueField(value); previousController.setFileValueField(value);
previousController.setChecked(checked);
/* /*
For when the last field is loaded from setState. For when the last field is loaded from setState.
@ -139,6 +140,7 @@ public class FormDataTabController implements Initializable {
previousController.isValueFieldEmpty()) { previousController.isValueFieldEmpty()) {
previousController.setKeyField(key); previousController.setKeyField(key);
previousController.setValueField(value); previousController.setValueField(value);
previousController.setChecked(checked);
/* /*
For when the last field is loaded from setState. For when the last field is loaded from setState.

View file

@ -74,6 +74,7 @@ public class HeaderTabController implements Initializable {
previousController.isValueFieldEmpty()) { previousController.isValueFieldEmpty()) {
previousController.setKeyField(key); previousController.setKeyField(key);
previousController.setValueField(value); previousController.setValueField(value);
previousController.setChecked(checked);
/* /*
For when the last field is loaded from setState. For when the last field is loaded from setState.

View file

@ -17,8 +17,8 @@
package com.rohitawate.everest.controllers; package com.rohitawate.everest.controllers;
import com.rohitawate.everest.controllers.search.SearchablePaneController; import com.rohitawate.everest.controllers.search.SearchablePaneController;
import com.rohitawate.everest.misc.Services;
import com.rohitawate.everest.state.ComposerState; import com.rohitawate.everest.state.ComposerState;
import com.rohitawate.everest.sync.SyncManager;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.input.MouseButton; import javafx.scene.input.MouseButton;
@ -34,7 +34,7 @@ public class HistoryPaneController extends SearchablePaneController<ComposerStat
@Override @Override
protected List<ComposerState> loadInitialEntries() { protected List<ComposerState> loadInitialEntries() {
return Services.historyManager.getHistory(); return SyncManager.getHistory();
} }
protected SearchEntry<ComposerState> createEntryFromState(ComposerState state) throws IOException { protected SearchEntry<ComposerState> createEntryFromState(ComposerState state) throws IOException {

View file

@ -24,6 +24,7 @@ import com.rohitawate.everest.misc.ThemeManager;
import com.rohitawate.everest.models.requests.HTTPConstants; import com.rohitawate.everest.models.requests.HTTPConstants;
import com.rohitawate.everest.state.ComposerState; import com.rohitawate.everest.state.ComposerState;
import com.rohitawate.everest.state.DashboardState; import com.rohitawate.everest.state.DashboardState;
import com.rohitawate.everest.sync.SyncManager;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
@ -63,6 +64,8 @@ public class HomeWindowController implements Initializable {
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
new SyncManager(this);
try { try {
FXMLLoader historyLoader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HistoryPane.fxml")); FXMLLoader historyLoader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HistoryPane.fxml"));
Parent historyFXML = historyLoader.load(); Parent historyFXML = historyLoader.load();

View file

@ -74,6 +74,7 @@ public class URLTabController implements Initializable {
previousController.isValueFieldEmpty()) { previousController.isValueFieldEmpty()) {
previousController.setKeyField(key); previousController.setKeyField(key);
previousController.setValueField(value); previousController.setValueField(value);
previousController.setChecked(checked);
/* /*
For when the last field is loaded from setState. For when the last field is loaded from setState.

View file

@ -1,6 +1,6 @@
package com.rohitawate.everest.controllers.codearea.highlighters; package com.rohitawate.everest.controllers.codearea.highlighters;
import com.rohitawate.everest.exceptions.DuplicateHighlighterException; import com.rohitawate.everest.exceptions.DuplicateException;
import com.rohitawate.everest.models.requests.HTTPConstants; import com.rohitawate.everest.models.requests.HTTPConstants;
import java.util.HashMap; import java.util.HashMap;
@ -35,12 +35,12 @@ public class HighlighterFactory {
* *
* @param name The display name for the Highlighter. * @param name The display name for the Highlighter.
* @param highlighter The Highlighter object * @param highlighter The Highlighter object
* @throws DuplicateHighlighterException If a Highlighter is already loaded by Everest with the same name. * @throws DuplicateException If a Highlighter is already loaded by Everest with the same name.
*/ */
public static void addHighlighter(String name, Highlighter highlighter) public static void addHighlighter(String name, Highlighter highlighter)
throws DuplicateHighlighterException { throws DuplicateException {
if (highlighters.containsKey(name)) { if (highlighters.containsKey(name)) {
throw new DuplicateHighlighterException("Highlighter already exists for the following type: " + name); throw new DuplicateException("Highlighter already exists for the following type: " + name);
} }
highlighters.put(name, highlighter); highlighters.put(name, highlighter);

View file

@ -0,0 +1,7 @@
package com.rohitawate.everest.exceptions;
public class DuplicateException extends Exception {
public DuplicateException(String message) {
super(message);
}
}

View file

@ -1,7 +0,0 @@
package com.rohitawate.everest.exceptions;
public class DuplicateFormatterException extends Exception {
public DuplicateFormatterException(String message) {
super(message);
}
}

View file

@ -1,7 +0,0 @@
package com.rohitawate.everest.exceptions;
public class DuplicateHighlighterException extends Exception {
public DuplicateHighlighterException(String message) {
super(message);
}
}

View file

@ -1,7 +1,6 @@
package com.rohitawate.everest.format; package com.rohitawate.everest.format;
import com.rohitawate.everest.exceptions.DuplicateFormatterException; import com.rohitawate.everest.exceptions.DuplicateException;
import com.rohitawate.everest.exceptions.DuplicateHighlighterException;
import com.rohitawate.everest.models.requests.HTTPConstants; import com.rohitawate.everest.models.requests.HTTPConstants;
import java.util.HashMap; import java.util.HashMap;
@ -30,12 +29,12 @@ public class FormatterFactory {
* *
* @param name The display name for the Formatter. * @param name The display name for the Formatter.
* @param formatter The Formatter object. * @param formatter The Formatter object.
* @throws DuplicateHighlighterException If a Formatter is already loaded by Everest with the same name. * @throws DuplicateException If a Formatter is already loaded by Everest with the same name.
*/ */
public static void addFormatter(String name, Formatter formatter) public static void addFormatter(String name, Formatter formatter)
throws DuplicateFormatterException { throws DuplicateException {
if (formatters.containsKey(name)) { if (formatters.containsKey(name)) {
throw new DuplicateFormatterException("Formatter already exists for the following type: " + name); throw new DuplicateException("Formatter already exists for the following type: " + name);
} }
formatters.put(name, formatter); formatters.put(name, formatter);

View file

@ -17,18 +17,13 @@
package com.rohitawate.everest.misc; package com.rohitawate.everest.misc;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.rohitawate.everest.controllers.HomeWindowController;
import com.rohitawate.everest.history.HistoryManager;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
public class Services { public class Services {
public static HistoryManager historyManager;
public static HomeWindowController homeWindowController;
public static Executor singleExecutor; public static Executor singleExecutor;
static { static {
historyManager = new HistoryManager();
singleExecutor = MoreExecutors.directExecutor(); singleExecutor = MoreExecutors.directExecutor();
} }
} }

View file

@ -185,7 +185,7 @@ public class RequestManager extends Service<EverestResponse> {
private Invocation appendBody(DataRequest dataRequest) throws Exception { private Invocation appendBody(DataRequest dataRequest) throws Exception {
/* /*
Checks if a custom mime-type is mentioned in the headers. Checks if a custom mime-type is mentioned in the headers.
If present, it will override the logical Content-Type. If present, it will override the auto-determined one.
*/ */
String overriddenContentType = request.getHeaders().get("Content-Type"); String overriddenContentType = request.getHeaders().get("Content-Type");
Invocation invocation = null; Invocation invocation = null;
@ -198,8 +198,8 @@ public class RequestManager extends Service<EverestResponse> {
// Adding the string tuples to the request // Adding the string tuples to the request
HashMap<String, String> pairs = dataRequest.getStringTuples(); HashMap<String, String> pairs = dataRequest.getStringTuples();
for (Map.Entry entry : pairs.entrySet()) { for (Map.Entry<String, String> entry : pairs.entrySet()) {
mapEntry = (Map.Entry) entry; mapEntry = entry;
formData.field(mapEntry.getKey(), mapEntry.getValue()); formData.field(mapEntry.getKey(), mapEntry.getValue());
} }
@ -210,8 +210,8 @@ public class RequestManager extends Service<EverestResponse> {
pairs = dataRequest.getFileTuples(); pairs = dataRequest.getFileTuples();
// Adding the file tuples to the request // Adding the file tuples to the request
for (Map.Entry entry : pairs.entrySet()) { for (Map.Entry<String, String> entry : pairs.entrySet()) {
mapEntry = (Map.Entry) entry; mapEntry = entry;
filePath = mapEntry.getValue(); filePath = mapEntry.getValue();
file = new File(filePath); file = new File(filePath);
@ -258,8 +258,8 @@ public class RequestManager extends Service<EverestResponse> {
Form form = new Form(); Form form = new Form();
for (Map.Entry entry : dataRequest.getStringTuples().entrySet()) { for (Map.Entry<String, String> entry : dataRequest.getStringTuples().entrySet()) {
mapEntry = (Map.Entry) entry; mapEntry = entry;
form.param(mapEntry.getKey(), mapEntry.getValue()); form.param(mapEntry.getKey(), mapEntry.getValue());
} }

View file

@ -32,4 +32,6 @@ public class Settings {
public static int showHistoryRange = 7; public static int showHistoryRange = 7;
public static boolean editorWrapText = true; public static boolean editorWrapText = true;
public static String fetchSource = "SQLite";
} }

View file

@ -0,0 +1,28 @@
package com.rohitawate.everest.sync;
import com.rohitawate.everest.state.ComposerState;
import java.util.List;
/**
* Manages the history and (in the future) the projects of Everest.
*/
public interface DataManager {
/**
* Saves the state of the Composer when the request was made.
*/
void saveState(ComposerState newState);
/**
* Fetches all the states of the Composer when the previous requests were made.
*
* @return A list of the states.
*/
List<ComposerState> getHistory();
/**
* Returns the identifier for the DataManager. Preferably, use the source as the identifier.
* For example, a DataManager using Google Drive may identify itself as 'Google Drive'.
*/
String getIdentifier();
}

View file

@ -14,10 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.rohitawate.everest.history; package com.rohitawate.everest.sync;
import com.rohitawate.everest.logging.LoggingService; import com.rohitawate.everest.logging.LoggingService;
import com.rohitawate.everest.misc.Services;
import com.rohitawate.everest.models.requests.HTTPConstants; import com.rohitawate.everest.models.requests.HTTPConstants;
import com.rohitawate.everest.settings.Settings; import com.rohitawate.everest.settings.Settings;
import com.rohitawate.everest.state.ComposerState; import com.rohitawate.everest.state.ComposerState;
@ -31,10 +30,9 @@ import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class HistoryManager { class SQLiteManager implements DataManager {
private Connection conn; private Connection conn;
private PreparedStatement statement; private PreparedStatement statement;
private HistorySaver historySaver = new HistorySaver();
private static class Queries { private static class Queries {
private static final String[] createQueries = { private static final String[] createQueries = {
@ -58,7 +56,7 @@ public class HistoryManager {
private static final String selectMostRecentRequest = "SELECT * FROM Requests ORDER BY ID DESC LIMIT 1"; private static final String selectMostRecentRequest = "SELECT * FROM Requests ORDER BY ID DESC LIMIT 1";
} }
public HistoryManager() { public SQLiteManager() {
try { try {
File configFolder = new File("Everest/config/"); File configFolder = new File("Everest/config/");
if (!configFolder.exists()) if (!configFolder.exists())
@ -67,7 +65,7 @@ public class HistoryManager {
conn = DriverManager.getConnection("jdbc:sqlite:Everest/config/history.sqlite"); conn = DriverManager.getConnection("jdbc:sqlite:Everest/config/history.sqlite");
createDatabase(); createDatabase();
} catch (Exception E) { } catch (Exception E) {
LoggingService.logSevere("Exception while initializing HistoryManager.", E, LocalDateTime.now()); LoggingService.logSevere("Exception while initializing DataManager.", E, LocalDateTime.now());
} finally { } finally {
System.out.println("Connected to database."); System.out.println("Connected to database.");
} }
@ -89,21 +87,63 @@ public class HistoryManager {
* *
* @param newState - The state of the Dashboard while making the request. * @param newState - The state of the Dashboard while making the request.
*/ */
public synchronized void saveHistory(ComposerState newState) { @Override
public synchronized void saveState(ComposerState newState) {
ComposerState lastState = getLastRequest(); ComposerState lastState = getLastRequest();
if (newState.equals(lastState)) if (newState.equals(lastState))
return; return;
historySaver.state = newState; try {
Services.singleExecutor.execute(historySaver); statement =
conn.prepareStatement(Queries.saveRequest);
// Appends this history item to the HistoryTab statement.setString(1, newState.httpMethod);
Services.homeWindowController.addHistoryItem(newState); statement.setString(2, newState.target);
statement.setString(3, LocalDate.now().toString());
statement.executeUpdate();
// Get latest RequestID to insert into Headers table
statement = conn.prepareStatement("SELECT MAX(ID) AS MaxID FROM Requests");
ResultSet RS = statement.executeQuery();
int requestID = -1;
if (RS.next())
requestID = RS.getInt("MaxID");
saveTuple(newState.headers, "Header", requestID);
saveTuple(newState.params, "Param", requestID);
if (!(newState.httpMethod.equals(HTTPConstants.GET) || newState.httpMethod.equals(HTTPConstants.DELETE))) {
// Maps the request to its ContentType for faster retrieval
statement = conn.prepareStatement(Queries.saveRequestContentPair);
statement.setInt(1, requestID);
statement.setString(2, newState.contentType);
statement.executeUpdate();
statement = conn.prepareStatement(Queries.saveBody);
statement.setInt(1, requestID);
statement.setString(2, newState.rawBody);
statement.setString(3, newState.rawBodyBoxValue);
statement.executeUpdate();
statement = conn.prepareStatement(Queries.saveFilePath);
statement.setInt(1, requestID);
statement.setString(2, newState.binaryFilePath);
statement.executeUpdate();
saveTuple(newState.urlStringTuples, "URLString", requestID);
saveTuple(newState.formStringTuples, "FormString", requestID);
saveTuple(newState.formFileTuples, "File", requestID);
}
} catch (SQLException e) {
LoggingService.logWarning("Database error.", e, LocalDateTime.now());
}
} }
/** /**
* Returns a list of all the recent requests. * Returns a list of all the recent requests.
*/ */
@Override
public synchronized List<ComposerState> getHistory() { public synchronized List<ComposerState> getHistory() {
List<ComposerState> history = new ArrayList<>(); List<ComposerState> history = new ArrayList<>();
try { try {
@ -257,75 +297,27 @@ public class HistoryManager {
return null; return null;
} }
private class HistorySaver implements Runnable { private void saveTuple(ArrayList<FieldState> tuples, String tupleType, int requestID) {
private ComposerState state; if (tuples.size() > 0) {
@Override
public void run() {
try { try {
statement = for (FieldState fieldState : tuples) {
conn.prepareStatement(Queries.saveRequest); statement = conn.prepareStatement(Queries.saveTuple);
statement.setString(1, state.httpMethod);
statement.setString(2, state.target);
statement.setString(3, LocalDate.now().toString());
statement.executeUpdate();
// Get latest RequestID to insert into Headers table
statement = conn.prepareStatement("SELECT MAX(ID) AS MaxID FROM Requests");
ResultSet RS = statement.executeQuery();
int requestID = -1;
if (RS.next())
requestID = RS.getInt("MaxID");
saveTuple(state.headers, "Header", requestID);
saveTuple(state.params, "Param", requestID);
if (!(state.httpMethod.equals(HTTPConstants.GET) || state.httpMethod.equals(HTTPConstants.DELETE))) {
// Maps the request to its ContentType for faster retrieval
statement = conn.prepareStatement(Queries.saveRequestContentPair);
statement.setInt(1, requestID); statement.setInt(1, requestID);
statement.setString(2, state.contentType); statement.setString(2, tupleType);
statement.executeUpdate(); statement.setString(3, fieldState.key);
statement.setString(4, fieldState.value);
statement = conn.prepareStatement(Queries.saveBody); statement.setInt(5, fieldState.checked ? 1 : 0);
statement.setInt(1, requestID); statement.addBatch();
statement.setString(2, state.rawBody);
statement.setString(3, state.rawBodyBoxValue);
statement.executeUpdate();
statement = conn.prepareStatement(Queries.saveFilePath);
statement.setInt(1, requestID);
statement.setString(2, state.binaryFilePath);
statement.executeUpdate();
saveTuple(state.urlStringTuples, "URLString", requestID);
saveTuple(state.formStringTuples, "FormString", requestID);
saveTuple(state.formFileTuples, "File", requestID);
} }
statement.executeBatch();
} catch (SQLException e) { } catch (SQLException e) {
LoggingService.logWarning("Database error.", e, LocalDateTime.now()); LoggingService.logSevere("Database error.", e, LocalDateTime.now());
}
}
private void saveTuple(ArrayList<FieldState> tuples, String tupleType, int requestID) {
if (tuples.size() > 0) {
try {
for (FieldState fieldState : tuples) {
statement = conn.prepareStatement(Queries.saveTuple);
statement.setInt(1, requestID);
statement.setString(2, tupleType);
statement.setString(3, fieldState.key);
statement.setString(4, fieldState.value);
statement.setInt(5, fieldState.checked ? 1 : 0);
statement.addBatch();
}
statement.executeBatch();
} catch (SQLException e) {
LoggingService.logSevere("Database error.", e, LocalDateTime.now());
}
} }
} }
} }
@Override
public String getIdentifier() {
return "SQLite";
}
} }

View file

@ -0,0 +1,86 @@
package com.rohitawate.everest.sync;
import com.google.common.util.concurrent.MoreExecutors;
import com.rohitawate.everest.controllers.HomeWindowController;
import com.rohitawate.everest.exceptions.DuplicateException;
import com.rohitawate.everest.logging.LoggingService;
import com.rohitawate.everest.settings.Settings;
import com.rohitawate.everest.state.ComposerState;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Manages all the DataManagers of Everest and registers new ones.
* Registers Everest's default SQLiteManager automatically.
*/
public class SyncManager {
private static HashMap<String, DataManager> managers;
private static HomeWindowController homeWindowController;
private static Executor executor = MoreExecutors.directExecutor();
private static HistorySaver historySaver;
/**
* @param homeWindowController - to add a HistoryItem by invoking addHistoryItem()
*/
public SyncManager(HomeWindowController homeWindowController) {
SyncManager.homeWindowController = homeWindowController;
managers = new HashMap<>();
historySaver = new HistorySaver();
// Registering the default
try {
registerManager(new SQLiteManager());
} catch (DuplicateException e) {
System.out.println("SQLite Manager already exists: Nope, will never happen.");
}
}
/**
* Asynchronously saves the new state by invoking all the registered DataManagers.
*/
public static void saveState(ComposerState newState) {
historySaver.newState = newState;
executor.execute(historySaver);
homeWindowController.addHistoryItem(newState);
}
/**
* Retrieves the history from the configured source.
*
* @return A list of all the requests
*/
public static List<ComposerState> getHistory() {
if (managers.get(Settings.fetchSource) == null) {
LoggingService.logSevere("No such source found: " + Settings.fetchSource, null, LocalDateTime.now());
return managers.get("SQLite").getHistory();
} else {
return managers.get(Settings.fetchSource).getHistory();
}
}
/**
* Registers a new DataManager to be used for syncing Everest's data
* at various sources.
*/
public static void registerManager(DataManager newManager) throws DuplicateException {
if (managers.containsKey(newManager.getIdentifier()))
throw new DuplicateException(
"Duplicate DataManager: Manager with identifier \'" + newManager.getIdentifier() + "\' already exists.");
else
managers.put(newManager.getIdentifier(), newManager);
}
private static class HistorySaver implements Runnable {
private ComposerState newState;
@Override
public void run() {
for (DataManager manager : managers.values())
manager.saveState(newState);
}
}
}