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;
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);

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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<ComposerStat
@Override
protected List<ComposerState> loadInitialEntries() {
return Services.historyManager.getHistory();
return SyncManager.getHistory();
}
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.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();

View file

@ -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.

View file

@ -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);

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;
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);

View file

@ -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();
}
}

View file

@ -185,7 +185,7 @@ public class RequestManager extends Service<EverestResponse> {
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<EverestResponse> {
// Adding the string tuples to the request
HashMap<String, String> pairs = dataRequest.getStringTuples();
for (Map.Entry entry : pairs.entrySet()) {
mapEntry = (Map.Entry) entry;
for (Map.Entry<String, String> entry : pairs.entrySet()) {
mapEntry = entry;
formData.field(mapEntry.getKey(), mapEntry.getValue());
}
@ -210,8 +210,8 @@ public class RequestManager extends Service<EverestResponse> {
pairs = dataRequest.getFileTuples();
// Adding the file tuples to the request
for (Map.Entry entry : pairs.entrySet()) {
mapEntry = (Map.Entry) entry;
for (Map.Entry<String, String> entry : pairs.entrySet()) {
mapEntry = entry;
filePath = mapEntry.getValue();
file = new File(filePath);
@ -258,8 +258,8 @@ public class RequestManager extends Service<EverestResponse> {
Form form = new Form();
for (Map.Entry entry : dataRequest.getStringTuples().entrySet()) {
mapEntry = (Map.Entry) entry;
for (Map.Entry<String, String> entry : dataRequest.getStringTuples().entrySet()) {
mapEntry = entry;
form.param(mapEntry.getKey(), mapEntry.getValue());
}

View file

@ -32,4 +32,6 @@ public class Settings {
public static int showHistoryRange = 7;
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.
*/
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<ComposerState> getHistory() {
List<ComposerState> 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<FieldState> 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<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());
}
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);
}
}
}