All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.rest.RestRequest Maven / Gradle / Ivy

// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you 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 org.apache.juneau.rest;

import static org.apache.juneau.common.internal.IOUtils.*;
import static org.apache.juneau.common.internal.ThrowableUtils.*;
import static org.apache.juneau.httppart.HttpPartType.*;
import static org.apache.juneau.internal.CollectionUtils.*;
import static java.lang.Integer.*;
import static java.util.Optional.*;

import java.io.*;
import java.lang.reflect.*;
import java.lang.reflect.Proxy;
import java.net.*;
import java.nio.charset.*;
import java.text.*;
import java.util.*;
import jakarta.servlet.*;
import jakarta.servlet.http.*;

import org.apache.http.*;
import org.apache.http.message.*;
import org.apache.juneau.*;
import org.apache.juneau.assertions.*;
import org.apache.juneau.common.internal.*;
import org.apache.juneau.config.*;
import org.apache.juneau.cp.Messages;
import org.apache.juneau.dto.swagger.*;
import org.apache.juneau.dto.swagger.Swagger;
import org.apache.juneau.http.annotation.Content;
import org.apache.juneau.http.annotation.FormData;
import org.apache.juneau.http.annotation.Header;
import org.apache.juneau.httppart.*;
import org.apache.juneau.httppart.bean.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.assertions.*;
import org.apache.juneau.rest.guard.*;
import org.apache.juneau.rest.httppart.*;
import org.apache.juneau.rest.logger.*;
import org.apache.juneau.http.header.*;
import org.apache.juneau.http.header.Date;
import org.apache.juneau.http.response.*;
import org.apache.juneau.http.response.BasicHttpException;
import org.apache.juneau.rest.staticfile.*;
import org.apache.juneau.rest.swagger.*;
import org.apache.juneau.rest.util.*;
import org.apache.juneau.svl.*;
import org.apache.juneau.uon.*;

