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.JFXSnackbar;
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.requestsmanager.GETRequestManager;
import com.rohitawate.restaurant.requestsmanager.POSTRequestManager;
import com.rohitawate.restaurant.requestsmanager.RequestManager;
import com.rohitawate.restaurant.settings.Settings;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
@ -33,7 +34,9 @@ import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ResourceBundle;
@ -56,34 +59,40 @@ public class DashboardController implements Initializable {
@FXML
private JFXButton cancelButton;
@FXML
private TabPane requestOptionsTab;
@FXML
private Tab authTab, headersTab, bodyTab;
private JFXSnackbar snackBar;
private final String[] httpMethods = {"GET", "POST", "PUT", "DELETE", "PATCH"};
private RequestManager requestManager;
private HeaderTabController headerTabController;
private BodyTabController bodyTabController;
@Override
public void initialize(URL url, ResourceBundle rb) {
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()));
parentLoader.setOnFailed(event -> parentLoader.getException().printStackTrace());
new Thread(parentLoader).start();
try {
// Loading the headers tab
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");
responseBox.getChildren().remove(0);
httpMethodBox.getItems().addAll(httpMethods);
httpMethodBox.setValue("GET");
httpMethodBox.getSelectionModel().select(1);
snackBar = new JFXSnackbar(dashboard);
bodyTab.disableProperty().bind(Bindings.and(httpMethodBox.valueProperty().isNotEqualTo("POST"),
@ -133,6 +142,53 @@ public class DashboardController implements Initializable {
});
requestManager.start();
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:
loadingLayer.setVisible(false);
}

View file

@ -20,6 +20,9 @@ import java.net.MalformedURLException;
import java.net.URL;
public class GETRequest extends RestaurantRequest {
public GETRequest() {
}
public GETRequest(URL 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 HashMap<String, String> headers;
RestaurantRequest() {
}
RestaurantRequest(String target) throws MalformedURLException {
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;
}
#httpMethodBox {
.combo-box {
-fx-background-color: #707070;
}
#httpMethodBox .list-cell {
.combo-box .list-cell {
-fx-background-color: #707070;
-fx-pref-height: 39px;
-fx-font-size: 18px;
@ -19,16 +19,16 @@
-fx-padding: 0 0 0 10px;
}
#httpMethodBox .list-cell:hover {
.combo-box .list-cell:hover {
-fx-background-color: orangered;
-fx-text-fill: white;
}
#httpMethodBox .arrow-button .arrow {
.combo-box .arrow-button .arrow {
-fx-background-color: white;
}
#httpMethodBox .list-view {
.combo-box .list-view {
-fx-background-color: transparent;
}
@ -40,23 +40,20 @@
-fx-background-color: #1b1b1b;
}
#responseArea {
.text-area {
-fx-font-family: "Liberation Mono";
-fx-text-fill: #a1a1a1;
-fx-background-radius: 0;
-fx-background-insets: 0;
-fx-background-color: transparent;
-fx-border-width: 0px;
}
#responseArea .content {
.text-area .content {
-fx-background-radius: 0;
-fx-background-color: #2a2a2a;
}
#responseArea {
-fx-border-width: 0px;
}
#loadingLayer {
-fx-background-color: #bf8829;
}
@ -70,7 +67,7 @@
}
.tab-pane:top .tab-header-area .tab-header-background {
-fx-background-color: #2f2f2f;
-fx-background-color: #6a6a6a;
}
.tab-pane .tab-content-area,
@ -83,6 +80,14 @@
-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 {
-fx-background-color: #6a6a6a;
}
@ -91,6 +96,7 @@
-fx-background-color: #55a15c;
}
/* Tab titles */
.tab-pane:top .tab-header-area .headers-region .tab:top .tab-container .tab-label .text {
-fx-fill: #b8b8b8;
}
@ -99,11 +105,14 @@
-fx-fill: white;
}
.tab {
-fx-background-radius: 0;
-fx-background-insets: 0;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
/* Tabs in the request 'Body' option */
#bodyTabPane:top .tab-header-area .tab-header-background,
#bodyTabPane:top .tab-header-area .headers-region .tab:top {
-fx-background-color: #3d3d3d;
}
#bodyTabPane .tab-header-area .headers-region .tab:selected:top {
-fx-background-color: #4e848f;
}
.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>
<AnchorPane maxHeight="250.0">
<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"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0">