package io.innerloop.neo4j.client.spi.impl.rest.http; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class represents an HTTP Request message. */ public class Request extends Message<Request> { private HttpURLConnection connection; private OutputStreamWriter writer; private URL url; private Map<String, String> query = new HashMap<>(); /** * The Constructor takes the url as a String. * * @param url * The url parameter does not need the query string parameters if they are going to be supplied via calls to * {@link #addQueryParameter(String, String)}. You can, however, supply the query parameters in the URL if * you wish. * * @throws IOException */ public Request(String url) throws IOException { this.url = new URL(url); connection = (HttpURLConnection) this.url.openConnection(); } /** * Adds a Query Parameter to a list. The list is converted to a String and appended to the URL when the Request is * submitted. * * @param name * The Query Parameter's name * @param value * The Query Parameter's value * * @return this Request, to support chained method calls */ public Request addQueryParameter(String name, String value) { this.query.put(name, value); return this; } /** * Removes the specified Query Parameter. * * @param name * The name of the Query Parameter to remove * * @return this Request, to support chained method calls */ public Request removeQueryParameter(String name) { this.query.remove(name); return this; } /** * Sets the URL that this Request will be sent to. * * @param url The url parameter does not need the query string parameters if * they are going to be supplied via calls to {@link #addQueryParameter(String, String)}. You can, however, supply * the query parameters in the URL if you wish. * @return this Request, to support chained method calls * @throws MalformedURLException If the supplied url is malformed. */ // public Request setUrl(String url) throws MalformedURLException { // this.url = new URL(url); // return this; // } /** * Issues a GET to the server. * * @return The {@link Response} from the server * * @throws IOException */ public Response getResource() throws IOException { return actionResponse("GET"); } private Response actionResponse(String get) throws IOException { buildQueryString(); buildHeaders(); connection.setDoOutput(true); connection.setRequestMethod(get); return readResponse(); } /** * Issues a PUT to the server. * * @return The {@link Response} from the server * * @throws IOException */ public Response putResource() throws IOException { return writeResource("PUT", this.body); } /** * Issues a POST to the server. * * @return The {@link Response} from the server * * @throws IOException */ public Response postResource() throws IOException { return writeResource("POST", this.body); } /** * Issues a DELETE to the server. * * @return The {@link Response} from the server * * @throws IOException */ public Response deleteResource() throws IOException { return actionResponse("DELETE"); } /** * A private method that handles issuing POST and PUT requests * * @param method * POST or PUT * @param body * The body of the Message * * @return the {@link Response} from the server * * @throws IOException */ private Response writeResource(String method, String body) throws IOException { buildQueryString(); buildHeaders(); connection.setDoOutput(true); connection.setRequestMethod(method); writer = new OutputStreamWriter(connection.getOutputStream()); writer.write(body); writer.flush(); writer.close(); return readResponse(); } /** * A private method that handles reading the Responses from the server. * * @return a {@link Response} from the server. * * @throws IOException */ private Response readResponse() throws IOException { connection.getResponseCode(); InputStream stream = connection.getErrorStream(); if (stream == null) { stream = connection.getInputStream(); } BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { builder.append(line); } reader.close(); return new Response().setResponseCode(connection.getResponseCode()) .setResponseMessage(connection.getResponseMessage()) .setHeaders(connection.getHeaderFields()) .setBody(builder.toString()); } /** * A private method that loops through the query parameter Map, building a String to be appended to the URL. * * @throws MalformedURLException */ private void buildQueryString() throws MalformedURLException { StringBuilder builder = new StringBuilder(); // Put the query parameters on the URL before issuing the request if (!query.isEmpty()) { for (Map.Entry param : query.entrySet()) { builder.append(param.getKey()); builder.append("="); builder.append(param.getValue()); builder.append("&"); } builder.deleteCharAt(builder.lastIndexOf("&")); // Remove the trailing ampersand } if (builder.length() > 0) { // If there was any query string at all, begin it with the question mark builder.insert(0, "?"); } url = new URL(url.toString() + builder.toString()); } /** * A private method that loops through the headers Map, putting them on the Request or Response object. */ private void buildHeaders() { if (!headers.isEmpty()) { for (Map.Entry<String, List<String>> entry : headers.entrySet()) { List<String> values = entry.getValue(); for (String value : values) { connection.addRequestProperty(entry.getKey(), value); } } } } }