From c3f22b73646be44d29ae42e0c5dc9531a1a36b31 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Sun, 23 Oct 2016 21:07:07 -0400 Subject: [PATCH] Add "mutate" builder to ServerWebExchange This commit adds a default mutate method to ServerWebExchange which prepares an immutable wrapper and returns the provided mutated properties. --- ...faultServerWebExchangeMutativeBuilder.java | 134 ++++++++++++++++++ .../web/server/ServerWebExchange.java | 44 ++++++ .../server/ServerWebExchangeDecorator.java | 16 ++- 3 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeMutativeBuilder.java diff --git a/spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeMutativeBuilder.java b/spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeMutativeBuilder.java new file mode 100644 index 00000000000..3e3a1d70a02 --- /dev/null +++ b/spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeMutativeBuilder.java @@ -0,0 +1,134 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * 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 org.springframework.web.server; + +import java.security.Principal; +import java.util.Optional; + +import reactor.core.publisher.Mono; + +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.util.Assert; + +/** + * Default implementation of + * {@link org.springframework.web.server.ServerWebExchange.MutativeBuilder}. + * + * @author Rossen Stoyanchev + * @since 5.0 + */ +class DefaultServerWebExchangeMutativeBuilder implements ServerWebExchange.MutativeBuilder { + + private final ServerWebExchange delegate; + + private ServerHttpRequest request; + + private ServerHttpResponse response; + + private Principal user; + + private Mono session; + + + public DefaultServerWebExchangeMutativeBuilder(ServerWebExchange delegate) { + Assert.notNull(delegate, "'delegate' is required."); + this.delegate = delegate; + } + + + @Override + public ServerWebExchange.MutativeBuilder setRequest(ServerHttpRequest request) { + this.request = request; + return this; + } + + @Override + public ServerWebExchange.MutativeBuilder setResponse(ServerHttpResponse response) { + this.response = response; + return this; + } + + @Override + public ServerWebExchange.MutativeBuilder setPrincipal(Principal user) { + this.user = user; + return this; + } + + @Override + public ServerWebExchange.MutativeBuilder setSession(Mono session) { + this.session = session; + return this; + } + + @Override + public ServerWebExchange build() { + return new MutativeDecorator(this.delegate, + this.request, this.response, this.user, this.session); + } + + + /** + * An immutable wrapper of an exchange returning property overrides -- given + * to the constructor -- or original values otherwise. + */ + private static class MutativeDecorator extends ServerWebExchangeDecorator { + + private final ServerHttpRequest request; + + private final ServerHttpResponse response; + + private final Principal user; + + private final Mono session; + + + public MutativeDecorator(ServerWebExchange delegate, + ServerHttpRequest request, ServerHttpResponse response, Principal user, + Mono session) { + + super(delegate); + this.request = request; + this.response = response; + this.user = user; + this.session = session; + } + + + @Override + public ServerHttpRequest getRequest() { + return (this.request != null ? this.request : getDelegate().getRequest()); + } + + @Override + public ServerHttpResponse getResponse() { + return (this.response != null ? this.response : getDelegate().getResponse()); + } + + @Override + public Mono getSession() { + return (this.session != null ? this.session : getDelegate().getSession()); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getPrincipal() { + return (this.user != null ? Optional.of((T) this.user) : getDelegate().getPrincipal()); + } + } + +} + diff --git a/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java b/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java index 3a48d41cba3..265e5673a35 100644 --- a/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java +++ b/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java @@ -118,4 +118,48 @@ public interface ServerWebExchange { */ boolean checkNotModified(String etag, Instant lastModified); + + /** + * Return a builder to mutate properties of this exchange. The resulting + * new exchange is an immutable {@link ServerWebExchangeDecorator decorator} + * around the current exchange instance that returns mutated values, where + * provided, or delegating to the decorated instance otherwise. + */ + default MutativeBuilder mutate() { + return new DefaultServerWebExchangeMutativeBuilder(this); + } + + + /** + * Builder for mutating properties of a {@link ServerWebExchange}. + */ + interface MutativeBuilder { + + /** + * Set the request to use. + */ + MutativeBuilder setRequest(ServerHttpRequest request); + + /** + * Set the response to use. + */ + MutativeBuilder setResponse(ServerHttpResponse response); + + /** + * Set the principal to use. + */ + MutativeBuilder setPrincipal(Principal user); + + /** + * Set the session to use. + */ + MutativeBuilder setSession(Mono session); + + /** + * Build an immutable wrapper that returning the mutated properties. + */ + ServerWebExchange build(); + + } + } diff --git a/spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java b/spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java index 9be776cda11..aeee3822eb1 100644 --- a/spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java +++ b/spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java @@ -27,20 +27,26 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; /** - * Wraps another {@link ServerWebExchange} and delegates all methods to it. - * Sub-classes can override specific methods, e.g. {@link #getPrincipal()} to - * return the authenticated user for the request. + * A convenient base class for classes that need to wrap another + * {@link ServerWebExchange}. Pre-implements all methods by delegating to the + * wrapped instance. + * + *

Note that if the purpose for wrapping is simply to override specific + * properties, e.g. {@link #getPrincipal()}, consider using + * {@link ServerWebExchange#mutate()} instead. * * @author Rossen Stoyanchev * @since 5.0 + * + * @see ServerWebExchange#mutate() */ public class ServerWebExchangeDecorator implements ServerWebExchange { private final ServerWebExchange delegate; - public ServerWebExchangeDecorator(ServerWebExchange delegate) { - Assert.notNull(delegate, "'delegate' is required."); + protected ServerWebExchangeDecorator(ServerWebExchange delegate) { + Assert.notNull(delegate, "ServerWebExchange 'delegate' is required."); this.delegate = delegate; }