diff --git a/src/main/java/com/rohitawate/everest/Main.java b/src/main/java/com/rohitawate/everest/Main.java index a58a16e..1d24981 100644 --- a/src/main/java/com/rohitawate/everest/Main.java +++ b/src/main/java/com/rohitawate/everest/Main.java @@ -15,7 +15,6 @@ */ package com.rohitawate.everest; -import com.rohitawate.everest.misc.Services; import com.rohitawate.everest.misc.ThemeManager; import com.rohitawate.everest.settings.SettingsLoader; import javafx.application.Application; @@ -35,7 +34,6 @@ public class Main extends Application { FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HomeWindow.fxml")); Parent homeWindow = loader.load(); - Services.homeWindowController = loader.getController(); Stage dashboardStage = new Stage(); ThemeManager.setTheme(homeWindow); diff --git a/src/main/java/com/rohitawate/everest/controllers/DashboardController.java b/src/main/java/com/rohitawate/everest/controllers/DashboardController.java index c2d6e05..407b03f 100644 --- a/src/main/java/com/rohitawate/everest/controllers/DashboardController.java +++ b/src/main/java/com/rohitawate/everest/controllers/DashboardController.java @@ -27,7 +27,6 @@ import com.rohitawate.everest.exceptions.RedirectException; import com.rohitawate.everest.format.FormatterFactory; import com.rohitawate.everest.logging.LoggingService; import com.rohitawate.everest.misc.EverestUtilities; -import com.rohitawate.everest.misc.Services; import com.rohitawate.everest.misc.ThemeManager; import com.rohitawate.everest.models.requests.DELETERequest; 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.DashboardState; import com.rohitawate.everest.state.FieldState; +import com.rohitawate.everest.sync.SyncManager; import javafx.beans.binding.Bindings; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; @@ -310,7 +310,7 @@ public class DashboardController implements Initializable { cancelButton.setOnAction(e -> requestManager.cancel()); requestManager.addHandlers(this::whileRunning, this::onSucceeded, this::onFailed, this::onCancelled); requestManager.start(); - Services.historyManager.saveHistory(getState().composer); + SyncManager.saveState(getState().composer); } catch (MalformedURLException MURLE) { showLayer(ResponseLayer.PROMPT); snackbar.show("Invalid address. Please verify and try again.", 3000); @@ -589,6 +589,7 @@ public class DashboardController implements Initializable { previousController.isValueFieldEmpty()) { previousController.setKeyField(key); previousController.setValueField(value); + previousController.setChecked(checked); /* For when the last field is loaded from setState. diff --git a/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java b/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java index 385d1b1..082b04a 100644 --- a/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java @@ -82,6 +82,7 @@ public class FormDataTabController implements Initializable { previousController.isFileValueFieldEmpty()) { previousController.setFileKeyField(key); previousController.setFileValueField(value); + previousController.setChecked(checked); /* For when the last field is loaded from setState. @@ -139,6 +140,7 @@ public class FormDataTabController implements Initializable { previousController.isValueFieldEmpty()) { previousController.setKeyField(key); previousController.setValueField(value); + previousController.setChecked(checked); /* For when the last field is loaded from setState. diff --git a/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java b/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java index bc97f1f..5b317c0 100644 --- a/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java @@ -74,6 +74,7 @@ public class HeaderTabController implements Initializable { previousController.isValueFieldEmpty()) { previousController.setKeyField(key); previousController.setValueField(value); + previousController.setChecked(checked); /* For when the last field is loaded from setState. diff --git a/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java b/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java index 4ba9904..0f9075f 100644 --- a/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java +++ b/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java @@ -17,8 +17,8 @@ package com.rohitawate.everest.controllers; import com.rohitawate.everest.controllers.search.SearchablePaneController; -import com.rohitawate.everest.misc.Services; import com.rohitawate.everest.state.ComposerState; +import com.rohitawate.everest.sync.SyncManager; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.input.MouseButton; @@ -34,7 +34,7 @@ public class HistoryPaneController extends SearchablePaneController loadInitialEntries() { - return Services.historyManager.getHistory(); + return SyncManager.getHistory(); } protected SearchEntry createEntryFromState(ComposerState state) throws IOException { diff --git a/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java b/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java index ee5ac1a..1ec65a3 100644 --- a/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java +++ b/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java @@ -24,6 +24,7 @@ import com.rohitawate.everest.misc.ThemeManager; import com.rohitawate.everest.models.requests.HTTPConstants; import com.rohitawate.everest.state.ComposerState; import com.rohitawate.everest.state.DashboardState; +import com.rohitawate.everest.sync.SyncManager; import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.property.StringProperty; @@ -63,6 +64,8 @@ public class HomeWindowController implements Initializable { @Override public void initialize(URL location, ResourceBundle resources) { + new SyncManager(this); + try { FXMLLoader historyLoader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HistoryPane.fxml")); Parent historyFXML = historyLoader.load(); diff --git a/src/main/java/com/rohitawate/everest/controllers/URLTabController.java b/src/main/java/com/rohitawate/everest/controllers/URLTabController.java index 8a6bca8..218500f 100644 --- a/src/main/java/com/rohitawate/everest/controllers/URLTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/URLTabController.java @@ -74,6 +74,7 @@ public class URLTabController implements Initializable { previousController.isValueFieldEmpty()) { previousController.setKeyField(key); previousController.setValueField(value); + previousController.setChecked(checked); /* For when the last field is loaded from setState. diff --git a/src/main/java/com/rohitawate/everest/controllers/codearea/highlighters/HighlighterFactory.java b/src/main/java/com/rohitawate/everest/controllers/codearea/highlighters/HighlighterFactory.java index 6ed234b..219e388 100644 --- a/src/main/java/com/rohitawate/everest/controllers/codearea/highlighters/HighlighterFactory.java +++ b/src/main/java/com/rohitawate/everest/controllers/codearea/highlighters/HighlighterFactory.java @@ -1,6 +1,6 @@ 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 java.util.HashMap; @@ -35,12 +35,12 @@ public class HighlighterFactory { * * @param name The display name for the Highlighter. * @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) - throws DuplicateHighlighterException { + throws DuplicateException { 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); diff --git a/src/main/java/com/rohitawate/everest/exceptions/DuplicateException.java b/src/main/java/com/rohitawate/everest/exceptions/DuplicateException.java new file mode 100644 index 0000000..ac5d57d --- /dev/null +++ b/src/main/java/com/rohitawate/everest/exceptions/DuplicateException.java @@ -0,0 +1,7 @@ +package com.rohitawate.everest.exceptions; + +public class DuplicateException extends Exception { + public DuplicateException(String message) { + super(message); + } +} diff --git a/src/main/java/com/rohitawate/everest/exceptions/DuplicateFormatterException.java b/src/main/java/com/rohitawate/everest/exceptions/DuplicateFormatterException.java deleted file mode 100644 index 1084fe7..0000000 --- a/src/main/java/com/rohitawate/everest/exceptions/DuplicateFormatterException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.rohitawate.everest.exceptions; - -public class DuplicateFormatterException extends Exception { - public DuplicateFormatterException(String message) { - super(message); - } -} diff --git a/src/main/java/com/rohitawate/everest/exceptions/DuplicateHighlighterException.java b/src/main/java/com/rohitawate/everest/exceptions/DuplicateHighlighterException.java deleted file mode 100644 index 12a6d8a..0000000 --- a/src/main/java/com/rohitawate/everest/exceptions/DuplicateHighlighterException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.rohitawate.everest.exceptions; - -public class DuplicateHighlighterException extends Exception { - public DuplicateHighlighterException(String message) { - super(message); - } -} diff --git a/src/main/java/com/rohitawate/everest/format/FormatterFactory.java b/src/main/java/com/rohitawate/everest/format/FormatterFactory.java index 3015f7b..53b7f26 100644 --- a/src/main/java/com/rohitawate/everest/format/FormatterFactory.java +++ b/src/main/java/com/rohitawate/everest/format/FormatterFactory.java @@ -1,7 +1,6 @@ package com.rohitawate.everest.format; -import com.rohitawate.everest.exceptions.DuplicateFormatterException; -import com.rohitawate.everest.exceptions.DuplicateHighlighterException; +import com.rohitawate.everest.exceptions.DuplicateException; import com.rohitawate.everest.models.requests.HTTPConstants; import java.util.HashMap; @@ -30,12 +29,12 @@ public class FormatterFactory { * * @param name The display name for the Formatter. * @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) - throws DuplicateFormatterException { + throws DuplicateException { 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); diff --git a/src/main/java/com/rohitawate/everest/misc/Services.java b/src/main/java/com/rohitawate/everest/misc/Services.java index 32f0bc4..2301d37 100644 --- a/src/main/java/com/rohitawate/everest/misc/Services.java +++ b/src/main/java/com/rohitawate/everest/misc/Services.java @@ -17,18 +17,13 @@ package com.rohitawate.everest.misc; import com.google.common.util.concurrent.MoreExecutors; -import com.rohitawate.everest.controllers.HomeWindowController; -import com.rohitawate.everest.history.HistoryManager; import java.util.concurrent.Executor; public class Services { - public static HistoryManager historyManager; - public static HomeWindowController homeWindowController; public static Executor singleExecutor; static { - historyManager = new HistoryManager(); singleExecutor = MoreExecutors.directExecutor(); } } diff --git a/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java b/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java index de06349..d1560b7 100644 --- a/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java +++ b/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java @@ -185,7 +185,7 @@ public class RequestManager extends Service { private Invocation appendBody(DataRequest dataRequest) throws Exception { /* 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"); Invocation invocation = null; @@ -198,8 +198,8 @@ public class RequestManager extends Service { // Adding the string tuples to the request HashMap pairs = dataRequest.getStringTuples(); - for (Map.Entry entry : pairs.entrySet()) { - mapEntry = (Map.Entry) entry; + for (Map.Entry entry : pairs.entrySet()) { + mapEntry = entry; formData.field(mapEntry.getKey(), mapEntry.getValue()); } @@ -210,8 +210,8 @@ public class RequestManager extends Service { pairs = dataRequest.getFileTuples(); // Adding the file tuples to the request - for (Map.Entry entry : pairs.entrySet()) { - mapEntry = (Map.Entry) entry; + for (Map.Entry entry : pairs.entrySet()) { + mapEntry = entry; filePath = mapEntry.getValue(); file = new File(filePath); @@ -258,8 +258,8 @@ public class RequestManager extends Service { Form form = new Form(); - for (Map.Entry entry : dataRequest.getStringTuples().entrySet()) { - mapEntry = (Map.Entry) entry; + for (Map.Entry entry : dataRequest.getStringTuples().entrySet()) { + mapEntry = entry; form.param(mapEntry.getKey(), mapEntry.getValue()); } diff --git a/src/main/java/com/rohitawate/everest/settings/Settings.java b/src/main/java/com/rohitawate/everest/settings/Settings.java index e1ff37d..4efcfd2 100644 --- a/src/main/java/com/rohitawate/everest/settings/Settings.java +++ b/src/main/java/com/rohitawate/everest/settings/Settings.java @@ -32,4 +32,6 @@ public class Settings { public static int showHistoryRange = 7; public static boolean editorWrapText = true; + + public static String fetchSource = "SQLite"; } diff --git a/src/main/java/com/rohitawate/everest/sync/DataManager.java b/src/main/java/com/rohitawate/everest/sync/DataManager.java new file mode 100644 index 0000000..037e90a --- /dev/null +++ b/src/main/java/com/rohitawate/everest/sync/DataManager.java @@ -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 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(); +} diff --git a/src/main/java/com/rohitawate/everest/history/HistoryManager.java b/src/main/java/com/rohitawate/everest/sync/SQLiteManager.java similarity index 75% rename from src/main/java/com/rohitawate/everest/history/HistoryManager.java rename to src/main/java/com/rohitawate/everest/sync/SQLiteManager.java index 15eb318..2eb024b 100644 --- a/src/main/java/com/rohitawate/everest/history/HistoryManager.java +++ b/src/main/java/com/rohitawate/everest/sync/SQLiteManager.java @@ -14,10 +14,9 @@ * limitations under the License. */ -package com.rohitawate.everest.history; +package com.rohitawate.everest.sync; import com.rohitawate.everest.logging.LoggingService; -import com.rohitawate.everest.misc.Services; import com.rohitawate.everest.models.requests.HTTPConstants; import com.rohitawate.everest.settings.Settings; import com.rohitawate.everest.state.ComposerState; @@ -31,10 +30,9 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -public class HistoryManager { +class SQLiteManager implements DataManager { private Connection conn; private PreparedStatement statement; - private HistorySaver historySaver = new HistorySaver(); private static class Queries { 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"; } - public HistoryManager() { + public SQLiteManager() { try { File configFolder = new File("Everest/config/"); if (!configFolder.exists()) @@ -67,7 +65,7 @@ public class HistoryManager { conn = DriverManager.getConnection("jdbc:sqlite:Everest/config/history.sqlite"); createDatabase(); } catch (Exception E) { - LoggingService.logSevere("Exception while initializing HistoryManager.", E, LocalDateTime.now()); + LoggingService.logSevere("Exception while initializing DataManager.", E, LocalDateTime.now()); } finally { System.out.println("Connected to database."); } @@ -89,21 +87,63 @@ public class HistoryManager { * * @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(); if (newState.equals(lastState)) return; - historySaver.state = newState; - Services.singleExecutor.execute(historySaver); + try { + statement = + conn.prepareStatement(Queries.saveRequest); - // Appends this history item to the HistoryTab - Services.homeWindowController.addHistoryItem(newState); + statement.setString(1, newState.httpMethod); + 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. */ + @Override public synchronized List getHistory() { List history = new ArrayList<>(); try { @@ -257,75 +297,27 @@ public class HistoryManager { return null; } - private class HistorySaver implements Runnable { - private ComposerState state; - - @Override - public void run() { + private void saveTuple(ArrayList tuples, String tupleType, int requestID) { + if (tuples.size() > 0) { try { - statement = - conn.prepareStatement(Queries.saveRequest); - - 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); + for (FieldState fieldState : tuples) { + statement = conn.prepareStatement(Queries.saveTuple); statement.setInt(1, requestID); - statement.setString(2, state.contentType); - statement.executeUpdate(); - - statement = conn.prepareStatement(Queries.saveBody); - statement.setInt(1, requestID); - 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.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.logWarning("Database error.", e, LocalDateTime.now()); - } - } - - private void saveTuple(ArrayList 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()); - } + LoggingService.logSevere("Database error.", e, LocalDateTime.now()); } } } + + @Override + public String getIdentifier() { + return "SQLite"; + } } \ No newline at end of file diff --git a/src/main/java/com/rohitawate/everest/sync/SyncManager.java b/src/main/java/com/rohitawate/everest/sync/SyncManager.java new file mode 100644 index 0000000..9a48e65 --- /dev/null +++ b/src/main/java/com/rohitawate/everest/sync/SyncManager.java @@ -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 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 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); + } + } +}