Merge "Additional updates for Subscriber docker image"
[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 \r
41     private static Logger intlogger = Logger.getLogger("org.onap.dmaap.datarouter.provisioning.internal");\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 final Queue<Connection> queue = new LinkedList<>();\r
48 \r
49     public static String HTTPS_PORT;\r
50     public static String HTTP_PORT;\r
51 \r
52     /**\r
53      * Construct a DB object.  If this is the very first creation of this object, it will load a copy of the properties\r
54      * for the server, and attempt to load the JDBC driver for the database.  If a fatal error occurs (e.g. either the\r
55      * properties file or the DB driver is missing), the JVM will exit.\r
56      */\r
57     public DB() {\r
58         if (props == null) {\r
59             props = new Properties();\r
60             try {\r
61                 props.load(new FileInputStream(System.getProperty(\r
62                     "org.onap.dmaap.datarouter.provserver.properties",\r
63                     "/opt/app/datartr/etc/provserver.properties")));\r
64                 String DB_DRIVER = (String) props.get("org.onap.dmaap.datarouter.db.driver");\r
65                 DB_URL = (String) props.get("org.onap.dmaap.datarouter.db.url");\r
66                 DB_LOGIN = (String) props.get("org.onap.dmaap.datarouter.db.login");\r
67                 DB_PASSWORD = (String) props.get("org.onap.dmaap.datarouter.db.password");\r
68                 HTTPS_PORT = (String) props.get("org.onap.dmaap.datarouter.provserver.https.port");\r
69                 HTTP_PORT = (String) props.get("org.onap.dmaap.datarouter.provserver.http.port");\r
70                 Class.forName(DB_DRIVER);\r
71             } catch (IOException e) {\r
72                 intlogger.fatal("PROV9003 Opening properties: " + e.getMessage());\r
73                 e.printStackTrace();\r
74                 System.exit(1);\r
75             } catch (ClassNotFoundException e) {\r
76                 intlogger.fatal("PROV9004 cannot find the DB driver: " + e);\r
77                 e.printStackTrace();\r
78                 System.exit(1);\r
79             }\r
80         }\r
81     }\r
82 \r
83     /**\r
84      * Get the provisioning server properties (loaded from provserver.properties).\r
85      *\r
86      * @return the Properties object\r
87      */\r
88     public Properties getProperties() {\r
89         return props;\r
90     }\r
91 \r
92     /**\r
93      * Get a JDBC connection to the DB from the pool.  Creates a new one if none are available.\r
94      *\r
95      * @return the Connection\r
96      */\r
97     @SuppressWarnings("resource")\r
98     public Connection getConnection() throws SQLException {\r
99         Connection connection = null;\r
100         while (connection == null) {\r
101             synchronized (queue) {\r
102                 try {\r
103                     connection = queue.remove();\r
104                 } catch (NoSuchElementException nseEx) {\r
105                     int n = 0;\r
106                     do {\r
107                         // Try up to 3 times to get a connection\r
108                         try {\r
109                             connection = DriverManager.getConnection(DB_URL, DB_LOGIN, DB_PASSWORD);\r
110                         } catch (SQLException sqlEx) {\r
111                             if (++n >= 3) {\r
112                                 throw sqlEx;\r
113                             }\r
114                         }\r
115                         finally {\r
116                             if (connection != null && !connection.isValid(1)) {\r
117                                 connection.close();\r
118                                 connection = null;\r
119                             }\r
120                         }\r
121                     } while (connection == null);\r
122                 }\r
123             }\r
124 \r
125         }\r
126         return connection;\r
127     }\r
128 \r
129     /**\r
130      * Returns a JDBC connection to the pool.\r
131      *\r
132      * @param connection the Connection to return\r
133      */\r
134     public void release(Connection connection) {\r
135         if (connection != null) {\r
136             synchronized (queue) {\r
137                 if (!queue.contains(connection)) {\r
138                     queue.add(connection);\r
139                 }\r
140             }\r
141         }\r
142     }\r
143 \r
144     /**\r
145      * Run all necessary retrofits required to bring the database up to the level required for this version of the\r
146      * provisioning server.  This should be run before the server itself is started.\r
147      *\r
148      * @return true if all retrofits worked, false otherwise\r
149      */\r
150     public boolean runRetroFits() {\r
151         return retroFit1();\r
152     }\r
153 \r
154     /**\r
155      * Retrofit 1 - Make sure the expected tables are in DB and are initialized. Uses sql_init_01.sql to setup the DB.\r
156      *\r
157      * @return true if the retrofit worked, false otherwise\r
158      */\r
159     private boolean retroFit1() {\r
160         final String[] expectedTables = {\r
161             "FEEDS", "FEED_ENDPOINT_ADDRS", "FEED_ENDPOINT_IDS", "PARAMETERS",\r
162             "SUBSCRIPTIONS", "LOG_RECORDS", "INGRESS_ROUTES", "EGRESS_ROUTES",\r
163             "NETWORK_ROUTES", "NODESETS", "NODES", "GROUPS"\r
164         };\r
165         Connection connection = null;\r
166         try {\r
167             connection = getConnection();\r
168             Set<String> actualTables = getTableSet(connection);\r
169             boolean initialize = false;\r
170             for (String table : expectedTables) {\r
171                 initialize |= !actualTables.contains(table.toLowerCase());\r
172             }\r
173             if (initialize) {\r
174                 intlogger.info("PROV9001: First time startup; The database is being initialized.");\r
175                 runInitScript(connection, 1);\r
176             }\r
177         } catch (SQLException e) {\r
178             intlogger.fatal("PROV9000: The database credentials are not working: " + e.getMessage());\r
179             return false;\r
180         } finally {\r
181             if (connection != null) {\r
182                 release(connection);\r
183             }\r
184         }\r
185         return true;\r
186     }\r
187 \r
188     /**\r
189      * Get a set of all table names in the DB.\r
190      *\r
191      * @param connection a DB connection\r
192      * @return the set of table names\r
193      */\r
194     private Set<String> getTableSet(Connection connection) {\r
195         Set<String> tables = new HashSet<String>();\r
196         try {\r
197             DatabaseMetaData md = connection.getMetaData();\r
198             ResultSet rs = md.getTables(null, null, "%", null);\r
199             if (rs != null) {\r
200                 while (rs.next()) {\r
201                     tables.add(rs.getString("TABLE_NAME"));\r
202                 }\r
203                 rs.close();\r
204             }\r
205         } catch (SQLException e) {\r
206             intlogger.fatal("PROV9010: Failed to get TABLE data from DB: " + e.getMessage());\r
207         }\r
208         return tables;\r
209     }\r
210 \r
211     /**\r
212      * Initialize the tables by running the initialization scripts located in the directory specified by the property\r
213      * <i>org.onap.dmaap.datarouter.provserver.dbscripts</i>.  Scripts have names of the form sql_init_NN.sql\r
214      *\r
215      * @param connection a DB connection\r
216      * @param scriptId the number of the sql_init_NN.sql script to run\r
217      */\r
218     private void runInitScript(Connection connection, int scriptId) {\r
219         String scriptDir = (String) props.get("org.onap.dmaap.datarouter.provserver.dbscripts");\r
220         StringBuilder strBuilder = new StringBuilder();\r
221         try {\r
222             String scriptFile = String.format("%s/sql_init_%02d.sql", scriptDir, scriptId);\r
223             if (!(new File(scriptFile)).exists()) {\r
224                 intlogger.fatal("PROV9005 Failed to load sql script from : " + scriptFile);\r
225                 System.exit(1);\r
226             }\r
227             LineNumberReader lineReader = new LineNumberReader(new FileReader(scriptFile));\r
228             String line;\r
229             while ((line = lineReader.readLine()) != null) {\r
230                 if (!line.startsWith("--")) {\r
231                     line = line.trim();\r
232                     strBuilder.append(line);\r
233                     if (line.endsWith(";")) {\r
234                         // Execute one DDL statement\r
235                         String sql = strBuilder.toString();\r
236                         strBuilder.setLength(0);\r
237                         Statement statement = connection.createStatement();\r
238                         statement.execute(sql);\r
239                         statement.close();\r
240                     }\r
241                 }\r
242             }\r
243             lineReader.close();\r
244             strBuilder.setLength(0);\r
245         } catch (Exception e) {\r
246             intlogger.fatal("PROV9002 Error when initializing table: " + e.getMessage());\r
247             System.exit(1);\r
248         }\r
249     }\r
250 }\r