/* * 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.client.reactive; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.client.reactive.ClientHttpRequest; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.util.DefaultUriTemplateHandler; import org.springframework.web.util.UriTemplateHandler; /** * Builds a {@link ClientHttpRequest} using a {@link Publisher} * as request body. * * <p>See static factory methods in {@link ClientWebRequestBuilders} * * @author Brian Clozel * @see ClientWebRequestBuilders */ public class DefaultClientWebRequestBuilder implements ClientWebRequestBuilder { private final UriTemplateHandler uriTemplateHandler = new DefaultUriTemplateHandler(); private HttpMethod httpMethod; private HttpHeaders httpHeaders; private URI url; private final MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>(); private Publisher body; private ResolvableType elementType; private List<ClientWebRequestPostProcessor> postProcessors = new ArrayList<>(); protected DefaultClientWebRequestBuilder() { } public DefaultClientWebRequestBuilder(HttpMethod httpMethod, String urlTemplate, Object... urlVariables) { this.httpMethod = httpMethod; this.httpHeaders = new HttpHeaders(); this.url = this.uriTemplateHandler.expand(urlTemplate, urlVariables); } public DefaultClientWebRequestBuilder(HttpMethod httpMethod, URI url) { this.httpMethod = httpMethod; this.httpHeaders = new HttpHeaders(); this.url = url; } /** * Add an HTTP request header */ public DefaultClientWebRequestBuilder header(String name, String... values) { Arrays.stream(values).forEach(value -> this.httpHeaders.add(name, value)); return this; } /** * Add all provided HTTP request headers */ public DefaultClientWebRequestBuilder headers(HttpHeaders httpHeaders) { this.httpHeaders = httpHeaders; return this; } /** * Set the Content-Type request header to the given {@link MediaType} */ public DefaultClientWebRequestBuilder contentType(MediaType contentType) { this.httpHeaders.setContentType(contentType); return this; } /** * Set the Content-Type request header to the given media type */ public DefaultClientWebRequestBuilder contentType(String contentType) { this.httpHeaders.setContentType(MediaType.parseMediaType(contentType)); return this; } /** * Set the Accept request header to the given {@link MediaType}s */ public DefaultClientWebRequestBuilder accept(MediaType... mediaTypes) { this.httpHeaders.setAccept(Arrays.asList(mediaTypes)); return this; } /** * Set the Accept request header to the given media types */ public DefaultClientWebRequestBuilder accept(String... mediaTypes) { this.httpHeaders.setAccept( Arrays.stream(mediaTypes).map(type -> MediaType.parseMediaType(type)) .collect(Collectors.toList())); return this; } /** * Add a Cookie to the HTTP request */ public DefaultClientWebRequestBuilder cookie(String name, String value) { return cookie(new HttpCookie(name, value)); } /** * Add a Cookie to the HTTP request */ public DefaultClientWebRequestBuilder cookie(HttpCookie cookie) { this.cookies.add(cookie.getName(), cookie); return this; } /** * Allows performing more complex operations with a strategy. For example, a * {@link ClientWebRequestPostProcessor} implementation might accept the arguments of username * and password and set an HTTP Basic authentication header. * * @param postProcessor the {@link ClientWebRequestPostProcessor} to use. Cannot be null. * * @return this instance for further modifications. */ public DefaultClientWebRequestBuilder apply(ClientWebRequestPostProcessor postProcessor) { Assert.notNull(postProcessor, "`postProcessor` is required"); this.postProcessors.add(postProcessor); return this; } /** * Use the given object as the request body */ public DefaultClientWebRequestBuilder body(Object content) { this.body = Mono.just(content); this.elementType = ResolvableType.forInstance(content); return this; } /** * Use the given {@link Publisher} as the request body and use its {@link ResolvableType} * as type information for the element published by this reactive stream */ public DefaultClientWebRequestBuilder body(Publisher<?> content, ResolvableType publisherType) { this.body = content; this.elementType = publisherType; return this; } @Override public ClientWebRequest build() { ClientWebRequest clientWebRequest = new ClientWebRequest(this.httpMethod, this.url); clientWebRequest.setHttpHeaders(this.httpHeaders); clientWebRequest.setCookies(this.cookies); clientWebRequest.setBody(this.body); clientWebRequest.setElementType(this.elementType); for (ClientWebRequestPostProcessor postProcessor : this.postProcessors) { clientWebRequest = postProcessor.postProcess(clientWebRequest); } return clientWebRequest; } }