Turned on checkstyle

This commit is contained in:
Marcin Grzejszczak
2019-02-01 15:48:32 +01:00
parent 94e9b8f2f8
commit e4b08a083c
268 changed files with 5114 additions and 3993 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -21,10 +21,17 @@ import org.springframework.cloud.function.context.catalog.FunctionInspector;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
/**
* Simple implementation of a {@link StringConverter}.
*
* @author Dave Syer
*/
public class BasicStringConverter implements StringConverter {
private ConversionService conversionService;
private ConfigurableListableBeanFactory registry;
private FunctionInspector inspector;
public BasicStringConverter(FunctionInspector inspector,
@@ -35,16 +42,14 @@ public class BasicStringConverter implements StringConverter {
@Override
public Object convert(Object function, String value) {
if (conversionService == null && registry != null) {
ConversionService conversionService = this.registry
.getConversionService();
if (this.conversionService == null && this.registry != null) {
ConversionService conversionService = this.registry.getConversionService();
this.conversionService = conversionService != null ? conversionService
: new DefaultConversionService();
}
Class<?> type = inspector.getInputType(function);
return conversionService.canConvert(String.class, type)
? conversionService.convert(value, type)
: value;
Class<?> type = this.inspector.getInputType(function);
return this.conversionService.canConvert(String.class, type)
? this.conversionService.convert(value, type) : value;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 the original author or authors.
* Copyright 2012-2019 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.
@@ -34,6 +34,8 @@ import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.function.context.catalog.FunctionInspector;
@@ -65,9 +67,6 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
* @author Oleg Zhurakousky
@@ -123,23 +122,27 @@ public class RequestProcessor {
.flatMap(body -> response(wrapper, body, false));
}
public Mono<ResponseEntity<?>> post(FunctionWrapper wrapper, String body, boolean stream) {
public Mono<ResponseEntity<?>> post(FunctionWrapper wrapper, String body,
boolean stream) {
Object function = wrapper.handler();
Class<?> inputType = inspector.getInputType(function);
Class<?> inputType = this.inspector.getInputType(function);
Type itemType = getItemType(function);
Object input = body;
if (StringUtils.hasText(body)) {
if (this.shouldUseJsonConversion(body, wrapper.headers.getContentType())) {
Type jsonType = body.startsWith("[") && Collection.class.isAssignableFrom(inputType) || body.startsWith("{") ? inputType : Collection.class;
Type jsonType = body.startsWith("[")
&& Collection.class.isAssignableFrom(inputType)
|| body.startsWith("{") ? inputType : Collection.class;
if (body.startsWith("[")) {
jsonType = ResolvableType.forClassWithGenerics((Class<?>)jsonType, (Class<?>) itemType).getType();
jsonType = ResolvableType.forClassWithGenerics((Class<?>) jsonType,
(Class<?>) itemType).getType();
}
input = mapper.toObject(body, jsonType);
input = this.mapper.toObject(body, jsonType);
}
else {
input = converter.convert(function, body);
input = this.converter.convert(function, body);
}
}
@@ -148,7 +151,8 @@ public class RequestProcessor {
private boolean shouldUseJsonConversion(String body, MediaType contentType) {
return (body.startsWith("[") || body.startsWith("{"))
&& (contentType == null || (contentType != null && !"text".equalsIgnoreCase(contentType.getType())));
&& (contentType == null || (contentType != null
&& !"text".equalsIgnoreCase(contentType.getType())));
}
public Mono<ResponseEntity<?>> stream(FunctionWrapper request) {
@@ -171,7 +175,7 @@ public class RequestProcessor {
Flux<?> flux;
if (body != null) {
if (Collection.class
.isAssignableFrom(inspector.getInputType(wrapper.handler()))) {
.isAssignableFrom(this.inspector.getInputType(wrapper.handler()))) {
flux = Flux.just(body);
}
else {
@@ -181,15 +185,18 @@ public class RequestProcessor {
flux = Flux.fromIterable(iterable);
}
}
else if (MultiValueMap.class.isAssignableFrom(inspector.getInputType(wrapper.handler()))) {
else if (MultiValueMap.class
.isAssignableFrom(this.inspector.getInputType(wrapper.handler()))) {
flux = Flux.just(wrapper.params());
}
else {
throw new IllegalStateException("Failed to determine input for function call with parameters: '" + wrapper.params
+ "' and headers: `" + wrapper.headers + "`");
throw new IllegalStateException(
"Failed to determine input for function call with parameters: '"
+ wrapper.params + "' and headers: `" + wrapper.headers
+ "`");
}
if (inspector.isMessage(function)) {
if (this.inspector.isMessage(function)) {
flux = messages(wrapper, function == null ? consumer : function, flux);
}
Mono<ResponseEntity<?>> responseEntityMono = null;
@@ -224,7 +231,7 @@ public class RequestProcessor {
private Mono<ResponseEntity<?>> stream(FunctionWrapper request, Publisher<?> result) {
BodyBuilder builder = ResponseEntity.ok();
if (inspector.isMessage(request.handler())) {
if (this.inspector.isMessage(request.handler())) {
result = Flux.from(result)
.doOnNext(value -> addHeaders(builder, (Message<?>) value))
.map(message -> MessageUtils.unpack(request.handler(), message)
@@ -242,7 +249,7 @@ public class RequestProcessor {
Publisher<?> result, Boolean single, boolean getter) {
BodyBuilder builder = ResponseEntity.ok();
if (inspector.isMessage(handler)) {
if (this.inspector.isMessage(handler)) {
result = Flux.from(result)
.map(message -> MessageUtils.unpack(handler, message))
.doOnNext(value -> addHeaders(builder, value))
@@ -267,8 +274,8 @@ public class RequestProcessor {
if (handler instanceof FluxWrapper) {
handler = ((FluxWrapper<?>) handler).getTarget();
}
Class<?> type = inspector.getInputType(handler);
Class<?> wrapper = inspector.getInputWrapper(handler);
Class<?> type = this.inspector.getInputType(handler);
Class<?> wrapper = this.inspector.getInputWrapper(handler);
return Collection.class.isAssignableFrom(type) || Flux.class.equals(wrapper);
}
@@ -276,8 +283,8 @@ public class RequestProcessor {
if (handler instanceof FluxWrapper) {
handler = ((FluxWrapper<?>) handler).getTarget();
}
Class<?> type = inspector.getOutputType(handler);
Class<?> wrapper = inspector.getOutputWrapper(handler);
Class<?> type = this.inspector.getOutputType(handler);
Class<?> wrapper = this.inspector.getOutputWrapper(handler);
if (Stream.class.isAssignableFrom(type)) {
return false;
}
@@ -294,8 +301,7 @@ public class RequestProcessor {
ResolvableType actualType = elementType;
Class<?> resolvedType = elementType.resolve();
ReactiveAdapter adapter = (resolvedType != null
? getAdapterRegistry().getAdapter(resolvedType)
: null);
? getAdapterRegistry().getAdapter(resolvedType) : null);
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
@@ -360,10 +366,8 @@ public class RequestProcessor {
}
private Throwable handleReadError(MethodParameter parameter, Throwable ex) {
return (ex instanceof DecodingException
? new ServerWebInputException("Failed to read HTTP message", parameter,
ex)
: ex);
return (ex instanceof DecodingException ? new ServerWebInputException(
"Failed to read HTTP message", parameter, ex) : ex);
}
private ServerWebInputException handleMissingBody(MethodParameter param) {
@@ -377,13 +381,14 @@ public class RequestProcessor {
private Publisher<?> value(Function<Publisher<?>, Publisher<?>> function,
Publisher<String> value) {
Flux<?> input = Flux.from(value).map(body -> converter.convert(function, body));
Flux<?> input = Flux.from(value)
.map(body -> this.converter.convert(function, body));
return Mono.from(function.apply(input));
}
private Object getTargetFunction(Object function) {
// we need to get the actual un-fluxed function so we can interrogate for types
Object target = inspector.getRegistration(function).getTarget();
Object target = this.inspector.getRegistration(function).getTarget();
if (target instanceof FluxWrapper) {
target = ((FluxWrapper<?>) target).getTarget();
}
@@ -391,12 +396,12 @@ public class RequestProcessor {
}
private Type getItemType(Object function) {
Class<?> inputType = inspector.getInputType(function);
Class<?> inputType = this.inspector.getInputType(function);
if (!Collection.class.isAssignableFrom(inputType)) {
return inputType;
}
Type type = inspector.getRegistration(this.getTargetFunction(function)).getType()
.getType();
Type type = this.inspector.getRegistration(this.getTargetFunction(function))
.getType().getType();
if (type instanceof ParameterizedType) {
type = ((ParameterizedType) type).getActualTypeArguments()[0];
}
@@ -417,6 +422,9 @@ public class RequestProcessor {
return type;
}
/**
* Wrapper for functions.
*/
public static class FunctionWrapper {
private final Function<Publisher<?>, Publisher<?>> function;
@@ -442,7 +450,8 @@ public class RequestProcessor {
}
public Object handler() {
return function != null ? function : consumer != null ? consumer : supplier;
return this.function != null ? this.function
: this.consumer != null ? this.consumer : this.supplier;
}
public Function<Publisher<?>, Publisher<?>> function() {
@@ -458,7 +467,7 @@ public class RequestProcessor {
}
public MultiValueMap<String, String> params() {
return params;
return this.params;
}
public HttpHeaders headers() {
@@ -488,5 +497,7 @@ public class RequestProcessor {
public Publisher<String> argument() {
return this.argument;
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-2019 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
* 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,
@@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
/**
* @author Mark Fisher
*/
// @checkstyle:off
@SpringBootConfiguration
@EnableAutoConfiguration
public class RestApplication {
@@ -30,5 +31,6 @@ public class RestApplication {
public static void main(String[] args) {
SpringApplication.run(RestApplication.class, args);
}
}
}
// @checkstyle:on

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.web;
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -23,15 +23,33 @@ package org.springframework.cloud.function.web.constants;
*/
public abstract class WebRequestConstants {
/**
* Function attribute name.
*/
public static final String FUNCTION = WebRequestConstants.class.getName()
+ ".function";
/**
* Consumer attribute name.
*/
public static final String CONSUMER = WebRequestConstants.class.getName()
+ ".consumer";
/**
* Supplier attribute name.
*/
public static final String SUPPLIER = WebRequestConstants.class.getName()
+ ".supplier";
/**
* Argument attribute name.
*/
public static final String ARGUMENT = WebRequestConstants.class.getName()
+ ".argument";
public static final String HANDLER = WebRequestConstants.class.getName()
+ ".handler";
/**
* Handler attribute name.
*/
public static final String HANDLER = WebRequestConstants.class.getName() + ".handler";
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -21,6 +21,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.cloud.function.web.RequestProcessor;
import org.springframework.cloud.function.web.RequestProcessor.FunctionWrapper;
@@ -38,8 +39,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
* @author Mark Fisher
@@ -58,7 +57,7 @@ public class FunctionController {
public Mono<ResponseEntity<?>> form(ServerWebExchange request) {
FunctionWrapper wrapper = wrapper(request);
return request.getFormData().doOnSuccess(params -> wrapper.params(params))
.then(Mono.defer(() -> processor.post(wrapper, null, false)));
.then(Mono.defer(() -> this.processor.post(wrapper, null, false)));
}
@PostMapping(path = "/**", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@@ -67,7 +66,7 @@ public class FunctionController {
FunctionWrapper wrapper = wrapper(request);
return request.getMultipartData()
.doOnSuccess(params -> wrapper.params(multi(params)))
.then(Mono.defer(() -> processor.post(wrapper, null, false)));
.then(Mono.defer(() -> this.processor.post(wrapper, null, false)));
}
private MultiValueMap<String, String> multi(MultiValueMap<String, Part> body) {
@@ -87,7 +86,7 @@ public class FunctionController {
@ResponseBody
public Mono<ResponseEntity<?>> post(ServerWebExchange request) {
FunctionWrapper wrapper = wrapper(request);
return processor.post(wrapper, request);
return this.processor.post(wrapper, request);
}
@PostMapping(path = "/**")
@@ -95,7 +94,7 @@ public class FunctionController {
public Mono<ResponseEntity<?>> post(ServerWebExchange request,
@RequestBody(required = false) String body) {
FunctionWrapper wrapper = wrapper(request);
return processor.post(wrapper, body, false);
return this.processor.post(wrapper, body, false);
}
@PostMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@@ -103,21 +102,21 @@ public class FunctionController {
public Mono<ResponseEntity<?>> postStream(ServerWebExchange request,
@RequestBody(required = false) String body) {
FunctionWrapper wrapper = wrapper(request);
return processor.post(wrapper, body, true);
return this.processor.post(wrapper, body, true);
}
@GetMapping(path = "/**")
@ResponseBody
public Mono<ResponseEntity<?>> get(ServerWebExchange request) {
FunctionWrapper wrapper = wrapper(request);
return processor.get(wrapper);
return this.processor.get(wrapper);
}
@GetMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@ResponseBody
public Mono<ResponseEntity<?>> getStream(ServerWebExchange request) {
FunctionWrapper wrapper = wrapper(request);
return processor.stream(wrapper);
return this.processor.stream(wrapper);
}
private FunctionWrapper wrapper(ServerWebExchange request) {
@@ -139,4 +138,5 @@ public class FunctionController {
}
return wrapper;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -21,6 +21,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,8 +36,6 @@ import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
*
@@ -57,7 +56,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
public FunctionHandlerMapping(FunctionCatalog catalog,
FunctionController controller) {
this.functions = catalog;
logger.info("FunctionCatalog: " + catalog);
this.logger.info("FunctionCatalog: " + catalog);
setOrder(super.getOrder() - 5);
this.controller = controller;
}
@@ -65,9 +64,9 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
detectHandlerMethods(controller);
while (prefix.endsWith("/")) {
prefix = prefix.substring(0, prefix.length() - 1);
detectHandlerMethods(this.controller);
while (this.prefix.endsWith("/")) {
this.prefix = this.prefix.substring(0, this.prefix.length() - 1);
}
}
@@ -78,23 +77,23 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
@Override
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange request) {
String path = request.getRequest().getPath().pathWithinApplication().value();
if (StringUtils.hasText(prefix) && !path.startsWith(prefix)) {
if (StringUtils.hasText(this.prefix) && !path.startsWith(this.prefix)) {
return Mono.empty();
}
Mono<HandlerMethod> handler = super.getHandlerInternal(request);
if (path == null) {
return handler;
}
if (path.startsWith(prefix)) {
path = path.substring(prefix.length());
if (path.startsWith(this.prefix)) {
path = path.substring(this.prefix.length());
}
Object function = findFunctionForGet(request, path);
if (function == null) {
function = findFunctionForPost(request, path);
}
if (function != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found function for POST: " + path);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Found function for POST: " + path);
}
request.getAttributes().put(WebRequestConstants.HANDLER, function);
}
@@ -107,12 +106,12 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
return null;
}
path = path.startsWith("/") ? path.substring(1) : path;
Consumer<Publisher<?>> consumer = functions.lookup(Consumer.class, path);
Consumer<Publisher<?>> consumer = this.functions.lookup(Consumer.class, path);
if (consumer != null) {
request.getAttributes().put(WebRequestConstants.CONSUMER, consumer);
return consumer;
}
Function<Object, Object> function = functions.lookup(Function.class, path);
Function<Object, Object> function = this.functions.lookup(Function.class, path);
if (function != null) {
request.getAttributes().put(WebRequestConstants.FUNCTION, function);
return function;
@@ -127,7 +126,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
path = path.startsWith("/") ? path.substring(1) : path;
Object functionForGet = null;
Supplier<Publisher<?>> supplier = functions.lookup(Supplier.class, path);
Supplier<Publisher<?>> supplier = this.functions.lookup(Supplier.class, path);
if (supplier != null) {
request.getAttributes().put(WebRequestConstants.SUPPLIER, supplier);
functionForGet = supplier;
@@ -135,7 +134,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
else {
StringBuilder builder = new StringBuilder();
String name = path;
String[] splitPath = path.split("/");
String[] splitPath = path.split("/");
Function<Object, Object> function = null;
for (int i = 0; i < splitPath.length || function != null; i++) {
String element = splitPath[i];
@@ -145,12 +144,11 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
builder.append(element);
name = builder.toString();
function = functions.lookup(Function.class, name);
function = this.functions.lookup(Function.class, name);
if (function != null) {
request.getAttributes().put(WebRequestConstants.FUNCTION, function);
String value = path.length() > name.length()
? path.substring(name.length() + 1)
: null;
? path.substring(name.length() + 1) : null;
request.getAttributes().put(WebRequestConstants.ARGUMENT, value);
functionForGet = function;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -16,6 +16,8 @@
package org.springframework.cloud.function.web.flux;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -34,8 +36,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import reactor.core.publisher.Flux;
/**
* @author Dave Syer
* @author Mark Fisher
@@ -43,8 +43,8 @@ import reactor.core.publisher.Flux;
*/
@Configuration
@ConditionalOnClass({ Flux.class, AsyncHandlerMethodReturnValueHandler.class })
@ConditionalOnWebApplication(type=Type.REACTIVE)
@Import({FunctionController.class, RequestProcessor.class})
@ConditionalOnWebApplication(type = Type.REACTIVE)
@Import({ FunctionController.class, RequestProcessor.class })
@AutoConfigureAfter({ JacksonAutoConfiguration.class, GsonAutoConfiguration.class })
public class ReactorAutoConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -23,6 +23,10 @@ import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
@@ -63,13 +67,7 @@ import static org.springframework.web.reactive.function.server.RequestPredicates
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.status;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;
/**
*
* @author Dave Syer
* @since 2.0
*
@@ -148,7 +146,7 @@ class FunctionEndpointInitializer
private GenericApplicationContext context;
public ServerListener(GenericApplicationContext context) {
ServerListener(GenericApplicationContext context) {
this.context = context;
}
@@ -212,7 +210,7 @@ class FunctionEndpointFactory {
private RequestProcessor processor;
public FunctionEndpointFactory(FunctionCatalog catalog, FunctionInspector inspector,
FunctionEndpointFactory(FunctionCatalog catalog, FunctionInspector inspector,
RequestProcessor processor, Environment environment) {
String handler = environment.resolvePlaceholders("${function.handler}");
if (handler.startsWith("$")) {
@@ -242,13 +240,13 @@ class FunctionEndpointFactory {
public <T> RouterFunction<?> functionEndpoints() {
return route(POST("/"), request -> {
Class<T> outputType = (Class<T>) this.inspector.getOutputType(this.function);
FunctionWrapper wrapper = RequestProcessor.wrapper(function, null, null);
FunctionWrapper wrapper = RequestProcessor.wrapper(this.function, null, null);
Mono<ResponseEntity<?>> stream = request.bodyToMono(String.class)
.flatMap(content -> processor.post(wrapper, content, false));
.flatMap(content -> this.processor.post(wrapper, content, false));
return stream.flatMap(entity -> status(entity.getStatusCode())
.headers(headers -> headers.addAll(entity.getHeaders()))
.body(Mono.just((T) entity.getBody()), outputType));
});
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -23,6 +23,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.cloud.function.web.RequestProcessor;
import org.springframework.cloud.function.web.RequestProcessor.FunctionWrapper;
@@ -36,8 +37,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
* @author Mark Fisher
@@ -56,7 +55,7 @@ public class FunctionController {
@ResponseBody
public Mono<ResponseEntity<?>> form(WebRequest request) {
FunctionWrapper wrapper = wrapper(request);
return processor.post(wrapper, null, false);
return this.processor.post(wrapper, null, false);
}
@PostMapping(path = "/**")
@@ -64,7 +63,7 @@ public class FunctionController {
public Mono<ResponseEntity<?>> post(WebRequest request,
@RequestBody(required = false) String body) {
FunctionWrapper wrapper = wrapper(request);
return processor.post(wrapper, body, false);
return this.processor.post(wrapper, body, false);
}
@PostMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@@ -72,22 +71,23 @@ public class FunctionController {
public Mono<ResponseEntity<Publisher<?>>> postStream(WebRequest request,
@RequestBody(required = false) String body) {
FunctionWrapper wrapper = wrapper(request);
return processor.post(wrapper, body, true).map(response -> ResponseEntity.ok()
.headers(response.getHeaders()).body((Publisher<?>) response.getBody()));
return this.processor.post(wrapper, body, true)
.map(response -> ResponseEntity.ok().headers(response.getHeaders())
.body((Publisher<?>) response.getBody()));
}
@GetMapping(path = "/**")
@ResponseBody
public Mono<ResponseEntity<?>> get(WebRequest request) {
FunctionWrapper wrapper = wrapper(request);
return processor.get(wrapper);
return this.processor.get(wrapper);
}
@GetMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@ResponseBody
public Mono<ResponseEntity<Publisher<?>>> getStream(WebRequest request) {
FunctionWrapper wrapper = wrapper(request);
return processor.stream(wrapper).map(response -> ResponseEntity.ok()
return this.processor.stream(wrapper).map(response -> ResponseEntity.ok()
.headers(response.getHeaders()).body((Publisher<?>) response.getBody()));
}
@@ -116,4 +116,5 @@ public class FunctionController {
}
return wrapper;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2019 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.
@@ -56,7 +56,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
public FunctionHandlerMapping(FunctionCatalog catalog,
FunctionController controller) {
this.functions = catalog;
logger.info("FunctionCatalog: " + catalog);
this.logger.info("FunctionCatalog: " + catalog);
setOrder(super.getOrder() - 5);
this.controller = controller;
}
@@ -64,9 +64,9 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
detectHandlerMethods(controller);
while (prefix.endsWith("/")) {
prefix = prefix.substring(0, prefix.length() - 1);
detectHandlerMethods(this.controller);
while (this.prefix.endsWith("/")) {
this.prefix = this.prefix.substring(0, this.prefix.length() - 1);
}
}
@@ -86,24 +86,24 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
if (path == null) {
return handler;
}
if (StringUtils.hasText(prefix) && !path.startsWith(prefix)) {
if (StringUtils.hasText(this.prefix) && !path.startsWith(this.prefix)) {
return null;
}
if (path.startsWith(prefix)) {
path = path.substring(prefix.length());
if (path.startsWith(this.prefix)) {
path = path.substring(this.prefix.length());
}
Object function = findFunctionForGet(request, path);
if (function != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found function for GET: " + path);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Found function for GET: " + path);
}
request.setAttribute(WebRequestConstants.HANDLER, function);
return handler;
}
function = findFunctionForPost(request, path);
if (function != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found function for POST: " + path);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Found function for POST: " + path);
}
request.setAttribute(WebRequestConstants.HANDLER, function);
return handler;
@@ -116,12 +116,12 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
return null;
}
path = path.startsWith("/") ? path.substring(1) : path;
Consumer<Publisher<?>> consumer = functions.lookup(Consumer.class, path);
Consumer<Publisher<?>> consumer = this.functions.lookup(Consumer.class, path);
if (consumer != null) {
request.setAttribute(WebRequestConstants.CONSUMER, consumer);
return consumer;
}
Function<Object, Object> function = functions.lookup(Function.class, path);
Function<Object, Object> function = this.functions.lookup(Function.class, path);
if (function != null) {
request.setAttribute(WebRequestConstants.FUNCTION, function);
return function;
@@ -134,7 +134,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
return null;
}
path = path.startsWith("/") ? path.substring(1) : path;
Supplier<Publisher<?>> supplier = functions.lookup(Supplier.class, path);
Supplier<Publisher<?>> supplier = this.functions.lookup(Supplier.class, path);
if (supplier != null) {
request.setAttribute(WebRequestConstants.SUPPLIER, supplier);
return supplier;
@@ -150,7 +150,8 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
name = builder.toString();
value = path.length() > name.length() ? path.substring(name.length() + 1)
: null;
Function<Object, Object> function = functions.lookup(Function.class, name);
Function<Object, Object> function = this.functions.lookup(Function.class,
name);
if (function != null) {
request.setAttribute(WebRequestConstants.FUNCTION, function);
request.setAttribute(WebRequestConstants.ARGUMENT, value);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -16,6 +16,8 @@
package org.springframework.cloud.function.web.mvc;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -34,15 +36,13 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import reactor.core.publisher.Flux;
/**
* @author Dave Syer
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
@Configuration
@ConditionalOnWebApplication(type=Type.SERVLET)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Flux.class, AsyncHandlerMethodReturnValueHandler.class })
@Import({ FunctionController.class, RequestProcessor.class })
@AutoConfigureAfter({ JacksonAutoConfiguration.class, GsonAutoConfiguration.class })
@@ -60,4 +60,5 @@ public class ReactorAutoConfiguration {
ConfigurableListableBeanFactory beanFactory) {
return new BasicStringConverter(inspector, beanFactory);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -25,4 +25,5 @@ import java.util.function.Supplier;
public interface DestinationResolver {
String destination(Supplier<?> supplier, String name, Object value);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -25,9 +25,9 @@ import org.springframework.http.HttpHeaders;
*
*/
public interface RequestBuilder {
URI uri(String destination);
HttpHeaders headers(String destination, Object value);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -31,7 +31,9 @@ import org.springframework.http.HttpHeaders;
class SimpleRequestBuilder implements RequestBuilder {
private String baseUrl = "http://${destination}";
private Map<String, String> headers = new LinkedHashMap<>();
private Environment environment;
SimpleRequestBuilder(Environment environment) {
@@ -42,10 +44,10 @@ class SimpleRequestBuilder implements RequestBuilder {
public HttpHeaders headers(String destination, Object value) {
// TODO: add message headers if any
HttpHeaders result = new HttpHeaders();
for (String key : headers.keySet()) {
String header = headers.get(key);
for (String key : this.headers.keySet()) {
String header = this.headers.get(key);
header = header.replace("${destination}", destination);
header = environment.resolvePlaceholders(header);
header = this.environment.resolvePlaceholders(header);
result.add(key, header);
}
return result;
@@ -54,8 +56,8 @@ class SimpleRequestBuilder implements RequestBuilder {
@Override
public URI uri(String destination) {
try {
return new URI(environment
.resolvePlaceholders(baseUrl.replace("${destination}", destination)));
return new URI(this.environment.resolvePlaceholders(
this.baseUrl.replace("${destination}", destination)));
}
catch (URISyntaxException e) {
throw new IllegalStateException("Cannot create URI", e);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -68,16 +68,20 @@ class SupplierAutoConfiguration {
static class SourceActiveCondition extends AnyNestedCondition {
public SourceActiveCondition() {
SourceActiveCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@ConditionalOnNotWebApplication
static class OnNotWebapp {
}
@ConditionalOnProperty(prefix = "spring.cloud.function.web.supplier", name = "enabled")
static class Enabled {
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -21,6 +21,11 @@ import java.util.Collections;
import java.util.Set;
import java.util.function.Supplier;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.context.SmartLifecycle;
import org.springframework.http.HttpHeaders;
@@ -28,11 +33,6 @@ import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
/**
* Forwards items obtained from a {@link Supplier} or set of suppliers to an external HTTP
* endpoint.
@@ -62,7 +62,7 @@ class SupplierExporter implements SmartLifecycle {
private volatile Disposable subscription;
public SupplierExporter(RequestBuilder requestBuilder,
SupplierExporter(RequestBuilder requestBuilder,
DestinationResolver destinationResolver, FunctionCatalog catalog,
WebClient client, SupplierProperties props) {
this.requestBuilder = requestBuilder;
@@ -84,10 +84,10 @@ class SupplierExporter implements SmartLifecycle {
this.ok = true;
Flux<Object> streams = Flux.empty();
Set<String> names = this.supplier == null ? catalog.getNames(Supplier.class)
Set<String> names = this.supplier == null ? this.catalog.getNames(Supplier.class)
: Collections.singleton(this.supplier);
for (String name : names) {
Supplier<Flux<Object>> supplier = catalog.lookup(Supplier.class, name);
Supplier<Flux<Object>> supplier = this.catalog.lookup(Supplier.class, name);
streams = streams.mergeWith(forward(supplier, name));
}
@@ -105,13 +105,14 @@ class SupplierExporter implements SmartLifecycle {
private Flux<ClientResponse> forward(Supplier<Flux<Object>> supplier, String name) {
return supplier.get().publishOn(Schedulers.parallel()).flatMap(value -> {
String destination = destinationResolver.destination(supplier, name, value);
String destination = this.destinationResolver.destination(supplier, name,
value);
return post(uri(destination), destination, value);
});
}
private Mono<ClientResponse> post(URI uri, String destination, Object value) {
Mono<ClientResponse> result = client.post().uri(uri)
Mono<ClientResponse> result = this.client.post().uri(uri)
.headers(headers -> headers(headers, destination, value))
.body(BodyInserters.fromObject(value)).exchange();
if (this.debug) {
@@ -121,11 +122,11 @@ class SupplierExporter implements SmartLifecycle {
}
private void headers(HttpHeaders headers, String destination, Object value) {
headers.putAll(requestBuilder.headers(destination, value));
headers.putAll(this.requestBuilder.headers(destination, value));
}
private URI uri(String destination) {
return requestBuilder.uri(destination);
return this.requestBuilder.uri(destination);
}
public boolean isOk() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -29,10 +29,17 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
public class SupplierProperties {
private boolean autoStartup = true;
private boolean debug = true;
private String name;
private String templateUrl;
private boolean enabled;
private Map<String, String> headers = new LinkedHashMap<>();
public boolean isEnabled() {
return this.enabled;
}
@@ -41,8 +48,6 @@ public class SupplierProperties {
this.enabled = enabled;
}
private Map<String, String> headers = new LinkedHashMap<>();
public boolean isAutoStartup() {
return this.autoStartup;
}
@@ -59,23 +64,24 @@ public class SupplierProperties {
this.debug = debug;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
public String getTemplateUrl() {
return this.templateUrl;
}
public void setTemplateUrl(String templateUrl) {
this.templateUrl = templateUrl;
}
public String getTemplateUrl() {
return this.templateUrl;
}
public Map<String, String> getHeaders() {
return this.headers;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.web.util;
import java.util.Arrays;
@@ -28,12 +29,16 @@ import org.springframework.messaging.MessageHeaders;
* @author Dave Syer
* @author Oleg Zhurakousky
*/
public class HeaderUtils {
public final class HeaderUtils {
private static HttpHeaders IGNORED = new HttpHeaders();
private static HttpHeaders REQUEST_ONLY = new HttpHeaders();
private HeaderUtils() {
throw new IllegalStateException("Can't instantiate a utility class");
}
static {
IGNORED.add(MessageHeaders.ID, "");
IGNORED.add(HttpHeaders.CONTENT_LENGTH, "0");
@@ -86,4 +91,5 @@ public class HeaderUtils {
private static Collection<?> multi(Object value) {
return value instanceof Collection ? (Collection<?>) value : Arrays.asList(value);
}
}

View File

@@ -1,9 +1,11 @@
{"properties": [
{
"name": "spring.cloud.function.web.path",
"type": "java.lang.String",
"description": "Path to web resources for functions (should start with / if not empty).",
"defaultValue": ""
}]
{
"properties": [
{
"name": "spring.cloud.function.web.path",
"type": "java.lang.String",
"description": "Path to web resources for functions (should start with / if not empty).",
"defaultValue": ""
}
]
}

View File

@@ -2,10 +2,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.function.web.flux.ReactorAutoConfiguration,\
org.springframework.cloud.function.web.mvc.ReactorAutoConfiguration,\
org.springframework.cloud.function.web.source.SupplierAutoConfiguration
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc=\
org.springframework.cloud.function.web.flux.ReactorAutoConfiguration,\
org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration
org.springframework.context.ApplicationContextInitializer=\
org.springframework.cloud.function.web.function.FunctionEndpointInitializer
org.springframework.cloud.function.web.function.FunctionEndpointInitializer