/* * Copyright 2017 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.integration.http.dsl; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import org.springframework.core.ParameterizedTypeReference; import org.springframework.expression.Expression; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.integration.dsl.ComponentsRegistration; import org.springframework.integration.dsl.MessageHandlerSpec; import org.springframework.integration.expression.FunctionExpression; import org.springframework.integration.expression.ValueExpression; import org.springframework.integration.http.outbound.AbstractHttpRequestExecutingMessageHandler; import org.springframework.integration.http.support.DefaultHttpHeaderMapper; import org.springframework.integration.mapping.HeaderMapper; import org.springframework.messaging.Message; import org.springframework.util.Assert; /** * The base {@link MessageHandlerSpec} for {@link AbstractHttpRequestExecutingMessageHandler}s. * * @param <S> the target {@link BaseHttpMessageHandlerSpec} implementation type. * @param <E> the target {@link AbstractHttpRequestExecutingMessageHandler} implementation type. * * @author Artem Bilan * @author Shiliang Li * * @since 5.0 */ public abstract class BaseHttpMessageHandlerSpec<S extends BaseHttpMessageHandlerSpec<S, E>, E extends AbstractHttpRequestExecutingMessageHandler> extends MessageHandlerSpec<S, E> implements ComponentsRegistration { private final Map<String, Expression> uriVariableExpressions = new HashMap<>(); private HeaderMapper<HttpHeaders> headerMapper = DefaultHttpHeaderMapper.outboundMapper(); private boolean headerMapperExplicitlySet; public BaseHttpMessageHandlerSpec(E handler) { this.target = handler; this.target.setHeaderMapper(this.headerMapper); } S expectReply(boolean expectReply) { this.target.setExpectReply(expectReply); return _this(); } /** * Specify whether the real URI should be encoded after <code>uriVariables</code> * expanding and before send request via underlying implementation. The default value is <code>true</code>. * @param encodeUri true if the URI should be encoded. * @return the spec */ public S encodeUri(boolean encodeUri) { this.target.setEncodeUri(encodeUri); return _this(); } /** * Specify the SpEL {@link Expression} to determine {@link HttpMethod} at runtime. * @param httpMethodExpression The method expression. * @return the spec */ public S httpMethodExpression(Expression httpMethodExpression) { this.target.setHttpMethodExpression(httpMethodExpression); return _this(); } /** * Specify a {@link Function} to determine {@link HttpMethod} at runtime. * @param httpMethodFunction The HTTP method {@link Function}. * @param <P> the payload type. * @return the spec */ public <P> S httpMethodFunction(Function<Message<P>, ?> httpMethodFunction) { return httpMethodExpression(new FunctionExpression<>(httpMethodFunction)); } /** * Specify the {@link HttpMethod} for requests. * The default method is {@code POST}. * @param httpMethod the {@link HttpMethod} to use. * @return the spec */ public S httpMethod(HttpMethod httpMethod) { this.target.setHttpMethod(httpMethod); return _this(); } /** * Specify whether the outbound message's payload should be extracted * when preparing the request body. * Otherwise the Message instance itself is serialized. * The default value is {@code true}. * @param extractPayload true if the payload should be extracted. * @return the spec */ public S extractPayload(boolean extractPayload) { this.target.setExtractPayload(extractPayload); return _this(); } /** * Specify the charset name to use for converting String-typed payloads to bytes. * The default is {@code UTF-8}. * @param charset The charset. * @return the spec */ public S charset(String charset) { this.target.setCharset(charset); return _this(); } /** * Specify the expected response type for the REST request. * @param expectedResponseType The expected type. * @return the spec */ public S expectedResponseType(Class<?> expectedResponseType) { this.target.setExpectedResponseType(expectedResponseType); return _this(); } /** * Specify a {@link ParameterizedTypeReference} for the expected response type for the REST request. * @param expectedResponseType The {@link ParameterizedTypeReference} for expected type. * @return the spec */ public S expectedResponseType(ParameterizedTypeReference<?> expectedResponseType) { return expectedResponseTypeExpression(new ValueExpression<ParameterizedTypeReference<?>>(expectedResponseType)); } /** * Specify a SpEL {@link Expression} to determine the type for the expected response * The returned value of the expression could be an instance of {@link Class} or * {@link String} representing a fully qualified class name. * @param expectedResponseTypeExpression The expected response type expression. * @return the spec */ public S expectedResponseTypeExpression(Expression expectedResponseTypeExpression) { this.target.setExpectedResponseTypeExpression(expectedResponseTypeExpression); return _this(); } /** * Specify a {@link Function} to determine the type for the expected response * The returned value of the expression could be an instance of {@link Class} or * {@link String} representing a fully qualified class name. * @param expectedResponseTypeFunction The expected response type {@link Function}. * @param <P> the payload type. * @return the spec */ public <P> S expectedResponseTypeFunction( Function<Message<P>, ?> expectedResponseTypeFunction) { return expectedResponseTypeExpression(new FunctionExpression<>(expectedResponseTypeFunction)); } /** * Set the {@link HeaderMapper} to use when mapping between HTTP headers and {@code MessageHeaders}. * @param headerMapper The header mapper. * @return the spec */ public S headerMapper(HeaderMapper<HttpHeaders> headerMapper) { this.headerMapper = headerMapper; this.target.setHeaderMapper(this.headerMapper); this.headerMapperExplicitlySet = true; return _this(); } /** * Provide the pattern array for request headers to map. * @param patterns the patterns for request headers to map. * @return the spec * @see DefaultHttpHeaderMapper#setOutboundHeaderNames(String[]) */ public S mappedRequestHeaders(String... patterns) { Assert.isTrue(!this.headerMapperExplicitlySet, "The 'mappedRequestHeaders' must be specified on the provided 'headerMapper': " + this.headerMapper); ((DefaultHttpHeaderMapper) this.headerMapper).setOutboundHeaderNames(patterns); return _this(); } /** * Provide the pattern array for response headers to map. * @param patterns the patterns for response headers to map. * @return the current Spec. * @see DefaultHttpHeaderMapper#setInboundHeaderNames(String[]) */ public S mappedResponseHeaders(String... patterns) { Assert.isTrue(!this.headerMapperExplicitlySet, "The 'mappedResponseHeaders' must be specified on the provided 'headerMapper': " + this.headerMapper); ((DefaultHttpHeaderMapper) this.headerMapper).setInboundHeaderNames(patterns); return _this(); } /** * Set the Map of URI variable expressions to evaluate against the outbound message * when replacing the variable placeholders in a URI template. * @param uriVariableExpressions The URI variable expressions. * @return the current Spec. * @see AbstractHttpRequestExecutingMessageHandler#setUriVariableExpressions(Map) */ public S uriVariableExpressions(Map<String, Expression> uriVariableExpressions) { this.uriVariableExpressions.clear(); this.uriVariableExpressions.putAll(uriVariableExpressions); return _this(); } /** * Specify an {@link Expression} to evaluate a value for the uri template variable. * @param variable the uri template variable. * @param expression the expression to evaluate value for te uri template variable. * @return the current Spec. * @see AbstractHttpRequestExecutingMessageHandler#setUriVariableExpressions(Map) * @see ValueExpression * @see org.springframework.expression.common.LiteralExpression */ public S uriVariable(String variable, Expression expression) { this.uriVariableExpressions.put(variable, expression); return _this(); } /** * Specify a value SpEL expression for the uri template variable. * @param variable the uri template variable. * @param expression the expression to evaluate value for te uri template variable. * @return the current Spec. * @see AbstractHttpRequestExecutingMessageHandler#setUriVariableExpressions(Map) */ public S uriVariable(String variable, String expression) { return uriVariable(variable, PARSER.parseExpression(expression)); } /** * Specify a {@link Function} to evaluate a value for the uri template variable. * @param variable the uri template variable. * @param valueFunction the {@link Function} to evaluate a value for the uri template variable. * @param <P> the payload type. * @return the current Spec. * @see AbstractHttpRequestExecutingMessageHandler#setUriVariableExpressions(Map) */ public <P> S uriVariable(String variable, Function<Message<P>, ?> valueFunction) { return uriVariable(variable, new FunctionExpression<>(valueFunction)); } /** * Specify a SpEL expression to evaluate a {@link Map} of URI variables at runtime against request message. * @param uriVariablesExpression to use. * @return the current Spec. * @see AbstractHttpRequestExecutingMessageHandler#setUriVariablesExpression(Expression) */ public S uriVariablesExpression(String uriVariablesExpression) { return uriVariablesExpression(PARSER.parseExpression(uriVariablesExpression)); } /** * Specify a SpEL expression to evaluate a {@link Map} of URI variables at runtime against request message. * @param uriVariablesExpression to use. * @return the current Spec. * @see AbstractHttpRequestExecutingMessageHandler#setUriVariablesExpression(Expression) */ public S uriVariablesExpression(Expression uriVariablesExpression) { this.target.setUriVariablesExpression(uriVariablesExpression); return _this(); } /** * Specify a {@link Function} to evaluate a {@link Map} of URI variables at runtime against request message. * @param uriVariablesFunction the {@link Function} to use. * @param <P> the payload type. * @return the current Spec. * @see AbstractHttpRequestExecutingMessageHandler#setUriVariablesExpression(Expression) */ public <P> S uriVariablesFunction(Function<Message<P>, Map<String, ?>> uriVariablesFunction) { return uriVariablesExpression(new FunctionExpression<>(uriVariablesFunction)); } /** * Set to {@code true} if you wish {@code Set-Cookie} header in response to be * transferred as {@code Cookie} header in subsequent interaction for a message. * @param transferCookies the transferCookies to set. * @return the current Spec. */ public S transferCookies(boolean transferCookies) { this.target.setTransferCookies(transferCookies); return _this(); } @Override public Collection<Object> getComponentsToRegister() { this.target.setUriVariableExpressions(this.uriVariableExpressions); return Collections.singletonList(this.headerMapper); } protected abstract boolean isClientSet(); }