Added POSTRequest processing with raw input

This commit is contained in:
Rohit Awate 2018-01-29 22:00:43 +05:30
parent 4ba67f13aa
commit 115c96a3aa
9 changed files with 372 additions and 32 deletions

View file

@ -0,0 +1,47 @@
/*
* 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.restaurant.dashboard;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextArea;
import java.net.URL;
import java.util.ResourceBundle;
public class BodyTabController implements Initializable {
@FXML
private ComboBox<String> rawInputTypeBox;
@FXML
private TextArea rawInputArea;
@Override
public void initialize(URL location, ResourceBundle resources) {
rawInputTypeBox.getItems().addAll("PLAIN TEXT", "JSON", "XML", "HTML");
rawInputTypeBox.getSelectionModel().select(0);
}
// Returns the request body (index 0) and media type (index 1)
public String[] getBody() {
String[] requestBody = new String[2];
requestBody[0] = rawInputArea.getText();
requestBody[1] = rawInputTypeBox.getValue();
return requestBody;
}
}

View file

@ -18,12 +18,13 @@ package com.rohitawate.restaurant.dashboard;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXSnackbar; import com.jfoenix.controls.JFXSnackbar;
import com.rohitawate.restaurant.models.requests.GETRequest; import com.rohitawate.restaurant.models.requests.GETRequest;
import com.rohitawate.restaurant.models.requests.POSTRequest;
import com.rohitawate.restaurant.models.responses.RestaurantResponse; import com.rohitawate.restaurant.models.responses.RestaurantResponse;
import com.rohitawate.restaurant.requestsmanager.GETRequestManager; import com.rohitawate.restaurant.requestsmanager.GETRequestManager;
import com.rohitawate.restaurant.requestsmanager.POSTRequestManager;
import com.rohitawate.restaurant.requestsmanager.RequestManager; import com.rohitawate.restaurant.requestsmanager.RequestManager;
import com.rohitawate.restaurant.settings.Settings; import com.rohitawate.restaurant.settings.Settings;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.concurrent.Task;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
@ -33,7 +34,9 @@ import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -56,34 +59,40 @@ public class DashboardController implements Initializable {
@FXML @FXML
private JFXButton cancelButton; private JFXButton cancelButton;
@FXML @FXML
private TabPane requestOptionsTab;
@FXML
private Tab authTab, headersTab, bodyTab; private Tab authTab, headersTab, bodyTab;
private JFXSnackbar snackBar; private JFXSnackbar snackBar;
private final String[] httpMethods = {"GET", "POST", "PUT", "DELETE", "PATCH"}; private final String[] httpMethods = {"GET", "POST", "PUT", "DELETE", "PATCH"};
private RequestManager requestManager; private RequestManager requestManager;
private HeaderTabController headerTabController; private HeaderTabController headerTabController;
private BodyTabController bodyTabController;
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
applySettings(); applySettings();
Task<Parent> parentLoader = new Task<Parent>() {
@Override
protected Parent call() throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/dashboard/HeaderTab.fxml"));
Parent parent = loader.load();
headerTabController = loader.getController();
return parent;
}
};
parentLoader.setOnSucceeded(event -> headersTab.setContent(parentLoader.getValue())); try {
parentLoader.setOnFailed(event -> parentLoader.getException().printStackTrace()); // Loading the headers tab
new Thread(parentLoader).start(); FXMLLoader headerTabLoader = new FXMLLoader(getClass().getResource("/fxml/dashboard/HeaderTab.fxml"));
Parent headerTabContent = headerTabLoader.load();
headerTabController = headerTabLoader.getController();
headersTab.setContent(headerTabContent);
// Loading the body tab
FXMLLoader bodyTabLoader = new FXMLLoader(getClass().getResource("/fxml/dashboard/BodyTab.fxml"));
Parent bodyTabContent = bodyTabLoader.load();
bodyTabController = bodyTabLoader.getController();
bodyTab.setContent(bodyTabContent);
} catch (IOException IOE) {
IOE.printStackTrace();
}
addressField.setText("https://api.chucknorris.io/jokes/random"); addressField.setText("https://api.chucknorris.io/jokes/random");
responseBox.getChildren().remove(0); responseBox.getChildren().remove(0);
httpMethodBox.getItems().addAll(httpMethods); httpMethodBox.getItems().addAll(httpMethods);
httpMethodBox.setValue("GET"); httpMethodBox.getSelectionModel().select(1);
snackBar = new JFXSnackbar(dashboard); snackBar = new JFXSnackbar(dashboard);
bodyTab.disableProperty().bind(Bindings.and(httpMethodBox.valueProperty().isNotEqualTo("POST"), bodyTab.disableProperty().bind(Bindings.and(httpMethodBox.valueProperty().isNotEqualTo("POST"),
@ -133,6 +142,53 @@ public class DashboardController implements Initializable {
}); });
requestManager.start(); requestManager.start();
break; break;
case "POST":
if (requestManager == null || requestManager.getClass() != POSTRequestManager.class)
requestManager = new POSTRequestManager();
else if (requestManager.isRunning()) {
snackBar.show("Please wait while the current request is processed.", 3000);
return;
}
String[] requestBody = bodyTabController.getBody();
POSTRequest postRequest = new POSTRequest(addressField.getText());
postRequest.setRequestBody(requestBody[0]);
MediaType requestMediaType = MediaType.WILDCARD_TYPE;
switch (requestBody[1]) {
case "PLAIN TEXT":
requestMediaType = MediaType.TEXT_PLAIN_TYPE;
break;
case "JSON":
requestMediaType = MediaType.APPLICATION_JSON_TYPE;
break;
case "XML":
requestMediaType = MediaType.APPLICATION_XML_TYPE;
break;
case "HTML":
requestMediaType = MediaType.TEXT_HTML_TYPE;
break;
}
postRequest.setRequestBodyMediaType(requestMediaType);
postRequest.addHeaders(headerTabController.getHeaders());
requestManager.setRequest(postRequest);
cancelButton.setOnAction(e -> requestManager.cancel());
requestManager.setOnRunning(e -> {
responseArea.clear();
loadingLayer.setVisible(true);
});
requestManager.setOnSucceeded(e -> {
updateDashboard(requestManager.getValue());
loadingLayer.setVisible(false);
requestManager.reset();
});
requestManager.setOnCancelled(e -> {
loadingLayer.setVisible(false);
snackBar.show("Request canceled.", 2000);
requestManager.reset();
});
requestManager.start();
break;
default: default:
loadingLayer.setVisible(false); loadingLayer.setVisible(false);
} }

View file

@ -20,6 +20,9 @@ import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
public class GETRequest extends RestaurantRequest { public class GETRequest extends RestaurantRequest {
public GETRequest() {
}
public GETRequest(URL target) { public GETRequest(URL target) {
super(target); super(target);
} }

View file

@ -0,0 +1,55 @@
/*
* 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.restaurant.models.requests;
import javax.ws.rs.core.MediaType;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
public class POSTRequest extends RestaurantRequest {
private String requestBody;
private MediaType requestBodyMediaType;
private File binaryBody;
public POSTRequest() {
}
public POSTRequest(URL target) {
super(target);
}
public POSTRequest(String target) throws MalformedURLException {
super(target);
}
public String getRequestBody() {
return requestBody;
}
public void setRequestBody(String requestBody) {
this.requestBody = requestBody;
}
public MediaType getRequestBodyMediaType() {
return requestBodyMediaType;
}
public void setRequestBodyMediaType(MediaType requestBodyMediaType) {
this.requestBodyMediaType = requestBodyMediaType;
}
}

View file

@ -24,6 +24,9 @@ public abstract class RestaurantRequest {
private URL target; private URL target;
private HashMap<String, String> headers; private HashMap<String, String> headers;
RestaurantRequest() {
}
RestaurantRequest(String target) throws MalformedURLException { RestaurantRequest(String target) throws MalformedURLException {
this.target = new URL(target); this.target = new URL(target);
} }

View file

@ -0,0 +1,109 @@
/*
* 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.restaurant.requestsmanager;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.rohitawate.restaurant.models.requests.POSTRequest;
import com.rohitawate.restaurant.models.responses.RestaurantResponse;
import javafx.concurrent.Task;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class POSTRequestManager extends RequestManager {
@Override
protected Task<RestaurantResponse> createTask() {
return new Task<RestaurantResponse>() {
@Override
protected RestaurantResponse call() throws Exception {
RestaurantResponse response = new RestaurantResponse();
WebTarget target = client.target(request.getTarget().toString());
Invocation.Builder requestBuilder = target.request();
HashMap<String, String> headers = request.getHeaders();
Map.Entry<String, String> mapEntry;
for (Map.Entry entry : headers.entrySet()) {
mapEntry = (Map.Entry) entry;
requestBuilder.header(mapEntry.getKey(), mapEntry.getValue());
}
long initialTime = System.currentTimeMillis();
Response serverResponse = requestBuilder.post(Entity.entity(((POSTRequest) request).getRequestBody(),
((POSTRequest) request).getRequestBodyMediaType()));
response.setTime(initialTime, System.currentTimeMillis());
if (serverResponse == null)
throw new IOException();
else if (serverResponse.getStatus() == 301) {
response.setStatusCode(301);
String newLocation = serverResponse.getHeaderString("location");
String responseHelpText;
if (newLocation == null)
responseHelpText = "The resource has been permanently moved to another location.\n\n" +
"Here's what you can do:\n" +
"- Find the new URL from the API documentation.\n" +
"- Try using https instead of http if you're not already.";
else
responseHelpText = "The resource has been permanently moved to: " + newLocation;
response.setBody(responseHelpText);
return response;
}
String type = (String) serverResponse.getHeaders().getFirst("Content-type");
String responseBody = serverResponse.readEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
switch (type.toLowerCase()) {
case "application/json; charset=utf-8":
case "application/json":
JsonNode node = mapper.readTree(responseBody);
response.setBody(mapper.writeValueAsString(node));
break;
case "application/xml; charset=utf-8":
case "application/xml":
response.setBody(mapper.writeValueAsString(responseBody));
break;
case "text/html":
case "text/html; charset=utf-8":
response.setBody(responseBody);
break;
default:
response.setBody(responseBody);
}
response.setMediaType(serverResponse.getMediaType());
response.setStatusCode(serverResponse.getStatus());
response.setSize(responseBody.length());
return response;
}
};
}
}

View file

@ -7,11 +7,11 @@
-fx-text-fill: white; -fx-text-fill: white;
} }
#httpMethodBox { .combo-box {
-fx-background-color: #707070; -fx-background-color: #707070;
} }
#httpMethodBox .list-cell { .combo-box .list-cell {
-fx-background-color: #707070; -fx-background-color: #707070;
-fx-pref-height: 39px; -fx-pref-height: 39px;
-fx-font-size: 18px; -fx-font-size: 18px;
@ -19,16 +19,16 @@
-fx-padding: 0 0 0 10px; -fx-padding: 0 0 0 10px;
} }
#httpMethodBox .list-cell:hover { .combo-box .list-cell:hover {
-fx-background-color: orangered; -fx-background-color: orangered;
-fx-text-fill: white; -fx-text-fill: white;
} }
#httpMethodBox .arrow-button .arrow { .combo-box .arrow-button .arrow {
-fx-background-color: white; -fx-background-color: white;
} }
#httpMethodBox .list-view { .combo-box .list-view {
-fx-background-color: transparent; -fx-background-color: transparent;
} }
@ -40,23 +40,20 @@
-fx-background-color: #1b1b1b; -fx-background-color: #1b1b1b;
} }
#responseArea { .text-area {
-fx-font-family: "Liberation Mono"; -fx-font-family: "Liberation Mono";
-fx-text-fill: #a1a1a1; -fx-text-fill: #a1a1a1;
-fx-background-radius: 0; -fx-background-radius: 0;
-fx-background-insets: 0; -fx-background-insets: 0;
-fx-background-color: transparent; -fx-background-color: transparent;
-fx-border-width: 0px;
} }
#responseArea .content { .text-area .content {
-fx-background-radius: 0; -fx-background-radius: 0;
-fx-background-color: #2a2a2a; -fx-background-color: #2a2a2a;
} }
#responseArea {
-fx-border-width: 0px;
}
#loadingLayer { #loadingLayer {
-fx-background-color: #bf8829; -fx-background-color: #bf8829;
} }
@ -70,7 +67,7 @@
} }
.tab-pane:top .tab-header-area .tab-header-background { .tab-pane:top .tab-header-area .tab-header-background {
-fx-background-color: #2f2f2f; -fx-background-color: #6a6a6a;
} }
.tab-pane .tab-content-area, .tab-pane .tab-content-area,
@ -83,6 +80,14 @@
-fx-background-color: #3d3d3d; -fx-background-color: #3d3d3d;
} }
/* Tab attributes */
.tab {
-fx-background-radius: 0;
-fx-background-insets: 0;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
}
.tab-pane:top .tab-header-area .headers-region .tab:top { .tab-pane:top .tab-header-area .headers-region .tab:top {
-fx-background-color: #6a6a6a; -fx-background-color: #6a6a6a;
} }
@ -91,6 +96,7 @@
-fx-background-color: #55a15c; -fx-background-color: #55a15c;
} }
/* Tab titles */
.tab-pane:top .tab-header-area .headers-region .tab:top .tab-container .tab-label .text { .tab-pane:top .tab-header-area .headers-region .tab:top .tab-container .tab-label .text {
-fx-fill: #b8b8b8; -fx-fill: #b8b8b8;
} }
@ -99,11 +105,14 @@
-fx-fill: white; -fx-fill: white;
} }
.tab { /* Tabs in the request 'Body' option */
-fx-background-radius: 0; #bodyTabPane:top .tab-header-area .tab-header-background,
-fx-background-insets: 0; #bodyTabPane:top .tab-header-area .headers-region .tab:top {
-fx-focus-color: transparent; -fx-background-color: #3d3d3d;
-fx-faint-focus-color: transparent; }
#bodyTabPane .tab-header-area .headers-region .tab:selected:top {
-fx-background-color: #4e848f;
} }
.scroll-pane .scroll-bar:vertical .thumb { .scroll-pane .scroll-bar:vertical .thumb {

View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<TabPane fx:id="bodyTabPane" stylesheets="@../../css/Default.css" tabClosingPolicy="UNAVAILABLE" tabMinWidth="100.0"
xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111"
fx:controller="com.rohitawate.restaurant.dashboard.BodyTabController">
<tabs>
<Tab text="RAW">
<content>
<ScrollPane fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER" vbarPolicy="ALWAYS">
<content>
<VBox alignment="CENTER">
<children>
<HBox alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
<children>
<ComboBox fx:id="rawInputTypeBox" HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</HBox.margin>
</ComboBox>
</children>
<VBox.margin>
<Insets/>
</VBox.margin>
</HBox>
<TextArea fx:id="rawInputArea" promptText="Raw data goes here..." wrapText="true"
VBox.vgrow="ALWAYS">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0"/>
</VBox.margin>
</TextArea>
</children>
</VBox>
</content>
</ScrollPane>
</content>
</Tab>
<Tab text="BINARY"/>
</tabs>
</TabPane>

View file

@ -70,7 +70,7 @@
<items> <items>
<AnchorPane maxHeight="250.0"> <AnchorPane maxHeight="250.0">
<children> <children>
<TabPane fx:id="requestTabs" maxHeight="200.0" minHeight="200.0" <TabPane fx:id="requestOptionsTab" maxHeight="200.0" minHeight="200.0"
tabClosingPolicy="UNAVAILABLE" tabMinWidth="150.0" AnchorPane.bottomAnchor="0.0" tabClosingPolicy="UNAVAILABLE" tabMinWidth="150.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0"> AnchorPane.topAnchor="0.0">