Fix sonar issues in feature-state-management
[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 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 /**
35  * This class audits the database
36  */
37 public class DbAudit extends DroolsPDPIntegrityMonitor.AuditBase
38 {
39         // get an instance of logger 
40   private static Logger  logger = LoggerFactory.getLogger(DbAudit.class);       
41   // single global instance of this audit object
42   private static final DbAudit instance = new DbAudit();
43
44   // This indicates if 'CREATE TABLE IF NOT EXISTS Audit ...' should be
45   // invoked -- doing this avoids the need to create the table in advance.
46   private static boolean createTableNeeded = true;
47   
48   private static boolean isJunit = false;
49
50   /**
51    * Constructor - set the name to 'Database'
52    */
53   private DbAudit()
54   {
55         super("Database");
56   }
57   
58   private static synchronized void setCreateTableNeeded(boolean b) {
59                 DbAudit.createTableNeeded = b;
60   }
61   
62   public static synchronized void setIsJunit(boolean b) {
63                 DbAudit.isJunit = b;
64   }
65   
66   public static boolean isJunit(){
67           return DbAudit.isJunit;
68   }
69   
70   
71   /**
72    * @return the single 'DbAudit' instance
73    */
74   public static DroolsPDPIntegrityMonitor.AuditBase getInstance()
75   {
76         return instance;
77   }
78
79   /**
80    * Invoke the audit
81    *
82    * @param properties properties to be passed to the audit
83    */
84   @Override
85         public void invoke(Properties properties)
86   {
87         logger.debug("Running 'DbAudit.invoke'");
88         boolean doCreate = createTableNeeded && !isJunit;
89         
90         if(!isActive()){                
91                 logger.info("DbAudit.invoke: exiting because isActive = false");
92                 return;
93         }
94         
95         // fetch DB properties from properties file -- they are already known
96         // to exist, because they were verified by the 'IntegrityMonitor'
97         // constructor
98         String url = properties.getProperty(StateManagementProperties.DB_URL);
99         String user = properties.getProperty(StateManagementProperties.DB_USER);
100         String password = properties.getProperty(StateManagementProperties.DB_PWD);
101
102         // operation phase currently running -- used to construct an error
103         // message, if needed
104         String phase = null;
105
106         // create connection to DB
107         phase = "creating connection";
108         logger.debug("DbAudit: Creating connection to {}", url);
109         try (Connection connection = DriverManager.getConnection(url, user, password))
110           {
111
112                 // create audit table, if needed
113                 if (doCreate)
114                   {
115                         phase = "create table";
116                         createTable(connection);
117                   }
118
119                 // insert an entry into the table
120                 phase = "insert entry";
121                 String key = UUID.randomUUID().toString();
122                 insertEntry(connection, key);
123                 
124                 phase = "fetch entry";
125                 findEntry(connection, key);
126                 
127                 phase = "delete entry";
128                 deleteEntry(connection, key);
129         }
130         catch (Exception e)
131           {
132                 String message = "DbAudit: Exception during audit, phase = " + phase;
133                 logger.error(message, e);
134                 setResponse(message);
135           }
136   }
137
138   /**
139    * Determines if the DbAudit is active, based on properties.  Defaults to
140    * {@code true}, if not found in the properties.
141    * @return {@code true} if DbAudit is active, {@code false} otherwise
142    */
143   private boolean isActive() {
144         String dbAuditIsActive = StateManagementProperties.getProperty("db.audit.is.active");
145         logger.debug("DbAudit.invoke: dbAuditIsActive = {}", dbAuditIsActive);
146         
147         if (dbAuditIsActive != null) {
148                 try {
149                         return Boolean.parseBoolean(dbAuditIsActive.trim());
150                 } catch (NumberFormatException e) {
151                         logger.warn("DbAudit.invoke: Ignoring invalid property: db.audit.is.active = {}", dbAuditIsActive);
152                 }
153         }
154         
155         return true;
156   }
157
158   /**
159    * Creates the table.
160    * @param connection
161    * @throws SQLException
162    */
163   private void createTable(Connection connection) throws SQLException {
164                 logger.info("DbAudit: Creating 'Audit' table, if needed");
165         try (PreparedStatement statement = connection.prepareStatement
166           ("CREATE TABLE IF NOT EXISTS Audit (\n"
167            + " name varchar(64) DEFAULT NULL,\n"
168            + " UNIQUE KEY name (name)\n"
169            + ") DEFAULT CHARSET=latin1;")) {
170                 statement.execute();
171                 DbAudit.setCreateTableNeeded(false);
172         }
173   }
174
175   /**
176    * Inserts an entry.
177    * @param connection
178    * @param key
179    * @throws SQLException
180    */
181   private void insertEntry(Connection connection, String key) throws SQLException {
182         try (PreparedStatement statement = connection.prepareStatement
183           ("INSERT INTO Audit (name) VALUES (?)")) {
184                 statement.setString(1, key);
185                 statement.executeUpdate();
186         }
187   }
188
189   /**
190    * Finds an entry.
191    * @param connection
192    * @param key
193    * @throws SQLException
194    */
195   private void findEntry(Connection connection, String key) throws SQLException {
196         try (PreparedStatement statement = connection.prepareStatement
197           ("SELECT name FROM Audit WHERE name = ?")) {
198                 statement.setString(1, key);
199                 getEntry(statement, key);
200         }
201   }
202
203   /**
204    * Executes the query to determine if the entry exists.  Sets the response
205    * if it fails.
206    * @param statement
207    * @param key
208    * @throws SQLException
209    */
210   private void getEntry(PreparedStatement statement, String key) throws SQLException {
211         try (ResultSet rs = statement.executeQuery()) {
212                 if (rs.first())
213                   {
214                         // found entry
215                         if(logger.isDebugEnabled()){
216                                 logger.debug("DbAudit: Found key {}", rs.getString(1));
217                         }
218                   }
219                 else
220                   {
221                         logger.error
222                           ("DbAudit: can't find newly-created entry with key {}", key);
223                         setResponse("Can't find newly-created entry");
224                   }
225         }
226   }
227
228   /**
229    * Deletes an entry.
230    * @param connection
231    * @param key
232    * @throws SQLException
233    */
234   private void deleteEntry(Connection connection, String key) throws SQLException {
235         try (PreparedStatement statement = connection.prepareStatement
236           ("DELETE FROM Audit WHERE name = ?")) {
237                 statement.setString(1, key);
238                 statement.executeUpdate();
239         }
240   }
241
242 }