org.springframework.cloud.function.web.source.HttpSupplier.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.cloud.function.web.source.HttpSupplier.java

Source

/*
 * Copyright 2018-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
 *
 *      https://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.cloud.function.web.source;

import java.time.Duration;
import java.util.function.Supplier;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.cloud.function.web.util.HeaderUtils;
import org.springframework.http.HttpStatus;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;

/**
 * A {@link Supplier} that pulls data from an HTTP endpoint. Repeatedly polls the endpoint
 * until a non-2xx response is received, at which point it will repeatedly produced a
 * Mono at 1 sec intervals until the next 2xx response.
 *
 * @author Dave Syer
 * @author Oleg Zhurakousky
 */
public class HttpSupplier implements Supplier<Flux<?>> {

    private static Log logger = LogFactory.getLog(HttpSupplier.class);

    private WebClient client;

    private ExporterProperties props;

    /**
     * @param client the WebClient to use. The baseUrl should be set.
     * @param props the ExporterProperties to use to parameterize the requests.
     */
    public HttpSupplier(WebClient client, ExporterProperties props) {
        this.client = client;
        this.props = props;
    }

    @Override
    public Flux<?> get() {
        return get(this.client);
    }

    private Flux<?> get(WebClient client) {
        Flux<?> result = client.get().uri(this.props.getSource().getUrl()).exchange().flatMap(this::transform)
                .repeat();
        if (this.props.isDebug()) {
            result = result.log();
        }
        return result.onErrorResume(TerminateException.class, error -> Mono.empty());
    }

    private Mono<?> transform(ClientResponse response) {
        HttpStatus status = response.statusCode();
        if (!status.is2xxSuccessful()) {
            if (this.props.isDebug()) {
                logger.info("Delaying supplier based on status=" + response.statusCode());
            }
            return Mono.delay(Duration.ofSeconds(1));
        }
        return response.bodyToMono(this.props.getSource().getType()).map(value -> message(response, value));
    }

    private Object message(ClientResponse response, Object payload) {
        if (!this.props.getSource().isIncludeHeaders()) {
            return payload;
        }
        return MessageBuilder.withPayload(payload)
                .copyHeaders(HeaderUtils.fromHttp(HeaderUtils.sanitize(response.headers().asHttpHeaders())))
                .build();
    }

    @SuppressWarnings("serial")
    private static class TerminateException extends RuntimeException {

        @SuppressWarnings("unused")
        TerminateException() {
            super("Planned termination");
        }

        @Override
        public synchronized Throwable fillInStackTrace() {
            return this;
        }

    }
}