Fix checkstyle for features submodules.
[policy/drools-pdp.git] / feature-state-management / src / main / java / org / onap / policy / drools / statemanagement / DbAudit.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * feature-state-management
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.drools.statemanagement;
22
23 import java.sql.Connection;
24 import java.sql.DriverManager;
25 import java.sql.PreparedStatement;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
28 import java.util.Properties;
29 import java.util.UUID;
30
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /** This class audits the database.
35  */
36 public class DbAudit extends DroolsPDPIntegrityMonitor.AuditBase {
37     // get an instance of logger
38     private static Logger logger = LoggerFactory.getLogger(DbAudit.class);
39     // single global instance of this audit object
40     private static final DbAudit instance = new DbAudit();
41
42     // This indicates if 'CREATE TABLE IF NOT EXISTS Audit ...' should be
43     // invoked -- doing this avoids the need to create the table in advance.
44     private static boolean createTableNeeded = true;
45
46     private static boolean isJunit = false;
47
48     /** Constructor - set the name to 'Database'. */
49     private DbAudit() {
50         super("Database");
51     }
52
53     private static synchronized void setCreateTableNeeded(boolean isNeeded) {
54         DbAudit.createTableNeeded = isNeeded;
55     }
56
57     public static synchronized void setIsJunit(boolean isJUnit) {
58         DbAudit.isJunit = isJUnit;
59     }
60
61     public static boolean isJunit() {
62         return DbAudit.isJunit;
63     }
64
65     /**
66      * Get the instance.
67      *  
68      * @return the single 'DbAudit' instance. */
69     public static DroolsPDPIntegrityMonitor.AuditBase getInstance() {
70         return instance;
71     }
72
73     /**
74      * Invoke the audit.
75      *
76      * @param properties properties to be passed to the audit
77      */
78     @Override
79     public void invoke(Properties properties) {
80         logger.debug("Running 'DbAudit.invoke'");
81         boolean doCreate = createTableNeeded && !isJunit;
82
83         if (!isActive()) {
84             logger.info("DbAudit.invoke: exiting because isActive = false");
85             return;
86         }
87
88         // fetch DB properties from properties file -- they are already known
89         // to exist, because they were verified by the 'IntegrityMonitor'
90         // constructor
91         String url = properties.getProperty(StateManagementProperties.DB_URL);
92         String user = properties.getProperty(StateManagementProperties.DB_USER);
93         String password = properties.getProperty(StateManagementProperties.DB_PWD);
94
95         // operation phase currently running -- used to construct an error
96         // message, if needed
97         String phase = null;
98
99         // create connection to DB
100         phase = "creating connection";
101         logger.debug("DbAudit: Creating connection to {}", url);
102         try (Connection connection = DriverManager.getConnection(url, user, password)) {
103
104             // create audit table, if needed
105             if (doCreate) {
106                 phase = "create table";
107                 createTable(connection);
108             }
109
110             // insert an entry into the table
111             phase = "insert entry";
112             String key = UUID.randomUUID().toString();
113             insertEntry(connection, key);
114
115             phase = "fetch entry";
116             findEntry(connection, key);
117
118             phase = "delete entry";
119             deleteEntry(connection, key);
120         } catch (Exception e) {
121             String message = "DbAudit: Exception during audit, phase = " + phase;
122             logger.error(message, e);
123             setResponse(message);
124         }
125     }
126
127     /**
128      * Determines if the DbAudit is active, based on properties. Defaults to {@code true}, if not
129      * found in the properties.
130      *
131      * @return {@code true} if DbAudit is active, {@code false} otherwise
132      */
133     private boolean isActive() {
134         String dbAuditIsActive = StateManagementProperties.getProperty("db.audit.is.active");
135         logger.debug("DbAudit.invoke: dbAuditIsActive = {}", dbAuditIsActive);
136
137         if (dbAuditIsActive != null) {
138             try {
139                 return Boolean.parseBoolean(dbAuditIsActive.trim());
140             } catch (NumberFormatException e) {
141                 logger.warn(
142                         "DbAudit.invoke: Ignoring invalid property: db.audit.is.active = {}", dbAuditIsActive);
143             }
144         }
145
146         return true;
147     }
148
149     /**
150      * Creates the table.
151      *
152      * @param connection connection
153      * @throws SQLException exception
154      */
155     private void createTable(Connection connection) throws SQLException {
156         logger.info("DbAudit: Creating 'Audit' table, if needed");
157         try (PreparedStatement statement =
158                 connection.prepareStatement(
159                         "CREATE TABLE IF NOT EXISTS Audit (\n"
160                                 + " name varchar(64) DEFAULT NULL,\n"
161                                 + " UNIQUE KEY name (name)\n"
162                                 + ") DEFAULT CHARSET=latin1;")) {
163             statement.execute();
164             DbAudit.setCreateTableNeeded(false);
165         }
166     }
167
168     /**
169      * Inserts an entry.
170      *
171      * @param connection connection
172      * @param key key
173      * @throws SQLException exception
174      */
175     private void insertEntry(Connection connection, String key) throws SQLException {
176         try (PreparedStatement statement =
177                 connection.prepareStatement("INSERT INTO Audit (name) VALUES (?)")) {
178             statement.setString(1, key);
179             statement.executeUpdate();
180         }
181     }
182
183     /**
184      * Finds an entry.
185      *
186      * @param connection connection
187      * @param key key
188      * @throws SQLException exception
189      */
190     private void findEntry(Connection connection, String key) throws SQLException {
191         try (PreparedStatement statement =
192                 connection.prepareStatement("SELECT name FROM Audit WHERE name = ?")) {
193             statement.setString(1, key);
194             getEntry(statement, key);
195         }
196     }
197
198     /**
199      * Executes the query to determine if the entry exists. Sets the response if it fails.
200      *
201      * @param statement statement
202      * @param key key
203      * @throws SQLException exception
204      */
205     private void getEntry(PreparedStatement statement, String key) throws SQLException {
206         try (ResultSet rs = statement.executeQuery()) {
207             if (rs.first()) {
208                 // found entry
209                 if (logger.isDebugEnabled()) {
210                     logger.debug("DbAudit: Found key {}", rs.getString(1));
211                 }
212             } else {
213                 logger.error("DbAudit: can't find newly-created entry with key {}", key);
214                 setResponse("Can't find newly-created entry");
215             }
216         }
217     }
218
219     /**
220      * Deletes an entry.
221      *
222      * @param connection connection
223      * @param key key
224      * @throws SQLException exception
225      */
226     private void deleteEntry(Connection connection, String key) throws SQLException {
227         try (PreparedStatement statement =
228                 connection.prepareStatement("DELETE FROM Audit WHERE name = ?")) {
229             statement.setString(1, key);
230             statement.executeUpdate();
231         }
232     }
233 }