Spring-boot 3 upgrade in resources
[aai/resources.git] / aai-resources / src / main / java / org / onap / aai / tasks / AaiGraphChecker.java
1 /*
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
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0
10  *
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=========================================================
17  */
18
19 package org.onap.aai.tasks;
20
21 import com.google.common.collect.Iterators;
22
23 import java.util.Iterator;
24 import java.util.Timer;
25 import java.util.TimerTask;
26
27 import jakarta.annotation.PostConstruct;
28 import jakarta.annotation.PreDestroy;
29
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;
44
45 /**
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.
48  */
49 @Component
50 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
51 public class AaiGraphChecker extends TimerTask {
52
53     private static final Logger LOGGER = LoggerFactory.getLogger(AaiGraphChecker.class);
54
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";
61
62     // Database availability cached indicator
63     private volatile Boolean isAaiGraphDbAvailableCache = null;
64
65     private Timer timer = null;
66
67     /**
68      * Enumeration of check type that can be made.
69      */
70     public enum CheckerType {
71         ACTUAL, CACHED
72     }
73
74     private AaiGraphChecker() {
75     }
76
77     @PostConstruct
78     private void setupTimer() {
79
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);
88
89         if (scheduleEnabled) {
90             timer = new Timer();
91             timer.schedule(this, scheduleDelay * 1000, schedulePeriod * 1000);
92         }
93     }
94
95     @PreDestroy
96     private void tearDownTimer() {
97         LOGGER.debug("Tear down AaiGraphChecker");
98         if (timer != null) {
99             timer.cancel();
100             timer = null;
101         }
102     }
103
104     @Override
105     public void run() {
106         isAaiGraphDbAvailable(CheckerType.ACTUAL);
107     }
108
109     /**
110      * Clear database availability cached indicator.
111      */
112     public void clearDbAvailabilityCachedIndicator() {
113         isAaiGraphDbAvailableCache = null;
114     }
115
116     /**
117      * Indicate if AAI Graph database is available either from actual db connection or from cached property state.
118      * 
119      * @param checkerType the type of check to be made (actual or cached). Null is not supported.
120      * @return
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>
124      */
125     public Boolean isAaiGraphDbAvailable(CheckerType checkerType) {
126         Validate.notNull(checkerType);
127         if (CheckerType.ACTUAL.equals(checkerType)) {
128             isAaiGraphDbAvailableCache = isAaiGraphDbAvailableActual();
129         }
130         logDbState(checkerType);
131         return isAaiGraphDbAvailableCache;
132     }
133
134     private Boolean isAaiGraphDbAvailableActual() {
135         Boolean dbAvailable;
136         JanusGraphTransaction transaction = null;
137         try {
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));
142             }
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;
151         } catch (Error e) {
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);
165             dbAvailable = null;
166         } finally {
167             if (transaction != null && !transaction.isClosed()) {
168                 // check if transaction is open then close instead of flag
169                 try {
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());
175                 }
176             }
177         }
178         return dbAvailable;
179     }
180
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);
186         } else {
187             LOGGER.error("Database availability is UNKNOWN from {} check.", type);
188         }
189     }
190
191     private String getConfigurationValueOrDefault(String property, String defaultValue) {
192         String result;
193         try {
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;
199         }
200         return result;
201     }
202
203 }