/**
 * Represents an HTTP request for a REST resource.
 *
 * 

* The {@link RestRequest} object is an extension of the HttpServletRequest class * with various built-in convenience methods for use in building REST interfaces. * It can be accessed by passing it as a parameter on your REST Java method: *

* *

* @RestPost(...) * public Object myMethod(RestRequest req) {...} *

* *

* The primary methods on this class are: *

*
    *
  • {@link RestRequest} *
      *
    • Methods for accessing the request content: *
        *
      • {@link RestRequest#getContent() getContent()} *
      • {@link RestRequest#getInputStream() getInputStream()} *
      • {@link RestRequest#getReader() getReader()} *
      *
    • Methods for accessing HTTP parts: *
        *
      • {@link RestRequest#containsFormParam(String) containsFormParam(String)} *
      • {@link RestRequest#containsHeader(String) containsHeader(String)} *
      • {@link RestRequest#containsQueryParam(String) containsQueryParam(String)} *
      • {@link RestRequest#getHeader(Class) getHeader(Class)} *
      • {@link RestRequest#getHeader(String) getHeader(String)} *
      • {@link RestRequest#getHeaders() getHeaders()} *
      • {@link RestRequest#getFormParam(Class) getFormParam(Class)} *
      • {@link RestRequest#getFormParam(String) getFormParam(String)} *
      • {@link RestRequest#getFormParams() getFormParams()} *
      • {@link RestRequest#getPathParam(Class) getPathParam(Class)} *
      • {@link RestRequest#getPathParam(String) getPathParam(String)} *
      • {@link RestRequest#getPathParams() getPathParams()} *
      • {@link RestRequest#getPathRemainder() getPathRemainder()} *
      • {@link RestRequest#getQueryParam(Class) getQueryParam(Class)} *
      • {@link RestRequest#getQueryParam(String) getQueryParam(String)} *
      • {@link RestRequest#getQueryParams() getQueryParams()} *
      • {@link RestRequest#getQueryString() getQueryString()} *
      *
    • Methods for localization: *
        *
      • {@link RestRequest#getLocale() getLocale()} *
      • {@link RestRequest#getMessage(String,Object...) getMessage(String,Object...)} *
      • {@link RestRequest#getMessages() getMessages()} *
      • {@link RestRequest#getTimeZone() getTimeZone()} *
      *
    • Methods for accessing static files: *
        *
      • {@link RestRequest#getStaticFiles() getStaticFiles()} *
      • {@link RestRequest#getVarResolverSession() getVarResolverSession()} *
      *
    • Methods for assertions: *
        *
      • {@link RestRequest#assertContent() assertContent()} *
      • {@link RestRequest#assertCharset() assertCharset()} *
      • {@link RestRequest#assertFormParam(String) assertFormParam(String)} *
      • {@link RestRequest#assertHeader(String) assertHeader(String)} *
      • {@link RestRequest#assertQueryParam(String) assertQueryParam(String)} *
      • {@link RestRequest#assertRequestLine() assertRequestLine()} *
      *
    • Other: *
        *
      • {@link RestRequest#getAttribute(String) getAttribute(String)} *
      • {@link RestRequest#getAttributes() getAttributes()} *
      • {@link RestRequest#getAuthorityPath() getAuthorityPath()} *
      • {@link RestRequest#getBeanSession() getBeanSession()} *
      • {@link RestRequest#getCharset() getCharset()} *
      • {@link RestRequest#getConfig() getConfig()} *
      • {@link RestRequest#getContext() getContext()} *
      • {@link RestRequest#getContextPath() getContextPath()} *
      • {@link RestRequest#getHttpServletRequest() getHttpServletRequest()} *
      • {@link RestRequest#getMethod() getMethod()} *
      • {@link RestRequest#getOpContext() getOpContext()} *
      • {@link RestRequest#getOperationSwagger() getOperationSwagger()} *
      • {@link RestRequest#getPartParserSession() getPartParserSession()} *
      • {@link RestRequest#getPartSerializerSession() getPartSerializerSession()} *
      • {@link RestRequest#getPathInfo() getPathInfo()} *
      • {@link RestRequest#getProtocolVersion() getProtocolVersion()} *
      • {@link RestRequest#getRequest(Class) getRequest(Class)} *
      • {@link RestRequest#getRequestLine() getRequestLine()} *
      • {@link RestRequest#getRequestURI() getRequestURI()} *
      • {@link RestRequest#getRequestURL() getRequestURL()} *
      • {@link RestRequest#getServletPath() getServletPath()} *
      • {@link RestRequest#getSession() getSession()} *
      • {@link RestRequest#getSwagger() getSwagger()} *
      • {@link RestRequest#getUriContext() getUriContext()} *
      • {@link RestRequest#getUriResolver() getUriResolver()} *
      • {@link RestRequest#isDebug() isDebug()} *
      • {@link RestRequest#isPlainText() isPlainText()} *
      • {@link RestRequest#isUserInRole(String) isUserInRole(String)} *
      • {@link RestRequest#setAttribute(String,Object) setAttribute(String,Object)} *
      • {@link RestRequest#setCharset(Charset) setCharset(Charset)} *
      • {@link RestRequest#setDebug() setDebug()} *
      • {@link RestRequest#setException(Throwable) setException(Throwable)} *
      • {@link RestRequest#setNoTrace() setNoTrace()} *
      *
    *
* *
See Also:
    *
*/ @SuppressWarnings({ "unchecked", "unused" }) public final class RestRequest extends HttpServletRequestWrapper { // Constructor initialized. private HttpServletRequest inner; private final RestContext context; private final RestOpContext opContext; private final RequestContent content; private final BeanSession beanSession; private final RequestQueryParams queryParams; private final RequestPathParams pathParams; private final RequestHeaders headers; private final RequestAttributes attrs; private final HttpPartParserSession partParserSession; private final RestSession session; // Lazy initialized. private VarResolverSession varSession; private RequestFormParams formParams; private UriContext uriContext; private String authorityPath; private Config config; private Swagger swagger; private Charset charset; /** * Constructor. */ RestRequest(RestOpContext opContext, RestSession session) throws Exception { super(session.getRequest()); this.session = session; this.opContext = opContext; inner = session.getRequest(); context = session.getContext(); attrs = new RequestAttributes(this); queryParams = new RequestQueryParams(this, session.getQueryParams(), true); headers = new RequestHeaders(this, queryParams, false); content = new RequestContent(this); if (context.isAllowContentParam()) { String b = queryParams.get("content").asString().orElse(null); if (b != null) { headers.set("Content-Type", UonSerializer.DEFAULT.getResponseContentType()); content.mediaType(MediaType.UON).parser(UonParser.DEFAULT).content(b.getBytes(UTF8)); } } pathParams = new RequestPathParams(session, this, true); beanSession = opContext.getBeanContext().getSession(); partParserSession = opContext.getPartParser().getPartSession(); pathParams.parser(partParserSession); queryParams .addDefault(opContext.getDefaultRequestQueryData().getAll()) .parser(partParserSession); headers .addDefault(opContext.getDefaultRequestHeaders().getAll()) .addDefault(context.getDefaultRequestHeaders().getAll()) .parser(partParserSession); content .encoders(opContext.getEncoders()) .parsers(opContext.getParsers()) .maxInput(opContext.getMaxInput()); attrs .addDefault(opContext.getDefaultRequestAttributes()) .addDefault(context.getDefaultRequestAttributes()); if (isDebug()) inner = CachingHttpServletRequest.wrap(inner); } //----------------------------------------------------------------------------------------------------------------- // Request line. //----------------------------------------------------------------------------------------------------------------- /** * Returns the request line of this request. * * @return The request line of this request. */ public RequestLine getRequestLine() { String x = inner.getProtocol(); int i = x.indexOf('/'); int j = x.indexOf('.', i); ProtocolVersion pv = new ProtocolVersion(x.substring(0,i), parseInt(x.substring(i+1,j)), parseInt(x.substring(j+1))); return new BasicRequestLine(inner.getMethod(), inner.getRequestURI(), pv); } /** * Returns the protocol version from the request line of this request. * * @return The protocol version from the request line of this request. */ public ProtocolVersion getProtocolVersion() { return getRequestLine().getProtocolVersion(); } //----------------------------------------------------------------------------------------------------------------- // Assertions //----------------------------------------------------------------------------------------------------------------- /** * Returns an assertion on the request line returned by {@link #getRequestLine()}. * *
Example:
*

* // Validates the request content contains "foo". * request * .assertRequestLine().protocol().minor().is(1); *

* * @return A new assertion object. */ public FluentRequestLineAssertion assertRequestLine() { return new FluentRequestLineAssertion<>(getRequestLine(), this); } /** * Returns a fluent assertion for the request content. * *
Example:
*

* // Validates the request content contains "foo". * request * .assertContent().asString().is("foo"); *

* * @return A new fluent assertion on the content, never null. */ public FluentRequestContentAssertion assertContent() { return new FluentRequestContentAssertion<>(getContent(), this); } /** * Returns a fluent assertion for the specified header. * *
Example:
*

* // Validates the content type is JSON. * request * .assertHeader("Content-Type").asString().is("application/json"); *

* * @param name The header name. * @return A new fluent assertion on the parameter, never null. */ public FluentRequestHeaderAssertion assertHeader(String name) { return new FluentRequestHeaderAssertion<>(getHeaderParam(name), this); } /** * Returns a fluent assertion for the specified query parameter. * *
Example:
*

* // Validates the content type is JSON. * request * .assertQueryParam("foo").asString().contains("bar"); *

* * @param name The query parameter name. * @return A new fluent assertion on the parameter, never null. */ public FluentRequestQueryParamAssertion assertQueryParam(String name) { return new FluentRequestQueryParamAssertion<>(getQueryParam(name), this); } /** * Returns a fluent assertion for the specified form parameter. * *
Example:
*

* // Validates the content type is JSON. * request * .assertFormParam("foo").asString().contains("bar"); *

* * @param name The query parameter name. * @return A new fluent assertion on the parameter, never null. */ public FluentRequestFormParamAssertion assertFormParam(String name) { return new FluentRequestFormParamAssertion<>(getFormParam(name), this); } //----------------------------------------------------------------------------------------------------------------- // Headers //----------------------------------------------------------------------------------------------------------------- /** * Request headers. * *

* Returns a {@link RequestHeaders} object that encapsulates access to HTTP headers on the request. * *

Example:
*

* @RestPost(...) * public Object myMethod(RestRequest req) { * * // Get access to headers. * RequestHeaders headers = req.getRequestHeaders(); * * // Add a default value. * headers.addDefault("ETag", DEFAULT_UUID); * * // Get a header value as a POJO. * UUID etag = headers.get("ETag").as(UUID.class).orElse(null); * * // Get a standard header. * Optional<CacheControl> = headers.getCacheControl(); * } *

* *
Notes:
    *
  • * This object is modifiable. *
  • * Values are converted from strings using the registered part parser on the resource class. *
  • * The {@link RequestHeaders} object can also be passed as a parameter on the method. *
  • * The {@link Header @Header} annotation can be used to access individual header values. *
* *
See Also:
* * @return * The headers on this request. *
Never null. */ public RequestHeaders getHeaders() { return headers; } /** * Returns the last header with a specified name of this message. * *

* If there is more than one matching header in the message the last element of getHeaders(String) is returned. *
If there is no matching header in the message, an empty request header object is returned. * *

Example:
*

* // Gets a header and throws a BadRequest if it doesn't exist. * request * .getHeader("Foo") * .assertValue().exists() * .get(); *

* * @param name The header name. * @return The request header object, never null. */ public RequestHeader getHeaderParam(String name) { return headers.getLast(name); } /** * Returns true if this request contains the specified header. * * @param name The header name. * @return true if this request contains the specified header. */ public boolean containsHeader(String name) { return headers.contains(name); } /** * Provides the ability to perform fluent-style assertions on the response character encoding. * *
Examples:
*

* // Validates that the response content charset is UTF-8. * request * .assertCharset().is("utf-8"); *

* * @return A new fluent assertion object. * @throws BasicHttpException If REST call failed. */ public FluentStringAssertion assertCharset() { return new FluentStringAssertion<>(getCharset().name(), this); } /** * Sets the charset to expect on the request content. * * @param value The new value to use for the request content. */ public void setCharset(Charset value) { this.charset = value; } /** * Returns the charset specified on the Content-Type header, or "UTF-8" if not specified. * * @return The charset to use to decode the request content. */ public Charset getCharset() { if (charset == null) { // Determine charset // NOTE: Don't use super.getCharacterEncoding() because the spec is implemented inconsistently. // Jetty returns the default charset instead of null if the character is not specified on the request. String h = getHeaderParam("Content-Type").orElse(null); if (h != null) { int i = h.indexOf(";charset="); if (i > 0) charset = Charset.forName(h.substring(i+9).trim()); } if (charset == null) charset = opContext.getDefaultCharset(); if (charset == null) charset = Charset.forName("UTF-8"); } return charset; } /** * Returns the preferred Locale that the client will accept content in, based on the Accept-Language header. * *

* If the client request doesn't provide an Accept-Language header, this method returns the default locale for the server. * * @return The preferred Locale that the client will accept content in. Never null. */ @Override public Locale getLocale() { Locale best = inner.getLocale(); String h = headers.get("Accept-Language").asString().orElse(null); if (h != null) { StringRanges sr = StringRanges.of(h); float qValue = 0; for (StringRange r : sr.toList()) { if (r.getQValue() > qValue) { best = toLocale(r.getName()); qValue = r.getQValue(); } } } return best; } //----------------------------------------------------------------------------------------------------------------- // Standard headers. //----------------------------------------------------------------------------------------------------------------- /** * Returns the request header of the specified type. * *

* Type must have a name specified via the {@link org.apache.juneau.http.annotation.Header} annotation * and a public constructor that takes in either value or name,value as strings. * *

* Typically any of the following: *

    *
  • {@link Accept} *
  • {@link AcceptCharset} *
  • {@link AcceptEncoding} *
  • {@link AcceptLanguage} *
  • {@link AcceptRanges} *
  • {@link Authorization} *
  • {@link CacheControl} *
  • {@link ClientVersion} *
  • {@link Connection} *
  • {@link ContentDisposition} *
  • {@link ContentEncoding} *
  • {@link ContentLength} *
  • {@link ContentType} *
  • {@link Date} *
  • {@link Debug} *
  • {@link Expect} *
  • {@link Forwarded} *
  • {@link From} *
  • {@link Host} *
  • {@link IfMatch} *
  • {@link IfModifiedSince} *
  • {@link IfNoneMatch} *
  • {@link IfRange} *
  • {@link IfUnmodifiedSince} *
  • {@link MaxForwards} *
  • {@link NoTrace} *
  • {@link Origin} *
  • {@link Pragma} *
  • {@link ProxyAuthorization} *
  • {@link Range} *
  • {@link Referer} *
  • {@link TE} *
  • {@link Thrown} *
  • {@link Upgrade} *
  • {@link UserAgent} *
  • {@link Warning} *
* * @param The bean type to create. * @param type The bean type to create. * @return The parsed header on the request, never null. */ public Optional getHeader(Class type) { return headers.get(type); } /** * Returns the Time-Zone header value on the request if there is one. * *

* Example: "GMT". * * @return The parsed header on the request, never null. */ public Optional getTimeZone() { String tz = headers.get("Time-Zone").asString().orElse(null); if (tz != null) return optional(TimeZone.getTimeZone(tz)); return Optional.empty(); } //----------------------------------------------------------------------------------------------------------------- // Attributes //----------------------------------------------------------------------------------------------------------------- /** * Request attributes. * *

* Returns a {@link RequestAttributes} object that encapsulates access to attributes on the request. * *

Example:
*

* @RestPost(...) * public Object myMethod(RestRequest req) { * * // Get access to attributes. * RequestAttributes attributes = req.getAttributes(); * * // Get a header value as a POJO. * UUID etag = attributes.get("ETag", UUID.class); * } *

* *
Notes:
    *
  • * This object is modifiable. *
  • * Values are converted from strings using the registered part parser on the resource class. *
  • * The {@link RequestAttributes} object can also be passed as a parameter on the method. *
  • * The {@link Attr @Attr} annotation can be used to access individual attribute values. *
* *
See Also:
* * @return * The headers on this request. *
Never null. */ public RequestAttributes getAttributes() { return attrs; } /** * Returns the request attribute with the specified name. * * @param name The attribute name. * @return The attribute value, never null. */ @Override public RequestAttribute getAttribute(String name) { return attrs.get(name); } /** * Sets a request attribute. * * @param name The attribute name. * @param value The attribute value. */ @Override public void setAttribute(String name, Object value) { attrs.set(name, value); } //----------------------------------------------------------------------------------------------------------------- // Query parameters //----------------------------------------------------------------------------------------------------------------- /** * Query parameters. * *

* Returns a {@link RequestQueryParams} object that encapsulates access to URL GET parameters. * *

* Similar to {@link HttpServletRequest#getParameterMap()} but only looks for query parameters in the URL and not form posts. * *

Example:
*

* @RestGet(...) * public void doGet(RestRequest req) { * * // Get access to query parameters on the URL. * RequestQueryParams query = req.getQuery(); * * // Get query parameters converted to various types. * int p1/ = query.getInteger("p1").orElse(null); * String p2 = query.getString("p2").orElse(null); * UUID p3 = query.get("p3").as(UUID.class).orElse(null); * } *

* *
Notes:
    *
  • * This object is modifiable. *
* *
See Also:
* * @return * The query parameters as a modifiable map. *
Never null. */ public RequestQueryParams getQueryParams() { return queryParams; } /** * Shortcut for calling getRequestQuery().getLast(name). * * @param name The query parameter name. * @return The query parameter, never null. */ public RequestQueryParam getQueryParam(String name) { return queryParams.get(name); } /** * Returns the request query parameter of the specified type. * *

* Type must have a name specified via the {@link org.apache.juneau.http.annotation.Query} annotation * and a public constructor that takes in either value or name,value as strings. * * @param The bean type to create. * @param type The bean type to create. * @return The parsed query parameter on the request, never null. */ public Optional getQueryParam(Class type) { return queryParams.get(type); } /** * Returns true if this request contains the specified header. * * @param name The header name. * @return true if this request contains the specified header. */ public boolean containsQueryParam(String name) { return queryParams.contains(name); } //----------------------------------------------------------------------------------------------------------------- // Form data parameters //----------------------------------------------------------------------------------------------------------------- /** * Form-data. * *

* Returns a {@link RequestFormParams} object that encapsulates access to form post parameters. * *

* Similar to {@link HttpServletRequest#getParameterMap()}, but only looks for form data in the HTTP content. * *

Example:
*

* @RestPost(...) * public void doPost(RestRequest req) { * * // Get access to parsed form data parameters. * RequestFormParams formParams = req.getFormParams(); * * // Get form data parameters converted to various types. * int p1 = formParams.get("p1").asInteger().orElse(0); * String p2 = formParams.get("p2").asString().orElse(null); * UUID p3 = formParams.get("p3").as(UUID.class).orElse(null); * } *

* *
Notes:
    *
  • * This object is modifiable. *
  • * Values are converted from strings using the registered part parser on the resource class. *
  • * The {@link RequestFormParams} object can also be passed as a parameter on the method. *
  • * The {@link FormData @FormDAta} annotation can be used to access individual form data parameter values. *
* *
See Also:
* * @return * The URL-encoded form data from the request. *
Never null. * @throws InternalServerError If query parameters could not be parsed. * @see org.apache.juneau.http.annotation.FormData */ public RequestFormParams getFormParams() throws InternalServerError { try { if (formParams == null) formParams = new RequestFormParams(this, true).parser(partParserSession); formParams.addDefault(opContext.getDefaultRequestFormData().getAll()); return formParams; } catch (Exception e) { throw new InternalServerError(e); } } /** * Shortcut for calling getFormData().getString(name). * * @param name The form data parameter name. * @return The form data parameter value, or null if not found. */ public RequestFormParam getFormParam(String name) { return getFormParams().get(name); } /** * Returns the request form-data parameter of the specified type. * *

* Type must have a name specified via the {@link org.apache.juneau.http.annotation.FormData} annotation * and a public constructor that takes in either value or name,value as strings. * * @param The bean type to create. * @param type The bean type to create. * @return The parsed form-data parameter on the request, never null. */ public Optional getFormParam(Class type) { return getFormParams().get(type); } /** * Returns true if this request contains the specified header. * * @param name The header name. * @return true if this request contains the specified header. */ public boolean containsFormParam(String name) { return getFormParams().contains(name); } //----------------------------------------------------------------------------------------------------------------- // Path parameters //----------------------------------------------------------------------------------------------------------------- /** * Path parameters. * *

* Returns a {@link RequestPathParams} object that encapsulates access to URL path parameters. * *

Example:
*

* @RestGet("/{foo}/{bar}/{baz}/*") * public void doGet(RestRequest req) { * * // Get access to path data. * RequestPathParams pathParams = req.getPathParams(); * * // Example URL: /123/qux/true/quux * * int foo = pathParams.get("foo").asInteger().orElse(-1); // =123 * String bar = pathParams.get("bar").orElse(null); // =qux * boolean baz = pathParams.get("baz").asBoolean().orElse(false); // =true * String remainder = pathParams.getRemainder().orElse(null); // =quux * } *

* *
Notes:
    *
  • * This object is modifiable. *
* * @return * The path parameters. *
Never null. */ public RequestPathParams getPathParams() { return pathParams; } /** * Shortcut for calling getPathParams().get(name). * * @param name The path parameter name. * @return The path parameter, never null. */ public RequestPathParam getPathParam(String name) { return pathParams.get(name); } /** * Returns the request path parameter of the specified type. * *

* Type must have a name specified via the {@link org.apache.juneau.http.annotation.Path} annotation * and a public constructor that takes in either value or name,value as strings. * * @param The bean type to create. * @param type The bean type to create. * @return The parsed form-data parameter on the request, never null. */ public Optional getPathParam(Class type) { return pathParams.get(type); } /** * Shortcut for calling getPathParams().getRemainder(). * * @return The path remainder value, never null. */ public RequestPathParam getPathRemainder() { return pathParams.getRemainder(); } //----------------------------------------------------------------------------------------------------------------- // Content methods //----------------------------------------------------------------------------------------------------------------- /** * Request content. * *

* Returns a {@link RequestContent} object that encapsulates access to the HTTP request content. * *

Example:
*

* @RestPost(...) * public void doPost(RestRequest req) { * * // Convert content to a linked list of Person objects. * List<Person> list = req.getContent().as(LinkedList.class, Person.class); * .. * } *

* *
Notes:
    *
  • * The {@link RequestContent} object can also be passed as a parameter on the method. *
  • * The {@link Content @Content} annotation can be used to access the content as well. *
* *
See Also:
* * @return * The content of this HTTP request. *
Never null. */ public RequestContent getContent() { return content; } /** * Returns the HTTP content content as a {@link Reader}. * *

* If {@code allowHeaderParams} init parameter is true, then first looks for {@code &content=xxx} in the URL query * string. * *

* Automatically handles GZipped input streams. * *

* This method is equivalent to calling getContent().getReader(). * * @return The HTTP content content as a {@link Reader}. * @throws IOException If content could not be read. */ @Override public BufferedReader getReader() throws IOException { return getContent().getReader(); } /** * Returns the HTTP content content as an {@link InputStream}. * *

* Automatically handles GZipped input streams. * *

* This method is equivalent to calling getContent().getInputStream(). * * @return The negotiated input stream. * @throws IOException If any error occurred while trying to get the input stream or wrap it in the GZIP wrapper. */ @Override public ServletInputStream getInputStream() throws IOException { return getContent().getInputStream(); } //----------------------------------------------------------------------------------------------------------------- // URI-related methods //----------------------------------------------------------------------------------------------------------------- /** * Returns the portion of the request URI that indicates the context of the request. * *

The context path always comes first in a request URI. * The path starts with a "/" character but does not end with a "/" character. * For servlets in the default (root) context, this method returns "". * The container does not decode this string. * * @return The context path, never null. * @see HttpServletRequest#getContextPath() */ @Override public String getContextPath() { String cp = context.getUriContext(); return cp == null ? inner.getContextPath() : cp; } /** * Returns the URI authority portion of the request. * * @return The URI authority portion of the request. */ public String getAuthorityPath() { if (authorityPath == null) authorityPath = context.getUriAuthority(); if (authorityPath == null) { String scheme = inner.getScheme(); int port = inner.getServerPort(); StringBuilder sb = new StringBuilder(inner.getScheme()).append("://").append(inner.getServerName()); if (! (port == 80 && "http".equals(scheme) || port == 443 && "https".equals(scheme))) sb.append(':').append(port); authorityPath = sb.toString(); } return authorityPath; } /** * Returns the part of this request's URL that calls the servlet. * *

* This path starts with a "/" character and includes either the servlet name or a path to the servlet, * but does not include any extra path information or a query string. * * @return The servlet path, never null. * @see HttpServletRequest#getServletPath() */ @Override public String getServletPath() { String cp = context.getUriContext(); String sp = inner.getServletPath(); return cp == null || ! sp.startsWith(cp) ? sp : sp.substring(cp.length()); } /** * Returns the URI context of the request. * *

* The URI context contains all the information about the URI of the request, such as the servlet URI, context * path, etc... * * @return The URI context of the request. */ public UriContext getUriContext() { if (uriContext == null) uriContext = UriContext.of(getAuthorityPath(), getContextPath(), getServletPath(), StringUtils.urlEncodePath(inner.getPathInfo())); return uriContext; } /** * Returns a URI resolver that can be used to convert URIs to absolute or root-relative form. * * @param resolution The URI resolution rule. * @param relativity The relative URI relativity rule. * @return The URI resolver for this request. */ public UriResolver getUriResolver(UriResolution resolution, UriRelativity relativity) { return UriResolver.of(resolution, relativity, getUriContext()); } /** * Shortcut for calling {@link #getUriResolver()} using {@link UriResolution#ROOT_RELATIVE} and * {@link UriRelativity#RESOURCE} * * @return The URI resolver for this request. */ public UriResolver getUriResolver() { return UriResolver.of(context.getUriResolution(), context.getUriRelativity(), getUriContext()); } /** * Returns the URI for this request. * *

* Similar to {@link #getRequestURI()} but returns the value as a {@link URI}. * It also gives you the capability to override the query parameters (e.g. add new query parameters to the existing * URI). * * @param includeQuery If true include the query parameters on the request. * @param addQueryParams Augment the request URI with the specified query parameters. * @return A new URI. */ public URI getUri(boolean includeQuery, Map addQueryParams) { String uri = inner.getRequestURI(); if (includeQuery || addQueryParams != null) { StringBuilder sb = new StringBuilder(uri); RequestQueryParams rq = this.queryParams.copy(); if (addQueryParams != null) for (Map.Entry e : addQueryParams.entrySet()) rq.set(e.getKey(), e.getValue()); if (! rq.isEmpty()) sb.append('?').append(rq.asQueryString()); uri = sb.toString(); } try { return new URI(uri); } catch (URISyntaxException e) { // Shouldn't happen. throw asRuntimeException(e); } } //----------------------------------------------------------------------------------------------------------------- // Labels //----------------------------------------------------------------------------------------------------------------- /** * Returns the localized swagger associated with the resource. * *

* A shortcut for calling getInfoProvider().getSwagger(request); * *

Example:
*

* @RestGet * public List<Tag> swaggerTags(RestRequest req) { * return req.getSwagger().getTags(); * } *

* *
Notes:
    *
  • * The {@link Swagger} object can also be passed as a parameter on the method. *
* *
See Also:
    *
  • {@link RestContext.Builder#swaggerProvider(Class)} *
  • {@link RestContext.Builder#swaggerProvider(SwaggerProvider)} *
* * @return * The swagger associated with the resource. *
Never null. */ public Optional getSwagger() { return context.getSwagger(getLocale()); } /** * Returns the swagger for the Java method invoked. * * @return The swagger for the Java method as an {@link Optional}. Never null. */ public Optional getOperationSwagger() { Optional swagger = getSwagger(); if (! swagger.isPresent()) return Optional.empty(); return ofNullable(swagger.get().getOperation(opContext.getPathPattern(), getMethod().toLowerCase())); } //----------------------------------------------------------------------------------------------------------------- // Other methods //----------------------------------------------------------------------------------------------------------------- /** * Returns the part serializer associated with this request. * * @return The part serializer associated with this request. */ public HttpPartParserSession getPartParserSession() { return partParserSession; } /** * Returns the HTTP method of this request. * *

* If allowHeaderParams init parameter is true, then first looks for * &method=xxx in the URL query string. * * @return The HTTP method of this request. */ @Override public String getMethod() { return session.getMethod(); } /** * Returns true if &plainText=true was specified as a URL parameter. * *

* This indicates that the Content-Type of the output should always be set to "text/plain" * to make it easy to render in a browser. * *

* This feature is useful for debugging. * * @return true if {@code &plainText=true} was specified as a URL parameter */ public boolean isPlainText() { return "true".equals(queryParams.get("plainText").asString().orElse("false")); } /** * Returns the resource bundle for the request locale. * *

Example:
*

* @RestGet * public String hello(RestRequest req, @Query("user") String user) { * * // Return a localized message. * return req.getMessages().getString("hello.message", user); * } *

* *
Notes:
    *
  • * The {@link Messages} object can also be passed as a parameter on the method. *
* *
See Also:
    *
  • {@link org.apache.juneau.rest.RestRequest#getMessage(String,Object...)} *
* * @return * The resource bundle. *
Never null. */ public Messages getMessages() { return context.getMessages().forLocale(getLocale()); } /** * Shortcut method for calling {@link RestRequest#getMessages()} and {@link Messages#getString(String,Object...)}. * * @param key The message key. * @param args Optional {@link MessageFormat}-style arguments. * @return The localized message. */ public String getMessage(String key, Object...args) { return getMessages().getString(key, args); } /** * Returns the resource context handling the request. * *

* Can be used to access servlet-init parameters or annotations during requests, such as in calls to * {@link RestGuard#guard(RestRequest, RestResponse)}.. * * @return The resource context handling the request. */ public RestContext getContext() { return context; } /** * Returns access to the inner {@link RestOpContext} of this method. * * @return The {@link RestOpContext} of this method. May be null if method has not yet been found. */ public RestOpContext getOpContext() { return opContext; } /** * Returns the {@link BeanSession} associated with this request. * * @return The request bean session. */ public BeanSession getBeanSession() { return beanSession; } /** * Returns true if debug mode is enabled. * * Debug mode is enabled by simply adding "?debug=true" to the query string or adding a Debug: true header on the request. * * @return true if debug mode is enabled. */ public boolean isDebug() { return getAttribute("Debug").as(Boolean.class).orElse(false); } /** * Sets the "Exception" attribute to the specified throwable. * *

* This exception is used by {@link CallLogger} for logging purposes. * * @param t The attribute value. * @return This object. */ public RestRequest setException(Throwable t) { setAttribute("Exception", t); return this; } /** * Sets the "NoTrace" attribute to the specified boolean. * *

* This flag is used by {@link CallLogger} and tells it not to log the current request. * * @param b The attribute value. * @return This object. */ public RestRequest setNoTrace(Boolean b) { setAttribute("NoTrace", b); return this; } /** * Shortcut for calling setNoTrace(true). * * @return This object. */ public RestRequest setNoTrace() { return setNoTrace(true); } /** * Sets the "Debug" attribute to the specified boolean. * *

* This flag is used by {@link CallLogger} to help determine how a request should be logged. * * @param b The attribute value. * @return This object. * @throws IOException If content could not be cached. */ public RestRequest setDebug(Boolean b) throws IOException { setAttribute("Debug", b); if (b) inner = CachingHttpServletRequest.wrap(inner); return this; } /** * Shortcut for calling setDebug(true). * * @return This object. * @throws IOException If content could not be cached. */ public RestRequest setDebug() throws IOException { return setDebug(true); } /** * Request-level variable resolver session. * *

* Used to resolve SVL variables in text. * *

Example:
*

* @RestGet * public String hello(RestRequest req) { * * // Get var resolver session. * VarResolverSession session = getVarResolverSession(); * * // Use it to construct a customized message from a query parameter. * return session.resolve("Hello $RQ{user}!"); * } *

* *
Notes:
    *
  • * The {@link VarResolverSession} object can also be passed as a parameter on the method. *
* *
See Also:
    *
  • {@link org.apache.juneau.rest.RestContext#getVarResolver()} *
* * @return The variable resolver for this request. */ public VarResolverSession getVarResolverSession() { if (varSession == null) varSession = context .getVarResolver() .createSession(session.getBeanStore()) .bean(RestRequest.class, this) .bean(RestSession.class, session); return varSession; } /** * Returns the static files registered on the REST resource context object. * *

* Used to retrieve localized files to be served up as static files through the REST API. * * @return This object. */ public StaticFiles getStaticFiles() { return context.getStaticFiles(); } /** * Config file associated with the resource. * *

* Returns a config file with session-level variable resolution. * * The config file is identified via one of the following: *

    *
  • {@link Rest#config()} *
  • {@link RestContext.Builder#config(Config)} *
* *
Example:
*

* @RestGet(...) * public void doGet(RestRequest req) { * * // Get config file. * Config config = req.getConfig(); * * // Get simple values from config file. * int timeout = config.get("MyResource/timeout").asInteger().orElse(=10000); * * // Get complex values from config file. * MyBean bean = config.get("MyResource/myBean").as(MyBean.class).orElse(null); * } *

* *
Notes:
    *
  • * The {@link Config} object can also be passed as a parameter on the method. *
* *
See Also:
* * @return * The config file associated with the resource, or null if resource does not have a config file * associated with it. */ public Config getConfig() { if (config == null) config = context.getConfig().resolving(getVarResolverSession()); return config; } /** * Creates a proxy interface to retrieve HTTP parts of this request as a proxy bean. * *
Examples:
*

* @RestPost("/mypath/{p1}/{p2}/*") * public void myMethod(@Request MyRequest requestBean) {...} * * public interface MyRequest { * * @Path // Path variable name inferred from getter. * String getP1(); * * @Path("p2") * String getX(); * * @Path("/*") * String getRemainder(); * * @Query * String getQ1(); * * // Schema-based query parameter: Pipe-delimited lists of comma-delimited lists of integers. * @Query( * collectionFormat="pipes" * items=@Items( * items=@SubItems( * collectionFormat="csv" * type="integer" * ) * ) * ) * int[][] getQ3(); * * @Header("*") * Map<String,Object> getHeaders(); *

* * @param The request bean interface to instantiate. * @param c The request bean interface to instantiate. * @return A new request bean proxy for this REST request. */ public T getRequest(Class c) { return getRequest(RequestBeanMeta.create(c, getContext().getAnnotations())); } /** * Same as {@link #getRequest(Class)} but used on pre-instantiated {@link RequestBeanMeta} objects. * * @param The request bean interface to instantiate. * @param rbm The metadata about the request bean interface to create. * @return A new request bean proxy for this REST request. */ public T getRequest(final RequestBeanMeta rbm) { try { Class c = (Class)rbm.getClassMeta().getInnerClass(); final BeanSession bs = getBeanSession(); final BeanMeta bm = bs.getBeanMeta(c); return (T)Proxy.newProxyInstance( c.getClassLoader(), new Class[] { c }, (InvocationHandler) (proxy, method, args) -> { RequestBeanPropertyMeta pm = rbm.getProperty(method.getName()); if (pm != null) { HttpPartParserSession pp = pm.getParser(getPartParserSession()); HttpPartSchema schema = pm.getSchema(); String name = pm.getPartName(); ClassMeta type = bs.getClassMeta(method.getGenericReturnType()); HttpPartType pt = pm.getPartType(); if (pt == HttpPartType.BODY) return getContent().setSchema(schema).as(type); if (pt == QUERY) return getQueryParam(name).parser(pp).schema(schema).as(type).orElse(null); if (pt == FORMDATA) return getFormParam(name).parser(pp).schema(schema).as(type).orElse(null); if (pt == HEADER) return getHeaderParam(name).parser(pp).schema(schema).as(type).orElse(null); if (pt == PATH) return getPathParam(name).parser(pp).schema(schema).as(type).orElse(null); } return null; }); } catch (Exception e) { throw asRuntimeException(e); } } /* Called by RestSession.finish() */ void close() { if (config != null) { try { config.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * Returns the wrapped servlet request. * * @return The wrapped servlet request. */ public HttpServletRequest getHttpServletRequest() { return inner; } /** * Returns the part serializer session for this request. * * @return The part serializer session for this request. */ public HttpPartSerializerSession getPartSerializerSession() { return opContext.getPartSerializer().getPartSession(); } @Override /* Object */ public String toString() { StringBuilder sb = new StringBuilder("\n").append(getRequestLine()).append("\n"); sb.append("---Headers---\n"); getHeaders().forEach(x -> sb.append("\t").append(x).append("\n")); String m = getMethod(); if (m.equals("PUT") || m.equals("POST")) { try { sb.append("---Content UTF-8---\n"); sb.append(content.asString()).append("\n"); sb.append("---Content Hex---\n"); sb.append(content.asSpacedHex()).append("\n"); } catch (Exception e1) { sb.append(e1.getLocalizedMessage()); } } return sb.toString(); } //----------------------------------------------------------------------------------------------------------------- // Utility methods //----------------------------------------------------------------------------------------------------------------- /* * Converts an Accept-Language value entry to a Locale. */ private static Locale toLocale(String lang) { String country = ""; int i = lang.indexOf('-'); if (i > -1) { country = lang.substring(i+1).trim(); lang = lang.substring(0,i).trim(); } return new Locale(lang, country); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy