DB utils update for db initialization
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / utils / DB.java
1 /*******************************************************************************\r
2  * ============LICENSE_START==================================================\r
3  * * org.onap.dmaap\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 \r
24 \r
25 package org.onap.dmaap.datarouter.provisioning.utils;\r
26 \r
27 import org.apache.log4j.Logger;\r
28 \r
29 import java.io.*;\r
30 import java.sql.*;\r
31 import java.util.*;\r
32 \r
33 /**\r
34  * Load the DB JDBC driver, and manage a simple pool of connections to the DB.\r
35  *\r
36  * @author Robert Eby\r
37  * @version $Id$\r
38  */\r
39 public class DB {\r
40         /** The name of the properties file (in CLASSPATH) */\r
41         private static final String CONFIG_FILE = "provserver.properties";\r
42 \r
43         private static String DB_URL;\r
44         private static String DB_LOGIN;\r
45         private static String DB_PASSWORD;\r
46         private static Properties props;\r
47         private static Logger intlogger = Logger.getLogger("org.onap.dmaap.datarouter.provisioning.internal");\r
48         private static final Queue<Connection> queue = new LinkedList<>();\r
49 \r
50         public static String HTTPS_PORT;\r
51         public static String HTTP_PORT;\r
52 \r
53         /**\r
54          * Construct a DB object.  If this is the very first creation of this object, it will load a copy\r
55          * of the properties for the server, and attempt to load the JDBC driver for the database.  If a fatal\r
56          * error occurs (e.g. either the properties file or the DB driver is missing), the JVM will exit.\r
57          */\r
58         public DB() {\r
59                 if (props == null) {\r
60                         props = new Properties();\r
61                         try (InputStream inStream = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)) {\r
62                                 props.load(inStream);\r
63                                 String DB_DRIVER = (String) props.get("org.onap.dmaap.datarouter.db.driver");\r
64                                 DB_URL = (String) props.get("org.onap.dmaap.datarouter.db.url");\r
65                                 DB_LOGIN = (String) props.get("org.onap.dmaap.datarouter.db.login");\r
66                                 DB_PASSWORD = (String) props.get("org.onap.dmaap.datarouter.db.password");\r
67                                 HTTPS_PORT = (String) props.get("org.onap.dmaap.datarouter.provserver.https.port");\r
68                                 HTTP_PORT = (String) props.get("org.onap.dmaap.datarouter.provserver.http.port");\r
69                                 Class.forName(DB_DRIVER);\r
70                         } catch (IOException e) {\r
71                                 intlogger.fatal("PROV9003 Opening properties: " + e.getMessage());\r
72                                 e.printStackTrace();\r
73                                 System.exit(1);\r
74                         } catch (ClassNotFoundException e) {\r
75                                 intlogger.fatal("PROV9004 cannot find the DB driver: " + e);\r
76                                 e.printStackTrace();\r
77                                 System.exit(1);\r
78                         }\r
79                 }\r
80         }\r
81         /**\r
82          * Get the provisioning server properties (loaded from provserver.properties).\r
83          * @return the Properties object\r
84          */\r
85         public Properties getProperties() {\r
86                 return props;\r
87         }\r
88         /**\r
89          * Get a JDBC connection to the DB from the pool.  Creates a new one if none are available.\r
90          * @return the Connection\r
91          * @throws SQLException\r
92          */\r
93         @SuppressWarnings("resource")\r
94         public Connection getConnection() throws SQLException {\r
95                 Connection connection = null;\r
96                 while (connection == null) {\r
97                         synchronized (queue) {\r
98                                 try {\r
99                                         connection = queue.remove();\r
100                                 } catch (NoSuchElementException nseEx) {\r
101                                         int n = 0;\r
102                                         do {\r
103                                                 // Try up to 3 times to get a connection\r
104                                                 try {\r
105                                                         connection = DriverManager.getConnection(DB_URL, DB_LOGIN, DB_PASSWORD);\r
106                                                 } catch (SQLException sqlEx) {\r
107                                                         if (++n >= 3)\r
108                                                                 throw sqlEx;\r
109                                                 }\r
110                                         } while (connection == null);\r
111                                 }\r
112                         }\r
113                         if (connection != null && !connection.isValid(1)) {\r
114                                 connection.close();\r
115                                 connection = null;\r
116                         }\r
117                 }\r
118                 return connection;\r
119         }\r
120         /**\r
121          * Returns a JDBC connection to the pool.\r
122          * @param connection the Connection to return\r
123          */\r
124         public void release(Connection connection) {\r
125                 if (connection != null) {\r
126                         synchronized (queue) {\r
127                                 if (!queue.contains(connection))\r
128                                         queue.add(connection);\r
129                         }\r
130                 }\r
131         }\r
132 \r
133         /**\r
134          * Run all necessary retrofits required to bring the database up to the level required for this version\r
135          * of the provisioning server.  This should be run before the server itself is started.\r
136          * @return true if all retrofits worked, false otherwise\r
137          */\r
138         public boolean runRetroFits() {\r
139                 return retroFit1();\r
140         }\r
141 \r
142         /**\r
143          * Retrofit 1 - Make sure the expected tables are in DB and are initialized.\r
144          * Uses sql_init_01.sql to setup the DB.\r
145          * @return true if the retrofit worked, false otherwise\r
146          */\r
147         private boolean retroFit1() {\r
148                 final String[] expectedTables = {\r
149                                 "FEEDS", "FEED_ENDPOINT_ADDRS", "FEED_ENDPOINT_IDS", "PARAMETERS",\r
150                                 "SUBSCRIPTIONS", "LOG_RECORDS", "INGRESS_ROUTES", "EGRESS_ROUTES",\r
151                                 "NETWORK_ROUTES", "NODESETS", "NODES", "GROUPS"\r
152                 };\r
153                 Connection connection = null;\r
154                 try {\r
155                         connection = getConnection();\r
156                         Set<String> actualTables = getTableSet(connection);\r
157                         boolean initialize = false;\r
158                         for (String table : expectedTables) {\r
159                                 initialize |= !actualTables.contains(table);\r
160                         }\r
161                         if (initialize) {\r
162                                 intlogger.info("PROV9001: First time startup; The database is being initialized.");\r
163                                 runInitScript(connection, 1);\r
164                         }\r
165                 } catch (SQLException e) {\r
166                         intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());\r
167                         return false;\r
168                 } finally {\r
169                         if (connection != null)\r
170                                 release(connection);\r
171                 }\r
172                 return true;\r
173         }\r
174 \r
175         /**\r
176          * Get a set of all table names in the DB.\r
177          * @param connection a DB connection\r
178          * @return the set of table names\r
179          */\r
180         private Set<String> getTableSet(Connection connection) {\r
181                 Set<String> tables = new HashSet<String>();\r
182                 try {\r
183                         DatabaseMetaData md = connection.getMetaData();\r
184                         ResultSet rs = md.getTables("datarouter", "", "", null);\r
185                         if (rs != null) {\r
186                                 while (rs.next()) {\r
187                                         tables.add(rs.getString("TABLE_NAME"));\r
188                                 }\r
189                                 rs.close();\r
190                         }\r
191                 } catch (SQLException e) {\r
192                 }\r
193                 return tables;\r
194         }\r
195         /**\r
196          * Initialize the tables by running the initialization scripts located in the directory specified\r
197          * by the property <i>org.onap.dmaap.datarouter.provserver.dbscripts</i>.  Scripts have names of\r
198          * the form sql_init_NN.sql\r
199          * @param connection a DB connection\r
200          * @param scriptId the number of the sql_init_NN.sql script to run\r
201          */\r
202         private void runInitScript(Connection connection, int scriptId) {\r
203                 String scriptDir = (String) props.get("org.onap.dmaap.datarouter.provserver.dbscripts");\r
204                 StringBuilder sb = new StringBuilder();\r
205                 try {\r
206                         String scriptFile = String.format("%s/sql_init_%02d.sql", scriptDir, scriptId);\r
207                         if (!(new File(scriptFile)).exists())\r
208                                 return;\r
209 \r
210                         LineNumberReader in = new LineNumberReader(new FileReader(scriptFile));\r
211                         String line;\r
212                         while ((line = in.readLine()) != null) {\r
213                                 if (!line.startsWith("--")) {\r
214                                         line = line.trim();\r
215                                         sb.append(line);\r
216                                         if (line.endsWith(";")) {\r
217                                                 // Execute one DDL statement\r
218                                                 String sql = sb.toString();\r
219                                                 sb.setLength(0);\r
220                                                 Statement s = connection.createStatement();\r
221                                                 s.execute(sql);\r
222                                                 s.close();\r
223                                         }\r
224                                 }\r
225                         }\r
226                         in.close();\r
227                         sb.setLength(0);\r
228                 } catch (Exception e) {\r
229                         intlogger.fatal("PROV9002 Error when initializing table: "+e.getMessage());\r
230                         System.exit(1);\r
231                 }\r
232         }\r
233 }\r