Fix issues with detecting duplicate ComposerStates while saving history
This commit is contained in:
parent
53a42f8de5
commit
6eb4595f91
8 changed files with 120 additions and 96 deletions
|
@ -100,6 +100,7 @@ public class DashboardController implements Initializable {
|
||||||
private IntegerProperty paramsCountProperty;
|
private IntegerProperty paramsCountProperty;
|
||||||
private Visualizer visualizer;
|
private Visualizer visualizer;
|
||||||
private ResponseHeadersViewer responseHeadersViewer;
|
private ResponseHeadersViewer responseHeadersViewer;
|
||||||
|
private SyncManager syncManager;
|
||||||
|
|
||||||
private GETRequest getRequest;
|
private GETRequest getRequest;
|
||||||
private DataRequest dataRequest;
|
private DataRequest dataRequest;
|
||||||
|
@ -293,7 +294,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();
|
||||||
SyncManager.saveState(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);
|
||||||
|
@ -614,6 +615,10 @@ public class DashboardController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSyncManager(SyncManager syncManager) {
|
||||||
|
this.syncManager = syncManager;
|
||||||
|
}
|
||||||
|
|
||||||
public ComposerTab getVisibleComposerTab() {
|
public ComposerTab getVisibleComposerTab() {
|
||||||
int visibleTab = requestOptionsTab.getSelectionModel().getSelectedIndex();
|
int visibleTab = requestOptionsTab.getSelectionModel().getSelectedIndex();
|
||||||
switch (visibleTab) {
|
switch (visibleTab) {
|
||||||
|
@ -628,7 +633,6 @@ public class DashboardController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ResponseTab getVisibleResponseTab() {
|
private ResponseTab getVisibleResponseTab() {
|
||||||
int visibleTab = responseTabPane.getSelectionModel().getSelectedIndex();
|
int visibleTab = responseTabPane.getSelectionModel().getSelectedIndex();
|
||||||
switch (visibleTab) {
|
switch (visibleTab) {
|
||||||
|
|
|
@ -129,7 +129,7 @@ public class HeaderTabController implements Initializable {
|
||||||
/**
|
/**
|
||||||
* Return a list of the state of all the fields in the Headers tab.
|
* Return a list of the state of all the fields in the Headers tab.
|
||||||
*/
|
*/
|
||||||
public ArrayList<FieldState> getFieldStates() {
|
public List<FieldState> getFieldStates() {
|
||||||
ArrayList<FieldState> states = new ArrayList<>();
|
ArrayList<FieldState> states = new ArrayList<>();
|
||||||
|
|
||||||
for (StringKeyValueFieldController controller : controllers) {
|
for (StringKeyValueFieldController controller : controllers) {
|
||||||
|
|
|
@ -29,12 +29,12 @@ import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class HistoryPaneController extends SearchablePaneController<ComposerState> {
|
public class HistoryPaneController extends SearchablePaneController<ComposerState> {
|
||||||
|
|
||||||
private List<Consumer<ComposerState>> stateClickHandler = new LinkedList<>();
|
private List<Consumer<ComposerState>> stateClickHandler = new LinkedList<>();
|
||||||
|
private SyncManager syncManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<ComposerState> loadInitialEntries() {
|
protected List<ComposerState> loadInitialEntries() {
|
||||||
return SyncManager.getHistory();
|
return syncManager.getHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SearchEntry<ComposerState> createEntryFromState(ComposerState state) throws IOException {
|
protected SearchEntry<ComposerState> createEntryFromState(ComposerState state) throws IOException {
|
||||||
|
@ -62,4 +62,8 @@ public class HistoryPaneController extends SearchablePaneController<ComposerStat
|
||||||
public void addItemClickHandler(Consumer<ComposerState> handler) {
|
public void addItemClickHandler(Consumer<ComposerState> handler) {
|
||||||
stateClickHandler.add(handler);
|
stateClickHandler.add(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSyncManager(SyncManager syncManager) {
|
||||||
|
this.syncManager = syncManager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,21 +61,24 @@ public class HomeWindowController implements Initializable {
|
||||||
private HistoryPaneController historyController;
|
private HistoryPaneController historyController;
|
||||||
private DashboardController dashboard;
|
private DashboardController dashboard;
|
||||||
private StringProperty addressProperty;
|
private StringProperty addressProperty;
|
||||||
|
private SyncManager syncManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
new SyncManager(this);
|
syncManager = 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();
|
||||||
splitPane.getItems().add(0, historyFXML);
|
splitPane.getItems().add(0, historyFXML);
|
||||||
historyController = historyLoader.getController();
|
historyController = historyLoader.getController();
|
||||||
|
historyController.setSyncManager(syncManager);
|
||||||
historyController.addItemClickHandler(this::addTab);
|
historyController.addItemClickHandler(this::addTab);
|
||||||
|
|
||||||
FXMLLoader dashboardLoader = new FXMLLoader(getClass().getResource("/fxml/homewindow/Dashboard.fxml"));
|
FXMLLoader dashboardLoader = new FXMLLoader(getClass().getResource("/fxml/homewindow/Dashboard.fxml"));
|
||||||
Parent dashboardFXML = dashboardLoader.load();
|
Parent dashboardFXML = dashboardLoader.load();
|
||||||
dashboard = dashboardLoader.getController();
|
dashboard = dashboardLoader.getController();
|
||||||
|
dashboard.setSyncManager(syncManager);
|
||||||
dashboardContainer.getChildren().add(dashboardFXML);
|
dashboardContainer.getChildren().add(dashboardFXML);
|
||||||
addressProperty = dashboard.addressField.textProperty();
|
addressProperty = dashboard.addressField.textProperty();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -57,12 +57,16 @@ public class ComposerState {
|
||||||
ComposerState state = (ComposerState) o;
|
ComposerState state = (ComposerState) o;
|
||||||
if (!target.equals(state.target)) return false;
|
if (!target.equals(state.target)) return false;
|
||||||
if (!httpMethod.equals(state.httpMethod)) 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 (!contentType.equals(state.contentType)) return false;
|
||||||
if (!rawBody.equals(state.rawBody)) return false;
|
if (!rawBody.equals(state.rawBody)) return false;
|
||||||
if (!rawBodyBoxValue.equals(state.rawBodyBoxValue)) return false;
|
if (!rawBodyBoxValue.equals(state.rawBodyBoxValue)) return false;
|
||||||
if (!binaryFilePath.equals(state.binaryFilePath)) 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 (!urlStringTuples.equals(state.urlStringTuples)) return false;
|
||||||
if (!formStringTuples.equals(state.formStringTuples)) return false;
|
if (!formStringTuples.equals(state.formStringTuples)) return false;
|
||||||
if (!formFileTuples.equals(state.formFileTuples)) return false;
|
if (!formFileTuples.equals(state.formFileTuples)) return false;
|
||||||
|
|
|
@ -11,14 +11,21 @@ public interface DataManager {
|
||||||
/**
|
/**
|
||||||
* Saves the state of the Composer when the request was made.
|
* 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.
|
* Fetches all the states of the Composer when the previous requests were made.
|
||||||
*
|
*
|
||||||
* @return A list of the states.
|
* @return A list of the states.
|
||||||
*/
|
*/
|
||||||
List<ComposerState> getHistory();
|
List<ComposerState> 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.
|
* Returns the identifier for the DataManager. Preferably, use the source as the identifier.
|
||||||
|
|
|
@ -91,55 +91,46 @@ class SQLiteManager implements DataManager {
|
||||||
* @param newState - The state of the Dashboard while making the request.
|
* @param newState - The state of the Dashboard while making the request.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void saveState(ComposerState newState) {
|
public synchronized void saveState(ComposerState newState) throws SQLException {
|
||||||
ComposerState lastState = getLastRequest();
|
statement = conn.prepareStatement(Queries.saveRequest);
|
||||||
if (newState.equals(lastState))
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
statement.setString(1, newState.httpMethod);
|
||||||
statement =
|
statement.setString(2, newState.target);
|
||||||
conn.prepareStatement(Queries.saveRequest);
|
statement.setString(3, LocalDate.now().toString());
|
||||||
|
statement.executeUpdate();
|
||||||
|
|
||||||
statement.setString(1, newState.httpMethod);
|
// Get latest RequestID to insert into Headers table
|
||||||
statement.setString(2, newState.target);
|
statement = conn.prepareStatement("SELECT MAX(ID) AS MaxID FROM Requests");
|
||||||
statement.setString(3, LocalDate.now().toString());
|
|
||||||
|
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.executeUpdate();
|
||||||
|
|
||||||
// Get latest RequestID to insert into Headers table
|
statement = conn.prepareStatement(Queries.saveBody);
|
||||||
statement = conn.prepareStatement("SELECT MAX(ID) AS MaxID FROM Requests");
|
statement.setInt(1, requestID);
|
||||||
|
statement.setString(2, newState.rawBody);
|
||||||
|
statement.setString(3, newState.rawBodyBoxValue);
|
||||||
|
statement.executeUpdate();
|
||||||
|
|
||||||
ResultSet RS = statement.executeQuery();
|
statement = conn.prepareStatement(Queries.saveFilePath);
|
||||||
int requestID = -1;
|
statement.setInt(1, requestID);
|
||||||
if (RS.next())
|
statement.setString(2, newState.binaryFilePath);
|
||||||
requestID = RS.getInt("MaxID");
|
statement.executeUpdate();
|
||||||
|
|
||||||
saveTuple(newState.headers, "Header", requestID);
|
saveTuple(newState.urlStringTuples, "URLString", requestID);
|
||||||
saveTuple(newState.params, "Param", requestID);
|
saveTuple(newState.formStringTuples, "FormString", requestID);
|
||||||
|
saveTuple(newState.formFileTuples, "File", 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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,49 +138,45 @@ class SQLiteManager implements DataManager {
|
||||||
* Returns a list of all the recent requests.
|
* Returns a list of all the recent requests.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<ComposerState> getHistory() {
|
public synchronized List<ComposerState> getHistory() throws SQLException {
|
||||||
List<ComposerState> history = new ArrayList<>();
|
List<ComposerState> history = new ArrayList<>();
|
||||||
try {
|
// Loads the requests from the last x number of days, x being Settings.showHistoryRange
|
||||||
// Loads the requests from the last x number of days, x being Settings.showHistoryRange
|
statement = conn.prepareStatement(Queries.selectRecentRequests);
|
||||||
statement = conn.prepareStatement(Queries.selectRecentRequests);
|
String historyStartDate = LocalDate.now().minusDays(Settings.showHistoryRange).toString();
|
||||||
String historyStartDate = LocalDate.now().minusDays(Settings.showHistoryRange).toString();
|
statement.setString(1, historyStartDate);
|
||||||
statement.setString(1, historyStartDate);
|
|
||||||
|
|
||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
|
|
||||||
ComposerState state;
|
ComposerState state;
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
state = new ComposerState();
|
state = new ComposerState();
|
||||||
|
|
||||||
state.target = resultSet.getString("Target");
|
state.target = resultSet.getString("Target");
|
||||||
|
|
||||||
int requestID = resultSet.getInt("ID");
|
int requestID = resultSet.getInt("ID");
|
||||||
state.headers = getTuples(requestID, "Header");
|
state.headers = getTuples(requestID, "Header");
|
||||||
state.params = getTuples(requestID, "Param");
|
state.params = getTuples(requestID, "Param");
|
||||||
state.httpMethod = resultSet.getString("Type");
|
state.httpMethod = resultSet.getString("Type");
|
||||||
|
|
||||||
if (!(state.httpMethod.equals(HTTPConstants.GET) || state.httpMethod.equals(HTTPConstants.DELETE))) {
|
if (!(state.httpMethod.equals(HTTPConstants.GET) || state.httpMethod.equals(HTTPConstants.DELETE))) {
|
||||||
// Retrieves request body ContentType for querying corresponding table
|
// Retrieves request body ContentType for querying corresponding table
|
||||||
state.contentType = getRequestContentType(requestID);
|
state.contentType = getRequestContentType(requestID);
|
||||||
|
|
||||||
Pair<String, String> rawBodyAndType = getRequestBody(requestID);
|
Pair<String, String> rawBodyAndType = getRequestBody(requestID);
|
||||||
|
|
||||||
if (rawBodyAndType != null) {
|
if (rawBodyAndType != null) {
|
||||||
state.rawBody = rawBodyAndType.getKey();
|
state.rawBody = rawBodyAndType.getKey();
|
||||||
state.rawBodyBoxValue = rawBodyAndType.getValue();
|
state.rawBodyBoxValue = rawBodyAndType.getValue();
|
||||||
}
|
|
||||||
|
|
||||||
state.binaryFilePath = getFilePath(requestID);
|
|
||||||
|
|
||||||
state.urlStringTuples = getTuples(requestID, "URLString");
|
|
||||||
state.formStringTuples = getTuples(requestID, "FormString");
|
|
||||||
state.formFileTuples = getTuples(requestID, "File");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return history;
|
||||||
|
@ -239,7 +226,8 @@ class SQLiteManager implements DataManager {
|
||||||
return fieldStates;
|
return fieldStates;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ComposerState getLastRequest() {
|
@Override
|
||||||
|
public ComposerState getLastAdded() {
|
||||||
ComposerState lastRequest = new ComposerState();
|
ComposerState lastRequest = new ComposerState();
|
||||||
try {
|
try {
|
||||||
statement = conn.prepareStatement(Queries.selectMostRecentRequest);
|
statement = conn.prepareStatement(Queries.selectMostRecentRequest);
|
||||||
|
|
|
@ -41,7 +41,10 @@ public class SyncManager {
|
||||||
/**
|
/**
|
||||||
* Asynchronously saves the new state by invoking all the registered DataManagers.
|
* 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;
|
historySaver.newState = newState;
|
||||||
executor.execute(historySaver);
|
executor.execute(historySaver);
|
||||||
|
|
||||||
|
@ -53,20 +56,27 @@ public class SyncManager {
|
||||||
*
|
*
|
||||||
* @return A list of all the requests
|
* @return A list of all the requests
|
||||||
*/
|
*/
|
||||||
public static List<ComposerState> getHistory() {
|
public List<ComposerState> getHistory() {
|
||||||
if (managers.get(Settings.fetchSource) == null) {
|
List<ComposerState> history = null;
|
||||||
LoggingService.logSevere("No such source found: " + Settings.fetchSource, null, LocalDateTime.now());
|
try {
|
||||||
return managers.get("SQLite").getHistory();
|
if (managers.get(Settings.fetchSource) == null) {
|
||||||
} else {
|
LoggingService.logSevere("No such source found: " + Settings.fetchSource, null, LocalDateTime.now());
|
||||||
return managers.get(Settings.fetchSource).getHistory();
|
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
|
* Registers a new DataManager to be used for syncing Everest's data
|
||||||
* at various sources.
|
* at various sources.
|
||||||
*/
|
*/
|
||||||
public static void registerManager(DataManager newManager) throws DuplicateException {
|
public void registerManager(DataManager newManager) throws DuplicateException {
|
||||||
if (managers.containsKey(newManager.getIdentifier()))
|
if (managers.containsKey(newManager.getIdentifier()))
|
||||||
throw new DuplicateException(
|
throw new DuplicateException(
|
||||||
"Duplicate DataManager: Manager with identifier \'" + newManager.getIdentifier() + "\' already exists.");
|
"Duplicate DataManager: Manager with identifier \'" + newManager.getIdentifier() + "\' already exists.");
|
||||||
|
@ -79,8 +89,12 @@ public class SyncManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (DataManager manager : managers.values())
|
try {
|
||||||
manager.saveState(newState);
|
for (DataManager manager : managers.values())
|
||||||
|
manager.saveState(newState);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LoggingService.logSevere("Could not save history.", e, LocalDateTime.now());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue