diff --git a/.gitignore b/.gitignore index c5d8653..1ac65c4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,12 @@ classes/ src/main/java/META-INF/ dependency-reduced-pom.xml -Everest/ # Hides Eclipse Artifacts .settings/ .classpath -.project \ No newline at end of file +.project + +/BugReporter/src/META-INF/ +BugReporter/src/META-INF/ +out/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ba18bd4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: java +sudo: true + +script: mvn clean package + +deploy: + provider: releases + api_key: + secure: yep + file: target/Everest-Alpha-1.0.jar diff --git a/src/main/java/com/rohitawate/everest/util/BugReporter.java b/BugReporter/src/BugReporter.java similarity index 72% rename from src/main/java/com/rohitawate/everest/util/BugReporter.java rename to BugReporter/src/BugReporter.java index ecc0b45..61be43f 100644 --- a/src/main/java/com/rohitawate/everest/util/BugReporter.java +++ b/BugReporter/src/BugReporter.java @@ -14,8 +14,6 @@ * limitations under the License. */ -package com.rohitawate.everest.util; - import java.io.*; import java.nio.charset.Charset; import java.time.LocalDate; @@ -28,44 +26,30 @@ public class BugReporter { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); System.out.println("Everest Bug Reporting Service"); - System.out.println(); - System.out.println("Please describe the issue with as much detail and clarity as possible: "); + System.out.println("-----------------------------\n"); + System.out.println("Please describe the issue with as much detail and clarity as possible (no newline): "); String userMessage = scanner.nextLine(); - StringBuilder builder = new StringBuilder(); - builder.append("\nThank you for your input! The issue was recorded.\n\n"); - builder.append("With your permission, this service can collect some anonymous, non-personal information about your system.\n"); - builder.append("This information will help us to better reproduce the issue and fix it quickly.\n"); - builder.append("This includes:\n"); - builder.append(" - Operating system details.\n"); - builder.append(" - Details about your Java Runtime Environment.\n\n"); - builder.append("Allow? (Y/N)\n>> "); - System.out.print(builder.toString()); - String allowSystemData = scanner.nextLine(); - - allowSystemData = allowSystemData.toLowerCase(); - - StringBuilder report = new StringBuilder(); - report.append("Log date: "); - report.append(LocalDateTime.now()); - report.append("\n\n"); - if (allowSystemData.equals("y") || allowSystemData.equals("yes")) { - report.append(generateSystemDetails()); - System.out.println("\nThat's great! We will include your system details in with the bug report."); - } else { - System.out.println("\nAlrighty! We will only include Everest's log files in the report."); - } - scanner.close(); - report.append("User Message:\n"); - report.append(userMessage); - generateReport(report.toString()); + + generateReportFile(generateReport(userMessage)); generateZipFile(); - System.out.println("\nYour issue was successfully reported and will be fixed soon."); + System.out.println("\nYour report was submitted successfully reported and will be evaluated soon."); System.out.println("Thank you! :)"); } - private static String generateSystemDetails() { + private static String generateReport(String userMessage) { + StringBuilder report = new StringBuilder(); + report.append("Report date: "); + report.append(LocalDateTime.now()); + report.append("\n\n"); + report.append(getSystemDetails()); + report.append("User Message:\n"); + report.append(userMessage); + return report.toString(); + } + + private static String getSystemDetails() { StringBuilder builder = new StringBuilder(); String OS = System.getProperty("os.name"); if (OS.equals("Linux")) { @@ -77,19 +61,18 @@ public class BugReporter { builder.append(System.getProperty("os.arch")); builder.append(" "); builder.append(System.getProperty("os.version")); - builder.append("\n"); - builder.append("Java VM: "); + builder.append("\nJava VM: "); builder.append(System.getProperty("java.vm.name")); - builder.append(" "); + builder.append("\nVM Version: "); builder.append(System.getProperty("java.version")); - builder.append("\nJava VM Vendor: "); + builder.append("\nVM Vendor: "); builder.append(System.getProperty("java.vendor")); builder.append("\n\n"); return builder.toString(); } - private static void generateReport(String reportContents) { + private static void generateReportFile(String reportContents) { String reportFileName = "Report - " + LocalDate.now() + ".txt"; try { BufferedWriter writer = new BufferedWriter(new FileWriter("logs/" + reportFileName)); @@ -104,7 +87,7 @@ public class BugReporter { try { Scanner scanner; FileInputStream fileInputStream; - ZipOutputStream zipStream = new ZipOutputStream(new FileOutputStream("Logs.zip"), Charset.forName("UTF-8")); + ZipOutputStream zipStream = new ZipOutputStream(new FileOutputStream("BugReport-" + LocalDate.now() + ".zip"), Charset.forName("UTF-8")); File sourceDir = new File("logs/"); String[] logFiles = sourceDir.list(); @@ -132,7 +115,7 @@ public class BugReporter { } private static String getLinuxDetails() { - String line = ""; + String line; try { File etcDir = new File("/etc/"); diff --git a/Everest.iml b/Everest.iml deleted file mode 100644 index d2de8f2..0000000 --- a/Everest.iml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index f71e7e0..accc1d1 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ - com.rohitawate.everest.main.Main + com.rohitawate.everest.Main diff --git a/src/main/java/com/rohitawate/everest/main/Main.java b/src/main/java/com/rohitawate/everest/Main.java similarity index 86% rename from src/main/java/com/rohitawate/everest/main/Main.java rename to src/main/java/com/rohitawate/everest/Main.java index eaf7870..889ad90 100644 --- a/src/main/java/com/rohitawate/everest/main/Main.java +++ b/src/main/java/com/rohitawate/everest/Main.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.rohitawate.everest.main; +package com.rohitawate.everest; import com.rohitawate.everest.util.EverestUtilities; import com.rohitawate.everest.util.Services; @@ -21,9 +21,11 @@ import com.rohitawate.everest.util.settings.SettingsLoader; import com.rohitawate.everest.util.themes.ThemeManager; import javafx.application.Application; import javafx.fxml.FXMLLoader; +import javafx.geometry.Rectangle2D; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; +import javafx.stage.Screen; import javafx.stage.Stage; public class Main extends Application { @@ -41,6 +43,10 @@ public class Main extends Application { Stage dashboardStage = new Stage(); ThemeManager.setTheme(homeWindow); + Rectangle2D screenBounds = Screen.getPrimary().getBounds(); + dashboardStage.setWidth(screenBounds.getWidth() * 0.83); + dashboardStage.setHeight(screenBounds.getHeight() * 0.74); + dashboardStage.getIcons().add(new Image(getClass().getResource("/assets/Logo.png").toExternalForm())); dashboardStage.setScene(new Scene(homeWindow)); dashboardStage.setTitle("Everest"); diff --git a/src/main/java/com/rohitawate/everest/controllers/BodyTabController.java b/src/main/java/com/rohitawate/everest/controllers/BodyTabController.java index e9147f9..21cb390 100644 --- a/src/main/java/com/rohitawate/everest/controllers/BodyTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/BodyTabController.java @@ -44,16 +44,16 @@ public class BodyTabController implements Initializable { @FXML private TabPane bodyTabPane; @FXML - private ComboBox rawInputTypeBox; + ComboBox rawInputTypeBox; @FXML - private TextArea rawInputArea; + TextArea rawInputArea; @FXML - private Tab rawTab, binaryTab, formTab, urlTab; + Tab rawTab, binaryTab, formTab, urlTab; @FXML - private TextField filePathField; + TextField filePathField; - private FormDataTabController formDataTabController; - private URLTabController urlTabController; + FormDataTabController formDataTabController; + URLTabController urlTabController; @Override public void initialize(URL location, ResourceBundle resources) { @@ -135,24 +135,16 @@ public class BodyTabController implements Initializable { try { switch (dashboardState.getContentType()) { case MediaType.TEXT_PLAIN: - rawInputArea.setText(dashboardState.getBody()); - rawInputTypeBox.getSelectionModel().select("PLAIN TEXT"); - bodyTabPane.getSelectionModel().select(rawTab); + setRawTab(dashboardState, "PLAIN TEXT"); break; case MediaType.APPLICATION_JSON: - rawInputArea.setText(dashboardState.getBody()); - rawInputTypeBox.getSelectionModel().select("JSON"); - bodyTabPane.getSelectionModel().select(rawTab); + setRawTab(dashboardState, "JSON"); break; case MediaType.APPLICATION_XML: - rawInputArea.setText(dashboardState.getBody()); - rawInputTypeBox.getSelectionModel().select("XML"); - bodyTabPane.getSelectionModel().select(rawTab); + setRawTab(dashboardState, "XML"); break; case MediaType.TEXT_HTML: - rawInputArea.setText(dashboardState.getBody()); - rawInputTypeBox.getSelectionModel().select("HTML"); - bodyTabPane.getSelectionModel().select(rawTab); + setRawTab(dashboardState, "HTML"); break; case MediaType.MULTIPART_FORM_DATA: // For file tuples @@ -178,4 +170,10 @@ public class BodyTabController implements Initializable { Services.loggingService.logInfo("Dashboard loaded with blank request body.", LocalDateTime.now()); } } + + private void setRawTab(DashboardState dashboardState, String contentType) { + rawInputArea.setText(dashboardState.getBody()); + rawInputTypeBox.getSelectionModel().select(contentType); + bodyTabPane.getSelectionModel().select(rawTab); + } } diff --git a/src/main/java/com/rohitawate/everest/controllers/DashboardController.java b/src/main/java/com/rohitawate/everest/controllers/DashboardController.java index 8e2b1c4..a5d3bd4 100644 --- a/src/main/java/com/rohitawate/everest/controllers/DashboardController.java +++ b/src/main/java/com/rohitawate/everest/controllers/DashboardController.java @@ -17,6 +17,7 @@ package com.rohitawate.everest.controllers; import com.fasterxml.jackson.databind.JsonNode; import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXProgressBar; import com.jfoenix.controls.JFXSnackbar; import com.rohitawate.everest.exceptions.RedirectException; import com.rohitawate.everest.exceptions.UnreliableResponseException; @@ -25,9 +26,7 @@ import com.rohitawate.everest.models.requests.DELETERequest; import com.rohitawate.everest.models.requests.DataDispatchRequest; import com.rohitawate.everest.models.requests.GETRequest; import com.rohitawate.everest.models.responses.EverestResponse; -import com.rohitawate.everest.requestmanager.DELETERequestManager; import com.rohitawate.everest.requestmanager.DataDispatchRequestManager; -import com.rohitawate.everest.requestmanager.GETRequestManager; import com.rohitawate.everest.requestmanager.RequestManager; import com.rohitawate.everest.util.EverestUtilities; import com.rohitawate.everest.util.Services; @@ -40,7 +39,6 @@ import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.CacheHint; import javafx.scene.Parent; import javafx.scene.control.*; import javafx.scene.input.KeyCode; @@ -49,14 +47,18 @@ import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javax.ws.rs.ProcessingException; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.time.LocalDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map.Entry; +import java.util.ResourceBundle; public class DashboardController implements Initializable { @FXML @@ -75,15 +77,15 @@ public class DashboardController implements Initializable { private Label statusCode, statusCodeDescription, responseTime, responseSize, errorTitle, errorDetails, responseType; @FXML - private JFXButton sendButton, cancelButton; + private JFXButton cancelButton, copyBodyButton; @FXML TabPane requestOptionsTab; @FXML Tab paramsTab, authTab, headersTab, bodyTab; @FXML - private Tab visualizerTab; + private Tab visualizerTab, responseHeadersTab; @FXML - private ScrollPane visualizer; + private JFXProgressBar progressBar; private JFXSnackbar snackbar; private final String[] httpMethods = {"GET", "POST", "PUT", "DELETE", "PATCH"}; @@ -93,7 +95,13 @@ public class DashboardController implements Initializable { private HeaderTabController headerTabController; private BodyTabController bodyTabController; private IntegerProperty paramsCountProperty; - private Accordion accordion; + private Visualizer visualizer; + private ResponseHeadersViewer responseHeadersViewer; + + private GETRequest getRequest; + private DataDispatchRequest dataRequest; + private DELETERequest deleteRequest; + private HashMap params; @Override public void initialize(URL url, ResourceBundle rb) { @@ -143,14 +151,30 @@ public class DashboardController implements Initializable { } }); + copyBodyButton.setOnAction(e -> { + responseArea.selectAll(); + responseArea.copy(); + responseArea.deselect(); + snackbar.show("Response body copied to clipboard.", 5000); + }); + errorTitle.setText("Oops... That's embarrassing!"); errorDetails.setText("Something went wrong. Try to make another request.\nRestart Everest if that doesn't work."); - setupVisualizer(); + visualizer = new Visualizer(); + visualizerTab.setContent(visualizer); + + responseHeadersViewer = new ResponseHeadersViewer(); + responseHeadersTab.setContent(responseHeadersViewer); } @FXML void sendRequest() { + if (requestManager != null && requestManager.isRunning()) { + snackbar.show("Please wait while the current request is processed.", 5000); + return; + } + promptLayer.setVisible(false); if (responseBox.getChildren().size() == 2) { responseBox.getChildren().remove(0); @@ -159,6 +183,14 @@ public class DashboardController implements Initializable { try { String address = addressField.getText(); + + // Prepends "https://" to the address if not already done. + if (!(address.startsWith("https://") || address.startsWith("http://"))) { + address = "https://" + address; + addressField.setText(address); + responseArea.requestFocus(); + } + if (address.equals("")) { promptLayer.setVisible(true); snackbar.show("Please enter an address.", 3000); @@ -166,62 +198,78 @@ public class DashboardController implements Initializable { } switch (httpMethodBox.getValue()) { case "GET": - GETRequest getRequest = new GETRequest(addressField.getText()); - getRequest.setHeaders(headerTabController.getHeaders()); + if (getRequest == null) + getRequest = new GETRequest(); - /* - Creates a new instance if its the first request of that session or - the HTTP method type was changed. Also checks if a request is already being processed. - */ - if (requestManager == null || requestManager.getClass() != GETRequestManager.class) - requestManager = new GETRequestManager(getRequest); - else if (requestManager.isRunning()) { - snackbar.show("Please wait while the current request is processed.", 3000); - return; - } else { - requestManager.setRequest(getRequest); - } + getRequest.setTarget(address); + getRequest.setHeaders(headerTabController.getSelectedHeaders()); + + requestManager = Services.pool.get(); + requestManager.setRequest(getRequest); cancelButton.setOnAction(e -> requestManager.cancel()); configureRequestManager(); requestManager.start(); break; - // DataDispatchRequestManager will generate appropriate request based on the type. case "POST": case "PUT": case "PATCH": - DataDispatchRequest dataDispatchRequest = - bodyTabController.getBasicRequest(httpMethodBox.getValue()); - dataDispatchRequest.setTarget(addressField.getText()); - dataDispatchRequest.setHeaders(headerTabController.getHeaders()); + if (dataRequest == null) + dataRequest = new DataDispatchRequest(); - if (requestManager == null || requestManager.getClass() != DataDispatchRequestManager.class) - requestManager = new DataDispatchRequestManager(dataDispatchRequest); - else if (requestManager.isRunning()) { - snackbar.show("Please wait while the current request is processed.", 3000); - return; - } else { - requestManager.setRequest(dataDispatchRequest); + dataRequest.setRequestType(httpMethodBox.getValue()); + dataRequest.setTarget(address); + dataRequest.setHeaders(headerTabController.getSelectedHeaders()); + + if (bodyTabController.rawTab.isSelected()) { + String contentType; + switch (bodyTabController.rawInputTypeBox.getValue()) { + case "PLAIN TEXT": + contentType = MediaType.TEXT_PLAIN; + break; + case "JSON": + contentType = MediaType.APPLICATION_JSON; + break; + case "XML": + contentType = MediaType.APPLICATION_XML; + break; + case "HTML": + contentType = MediaType.TEXT_HTML; + break; + default: + contentType = MediaType.TEXT_PLAIN; + } + dataRequest.setContentType(contentType); + dataRequest.setBody(bodyTabController.rawInputArea.getText()); + } else if (bodyTabController.formTab.isSelected()) { + dataRequest.setStringTuples(bodyTabController.formDataTabController.getStringTuples()); + dataRequest.setFileTuples(bodyTabController.formDataTabController.getFileTuples()); + dataRequest.setContentType(MediaType.MULTIPART_FORM_DATA); + } else if (bodyTabController.binaryTab.isSelected()) { + dataRequest.setBody(bodyTabController.filePathField.getText()); + dataRequest.setContentType(MediaType.APPLICATION_OCTET_STREAM); + } else if (bodyTabController.urlTab.isSelected()) { + dataRequest.setStringTuples(bodyTabController.urlTabController.getStringTuples()); + dataRequest.setContentType(MediaType.APPLICATION_FORM_URLENCODED); } + requestManager = Services.pool.data(); + requestManager.setRequest(dataRequest); + cancelButton.setOnAction(e -> requestManager.cancel()); configureRequestManager(); requestManager.start(); break; case "DELETE": - DELETERequest deleteRequest = new DELETERequest(addressField.getText()); - deleteRequest.setHeaders(headerTabController.getHeaders()); + if (deleteRequest == null) + deleteRequest = new DELETERequest(); - if (requestManager == null || requestManager.getClass() != DELETERequestManager.class) - requestManager = new DELETERequestManager(deleteRequest); - else if (requestManager.isRunning()) { - snackbar.show("Please wait while the current request is processed.", 3000); - return; - } else { - requestManager.setRequest(deleteRequest); - } + deleteRequest.setTarget(address); + deleteRequest.setHeaders(headerTabController.getSelectedHeaders()); + requestManager = Services.pool.delete(); requestManager.setRequest(deleteRequest); + cancelButton.setOnAction(e -> requestManager.cancel()); configureRequestManager(); requestManager.start(); @@ -242,6 +290,7 @@ public class DashboardController implements Initializable { } private void configureRequestManager() { + progressBar.progressProperty().bind(requestManager.progressProperty()); requestManager.setOnRunning(e -> whileRunning()); requestManager.setOnSucceeded(e -> onSucceeded()); requestManager.setOnCancelled(e -> onCancelled()); @@ -293,7 +342,7 @@ public class DashboardController implements Initializable { } private void onSucceeded() { - updateDashboard(requestManager.getValue()); + displayResponse(requestManager.getValue()); errorLayer.setVisible(false); loadingLayer.setVisible(false); requestManager.reset(); @@ -305,13 +354,14 @@ public class DashboardController implements Initializable { loadingLayer.setVisible(true); } - private void updateDashboard(EverestResponse response) { + private void displayResponse(EverestResponse response) { prettifyResponseBody(response); responseBox.getChildren().add(0, responseDetails); statusCode.setText(Integer.toString(response.getStatusCode())); statusCodeDescription.setText(Response.Status.fromStatusCode(response.getStatusCode()).getReasonPhrase()); responseTime.setText(Long.toString(response.getTime()) + " ms"); responseSize.setText(Integer.toString(response.getSize()) + " B"); + responseHeadersViewer.populate(response); } private void prettifyResponseBody(EverestResponse response) { @@ -324,20 +374,20 @@ public class DashboardController implements Initializable { String responseBody = response.getBody(); + visualizerTab.setDisable(true); + visualizer.clear(); try { if (type != null) { // Selects only the part preceding the ';', skipping the character encoding type = type.split(";")[0]; - visualizerTab.setDisable(true); switch (type.toLowerCase()) { case "application/json": responseType.setText("JSON"); JsonNode node = EverestUtilities.mapper.readTree(responseBody); responseArea.setText(EverestUtilities.mapper.writeValueAsString(node)); - accordion.getPanes().clear(); visualizerTab.setDisable(false); - populateVisualizer(accordion, "root", node); + visualizer.populate(node); break; case "application/xml": responseType.setText("XML"); @@ -364,84 +414,6 @@ public class DashboardController implements Initializable { } } - private void setupVisualizer() { - accordion = new Accordion(); - accordion.setCache(true); - accordion.setCacheHint(CacheHint.SPEED); - visualizer.setContent(accordion); - } - - private void populateVisualizer(Accordion rootAccordion, String rootName, JsonNode root) { - JsonNode currentNode; - VBox container = new VBox(); - container.setStyle("-fx-padding: 3px 30px"); - Label valueLabel; - TitledPane pane = new TitledPane(rootName, container); - Tooltip valueTooltip; - - if (root.isArray()) { - Iterator iterator = root.elements(); - - while (iterator.hasNext()) { - currentNode = iterator.next(); - - if (currentNode.isValueNode()) { - valueLabel = new Label(currentNode.toString()); - valueLabel.getStyleClass().add("visualizerValueLabel"); - valueLabel.setWrapText(true); - valueTooltip = new Tooltip(currentNode.toString()); - valueLabel.setTooltip(valueTooltip); - - container.getChildren().add(valueLabel); - } else if (currentNode.isObject()) { - Accordion arrayAccordion = new Accordion(); - container.getChildren().add(arrayAccordion); - populateVisualizer(arrayAccordion, "", currentNode); - } - } - rootAccordion.getPanes().add(pane); - } else { - Iterator> iterator = root.fields(); - Entry currentEntry; - HBox valueContainer; - Label keyLabel; - Tooltip keyTooltip; - - while (iterator.hasNext()) { - currentEntry = iterator.next(); - currentNode = currentEntry.getValue(); - - if (currentNode.isValueNode()) { - keyLabel = new Label(currentEntry.getKey() + ": "); - keyLabel.setStyle("-fx-font-weight: bold"); - keyLabel.getStyleClass().add("visualizerKeyLabel"); - keyTooltip = new Tooltip(currentEntry.getKey()); - keyLabel.setTooltip(keyTooltip); - - valueLabel = new Label(currentNode.toString()); - valueLabel.getStyleClass().add("visualizerValueLabel"); - valueLabel.setWrapText(true); - valueTooltip = new Tooltip(currentNode.toString()); - valueLabel.setTooltip(valueTooltip); - - valueContainer = new HBox(keyLabel, valueLabel); - container.getChildren().add(valueContainer); - } else if (currentNode.isArray() || currentNode.isObject()) { - Accordion arrayAccordion = new Accordion(); - container.getChildren().add(arrayAccordion); - populateVisualizer(arrayAccordion, currentEntry.getKey(), currentNode); - } - } - rootAccordion.getPanes().add(pane); - } - - if (!rootName.equals("root")) { - pane.getStyleClass().add("nonRootTitledPane"); // Special CSS class to set padding for non-root panes only - } else { - rootAccordion.setExpandedPane(pane); - } - } - private void applyDashboardSettings() { String responseAreaCSS = "-fx-font-family: " + Settings.responseAreaFont + ";" + "-fx-font-size: " + Settings.responseAreaFontSize; @@ -472,8 +444,10 @@ public class DashboardController implements Initializable { } private HashMap getParams() { - HashMap params = new HashMap<>(); + if (params == null) + params = new HashMap<>(); + params.clear(); for (StringKeyValueFieldController controller : paramsControllers) if (controller.isChecked()) params.put(controller.getHeader().getKey(), controller.getHeader().getValue()); @@ -542,7 +516,7 @@ public class DashboardController implements Initializable { case "PUT": case "PATCH": dashboardState = new DashboardState(bodyTabController.getBasicRequest(httpMethodBox.getValue())); - dashboardState.setHeaders(headerTabController.getHeaders()); + dashboardState.setHeaders(headerTabController.getSelectedHeaders()); break; default: // For GET, DELETE requests @@ -555,7 +529,7 @@ public class DashboardController implements Initializable { Services.loggingService.logInfo("Dashboard state was saved with an invalid URL.", LocalDateTime.now()); } dashboardState.setHttpMethod(httpMethodBox.getValue()); - dashboardState.setHeaders(headerTabController.getHeaders()); + dashboardState.setHeaders(headerTabController.getSelectedHeaders()); dashboardState.setParams(getParams()); return dashboardState; diff --git a/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java b/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java index 4c77787..0935258 100644 --- a/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/FormDataTabController.java @@ -44,6 +44,9 @@ public class FormDataTabController implements Initializable { private List fileControllers; private IntegerProperty fileControllersCount, stringControllersCount; + private HashMap stringMap; + private HashMap fileMap; + @Override public void initialize(URL location, ResourceBundle resources) { stringControllers = new ArrayList<>(); @@ -56,24 +59,22 @@ public class FormDataTabController implements Initializable { addStringField(); } - private void addFileField() { - addFileField("", "", null); - } @FXML private void addFileField(ActionEvent event) { addFileField("", "", event); } + private void addFileField() { + addFileField("", "", null); + } + public void addFileField(String key, String value) { addFileField(key, value, null); } private void addFileField(String key, String value, ActionEvent event) { - /* - Re-uses previous field if it is empty, - else loads a new one. - */ + //Re-uses previous field if it is empty else loads a new one. if (fileControllers.size() > 0 && event == null) { FileKeyValueFieldController previousController = fileControllers.get(fileControllers.size() - 1); @@ -106,15 +107,15 @@ public class FormDataTabController implements Initializable { } } - private void addStringField() { - addStringField("", "", null); - } - @FXML private void addStringField(ActionEvent event) { addStringField("", "", event); } + private void addStringField() { + addStringField("", "", null); + } + public void addStringField(String key, String value) { addStringField(key, value, null); } @@ -156,20 +157,26 @@ public class FormDataTabController implements Initializable { } public HashMap getStringTuples() { - HashMap tuples = new HashMap<>(); + if (stringMap == null) + stringMap = new HashMap<>(); + + stringMap.clear(); for (StringKeyValueFieldController controller : stringControllers) { if (controller.isChecked()) - tuples.put(controller.getHeader().getKey(), controller.getHeader().getValue()); + stringMap.put(controller.getHeader().getKey(), controller.getHeader().getValue()); } - return tuples; + return stringMap; } public HashMap getFileTuples() { - HashMap tuples = new HashMap<>(); + if (fileMap == null) + fileMap = new HashMap<>(); + + fileMap.clear(); for (FileKeyValueFieldController controller : fileControllers) { if (controller.isChecked()) - tuples.put(controller.getHeader().getKey(), controller.getHeader().getValue()); + fileMap.put(controller.getHeader().getKey(), controller.getHeader().getValue()); } - return tuples; + return fileMap; } } diff --git a/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java b/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java index 2722c1e..cbe6f6f 100644 --- a/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/HeaderTabController.java @@ -43,6 +43,8 @@ public class HeaderTabController implements Initializable { private List controllers; private IntegerProperty controllersCount; + private HashMap headers; + @Override public void initialize(URL location, ResourceBundle resources) { controllers = new ArrayList<>(); @@ -100,9 +102,14 @@ public class HeaderTabController implements Initializable { } } + /** + * Returns a map of the selected headers. + */ + public HashMap getSelectedHeaders() { + if (headers == null) + headers = new HashMap<>(); - public HashMap getHeaders() { - HashMap headers = new HashMap<>(); + headers.clear(); for (StringKeyValueFieldController controller : controllers) { if (controller.isChecked()) headers.put(controller.getHeader().getKey(), controller.getHeader().getValue()); diff --git a/src/main/java/com/rohitawate/everest/controllers/ResponseHeadersViewer.java b/src/main/java/com/rohitawate/everest/controllers/ResponseHeadersViewer.java new file mode 100644 index 0000000..23f2dce --- /dev/null +++ b/src/main/java/com/rohitawate/everest/controllers/ResponseHeadersViewer.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Rohit Awate. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rohitawate.everest.controllers; + +import com.rohitawate.everest.models.responses.EverestResponse; +import javafx.geometry.Insets; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +class ResponseHeadersViewer extends ScrollPane { + private VBox container; + + ResponseHeadersViewer() { + this.container = new VBox(); + container.setPadding(new Insets(10, 20, 10, 20)); + this.setContent(container); + + this.setFitToHeight(true); + this.setFitToWidth(true); + } + + void populate(EverestResponse response) { + container.getChildren().clear(); + + response.getHeaders().forEach((key, value) -> { + Label keyLabel = new Label(key + ": "); + keyLabel.getStyleClass().addAll("visualizerKeyLabel", "visualizerLabel"); + + Label valueLabel = new Label(value.get(0)); + valueLabel.getStyleClass().addAll("visualizerValueLabel", "visualizerLabel"); + + container.getChildren().add(new HBox(keyLabel, valueLabel)); + }); + } +} diff --git a/src/main/java/com/rohitawate/everest/controllers/URLTabController.java b/src/main/java/com/rohitawate/everest/controllers/URLTabController.java index cb52339..69449e1 100644 --- a/src/main/java/com/rohitawate/everest/controllers/URLTabController.java +++ b/src/main/java/com/rohitawate/everest/controllers/URLTabController.java @@ -42,6 +42,7 @@ public class URLTabController implements Initializable { private List controllers; private IntegerProperty controllersCount; + private HashMap tuples; @Override public void initialize(URL location, ResourceBundle resources) { @@ -101,11 +102,14 @@ public class URLTabController implements Initializable { } public HashMap getStringTuples() { - HashMap headers = new HashMap<>(); + if (tuples == null) + tuples = new HashMap<>(); + + tuples.clear(); for (StringKeyValueFieldController controller : controllers) { if (controller.isChecked()) - headers.put(controller.getHeader().getKey(), controller.getHeader().getValue()); + tuples.put(controller.getHeader().getKey(), controller.getHeader().getValue()); } - return headers; + return tuples; } } diff --git a/src/main/java/com/rohitawate/everest/controllers/Visualizer.java b/src/main/java/com/rohitawate/everest/controllers/Visualizer.java new file mode 100644 index 0000000..7712367 --- /dev/null +++ b/src/main/java/com/rohitawate/everest/controllers/Visualizer.java @@ -0,0 +1,119 @@ +/* + * Copyright 2018 Rohit Awate. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rohitawate.everest.controllers; + +import com.fasterxml.jackson.databind.JsonNode; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +class Visualizer extends ScrollPane { + private TreeView visualizer; + + Visualizer() { + this.visualizer = new TreeView<>(); + this.visualizer.setShowRoot(false); + this.setContent(this.visualizer); + + this.setFitToHeight(true); + this.setFitToWidth(true); + } + + void populate(JsonNode node) { + this.populate(new TreeItem<>(), "root", node); + } + + private void populate(TreeItem rootItem, String rootName, JsonNode root) { + if (rootName.equals("root")) { + this.visualizer.setRoot(rootItem); + } + + Label rootLabel = new Label(rootName); + rootLabel.getStyleClass().addAll("visualizerRootLabel", "visualizerLabel"); + rootItem.setValue(new HBox(rootLabel)); + + JsonNode currentNode; + Label valueLabel; + HBox valueContainer; + List> items = new LinkedList<>(); + Tooltip valueTooltip; + + if (root.isArray()) { + Iterator iterator = root.elements(); + int i = 0; + + while (iterator.hasNext()) { + currentNode = iterator.next(); + + if (currentNode.isValueNode()) { + valueLabel = new Label(i++ + ": " + currentNode.toString()); + valueLabel.getStyleClass().addAll("visualizerValueLabel", "visualizerLabel"); + valueLabel.setWrapText(true); + valueTooltip = new Tooltip(currentNode.toString()); + valueLabel.setTooltip(valueTooltip); + + valueContainer = new HBox(valueLabel); + items.add(new TreeItem<>(valueContainer)); + } else if (currentNode.isObject()) { + TreeItem newRoot = new TreeItem<>(); + items.add(newRoot); + populate(newRoot, i++ + ": [Anonymous Object]", currentNode); + } + } + } else { + Iterator> iterator = root.fields(); + Map.Entry currentEntry; + Label keyLabel; + Tooltip keyTooltip; + + while (iterator.hasNext()) { + currentEntry = iterator.next(); + currentNode = currentEntry.getValue(); + + if (currentNode.isValueNode()) { + keyLabel = new Label(currentEntry.getKey() + ": "); + keyLabel.getStyleClass().addAll("visualizerKeyLabel", "visualizerLabel"); + keyTooltip = new Tooltip(currentEntry.getKey()); + keyLabel.setTooltip(keyTooltip); + + valueLabel = new Label(currentNode.toString()); + valueLabel.getStyleClass().addAll("visualizerValueLabel", "visualizerLabel"); + valueLabel.setWrapText(true); + valueTooltip = new Tooltip(currentNode.toString()); + valueLabel.setTooltip(valueTooltip); + + valueContainer = new HBox(keyLabel, valueLabel); + items.add(new TreeItem<>(valueContainer)); + } else if (currentNode.isArray() || currentNode.isObject()) { + TreeItem newRoot = new TreeItem<>(); + items.add(newRoot); + populate(newRoot, currentEntry.getKey(), currentNode); + } + } + } + + rootItem.getChildren().addAll(items); + } + + public void clear() { + this.visualizer.setRoot(null); + } +} diff --git a/src/main/java/com/rohitawate/everest/models/requests/DataDispatchRequest.java b/src/main/java/com/rohitawate/everest/models/requests/DataDispatchRequest.java index d8a499a..2638b3b 100644 --- a/src/main/java/com/rohitawate/everest/models/requests/DataDispatchRequest.java +++ b/src/main/java/com/rohitawate/everest/models/requests/DataDispatchRequest.java @@ -71,4 +71,8 @@ public class DataDispatchRequest extends EverestRequest implements Serializable public String getRequestType() { return requestType; } + + public void setRequestType(String requestType) { + this.requestType = requestType; + } } diff --git a/src/main/java/com/rohitawate/everest/models/responses/EverestResponse.java b/src/main/java/com/rohitawate/everest/models/responses/EverestResponse.java index d538920..1d7f0b6 100644 --- a/src/main/java/com/rohitawate/everest/models/responses/EverestResponse.java +++ b/src/main/java/com/rohitawate/everest/models/responses/EverestResponse.java @@ -17,6 +17,7 @@ package com.rohitawate.everest.models.responses; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; public class EverestResponse { private String body; @@ -24,6 +25,7 @@ public class EverestResponse { private long time; private int size; private MediaType mediaType; + private MultivaluedMap headers; public String getBody() { return body; @@ -64,4 +66,12 @@ public class EverestResponse { public void setStatusCode(int statusCode) { this.statusCode = statusCode; } + + public MultivaluedMap getHeaders() { + return headers; + } + + public void setHeaders(MultivaluedMap headers) { + this.headers = headers; + } } diff --git a/src/main/java/com/rohitawate/everest/requestmanager/DELETERequestManager.java b/src/main/java/com/rohitawate/everest/requestmanager/DELETERequestManager.java index 693167a..61ae6b6 100644 --- a/src/main/java/com/rohitawate/everest/requestmanager/DELETERequestManager.java +++ b/src/main/java/com/rohitawate/everest/requestmanager/DELETERequestManager.java @@ -16,7 +16,6 @@ package com.rohitawate.everest.requestmanager; -import com.rohitawate.everest.models.requests.EverestRequest; import com.rohitawate.everest.models.responses.EverestResponse; import javafx.concurrent.Task; @@ -25,8 +24,8 @@ import javax.ws.rs.core.Response; public class DELETERequestManager extends RequestManager { - public DELETERequestManager(EverestRequest request) { - super(request); + DELETERequestManager() { + } @Override @@ -36,9 +35,9 @@ public class DELETERequestManager extends RequestManager { protected EverestResponse call() throws Exception { Invocation invocation = requestBuilder.buildDelete(); - long initialTime = System.currentTimeMillis(); + initialTime = System.currentTimeMillis(); Response serverResponse = invocation.invoke(); - response.setTime(initialTime, System.currentTimeMillis()); + finalTime = System.currentTimeMillis(); processServerResponse(serverResponse); diff --git a/src/main/java/com/rohitawate/everest/requestmanager/DataDispatchRequestManager.java b/src/main/java/com/rohitawate/everest/requestmanager/DataDispatchRequestManager.java index 42d0ce8..1ada390 100644 --- a/src/main/java/com/rohitawate/everest/requestmanager/DataDispatchRequestManager.java +++ b/src/main/java/com/rohitawate/everest/requestmanager/DataDispatchRequestManager.java @@ -17,7 +17,6 @@ package com.rohitawate.everest.requestmanager; import com.rohitawate.everest.models.requests.DataDispatchRequest; -import com.rohitawate.everest.models.requests.EverestRequest; import com.rohitawate.everest.models.responses.EverestResponse; import javafx.concurrent.Task; import org.glassfish.jersey.media.multipart.FormDataMultiPart; @@ -42,8 +41,8 @@ public class DataDispatchRequestManager extends RequestManager { private DataDispatchRequest dataDispatchRequest; private String requestType; - public DataDispatchRequestManager(EverestRequest request) { - super(request); + DataDispatchRequestManager() { + } @Override @@ -55,9 +54,9 @@ public class DataDispatchRequestManager extends RequestManager { requestType = dataDispatchRequest.getRequestType(); Invocation invocation = appendBody(); - long initialTime = System.currentTimeMillis(); + initialTime = System.currentTimeMillis(); Response serverResponse = invocation.invoke(); - response.setTime(initialTime, System.currentTimeMillis()); + finalTime = System.currentTimeMillis(); processServerResponse(serverResponse); @@ -73,6 +72,11 @@ public class DataDispatchRequestManager extends RequestManager { * @return invocation object */ private Invocation appendBody() throws Exception { + /* + Checks if a custom mime-type is mentioned in the headers. + If present, it will override the logical Content-Type. + */ + String overriddenContentType = request.getHeaders().get("Content-Type"); Invocation invocation = null; Map.Entry mapEntry; @@ -80,6 +84,7 @@ public class DataDispatchRequestManager extends RequestManager { case MediaType.MULTIPART_FORM_DATA: FormDataMultiPart formData = new FormDataMultiPart(); + // Adding the string tuples to the request HashMap pairs = dataDispatchRequest.getStringTuples(); for (Map.Entry entry : pairs.entrySet()) { mapEntry = (Map.Entry) entry; @@ -89,8 +94,10 @@ public class DataDispatchRequestManager extends RequestManager { String filePath; File file; boolean fileException = false; - StringBuilder fileExceptionMessage = new StringBuilder(); + String fileExceptionMessage = null; pairs = dataDispatchRequest.getFileTuples(); + + // Adding the file tuples to the request for (Map.Entry entry : pairs.entrySet()) { mapEntry = (Map.Entry) entry; filePath = mapEntry.getValue(); @@ -101,14 +108,13 @@ public class DataDispatchRequestManager extends RequestManager { file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); else { fileException = true; - fileExceptionMessage.append(" - "); - fileExceptionMessage.append(filePath); - fileExceptionMessage.append("\n"); + // For pretty-printing FileNotFoundException to the UI + fileExceptionMessage = " - " + filePath + "\n"; } } if (fileException) { - throw new FileNotFoundException(fileExceptionMessage.toString()); + throw new FileNotFoundException(fileExceptionMessage); } formData.setMediaType(MediaType.MULTIPART_FORM_DATA_TYPE); @@ -119,6 +125,8 @@ public class DataDispatchRequestManager extends RequestManager { invocation = requestBuilder.buildPut(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA_TYPE)); break; case MediaType.APPLICATION_OCTET_STREAM: + if (overriddenContentType == null) + overriddenContentType = MediaType.APPLICATION_OCTET_STREAM; filePath = dataDispatchRequest.getBody(); File check = new File(filePath); @@ -130,11 +138,14 @@ public class DataDispatchRequestManager extends RequestManager { FileInputStream stream = new FileInputStream(filePath); if (requestType.equals("POST")) - invocation = requestBuilder.buildPost(Entity.entity(stream, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + invocation = requestBuilder.buildPost(Entity.entity(stream, overriddenContentType)); else - invocation = requestBuilder.buildPut(Entity.entity(stream, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + invocation = requestBuilder.buildPut(Entity.entity(stream, overriddenContentType)); break; case MediaType.APPLICATION_FORM_URLENCODED: + if (overriddenContentType == null) + overriddenContentType = MediaType.APPLICATION_FORM_URLENCODED; + Form form = new Form(); for (Map.Entry entry : dataDispatchRequest.getStringTuples().entrySet()) { @@ -143,24 +154,27 @@ public class DataDispatchRequestManager extends RequestManager { } if (requestType.equals("POST")) - invocation = requestBuilder.buildPost(Entity.form(form)); + invocation = requestBuilder.buildPost(Entity.entity(form, overriddenContentType)); else - invocation = requestBuilder.buildPut(Entity.form(form)); + invocation = requestBuilder.buildPut(Entity.entity(form, overriddenContentType)); break; default: // Handles raw data types (JSON, Plain text, XML, HTML) + String originalContentType = dataDispatchRequest.getContentType(); + if (overriddenContentType == null) + overriddenContentType = originalContentType; switch (requestType) { case "POST": invocation = requestBuilder - .buildPost(Entity.entity(dataDispatchRequest.getBody(), dataDispatchRequest.getContentType())); + .buildPost(Entity.entity(dataDispatchRequest.getBody(), overriddenContentType)); break; case "PUT": invocation = requestBuilder - .buildPut(Entity.entity(dataDispatchRequest.getBody(), dataDispatchRequest.getContentType())); + .buildPut(Entity.entity(dataDispatchRequest.getBody(), overriddenContentType)); break; case "PATCH": invocation = requestBuilder - .build("PATCH", Entity.entity(dataDispatchRequest.getBody(), dataDispatchRequest.getContentType())); + .build("PATCH", Entity.entity(dataDispatchRequest.getBody(), overriddenContentType)); break; } } diff --git a/src/main/java/com/rohitawate/everest/requestmanager/GETRequestManager.java b/src/main/java/com/rohitawate/everest/requestmanager/GETRequestManager.java index bbf18dc..951510f 100644 --- a/src/main/java/com/rohitawate/everest/requestmanager/GETRequestManager.java +++ b/src/main/java/com/rohitawate/everest/requestmanager/GETRequestManager.java @@ -16,7 +16,6 @@ package com.rohitawate.everest.requestmanager; -import com.rohitawate.everest.models.requests.EverestRequest; import com.rohitawate.everest.models.responses.EverestResponse; import javafx.concurrent.Task; @@ -24,8 +23,8 @@ import javax.ws.rs.core.Response; public class GETRequestManager extends RequestManager { - public GETRequestManager(EverestRequest request) { - super(request); + GETRequestManager() { + } @Override @@ -33,9 +32,9 @@ public class GETRequestManager extends RequestManager { return new Task() { @Override protected EverestResponse call() throws Exception { - long initialTime = System.currentTimeMillis(); + initialTime = System.currentTimeMillis(); Response serverResponse = requestBuilder.get(); - response.setTime(initialTime, System.currentTimeMillis()); + finalTime = System.currentTimeMillis(); processServerResponse(serverResponse); diff --git a/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java b/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java index 532183f..2e9f84a 100644 --- a/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java +++ b/src/main/java/com/rohitawate/everest/requestmanager/RequestManager.java @@ -34,23 +34,32 @@ import java.util.Map; public abstract class RequestManager extends Service { private final Client client; + long initialTime; + long finalTime; + EverestRequest request; EverestResponse response; Builder requestBuilder; - RequestManager(EverestRequest request) { + RequestManager() { + this.client = initClient(); + } + + private Client initClient() { + Client client; client = ClientBuilder.newBuilder() .register(MultiPartFeature.class) .build(); + // Required for making PATCH requests through Jersey client.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true); + if (Settings.connectionTimeOutEnable) client.property(ClientProperties.CONNECT_TIMEOUT, Settings.connectionTimeOut); if (Settings.connectionReadTimeOutEnable) client.property(ClientProperties.READ_TIMEOUT, Settings.connectionReadTimeOut); - response = new EverestResponse(); - setRequest(request); + return client; } public void setRequest(EverestRequest request) { @@ -80,7 +89,10 @@ public abstract class RequestManager extends Service { } String responseBody = serverResponse.readEntity(String.class); + response = new EverestResponse(); + response.setHeaders(serverResponse.getStringHeaders()); + response.setTime(initialTime, finalTime); response.setBody(responseBody); response.setMediaType(serverResponse.getMediaType()); response.setStatusCode(serverResponse.getStatus()); diff --git a/src/main/java/com/rohitawate/everest/requestmanager/RequestManagersPool.java b/src/main/java/com/rohitawate/everest/requestmanager/RequestManagersPool.java new file mode 100644 index 0000000..a081c0e --- /dev/null +++ b/src/main/java/com/rohitawate/everest/requestmanager/RequestManagersPool.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 Rohit Awate. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rohitawate.everest.requestmanager; + +import java.util.LinkedList; + +public class RequestManagersPool { + private LinkedList getManagers; + private LinkedList dataManagers; + private LinkedList deleteManagers; + + public GETRequestManager get() { + if (getManagers == null) { + GETRequestManager newManager = new GETRequestManager(); + + new Thread(() -> { + getManagers = new LinkedList<>(); + getManagers.add(newManager); + }).start(); + + return newManager; + } else { + for (GETRequestManager getManager : getManagers) { + if (!getManager.isRunning()) + return getManager; + } + + GETRequestManager newManager = new GETRequestManager(); + getManagers.add(newManager); + + return newManager; + } + } + + public DataDispatchRequestManager data() { + if (dataManagers == null) { + DataDispatchRequestManager newManager = new DataDispatchRequestManager(); + + new Thread(() -> { + dataManagers = new LinkedList<>(); + dataManagers.add(newManager); + }).start(); + + return newManager; + } else { + for (DataDispatchRequestManager dataManager : dataManagers) { + if (!dataManager.isRunning()) + return dataManager; + } + + DataDispatchRequestManager newManager = new DataDispatchRequestManager(); + dataManagers.add(newManager); + + return newManager; + } + } + + public DELETERequestManager delete() { + if (deleteManagers == null) { + DELETERequestManager newManager = new DELETERequestManager(); + + new Thread(() -> { + deleteManagers = new LinkedList<>(); + deleteManagers.add(newManager); + }).start(); + + return newManager; + } else { + for (DELETERequestManager deleteManager : deleteManagers) { + if (!deleteManager.isRunning()) + return deleteManager; + } + + DELETERequestManager newManager = new DELETERequestManager(); + deleteManagers.add(newManager); + + return newManager; + } + } +} diff --git a/src/main/java/com/rohitawate/everest/util/EverestUtilities.java b/src/main/java/com/rohitawate/everest/util/EverestUtilities.java index 8b06948..6e8eb11 100644 --- a/src/main/java/com/rohitawate/everest/util/EverestUtilities.java +++ b/src/main/java/com/rohitawate/everest/util/EverestUtilities.java @@ -19,12 +19,12 @@ package com.rohitawate.everest.util; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.time.LocalDateTime; public class EverestUtilities { @@ -50,19 +50,15 @@ public class EverestUtilities { */ public static void createBugReporter() { new Thread(() -> { - File bugReporterFile = new File("Everest/BugReporter.jar"); - if (!bugReporterFile.exists()) { - InputStream inputStream = EverestUtilities.class.getResourceAsStream("/BugReporter.jar"); - Path bugReporter = Paths.get("Everest/BugReporter.jar"); - try { - Files.copy(inputStream, bugReporter); - } catch (IOException e) { - e.printStackTrace(); - } - Services.loggingService.logInfo("BugReporter was copied to installation folder.", LocalDateTime.now()); - } else { - Services.loggingService.logInfo("BugReporter was found.", LocalDateTime.now()); + InputStream inputStream = EverestUtilities.class.getResourceAsStream("/BugReporter.jar"); + Path bugReporter = Paths.get("Everest/BugReporter.jar"); + try { + Files.copy(inputStream, bugReporter, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); } + Services.loggingService.logInfo("BugReporter was copied to installation folder.", LocalDateTime.now()); + }).start(); } } diff --git a/src/main/java/com/rohitawate/everest/util/Services.java b/src/main/java/com/rohitawate/everest/util/Services.java index d165e1a..4f84c57 100644 --- a/src/main/java/com/rohitawate/everest/util/Services.java +++ b/src/main/java/com/rohitawate/everest/util/Services.java @@ -18,6 +18,7 @@ package com.rohitawate.everest.util; import com.google.common.util.concurrent.MoreExecutors; import com.rohitawate.everest.controllers.HomeWindowController; +import com.rohitawate.everest.requestmanager.RequestManagersPool; import com.rohitawate.everest.util.history.HistoryManager; import com.rohitawate.everest.util.logging.Level; import com.rohitawate.everest.util.logging.LoggingService; @@ -30,12 +31,14 @@ public class Services { public static LoggingService loggingService; public static HomeWindowController homeWindowController; public static Executor singleExecutor; + public static RequestManagersPool pool; public static void start() { startServicesThread = new Thread(() -> { loggingService = new LoggingService(Level.INFO); historyManager = new HistoryManager(); singleExecutor = MoreExecutors.directExecutor(); + pool = new RequestManagersPool(); }); startServicesThread.start(); diff --git a/src/main/java/com/rohitawate/everest/util/history/HistoryManager.java b/src/main/java/com/rohitawate/everest/util/history/HistoryManager.java index 3512860..bb7d4f0 100644 --- a/src/main/java/com/rohitawate/everest/util/history/HistoryManager.java +++ b/src/main/java/com/rohitawate/everest/util/history/HistoryManager.java @@ -61,8 +61,8 @@ public class HistoryManager { /** * Creates and initializes the database with necessary tables if not already done. * - * @throws IOException - * @throws SQLException + * @throws IOException - If unable to establish a connection to the database. + * @throws SQLException - If invalid statement is executed on the database. */ private void initDatabase() throws IOException, SQLException { // Read all queries from Queries.json diff --git a/src/main/java/com/rohitawate/everest/util/logging/Log.java b/src/main/java/com/rohitawate/everest/util/logging/Log.java index 397493c..8cb9032 100644 --- a/src/main/java/com/rohitawate/everest/util/logging/Log.java +++ b/src/main/java/com/rohitawate/everest/util/logging/Log.java @@ -17,40 +17,8 @@ package com.rohitawate.everest.util.logging; class Log { - private Level level; - private String message; - private String time; - private Exception exception; - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public String getTime() { - return time; - } - - public void setTime(String time) { - this.time = time; - } - - public Exception getException() { - return exception; - } - - public void setException(Exception exception) { - this.exception = exception; - } + Level level; + String message; + String time; + Exception exception; } diff --git a/src/main/java/com/rohitawate/everest/util/logging/Logger.java b/src/main/java/com/rohitawate/everest/util/logging/Logger.java index cf678c3..ac21aef 100644 --- a/src/main/java/com/rohitawate/everest/util/logging/Logger.java +++ b/src/main/java/com/rohitawate/everest/util/logging/Logger.java @@ -39,15 +39,11 @@ class Logger { * @param log - The log to be written to file. */ synchronized void log(Log log) { - if (log.getLevel().greaterThanEqualTo(this.writerLevel)) { - try { - String logFileContents = readFile(logFilePath); - String logEntry = generateLogEntry(log); - logFileContents = logFileContents.replace("", logEntry); - BufferedWriter writer = new BufferedWriter(new FileWriter(logFilePath)); + System.out.println(log.message); + if (log.level.greaterThanEqualTo(this.writerLevel)) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(logFilePath, true))) { writer.flush(); - writer.write(logFileContents); - writer.close(); + writer.append(getLogEntry(log)); } catch (IOException e) { e.printStackTrace(); } @@ -63,19 +59,19 @@ class Logger { * Yellow = Warning * Green = Info */ - private String generateLogEntry(Log log) { + private String getLogEntry(Log log) { String logEntry = this.logEntryTemplate; - logEntry = logEntry.replace("%% LogLevel %%", log.getLevel().toString()); - logEntry = logEntry.replace("%% Time %%", log.getTime()); - logEntry = logEntry.replace("%% Message %%", log.getMessage()); + logEntry = logEntry.replace("%% LogLevel %%", log.level.toString()); + logEntry = logEntry.replace("%% Time %%", log.time); + logEntry = logEntry.replace("%% Message %%", log.message); StringBuilder builder = new StringBuilder(); - if (log.getException() != null) { - StackTraceElement[] stackTrace = log.getException().getStackTrace(); - builder.append(log.getException().toString()); + if (log.exception != null) { + StackTraceElement[] stackTrace = log.exception.getStackTrace(); + builder.append(log.exception.toString()); builder.append("
\n"); if (stackTrace.length != 0) { - for (StackTraceElement element : log.getException().getStackTrace()) { + for (StackTraceElement element : log.exception.getStackTrace()) { builder.append(" -- "); builder.append(element.toString()); builder.append("
\n"); @@ -129,23 +125,4 @@ class Logger { return builder.toString(); } - - private String readFile(String filePath) { - StringBuilder builder = new StringBuilder(); - try { - BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath)); - Scanner scanner = new Scanner(bufferedReader); - - while (scanner.hasNext()) { - builder.append(scanner.nextLine()); - builder.append("\n"); - } - scanner.close(); - bufferedReader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - return builder.toString(); - } } diff --git a/src/main/java/com/rohitawate/everest/util/logging/LoggingService.java b/src/main/java/com/rohitawate/everest/util/logging/LoggingService.java index 84f582c..b0d8c31 100644 --- a/src/main/java/com/rohitawate/everest/util/logging/LoggingService.java +++ b/src/main/java/com/rohitawate/everest/util/logging/LoggingService.java @@ -24,17 +24,12 @@ import java.time.format.DateTimeFormatter; public class LoggingService { private Logger logger; private DateTimeFormatter dateFormat; - private String message; - private Exception exception; - private LocalDateTime time; - - private SevereLogger severeLogger = new SevereLogger(); - private WarningLogger warningLogger = new WarningLogger(); - private InfoLogger infoLogger = new InfoLogger(); + private Log log; public LoggingService(Level writerLevel) { - logger = new Logger(writerLevel); - dateFormat = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); + this.log = new Log(); + this.logger = new Logger(writerLevel); + this.dateFormat = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); } public void logSevere(String message, Exception exception, LocalDateTime time) { @@ -53,47 +48,23 @@ public class LoggingService { } private void setValues(String message, Exception exception, LocalDateTime time) { - this.message = message; - this.exception = exception; - this.time = time; + this.log.message = message; + this.log.exception = exception; + this.log.time = dateFormat.format(time); } - private class SevereLogger implements Runnable { - @Override - public void run() { - System.out.println(message); - Log log = new Log(); - log.setLevel(Level.SEVERE); - log.setMessage(message); - log.setException(exception); - log.setTime(dateFormat.format(time)); - logger.log(log); - } - } + private Runnable severeLogger = () -> { + this.log.level = Level.SEVERE; + this.logger.log(this.log); + }; - private class WarningLogger implements Runnable { - @Override - public void run() { - System.out.println(message); - Log log = new Log(); - log.setLevel(Level.WARNING); - log.setMessage(message); - log.setException(exception); - log.setTime(dateFormat.format(time)); - logger.log(log); - } - } + private Runnable warningLogger = () -> { + this.log.level = Level.WARNING; + this.logger.log(log); + }; - - private class InfoLogger implements Runnable { - @Override - public void run() { - System.out.println(message); - Log log = new Log(); - log.setLevel(Level.INFO); - log.setMessage(message); - log.setTime(dateFormat.format(time)); - logger.log(log); - } - } + private Runnable infoLogger = () -> { + this.log.level = Level.INFO; + this.logger.log(log); + }; } diff --git a/src/main/java/com/rohitawate/everest/util/settings/Settings.java b/src/main/java/com/rohitawate/everest/util/settings/Settings.java index c310279..bb01168 100644 --- a/src/main/java/com/rohitawate/everest/util/settings/Settings.java +++ b/src/main/java/com/rohitawate/everest/util/settings/Settings.java @@ -31,5 +31,5 @@ public class Settings { public static int connectionReadTimeOut = 30000; public static String theme = "Adreana"; - public static int showHistoryRange = 3; + public static int showHistoryRange = 7; } diff --git a/src/main/java/com/rohitawate/everest/util/settings/SettingsLoader.java b/src/main/java/com/rohitawate/everest/util/settings/SettingsLoader.java index 94b50d3..72f3a37 100644 --- a/src/main/java/com/rohitawate/everest/util/settings/SettingsLoader.java +++ b/src/main/java/com/rohitawate/everest/util/settings/SettingsLoader.java @@ -17,7 +17,6 @@ package com.rohitawate.everest.util.settings; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.rohitawate.everest.util.EverestUtilities; import com.rohitawate.everest.util.Services; @@ -44,8 +43,7 @@ public class SettingsLoader implements Runnable { System.out.println("Settings file found. Loading settings... "); - ObjectMapper mapper = new ObjectMapper(); - nodes = mapper.readTree(settingsFile); + nodes = EverestUtilities.mapper.readTree(settingsFile); Settings.responseAreaFont = setStringSetting(Settings.responseAreaFont, "responseAreaFont"); Settings.responseAreaFontSize = setIntegerSetting(Settings.responseAreaFontSize, "responseAreaFontSize"); @@ -61,7 +59,7 @@ public class SettingsLoader implements Runnable { Settings.theme = EverestUtilities.trimString(setStringSetting(Settings.theme, "theme")); Settings.showHistoryRange = setIntegerSetting(Settings.showHistoryRange, "showHistoryRange"); } catch (IOException IOE) { - Services.loggingService.logInfo("Settings file not found. Using defaults", LocalDateTime.now()); + Services.loggingService.logInfo("Settings file not found. Using defaults.", LocalDateTime.now()); } } diff --git a/src/main/java/com/rohitawate/everest/util/themes/ThemeManager.java b/src/main/java/com/rohitawate/everest/util/themes/ThemeManager.java index 7a6a0d2..921c26b 100644 --- a/src/main/java/com/rohitawate/everest/util/themes/ThemeManager.java +++ b/src/main/java/com/rohitawate/everest/util/themes/ThemeManager.java @@ -27,6 +27,7 @@ import java.util.List; public class ThemeManager { private static List parentNodes = new ArrayList<>(); + private static File themeFile = new File("Everest/themes/" + Settings.theme + ".css"); /** * Refreshes the theme of all the registered parents by replacing @@ -35,7 +36,6 @@ public class ThemeManager { */ public static void refreshTheme() { if (!Settings.theme.equals("Adreana")) { - File themeFile = new File("Everest/themes/" + Settings.theme + ".css"); if (themeFile.exists()) { String themePath = themeFile.toURI().toString(); @@ -53,7 +53,6 @@ public class ThemeManager { public static void setTheme(Parent parent) { if (!Settings.theme.equals("Adreana")) { - File themeFile = new File("Everest/themes/" + Settings.theme + ".css"); if (themeFile.exists()) { parent.getStylesheets().add(themeFile.toURI().toString()); parentNodes.add(parent); diff --git a/src/main/resources/BugReporter.jar b/src/main/resources/BugReporter.jar index be670cf..bdde1bf 100644 Binary files a/src/main/resources/BugReporter.jar and b/src/main/resources/BugReporter.jar differ diff --git a/src/main/resources/assets/Copy.png b/src/main/resources/assets/Copy.png new file mode 100644 index 0000000..70eb073 Binary files /dev/null and b/src/main/resources/assets/Copy.png differ diff --git a/src/main/resources/assets/LoadingCircle_WhiteOnOrange.gif b/src/main/resources/assets/LoadingCircle_WhiteOnOrange.gif deleted file mode 100644 index af7cf6e..0000000 Binary files a/src/main/resources/assets/LoadingCircle_WhiteOnOrange.gif and /dev/null differ diff --git a/src/main/resources/css/Adreana.css b/src/main/resources/css/Adreana.css index ae9f53f..111fd78 100644 --- a/src/main/resources/css/Adreana.css +++ b/src/main/resources/css/Adreana.css @@ -71,6 +71,10 @@ -fx-background-color: #1b1b1b; } +#copyBodyButton { + -fx-background-color: transparent; +} + #clearResponseAreaButton { -fx-background-color: #822f2f; } @@ -312,41 +316,64 @@ -fx-background-color: #2a2a2a; } -.nonRootTitledPane { - -fx-padding: 3px 0px; -} - -.titled-pane .title { +.visualizerLabel { -fx-font-family: "Liberation Mono", monospace; - -fx-background-color: #404040; } -.titled-pane .content { +.visualizerRootLabel { + -fx-font-size: 17px; + -fx-text-fill: #dedede; + -fx-font-weight: bold; +} + +.visualizerKeyLabel { + -fx-font-size: 17px; + -fx-text-fill: #bababa; + -fx-font-weight: bold; +} + +.visualizerValueLabel { + -fx-font-size: 16px; + -fx-text-fill: #959595; +} + +/* Visualizer tree */ +.tree-view { + -fx-background-color: #353535; +} + +.tree-cell .tree-disclosure-node .arrow { + -fx-background-color: orangered; +} + +.tree-cell:selected .tree-disclosure-node .arrow, +.tree-cell:focused .tree-disclosure-node .arrow { + -fx-background-color: white; +} + +.tree-cell { -fx-background-color: #282828; -fx-border-width: 0px; } -.titled-pane .content { - -fx-font-family: "Liberation Mono", monospace; - -fx-padding: 3px 0px; +.tree-cell:expanded { + -fx-background-color: #454545; } -.visualizerKeyLabel { - -fx-font-size: 18px; - -fx-text-fill: #bababa; - -fx-text-alignment: left; +.tree-cell:selected, +.tree-cell:focused { + -fx-background-color: cornflowerblue; } -.visualizerValueLabel { - -fx-font-size: 18px; - -fx-text-fill: #959595; - -fx-text-alignment: left; +.tree-cell:selected .label { + -fx-text-fill: white; } -.titled-pane .title .text, -.titled-pane .title .arrow-button .arrow { - -fx-background-color: #dadada; - -fx-fill: #dadada; +.tree-view .scroll-bar:horizontal .increment-arrow, +.tree-view .scroll-bar:horizontal .decrement-arrow, +.tree-view .scroll-bar:horizontal .increment-button, +.tree-view .scroll-bar:horizontal .decrement-button { + -fx-padding: 0; } /* SnackBar */ diff --git a/src/main/resources/fxml/homewindow/Dashboard.fxml b/src/main/resources/fxml/homewindow/Dashboard.fxml index c340562..6fbcdd6 100644 --- a/src/main/resources/fxml/homewindow/Dashboard.fxml +++ b/src/main/resources/fxml/homewindow/Dashboard.fxml @@ -16,37 +16,47 @@ ~ limitations under the License. --> - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - + - + - + @@ -59,7 +69,7 @@ - + @@ -71,16 +81,14 @@ - + - + @@ -140,8 +148,7 @@ - + @@ -162,25 +169,34 @@ + + + + + + + + + @@ -204,36 +220,22 @@ -