001/*
002 * Copyright 2012-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.actuate.jms;
018
019import java.util.concurrent.CountDownLatch;
020import java.util.concurrent.TimeUnit;
021
022import javax.jms.Connection;
023import javax.jms.ConnectionFactory;
024import javax.jms.JMSException;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028
029import org.springframework.boot.actuate.health.AbstractHealthIndicator;
030import org.springframework.boot.actuate.health.Health;
031import org.springframework.boot.actuate.health.HealthIndicator;
032
033/**
034 * {@link HealthIndicator} for a JMS {@link ConnectionFactory}.
035 *
036 * @author Stephane Nicoll
037 * @since 2.0.0
038 */
039public class JmsHealthIndicator extends AbstractHealthIndicator {
040
041        private final Log logger = LogFactory.getLog(JmsHealthIndicator.class);
042
043        private final ConnectionFactory connectionFactory;
044
045        public JmsHealthIndicator(ConnectionFactory connectionFactory) {
046                super("JMS health check failed");
047                this.connectionFactory = connectionFactory;
048        }
049
050        @Override
051        protected void doHealthCheck(Health.Builder builder) throws Exception {
052                try (Connection connection = this.connectionFactory.createConnection()) {
053                        new MonitoredConnection(connection).start();
054                        builder.up().withDetail("provider",
055                                        connection.getMetaData().getJMSProviderName());
056                }
057        }
058
059        private final class MonitoredConnection {
060
061                private final CountDownLatch latch = new CountDownLatch(1);
062
063                private final Connection connection;
064
065                MonitoredConnection(Connection connection) {
066                        this.connection = connection;
067                }
068
069                public void start() throws JMSException {
070                        new Thread(() -> {
071                                try {
072                                        if (!this.latch.await(5, TimeUnit.SECONDS)) {
073                                                JmsHealthIndicator.this.logger.warn(
074                                                                "Connection failed to start within 5 seconds and will be closed.");
075                                                closeConnection();
076                                        }
077                                }
078                                catch (InterruptedException ex) {
079                                        Thread.currentThread().interrupt();
080                                }
081                        }, "jms-health-indicator").start();
082                        this.connection.start();
083                        this.latch.countDown();
084                }
085
086                private void closeConnection() {
087                        try {
088                                this.connection.close();
089                        }
090                        catch (Exception ex) {
091                                // Continue
092                        }
093                }
094
095        }
096
097}