Summary
This CSR proposes to add two new static factory methods to com.sun.net.httpserver.Filter
to facilitate the creation of pre- and post-processing filters, Filter beforeHandler(String description, Consumer<HttpExchange> operation)
and Filter afterHandler(String description, Consumer<HttpExchange> operation)
. Filters are used to process an exchange before and/or after it is handled. While the notion of pre- and post-processing filters already exists, these new methods provide a convenient means for creating such filters.
Problem
Currently, there is no convenient way to create pre- or post-processing filters. Instead, the abstract Filter
class has to be extended by a subclass that implements the filter logic. An instance of the subclass is then added to an HttpContext
. Multiple filters can be added to a context and a filter typically applies a small set of operations to an exchange. As such, filters lend themselves to factory methods, which can provide a more compact way of filter creation.
Solution
The two factory methods avoid the overhead of subclassing the Filter class. A pre- or post-processing filter can easily be created by passing the description and the operation of the filter to the static methods.
Specification
src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java
+ /**
+ * Returns a pre-processing {@code Filter} with the given description and
+ * operation.
+ *
+ * <p>The {@link java.util.function.Consumer operation} is the effective implementation of the
+ * filter. It is executed for each {@code HttpExchange} before invoking
+ * either the next filter in the chain or the exchange handler (if this is
+ * the final filter in the chain).
+ *
+ * @apiNote
+ * A beforeHandler filter is typically used to examine or modify the
+ * exchange state before it is handled. The filter {@code operation} is
+ * executed before {@link com.sun.net.httpserver.Filter.Chain#doFilter(HttpExchange)} is invoked,
+ * so before any subsequent filters in the chain and the exchange handler
+ * are executed. The filter {@code operation} is not expected to handle the
+ * request or {@linkplain com.sun.net.httpserver.HttpExchange#sendResponseHeaders(int, long) send response headers},
+ * since this is commonly done by the exchange handler.
+ *
+ * <p> Example of adding the {@code "Foo"} response header to all responses:
+ * <pre>{@code
+ * var filter = Filter.beforeHandler("Add response header Foo",
+ * e -> e.getResponseHeaders().set("Foo", "Bar"));
+ * httpContext.getFilters().add(filter);
+ * }</pre>
+ *
+ * @param description the string to be returned from {@link #description()}
+ * @param operation the operation of the returned filter
+ * @return a filter whose operation is invoked before the exchange is handled
+ * @throws NullPointerException if any argument is null
+ * @since 17
+ */
+ public static Filter beforeHandler(String description, Consumer<HttpExchange> operation) { }
+ /**
+ * Returns a post-processing {@code Filter} with the given description and
+ * operation.
+ *
+ * <p>The {@link java.util.function.Consumer operation} is the effective implementation of the
+ * filter. It is executed for each {@code HttpExchange} after invoking
+ * either the next filter in the chain or the exchange handler (if this
+ * filter is the final filter in the chain).
+ *
+ * @apiNote
+ * An afterHandler filter is typically used to examine the exchange state
+ * rather than modifying it. The filter {@code operation} is executed after
+ * {@link com.sun.net.httpserver.Filter.Chain#doFilter(HttpExchange)} is invoked, this means any
+ * subsequent filters in the chain and the exchange handler have been
+ * executed. The filter {@code operation} is not expected to handle the
+ * exchange or {@linkplain com.sun.net.httpserver.HttpExchange#sendResponseHeaders(int, long) send the response headers}.
+ * Doing so is likely to fail, since the exchange has commonly been handled
+ * before the operation is invoked.
+ *
+ * <p> Example of adding a filter that logs the response code of all exchanges:
+ * <pre>{@code
+ * var filter = Filter.afterHandler("Log response code", e -> log(e.getResponseCode());
+ * httpContext.getFilters().add(filter);
+ * }</pre>
+ *
+ * <p> Example of adding a sequence of afterHandler filters to a context:<br>
+ * The order in which the filter operations are invoked is reverse to the
+ * order in which the filters are added to the context's filter-list.
+ *
+ * <pre>{@code
+ * var a1Set = Filter.afterHandler("Set a1", e -> e.setAttribute("a1", "some value"));
+ * var a1Get = Filter.afterHandler("Get a1", e -> doSomething(e.getAttribute("a1")));
+ * httpContext.getFilters().addAll(List.of(a1Get, a1Set));
+ * }</pre>
+ * <p>The operation of {@code a1Get} will be invoked after the operation of
+ * {@code a1Set} because {@code a1Get} was added before {@code a1Set}.
+ *
+ * @param description the string to be returned from {@link #description()}
+ * @param operation the operation of the returned filter
+ * @return a filter whose operation is invoked after the exchange is handled
+ * @throws NullPointerException if any argument is null
+ * @since 17
+ */
+ public static Filter afterHandler(String description, Consumer<HttpExchange> operation) { }
- csr of
-
JDK-8265123 Add static factory methods to com.sun.net.httpserver.Filter
-
- Resolved
-
- relates to
-
JDK-8267379 com/sun/net/httpserver/Filter improve API documentation of static methods
-
- Closed
-