From 6eb4595f915f26499053111b63179b1ef910b790 Mon Sep 17 00:00:00 2001 From: Rohit Awate Date: Sat, 18 Aug 2018 22:27:11 +0530 Subject: [PATCH] Fix issues with detecting duplicate ComposerStates while saving history --- .../controllers/DashboardController.java | 8 +- .../controllers/HeaderTabController.java | 2 +- .../controllers/HistoryPaneController.java | 8 +- .../controllers/HomeWindowController.java | 5 +- .../everest/state/ComposerState.java | 8 +- .../rohitawate/everest/sync/DataManager.java | 11 +- .../everest/sync/SQLiteManager.java | 140 ++++++++---------- .../rohitawate/everest/sync/SyncManager.java | 34 +++-- 8 files changed, 120 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/rohitawate/everest/controllers/DashboardController.java b/src/main/java/com/rohitawate/everest/controllers/DashboardController.java index 03adf82..78d198a 100644 --- a/src/main/java/com/rohitawate/everest/controllers/DashboardController.java +++ b/src/main/java/com/rohitawate/everest/controllers/DashboardController.java @@ -100,6 +100,7 @@ public class DashboardController implements Initializable { private IntegerProperty paramsCountProperty; private Visualizer visualizer; private ResponseHeadersViewer responseHeadersViewer; + private SyncManager syncManager; private GETRequest getRequest; private DataRequest dataRequest; @@ -293,7 +294,7 @@ public class DashboardController implements Initializable { cancelButton.setOnAction(e -> requestManager.cancel()); requestManager.addHandlers(this::whileRunning, this::onSucceeded, this::onFailed, this::onCancelled); requestManager.start(); - SyncManager.saveState(getState().composer); + syncManager.saveState(getState().composer); } catch (MalformedURLException MURLE) { showLayer(ResponseLayer.PROMPT); snackbar.show("Invalid address. Please verify and try again.", 3000); @@ -614,6 +615,10 @@ public class DashboardController implements Initializable { } } + public void setSyncManager(SyncManager syncManager) { + this.syncManager = syncManager; + } + public ComposerTab getVisibleComposerTab() { int visibleTab = requestOptionsTab.getSelectionModel().getSelectedIndex(); switch (visibleTab) { @@ -628,7 +633,6 @@ public class DashboardController implements Initializable { } } - private ResponseTab getVisibleResponseTab() { int visibleTab = responseTabPane.getSelectionModel().getSelectedIndex(); switch (visibleTab) { diff --git a/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java b/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java index 5b317c0..a2ab1e1 100644 --- a/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java @@ -129,7 +129,7 @@ public class HeaderTabController implements Initializable { /** * Return a list of the state of all the fields in the Headers tab. */ - public ArrayList getFieldStates() { + public List getFieldStates() { ArrayList states = new ArrayList<>(); for (StringKeyValueFieldController controller : controllers) { diff --git a/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java b/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java index 0f9075f..b9a02a7 100644 --- a/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java +++ b/src/main/java/com/rohitawate/everest/controllers/HistoryPaneController.java @@ -29,12 +29,12 @@ import java.util.List; import java.util.function.Consumer; public class HistoryPaneController extends SearchablePaneController { - private List> stateClickHandler = new LinkedList<>(); + private SyncManager syncManager; @Override protected List loadInitialEntries() { - return SyncManager.getHistory(); + return syncManager.getHistory(); } protected SearchEntry createEntryFromState(ComposerState state) throws IOException { @@ -62,4 +62,8 @@ public class HistoryPaneController extends SearchablePaneController handler) { stateClickHandler.add(handler); } + + public void setSyncManager(SyncManager syncManager) { + this.syncManager = syncManager; + } } diff --git a/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java b/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java index 1ec65a3..f383205 100644 --- a/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java +++ b/src/main/java/com/rohitawate/everest/controllers/HomeWindowController.java @@ -61,21 +61,24 @@ public class HomeWindowController implements Initializable { private HistoryPaneController historyController; private DashboardController dashboard; private StringProperty addressProperty; + private SyncManager syncManager; @Override public void initialize(URL location, ResourceBundle resources) { - new SyncManager(this); + syncManager = new SyncManager(this); try { FXMLLoader historyLoader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HistoryPane.fxml")); Parent historyFXML = historyLoader.load(); splitPane.getItems().add(0, historyFXML); historyController = historyLoader.getController(); + historyController.setSyncManager(syncManager); historyController.addItemClickHandler(this::addTab); FXMLLoader dashboardLoader = new FXMLLoader(getClass().getResource("/fxml/homewindow/Dashboard.fxml")); Parent dashboardFXML = dashboardLoader.load(); dashboard = dashboardLoader.getController(); + dashboard.setSyncManager(syncManager); dashboardContainer.getChildren().add(dashboardFXML); addressProperty = dashboard.addressField.textProperty(); } catch (IOException e) { diff --git a/src/main/java/com/rohitawate/everest/state/ComposerState.java b/src/main/java/com/rohitawate/everest/state/ComposerState.java index 4c1e651..bb02b74 100644 --- a/src/main/java/com/rohitawate/everest/state/ComposerState.java +++ b/src/main/java/com/rohitawate/everest/state/ComposerState.java @@ -57,12 +57,16 @@ public class ComposerState { ComposerState state = (ComposerState) o; if (!target.equals(state.target)) return false; if (!httpMethod.equals(state.httpMethod)) return false; + if (!params.equals(state.params)) return false; + if (!headers.equals(state.headers)) return false; + + if (state.httpMethod.equals(HTTPConstants.GET) + || state.httpMethod.equals(HTTPConstants.DELETE)) return true; + if (!contentType.equals(state.contentType)) return false; if (!rawBody.equals(state.rawBody)) return false; if (!rawBodyBoxValue.equals(state.rawBodyBoxValue)) return false; if (!binaryFilePath.equals(state.binaryFilePath)) return false; - if (!params.equals(state.params)) return false; - if (!headers.equals(state.headers)) return false; if (!urlStringTuples.equals(state.urlStringTuples)) return false; if (!formStringTuples.equals(state.formStringTuples)) return false; if (!formFileTuples.equals(state.formFileTuples)) return false; diff --git a/src/main/java/com/rohitawate/everest/sync/DataManager.java b/src/main/java/com/rohitawate/everest/sync/DataManager.java index 037e90a..3cc8fe2 100644 --- a/src/main/java/com/rohitawate/everest/sync/DataManager.java +++ b/src/main/java/com/rohitawate/everest/sync/DataManager.java @@ -11,14 +11,21 @@ public interface DataManager { /** * Saves the state of the Composer when the request was made. */ - void saveState(ComposerState newState); + void saveState(ComposerState newState) throws Exception; /** * Fetches all the states of the Composer when the previous requests were made. * * @return A list of the states. */ - List getHistory(); + List getHistory() throws Exception; + + /** + * Returns the state of the Composer when the last request was made. + * If this DataManager is the primary fetching source, SyncManager uses + * calls this method before attempting to save a new state. + */ + ComposerState getLastAdded(); /** * Returns the identifier for the DataManager. Preferably, use the source as the identifier. diff --git a/src/main/java/com/rohitawate/everest/sync/SQLiteManager.java b/src/main/java/com/rohitawate/everest/sync/SQLiteManager.java index 515c781..3a379f2 100644 --- a/src/main/java/com/rohitawate/everest/sync/SQLiteManager.java +++ b/src/main/java/com/rohitawate/everest/sync/SQLiteManager.java @@ -91,55 +91,46 @@ class SQLiteManager implements DataManager { * @param newState - The state of the Dashboard while making the request. */ @Override - public synchronized void saveState(ComposerState newState) { - ComposerState lastState = getLastRequest(); - if (newState.equals(lastState)) - return; + public synchronized void saveState(ComposerState newState) throws SQLException { + statement = conn.prepareStatement(Queries.saveRequest); - try { - statement = - conn.prepareStatement(Queries.saveRequest); + statement.setString(1, newState.httpMethod); + statement.setString(2, newState.target); + statement.setString(3, LocalDate.now().toString()); + statement.executeUpdate(); - statement.setString(1, newState.httpMethod); - statement.setString(2, newState.target); - statement.setString(3, LocalDate.now().toString()); + // 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(); - // Get latest RequestID to insert into Headers table - statement = conn.prepareStatement("SELECT MAX(ID) AS MaxID FROM Requests"); + statement = conn.prepareStatement(Queries.saveBody); + statement.setInt(1, requestID); + statement.setString(2, newState.rawBody); + statement.setString(3, newState.rawBodyBoxValue); + statement.executeUpdate(); - ResultSet RS = statement.executeQuery(); - int requestID = -1; - if (RS.next()) - requestID = RS.getInt("MaxID"); + statement = conn.prepareStatement(Queries.saveFilePath); + statement.setInt(1, requestID); + statement.setString(2, newState.binaryFilePath); + statement.executeUpdate(); - 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()); + saveTuple(newState.urlStringTuples, "URLString", requestID); + saveTuple(newState.formStringTuples, "FormString", requestID); + saveTuple(newState.formFileTuples, "File", requestID); } } @@ -147,49 +138,45 @@ class SQLiteManager implements DataManager { * Returns a list of all the recent requests. */ @Override - public synchronized List getHistory() { + public synchronized List getHistory() throws SQLException { List history = new ArrayList<>(); - try { - // Loads the requests from the last x number of days, x being Settings.showHistoryRange - statement = conn.prepareStatement(Queries.selectRecentRequests); - String historyStartDate = LocalDate.now().minusDays(Settings.showHistoryRange).toString(); - statement.setString(1, historyStartDate); + // Loads the requests from the last x number of days, x being Settings.showHistoryRange + statement = conn.prepareStatement(Queries.selectRecentRequests); + String historyStartDate = LocalDate.now().minusDays(Settings.showHistoryRange).toString(); + statement.setString(1, historyStartDate); - ResultSet resultSet = statement.executeQuery(); + ResultSet resultSet = statement.executeQuery(); - ComposerState state; - while (resultSet.next()) { - state = new ComposerState(); + ComposerState state; + while (resultSet.next()) { + state = new ComposerState(); - state.target = resultSet.getString("Target"); + state.target = resultSet.getString("Target"); - int requestID = resultSet.getInt("ID"); - state.headers = getTuples(requestID, "Header"); - state.params = getTuples(requestID, "Param"); - state.httpMethod = resultSet.getString("Type"); + int requestID = resultSet.getInt("ID"); + state.headers = getTuples(requestID, "Header"); + state.params = getTuples(requestID, "Param"); + state.httpMethod = resultSet.getString("Type"); - if (!(state.httpMethod.equals(HTTPConstants.GET) || state.httpMethod.equals(HTTPConstants.DELETE))) { - // Retrieves request body ContentType for querying corresponding table - state.contentType = getRequestContentType(requestID); + if (!(state.httpMethod.equals(HTTPConstants.GET) || state.httpMethod.equals(HTTPConstants.DELETE))) { + // Retrieves request body ContentType for querying corresponding table + state.contentType = getRequestContentType(requestID); - Pair rawBodyAndType = getRequestBody(requestID); + Pair rawBodyAndType = getRequestBody(requestID); - if (rawBodyAndType != null) { - state.rawBody = rawBodyAndType.getKey(); - state.rawBodyBoxValue = rawBodyAndType.getValue(); - } - - state.binaryFilePath = getFilePath(requestID); - - state.urlStringTuples = getTuples(requestID, "URLString"); - state.formStringTuples = getTuples(requestID, "FormString"); - state.formFileTuples = getTuples(requestID, "File"); + if (rawBodyAndType != null) { + state.rawBody = rawBodyAndType.getKey(); + state.rawBodyBoxValue = rawBodyAndType.getValue(); } - history.add(state); + state.binaryFilePath = getFilePath(requestID); + + state.urlStringTuples = getTuples(requestID, "URLString"); + state.formStringTuples = getTuples(requestID, "FormString"); + state.formFileTuples = getTuples(requestID, "File"); } - } catch (SQLException e) { - LoggingService.logWarning("Database error.", e, LocalDateTime.now()); + + history.add(state); } return history; @@ -239,7 +226,8 @@ class SQLiteManager implements DataManager { return fieldStates; } - private ComposerState getLastRequest() { + @Override + public ComposerState getLastAdded() { ComposerState lastRequest = new ComposerState(); try { statement = conn.prepareStatement(Queries.selectMostRecentRequest); diff --git a/src/main/java/com/rohitawate/everest/sync/SyncManager.java b/src/main/java/com/rohitawate/everest/sync/SyncManager.java index 9a48e65..4ef7871 100644 --- a/src/main/java/com/rohitawate/everest/sync/SyncManager.java +++ b/src/main/java/com/rohitawate/everest/sync/SyncManager.java @@ -41,7 +41,10 @@ public class SyncManager { /** * Asynchronously saves the new state by invoking all the registered DataManagers. */ - public static void saveState(ComposerState newState) { + public void saveState(ComposerState newState) { + if (newState.equals(managers.get(Settings.fetchSource).getLastAdded())) + return; + historySaver.newState = newState; executor.execute(historySaver); @@ -53,20 +56,27 @@ public class SyncManager { * * @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(); + public List getHistory() { + List history = null; + try { + if (managers.get(Settings.fetchSource) == null) { + LoggingService.logSevere("No such source found: " + Settings.fetchSource, null, LocalDateTime.now()); + history = managers.get("SQLite").getHistory(); + } else { + history = managers.get(Settings.fetchSource).getHistory(); + } + } catch (Exception e) { + LoggingService.logSevere("History could not be fetched.", e, LocalDateTime.now()); } + + return history; } /** * Registers a new DataManager to be used for syncing Everest's data * at various sources. */ - public static void registerManager(DataManager newManager) throws DuplicateException { + public void registerManager(DataManager newManager) throws DuplicateException { if (managers.containsKey(newManager.getIdentifier())) throw new DuplicateException( "Duplicate DataManager: Manager with identifier \'" + newManager.getIdentifier() + "\' already exists."); @@ -79,8 +89,12 @@ public class SyncManager { @Override public void run() { - for (DataManager manager : managers.values()) - manager.saveState(newState); + try { + for (DataManager manager : managers.values()) + manager.saveState(newState); + } catch (Exception e) { + LoggingService.logSevere("Could not save history.", e, LocalDateTime.now()); + } } } }