org.springframework.integration.handler.AbstractMessageHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.integration.handler.AbstractMessageHandler.java

Source

/*
 * Copyright 2002-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.integration.handler;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.reactivestreams.Subscription;

import org.springframework.core.Ordered;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.context.Orderable;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.support.management.AbstractMessageHandlerMetrics;
import org.springframework.integration.support.management.ConfigurableMetricsAware;
import org.springframework.integration.support.management.DefaultMessageHandlerMetrics;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.integration.support.management.TrackableComponent;
import org.springframework.integration.support.management.metrics.MeterFacade;
import org.springframework.integration.support.management.metrics.MetricsCaptor;
import org.springframework.integration.support.management.metrics.SampleFacade;
import org.springframework.integration.support.management.metrics.TimerFacade;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.util.Assert;

import reactor.core.CoreSubscriber;

/**
 * Base class for MessageHandler implementations that provides basic validation
 * and error handling capabilities. Asserts that the incoming Message is not
 * null and that it does not contain a null payload. Converts checked exceptions
 * into runtime {@link org.springframework.messaging.MessagingException}s.
 *
 * @author Mark Fisher
 * @author Oleg Zhurakousky
 * @author Gary Russell
 * @author Artem Bilan
 * @author Amit Sadafule
 */
@SuppressWarnings("deprecation")
@IntegrationManagedResource
public abstract class AbstractMessageHandler extends IntegrationObjectSupport
        implements MessageHandler, org.springframework.integration.support.management.MessageHandlerMetrics,
        ConfigurableMetricsAware<AbstractMessageHandlerMetrics>, TrackableComponent, Orderable,
        CoreSubscriber<Message<?>> {

    private final ManagementOverrides managementOverrides = new ManagementOverrides();

    private final Set<TimerFacade> timers = ConcurrentHashMap.newKeySet();

    private volatile boolean shouldTrack = false;

    private volatile int order = Ordered.LOWEST_PRECEDENCE;

    private volatile AbstractMessageHandlerMetrics handlerMetrics = new DefaultMessageHandlerMetrics();

    private volatile boolean statsEnabled;

    private volatile boolean countsEnabled;

    private volatile String managedName;

    private volatile String managedType;

    private volatile boolean loggingEnabled = true;

    private MetricsCaptor metricsCaptor;

    private TimerFacade successTimer;

    @Override
    public boolean isLoggingEnabled() {
        return this.loggingEnabled;
    }

    @Override
    public void setLoggingEnabled(boolean loggingEnabled) {
        this.loggingEnabled = loggingEnabled;
        this.managementOverrides.loggingConfigured = true;
    }

    @Override
    public void registerMetricsCaptor(MetricsCaptor metricsCaptorToRegister) {
        this.metricsCaptor = metricsCaptorToRegister;
    }

    @Nullable
    protected MetricsCaptor getMetricsCaptor() {
        return this.metricsCaptor;
    }

    @Override
    public void setOrder(int order) {
        this.order = order;
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    @Override
    public String getComponentType() {
        return "message-handler";
    }

    @Override
    public void setShouldTrack(boolean shouldTrack) {
        this.shouldTrack = shouldTrack;
    }

    @Override
    public void configureMetrics(AbstractMessageHandlerMetrics metrics) {
        Assert.notNull(metrics, "'metrics' must not be null");
        this.handlerMetrics = metrics;
        this.managementOverrides.metricsConfigured = true;
    }

    @Override
    public ManagementOverrides getOverrides() {
        return this.managementOverrides;
    }

    @Override
    protected void onInit() {
        if (this.statsEnabled) {
            this.handlerMetrics.setFullStatsEnabled(true);
        }
    }

    @Override
    public void handleMessage(Message<?> messageArg) {
        Message<?> message = messageArg;
        Assert.notNull(message, "Message must not be null");
        Assert.notNull(message.getPayload(), "Message payload must not be null"); //NOSONAR - false positive
        if (this.loggingEnabled && this.logger.isDebugEnabled()) {
            this.logger.debug(this + " received message: " + message);
        }
        org.springframework.integration.support.management.MetricsContext start = null;
        boolean countsAreEnabled = this.countsEnabled;
        AbstractMessageHandlerMetrics metrics = this.handlerMetrics;
        SampleFacade sample = null;
        if (countsAreEnabled && this.metricsCaptor != null) {
            sample = this.metricsCaptor.start();
        }
        try {
            if (this.shouldTrack) {
                message = MessageHistory.write(message, this, getMessageBuilderFactory());
            }
            if (countsAreEnabled) {
                start = metrics.beforeHandle();
                handleMessageInternal(message);
                if (sample != null) {
                    sample.stop(sendTimer());
                }
                metrics.afterHandle(start, true);
            } else {
                handleMessageInternal(message);
            }
        } catch (Exception e) {
            if (sample != null) {
                sample.stop(buildSendTimer(false, e.getClass().getSimpleName()));
            }
            if (countsAreEnabled) {
                metrics.afterHandle(start, false);
            }
            throw IntegrationUtils.wrapInHandlingExceptionIfNecessary(message,
                    () -> "error occurred in message handler [" + this + "]", e);
        }
    }

    private TimerFacade sendTimer() {
        if (this.successTimer == null) {
            this.successTimer = buildSendTimer(true, "none");
        }
        return this.successTimer;
    }

    private TimerFacade buildSendTimer(boolean success, String exception) {
        TimerFacade timer = this.metricsCaptor.timerBuilder(SEND_TIMER_NAME).tag("type", "handler")
                .tag("name", getComponentName() == null ? "unknown" : getComponentName())
                .tag("result", success ? "success" : "failure").tag("exception", exception)
                .description("Send processing time").build();
        this.timers.add(timer);
        return timer;
    }

    @Override
    public void onSubscribe(Subscription subscription) {
        Assert.notNull(subscription, "'subscription' must not be null");
        subscription.request(Long.MAX_VALUE);
    }

    @Override
    public void onNext(Message<?> message) {
        handleMessage(message);
    }

    @Override
    public void onError(Throwable throwable) {

    }

    @Override
    public void onComplete() {

    }

    protected abstract void handleMessageInternal(Message<?> message);

    @Override
    public void reset() {
        this.handlerMetrics.reset();
    }

    @Override
    public long getHandleCountLong() {
        return this.handlerMetrics.getHandleCountLong();
    }

    @Override
    public int getHandleCount() {
        return this.handlerMetrics.getHandleCount();
    }

    @Override
    public int getErrorCount() {
        return this.handlerMetrics.getErrorCount();
    }

    @Override
    public long getErrorCountLong() {
        return this.handlerMetrics.getErrorCountLong();
    }

    @Override
    public double getMeanDuration() {
        return this.handlerMetrics.getMeanDuration();
    }

    @Override
    public double getMinDuration() {
        return this.handlerMetrics.getMinDuration();
    }

    @Override
    public double getMaxDuration() {
        return this.handlerMetrics.getMaxDuration();
    }

    @Override
    public double getStandardDeviationDuration() {
        return this.handlerMetrics.getStandardDeviationDuration();
    }

    @Override
    public int getActiveCount() {
        return this.handlerMetrics.getActiveCount();
    }

    @Override
    public long getActiveCountLong() {
        return this.handlerMetrics.getActiveCountLong();
    }

    @Override
    public org.springframework.integration.support.management.Statistics getDuration() {
        return this.handlerMetrics.getDuration();
    }

    @Override
    public void setStatsEnabled(boolean statsEnabled) {
        if (statsEnabled) {
            this.countsEnabled = true;
            this.managementOverrides.countsConfigured = true;
        }
        this.statsEnabled = statsEnabled;
        if (this.handlerMetrics != null) {
            this.handlerMetrics.setFullStatsEnabled(statsEnabled);
        }
        this.managementOverrides.statsConfigured = true;
    }

    @Override
    public boolean isStatsEnabled() {
        return this.statsEnabled;
    }

    @Override
    public void setCountsEnabled(boolean countsEnabled) {
        this.countsEnabled = countsEnabled;
        this.managementOverrides.countsConfigured = true;
        if (!countsEnabled) {
            this.statsEnabled = false;
            this.managementOverrides.statsConfigured = true;
        }
    }

    @Override
    public boolean isCountsEnabled() {
        return this.countsEnabled;
    }

    @Override
    public void setManagedName(String managedName) {
        this.managedName = managedName;
    }

    @Override
    public String getManagedName() {
        return this.managedName;
    }

    @Override
    public void setManagedType(String managedType) {
        this.managedType = managedType;
    }

    @Override
    public String getManagedType() {
        return this.managedType;
    }

    @Override
    public void destroy() {
        this.timers.forEach(MeterFacade::remove);
    }

}