2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2022 Bell Canada
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ============LICENSE_END=========================================================
19 package org.onap.aai.tasks;
21 import com.google.common.collect.Iterators;
23 import java.util.Iterator;
24 import java.util.Timer;
25 import java.util.TimerTask;
27 import jakarta.annotation.PostConstruct;
28 import jakarta.annotation.PreDestroy;
30 import org.apache.commons.lang3.BooleanUtils;
31 import org.apache.commons.lang3.Validate;
32 import org.janusgraph.core.JanusGraphException;
33 import org.janusgraph.core.JanusGraphTransaction;
34 import org.janusgraph.core.JanusGraphVertex;
35 import org.onap.aai.dbmap.AAIGraph;
36 import org.onap.aai.exceptions.AAIException;
37 import org.onap.aai.logging.ErrorLogHelper;
38 import org.onap.aai.util.AAIConfig;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
42 import org.springframework.context.annotation.Scope;
43 import org.springframework.stereotype.Component;
46 * Singleton class responsible to check that AAI service is able to connect to its back-end database.
47 * The check can run as a scheduled task or on demand.
50 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
51 public class AaiGraphChecker extends TimerTask {
53 private static final Logger LOGGER = LoggerFactory.getLogger(AaiGraphChecker.class);
55 // Default indicator to enable or disable scheduled task
56 private static final String DEFAULT_SCHEDULE_ENABLED_VALUE = "false";
57 // Default delay, in seconds, before the scheduled task is started, if enabled
58 private static final String DEFAULT_SCHEDULE_DELAY_VALUE = "5";
59 // Default period, in seconds, between two consecutive executions of the scheduled task, if enabled
60 private static final String DEFAULT_SCHEDULE_PERIOD_VALUE = "60";
62 // Database availability cached indicator
63 private volatile Boolean isAaiGraphDbAvailableCache = null;
65 private Timer timer = null;
68 * Enumeration of check type that can be made.
70 public enum CheckerType {
74 private AaiGraphChecker() {
78 private void setupTimer() {
80 boolean scheduleEnabled = Boolean.parseBoolean(
81 getConfigurationValueOrDefault("aai.graph.checker.task.enabled", DEFAULT_SCHEDULE_ENABLED_VALUE));
82 long scheduleDelay = Long.parseLong(
83 getConfigurationValueOrDefault("aai.graph.checker.task.delay", DEFAULT_SCHEDULE_DELAY_VALUE));
84 long schedulePeriod = Long.parseLong(
85 getConfigurationValueOrDefault("aai.graph.checker.task.period", DEFAULT_SCHEDULE_PERIOD_VALUE));
86 LOGGER.debug("Setting up AaiGraphChecker with scheduleEnabled={}, scheduleDelay={}, schedulePeriod={} ",
87 scheduleEnabled, scheduleDelay, schedulePeriod);
89 if (scheduleEnabled) {
91 timer.schedule(this, scheduleDelay * 1000, schedulePeriod * 1000);
96 private void tearDownTimer() {
97 LOGGER.debug("Tear down AaiGraphChecker");
106 isAaiGraphDbAvailable(CheckerType.ACTUAL);
110 * Clear database availability cached indicator.
112 public void clearDbAvailabilityCachedIndicator() {
113 isAaiGraphDbAvailableCache = null;
117 * Indicate if AAI Graph database is available either from actual db connection or from cached property state.
119 * @param checkerType the type of check to be made (actual or cached). Null is not supported.
121 * <li>true, if database is available</li>
122 * <li>false, if database is NOT available</li>
123 * <li>null, if database availability can not be determined</li>
125 public Boolean isAaiGraphDbAvailable(CheckerType checkerType) {
126 Validate.notNull(checkerType);
127 if (CheckerType.ACTUAL.equals(checkerType)) {
128 isAaiGraphDbAvailableCache = isAaiGraphDbAvailableActual();
130 logDbState(checkerType);
131 return isAaiGraphDbAvailableCache;
134 private Boolean isAaiGraphDbAvailableActual() {
136 JanusGraphTransaction transaction = null;
138 transaction = AAIGraph.getInstance().getGraph().newTransaction();
139 final Iterator<JanusGraphVertex> vertexIterator = transaction.query().limit(1).vertices().iterator();
140 if (LOGGER.isDebugEnabled()) {
141 LOGGER.debug("Number of vertices retrieved while checking db: {}", Iterators.size(vertexIterator));
143 vertexIterator.hasNext();
144 LOGGER.debug("Actual database availability is true");
145 dbAvailable = Boolean.TRUE;
146 } catch (JanusGraphException e) {
147 String message = "Actual database availability is false (after JanusGraph exception)";
148 ErrorLogHelper.logError("500", message + ": " + e.getMessage());
149 LOGGER.error(message, e);
150 dbAvailable = Boolean.FALSE;
152 // Following error occurs when aai resources is starting:
153 // - UnsatisfiedLinkError (for org.onap.aai.dbmap.AAIGraph$Helper instantiation)
154 // Following errors are raised when aai resources is starting and cassandra is not running:
155 // - ExceptionInInitializerError
156 // - NoClassDefFoundError (definition for org.onap.aai.dbmap.AAIGraph$Helper is not found)
157 String message = "Actual database availability is false (after error)";
158 ErrorLogHelper.logError("500", message + ": " + e.getMessage());
159 LOGGER.error(message, e);
160 dbAvailable = Boolean.FALSE;
161 } catch (Exception e) {
162 String message = "Actual database availability can not be determined";
163 ErrorLogHelper.logError("500", message + ": " + e.getMessage());
164 LOGGER.error(message, e);
167 if (transaction != null && !transaction.isClosed()) {
168 // check if transaction is open then close instead of flag
170 transaction.rollback();
171 } catch (Exception e) {
172 String message = "Exception occurred while closing transaction";
173 LOGGER.error(message, e);
174 ErrorLogHelper.logError("500", message + ": " + e.getMessage());
181 private void logDbState(CheckerType type) {
182 if (BooleanUtils.isTrue(isAaiGraphDbAvailableCache)) {
183 LOGGER.debug("Database is available from {} check.", type);
184 } else if (BooleanUtils.isFalse(isAaiGraphDbAvailableCache)) {
185 LOGGER.error("Database is NOT available from {} check.", type);
187 LOGGER.error("Database availability is UNKNOWN from {} check.", type);
191 private String getConfigurationValueOrDefault(String property, String defaultValue) {
194 result = AAIConfig.get(property);
195 } catch (AAIException e) {
196 LOGGER.error("Unable to get defined configuration value for '{}' property, then default '{}' value is used",
197 property, defaultValue);
198 result = defaultValue;