Java tutorial
/** * Copyright (c) 2011 Martin Geisse * * This file is distributed under the terms of the MIT license. */ package name.martingeisse.api.request; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.Serializable; import java.io.StringReader; import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import name.martingeisse.api.servlet.ServletUtil; import name.martingeisse.common.javascript.analyze.JsonAnalyzer; import org.apache.commons.io.IOUtils; /** * Stores information about a request cycle, such as {@link HttpServletRequest}, * {@link HttpServletResponse}, decoded request data, etc. * * The request cycle is able to store arbitrary attributes in addition to * the request parameters. The difference is that attributes are always * set programmatically (never by the client), but can store values of * arbitrary type, not just strings. */ public final class ApiRequestCycle { /** * the EXCEPTION_REQUEST_ATTRIBUTE_KEY */ public static final ApiRequestAttributeKey<Throwable> EXCEPTION_REQUEST_ATTRIBUTE_KEY = new ApiRequestAttributeKey<Throwable>( Throwable.class); /** * The session key for the locale setting. */ public static final SessionKey<Locale> LOCALE_SESSION_KEY = new SessionKey<Locale>(); /** * the useSessions */ private static volatile boolean useSessions = true; /** * Setter method for the useSessions. * @param useSessions the useSessions to set */ public static void setUseSessions(boolean useSessions) { ApiRequestCycle.useSessions = useSessions; } /** * the request */ private final HttpServletRequest request; /** * the response */ private final HttpServletResponse response; /** * the requestMethod */ private final ApiRequestMethod requestMethod; /** * the requestPath */ private final ApiRequestPathChain requestPath; /** * the parameters */ private final ApiRequestParameters parameters; /** * the attributes */ private final Map<ApiRequestAttributeKey<?>, Object> attributes; /** * Constructor. * @param request the request * @param response the response * @throws MalformedRequestPathException if the request path (taken from the request URI) is malformed */ public ApiRequestCycle(final HttpServletRequest request, final HttpServletResponse response) throws MalformedRequestPathException { this.request = request; this.response = response; this.requestMethod = (request.getMethod().equalsIgnoreCase("POST") ? ApiRequestMethod.POST : ApiRequestMethod.GET); final String uri = request.getRequestURI(); final String requestPathText = (uri.startsWith("/") ? uri.substring(1) : uri); this.requestPath = ApiRequestPathChain.parse(requestPathText); this.parameters = new ApiRequestParameters(request); this.attributes = new HashMap<ApiRequestAttributeKey<?>, Object>(); } /** * Getter method for the request. * @return the request */ public HttpServletRequest getRequest() { return request; } /** * Getter method for the response. * @return the response */ public HttpServletResponse getResponse() { return response; } /** * Getter method for the requestMethod. * @return the requestMethod */ public ApiRequestMethod getRequestMethod() { return requestMethod; } /** * Getter method for the requestPath. * @return the requestPath */ public ApiRequestPathChain getRequestPath() { return requestPath; } /** * Getter method for the parameters. * @return the parameters */ public ApiRequestParameters getParameters() { return parameters; } /** * Returns the value of a request attribute. * @param key the attribute key * @return the attribute value */ public <T> T getAttribute(ApiRequestAttributeKey<T> key) { return key.cast(attributes.get(key)); } /** * Sets the value of a request attribute. * @param key the attribute key * @param value the attribute value */ public <T> void setAttribute(ApiRequestAttributeKey<T> key, T value) { attributes.put(key, value); } /** * Returns either the raw POST body, or the value of the "body" POST parameter * (if the Content-Type is "application/x-www-form-urlencoded"), as a {@link Reader}. * * @return the reader * @throws IOException on I/O errors */ public Reader getBodyAsReader() throws IOException { if (isFormRequest()) { return new StringReader(parameters.getString("body", true)); } else { return new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8); } } /** * Returns either the raw POST body, or the value of the "body" POST parameter * (if the Content-Type is "application/x-www-form-urlencoded"), as a {@link String}. * * @return the string * @throws IOException on I/O errors */ public String getBodyAsString() throws IOException { if (isFormRequest()) { return parameters.getString("body", true); } else { return IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); } } /** * Returns either the raw POST body, or the value of the "body" POST parameter * (if the Content-Type is "application/x-www-form-urlencoded"), as a {@link JsonAnalyzer}. * * @return the JSON analyuer * @throws IOException on I/O errors */ public JsonAnalyzer getBodyAsJsonAnalyzer() throws IOException { if (isFormRequest()) { return JsonAnalyzer.parse(parameters.getString("body", true)); } else { return JsonAnalyzer.parse(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8)); } } /** * */ private boolean isFormRequest() { return request.getContentType().startsWith("application/x-www-form-urlencoded"); } /** * @return the writer of the response * @throws IOException on I/O errors */ public PrintWriter getWriter() throws IOException { return response.getWriter(); } /** * @return the output stream of the response * @throws IOException on I/O errors */ public OutputStream getOutputStream() throws IOException { return response.getOutputStream(); } /** * Prepares a plain-text response (text/plain, utf-8). Leaves the status code of the response alone. * @throws IOException on I/O errors */ public void preparePlainTextResponse() throws IOException { ServletUtil.preparePlainTextResponse(response); } /** * Prepares a plain-text response (text/plain, utf-8), using the specified status code. * @param statusCode the HTTP status code to use * @throws IOException on I/O errors */ public void preparePlainTextResponse(final int statusCode) throws IOException { ServletUtil.preparePlainTextResponse(response, statusCode); } /** * Finishes a text-based response. This method can be used for any response the uses * the {@link HttpServletResponse}'s {@link Writer}. * @throws IOException on I/O errors */ public void finishTextResponse() throws IOException { ServletUtil.finishTextResponse(response); } /** * Writes a response using the specified status code and content, with content type * text/plain (utf-8). * @param statusCode the HTTP status code * @param message the message to write * @throws IOException on I/O errors */ public void emitMessageResponse(final int statusCode, final String message) throws IOException { ServletUtil.emitMessageResponse(response, statusCode, message); } /** * Renders an HTML page that shows a form to manually enter a request body. Only works * in combination with the getBodyAs*() methods or similar that can accept a POST form * parameter named "body" instead of a raw POST body. * * @throws IOException on I/O errors */ public void emitBodyFormPage() throws IOException { // build the page StringBuilder builder = new StringBuilder(); builder.append( "<html><body><form method=\"post\" style=\"width: 800px; margin-left: auto; margin-right: auto; \">"); builder.append( "<textarea name=\"body\" style=\"display: block; width: 100%; height: 300px; margin-top: 30px; font-family: monospace; font-size: 12pt; \">{\n}</textarea>"); builder.append( "<input type=\"submit\" value=\"Submit\" style=\"display: block; width: 100%; height: 40px; margin-top: 20px; background-color: #ddd; border: 1px solid #aaa; \">"); builder.append("</form></body></html>"); // emit the response response.setCharacterEncoding("utf-8"); response.setContentType("text/html; charset=utf-8"); response.getWriter().print(builder); response.getWriter().flush(); response.getWriter().close(); } /** * Sets the session object for the specified key. * @param key the session key * @param value the value to set */ public <T extends Serializable> void setSessionValue(SessionKey<T> key, T value) { if (useSessions) { request.getSession().setAttribute(key.getInternalKey(), value); } } /** * Obtains the session object for the specified key * @param key the session key * @return the value for the specified key */ @SuppressWarnings("unchecked") public <T extends Serializable> T getSessionValue(SessionKey<T> key) { if (useSessions) { return (T) request.getSession().getAttribute(key.getInternalKey()); } else { return null; } } }