1 | /** |
2 | * Copyright 2007 ATG DUST Project |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * |
7 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software |
10 | * distributed under the License is distributed on an "AS IS" BASIS, |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | * See the License for the specific language governing permissions and limitations under the License. |
13 | */ |
14 | |
15 | package atg.test.util; |
16 | |
17 | import java.io.File; |
18 | import java.io.IOException; |
19 | import java.sql.Connection; |
20 | import java.sql.DriverManager; |
21 | import java.sql.ResultSet; |
22 | import java.sql.ResultSetMetaData; |
23 | import java.sql.SQLException; |
24 | import java.sql.Statement; |
25 | import java.util.Collection; |
26 | import java.util.Iterator; |
27 | import java.util.Properties; |
28 | |
29 | import org.apache.log4j.Logger; |
30 | |
31 | import atg.adapter.gsa.GSATestUtils; |
32 | import atg.adapter.gsa.SQLFileParser; |
33 | import atg.core.util.StringUtils; |
34 | |
35 | /** |
36 | * Utility code for getting a connection to a database. |
37 | * The most common method is getHSQLDBInMemoryDBConnection. |
38 | * This returns a connection to an in-memory HSQL database. |
39 | * @author adamb |
40 | * |
41 | */ |
42 | public class DBUtils { |
43 | |
44 | public Connection conn; //our connnection to the db - presist for life of |
45 | private Properties mJDBCProperties; |
46 | |
47 | private static Logger log = Logger.getLogger(DBUtils.class); |
48 | // --------------------------- |
49 | /** |
50 | * Returns a Properties object preconfigured to create |
51 | * an HSQLDB in memory database connecting with user "sa" |
52 | * password "" |
53 | * @param pTestDBName |
54 | */ |
55 | public static Properties getHSQLDBInMemoryDBConnection(String pTestDBName) { |
56 | Properties props = new Properties(); |
57 | props.put("driver", "org.hsqldb.jdbcDriver"); |
58 | if(pTestDBName != null) |
59 | props.put("URL", "jdbc:hsqldb:mem:" + pTestDBName); |
60 | else |
61 | props.put("URL", "jdbc:hsqldb:."); |
62 | props.put("user", "sa"); |
63 | props.put("password", ""); |
64 | return props; |
65 | } |
66 | |
67 | |
68 | /** |
69 | * Returns a Properties object preconfigured to create |
70 | * an HSQLDB in memory database connecting with user "sa" |
71 | * password "" |
72 | * @param pTestDBName |
73 | */ |
74 | public static Properties getHSQLDBRegularDBConnection(String pTestDBName, String pHostName, Object pUser, Object pPassword) { |
75 | Properties props = new Properties(); |
76 | props.put("driver", "org.hsqldb.jdbcDriver"); |
77 | props.put("URL", "jdbc:hsqldb:hsql://" + pHostName+ "/"+pTestDBName); |
78 | props.put("user", pUser); |
79 | props.put("password", pPassword); |
80 | return props; |
81 | } |
82 | |
83 | /** |
84 | * Returns a Properties object preconfigured to create |
85 | * an HSQLDB in memory database connecting with user "sa" |
86 | * password "" |
87 | * @param pTestDBName |
88 | */ |
89 | public static Properties getHSQLDBFileDBConnection(String pPath) { |
90 | Properties props = new Properties(); |
91 | props.put("driver", "org.hsqldb.jdbcDriver"); |
92 | props.put("URL", "jdbc:hsqldb:file:" + pPath); |
93 | props.put("user", "sa"); |
94 | props.put("password", ""); |
95 | return props; |
96 | } |
97 | |
98 | // --------------------------- |
99 | /** |
100 | * Returns connection properties for MSSQL |
101 | * @param pHostName host name of db server |
102 | * @param pPort port number of db |
103 | * @param pDBName database name |
104 | * @param pUser database username |
105 | * @param pPassword database user's password |
106 | * @return |
107 | */ |
108 | |
109 | public static Properties getMSSQLDBConnection(String pHostName, String pPort, String pDBName, String pUser, String pPassword) { |
110 | Properties props = new Properties(); |
111 | props.put("driver", "com.inet.tds.TdsDriver"); |
112 | props.put("URL", "jdbc:inetdae:" + pHostName + ":" + pPort + "?database=" + pDBName); |
113 | props.put("user", pUser); |
114 | props.put("password", pPassword); |
115 | return props; |
116 | } |
117 | |
118 | // --------------------------- |
119 | /** |
120 | * Returns connection properties for mysql |
121 | * @param pHostName host name of db server |
122 | * @param pPort port number of db |
123 | * @param pDBName database name |
124 | * @param pUser database username |
125 | * @param pPassword database user's password |
126 | * @return |
127 | */ |
128 | |
129 | public static Properties getMySQLDBConnection(String pHostName, String pPort, String pDBName, String pUser, String pPassword) { |
130 | if(pPort == null)pPort = "3306"; |
131 | Properties props = new Properties(); |
132 | props.put("driver", "com.mysql.jdbc.Driver"); |
133 | props.put("URL", "jdbc:mysql://" + pHostName + ":" + pPort + "/" + pDBName); |
134 | props.put("user", pUser); |
135 | props.put("password", pPassword); |
136 | return props; |
137 | } |
138 | |
139 | /** |
140 | * @param pString |
141 | * @param pString2 |
142 | * @param pString3 |
143 | * @param pString4 |
144 | * @param pString5 |
145 | * @return |
146 | */ |
147 | public static Properties getDB2DBConnection(String pHostName, String pPort, String pDBName, String pUser, String pPassword) { |
148 | Properties props = new Properties(); |
149 | props.put("driver", "com.ibm.db2.jcc.DB2Driver"); |
150 | // props.put("driver", "COM.ibm.db2.jdbc.app.DB2Drive"); |
151 | props.put("URL", "jdbc:db2://" + pHostName + ":" + pPort + "/" + pDBName); |
152 | props.put("user", pUser); |
153 | props.put("password", pPassword); |
154 | return props; |
155 | } |
156 | // --------------------------- |
157 | /** |
158 | * Returns connection properties for MSSQL |
159 | * @param pHostName host name of db server |
160 | * @param pPort port number of db |
161 | * @param pDBName database name |
162 | * @param pUser database username |
163 | * @param pPassword database user's password |
164 | * @return |
165 | */ |
166 | |
167 | public static Properties getOracleDBConnection(String pHostName, String pPort, String pDBName, String pUser, String pPassword) { |
168 | Properties props = new Properties(); |
169 | props = new Properties(); |
170 | String port = pPort; |
171 | if(pPort == null) |
172 | port = "1521"; |
173 | props.put("driver", "oracle.jdbc.OracleDriver"); |
174 | props.put("URL", "jdbc:oracle:thin:@"+pHostName+":"+port+":"+pDBName); |
175 | props.put("user", pUser); |
176 | props.put("password", pPassword); |
177 | return props; |
178 | } |
179 | // --------------------------- |
180 | /** |
181 | * Returns connection properties for MSSQL |
182 | * @param pHostName host name of db server |
183 | * @param pPort port number of db |
184 | * @param pDBName database name |
185 | * @param pUser database username |
186 | * @param pPassword database user's password |
187 | * @return |
188 | */ |
189 | |
190 | public static Properties getSolidDBConnection(String pHostName, String pPort, String pUser, String pPassword) { |
191 | Properties props = new Properties(); |
192 | props = new Properties(); |
193 | String port = pPort; |
194 | if(pPort == null) |
195 | port = "1313"; |
196 | props.put("driver", "solid.jdbc.SolidDriver"); |
197 | props.put("URL", "jdbc:solid://"+pHostName+":"+port); |
198 | props.put("user", pUser); |
199 | props.put("password", pPassword); |
200 | return props; |
201 | } |
202 | |
203 | // --------------------------- |
204 | /** |
205 | * Returns connection properties for MSSQL |
206 | * @param pHostName host name of db server |
207 | * @param pPort port number of db |
208 | * @param pDBName database name |
209 | * @param pUser database username |
210 | * @param pPassword database user's password |
211 | * @return |
212 | */ |
213 | |
214 | public static Properties getSybaseDBConnection(String pHostName, String pPort, String pDBName, String pUser, String pPassword) { |
215 | Properties props = new Properties(); |
216 | props = new Properties(); |
217 | String port = pPort; |
218 | if(pPort == null) |
219 | port = "5000"; |
220 | props.put("driver", "com.sybase.jdbc2.jdbc.SybDriver"); |
221 | props.put("URL", " jdbc:sybase:Tds:"+pHostName+":"+port+"/"+pDBName); |
222 | props.put("user", pUser); |
223 | props.put("password", pPassword); |
224 | return props; |
225 | } |
226 | |
227 | /** |
228 | * Returns a Properties object preconfigured to create |
229 | * an HSQLDB in memory database connecting with user "sa" |
230 | * password "" |
231 | * @param pTestDBName |
232 | */ |
233 | public static Properties getHSQLDBInMemoryDBConnection() { |
234 | return getHSQLDBInMemoryDBConnection("testdb"); |
235 | } |
236 | |
237 | // --------------------------- |
238 | /** |
239 | * Creates a new DBUtils given a Properties object containing connection info |
240 | * Expected keys: |
241 | * URL<BR> |
242 | * driver<BR> |
243 | * user<BR> |
244 | * password<BR> |
245 | * <BR> |
246 | * @param pProps |
247 | * @throws Exception |
248 | */ |
249 | public DBUtils(Properties pProps) throws Exception { |
250 | this(pProps.getProperty("URL"),pProps.getProperty("driver"),pProps.getProperty("user"),pProps.getProperty("password")); |
251 | } |
252 | public String mDatabaseType = null; |
253 | private String mDatabaseVersion; |
254 | // --------------------------- |
255 | public DBUtils(String pURL, String pJDBCDriver, |
256 | String pUser, String pPassword) throws Exception { |
257 | |
258 | mJDBCProperties = new Properties(); |
259 | mJDBCProperties.put("driver", pJDBCDriver); |
260 | mJDBCProperties.put("URL", pURL); |
261 | mJDBCProperties.put("user", pUser); |
262 | mJDBCProperties.put("password",pPassword); |
263 | |
264 | // general |
265 | // exception |
266 | |
267 | // Load the HSQL Database Engine JDBC driver |
268 | // hsqldb.jar should be in the class path or made part of the current jar |
269 | Class.forName(pJDBCDriver); |
270 | |
271 | |
272 | // connect to the database. This will load the db files and start the |
273 | // database if it is not alread running. |
274 | // db_file_name_prefix is used to open or create files that hold the state |
275 | // of the db. |
276 | // It can contain directory names relative to the |
277 | // current working directory |
278 | conn = DriverManager.getConnection(pURL, // filenames |
279 | pUser, // username |
280 | pPassword); // password |
281 | mDatabaseType = conn.getMetaData().getDatabaseProductName(); |
282 | mDatabaseVersion = conn.getMetaData().getDatabaseProductVersion(); |
283 | log.info("Connected to " |
284 | + mDatabaseType + " Version: "+ mDatabaseVersion); |
285 | executeCreateIdGenerator(); |
286 | } |
287 | |
288 | public void shutdown() throws SQLException { |
289 | if(!conn.isClosed()){ |
290 | Statement st = conn.createStatement(); |
291 | |
292 | // db writes out to files and performs clean shuts down |
293 | // otherwise there will be an unclean shutdown |
294 | // when program ends |
295 | if (conn.getMetaData().getDatabaseProductName().startsWith("HSQL")) |
296 | st.execute("SHUTDOWN"); |
297 | conn.close(); // if there are no other open connection |
298 | } |
299 | } |
300 | |
301 | public int getRowCount(String pTable) throws SQLException { |
302 | Statement st = null; |
303 | ResultSet rs = null; |
304 | try { |
305 | st = conn.createStatement(); // statement objects can be reused with |
306 | |
307 | // repeated calls to execute but we |
308 | // choose to make a new one each time |
309 | rs = st.executeQuery("SELECT COUNT(*) FROM " + pTable); // run the query |
310 | |
311 | rs.next(); |
312 | int count = rs.getInt(1); |
313 | return count; |
314 | } |
315 | finally { |
316 | st.close(); // NOTE!! if you close a statement the associated ResultSet is |
317 | } |
318 | |
319 | } |
320 | |
321 | //use for SQL command SELECT |
322 | public synchronized void query(String expression) throws SQLException { |
323 | |
324 | Statement st = null; |
325 | ResultSet rs = null; |
326 | |
327 | st = conn.createStatement(); // statement objects can be reused with |
328 | |
329 | // repeated calls to execute but we |
330 | // choose to make a new one each time |
331 | rs = st.executeQuery(expression); // run the query |
332 | |
333 | // do something with the result set. |
334 | dump(rs); |
335 | st.close(); // NOTE!! if you close a statement the associated ResultSet is |
336 | |
337 | // closed too |
338 | // so you should copy the contents to some other object. |
339 | // the result set is invalidated also if you recycle an Statement |
340 | // and try to execute some other query before the result set has been |
341 | // completely examined. |
342 | } |
343 | |
344 | //use for SQL commands CREATE, DROP, INSERT and UPDATE |
345 | public synchronized void update(String expression) throws SQLException { |
346 | //log.info("DBUtils.update : " + expression); |
347 | Statement st = null; |
348 | |
349 | st = conn.createStatement(); // statements |
350 | |
351 | int i = st.executeUpdate(expression); // run the query |
352 | |
353 | if (i == -1) { |
354 | log.info("db error : " + expression); |
355 | } |
356 | |
357 | st.close(); |
358 | } // void update() |
359 | |
360 | public void dump(ResultSet rs) throws SQLException { |
361 | |
362 | // the order of the rows in a cursor |
363 | // are implementation dependent unless you use the SQL ORDER statement |
364 | ResultSetMetaData meta = rs.getMetaData(); |
365 | int colmax = meta.getColumnCount(); |
366 | int i; |
367 | Object o = null; |
368 | |
369 | // the result set is a cursor into the data. You can only |
370 | // point to one row at a time |
371 | // assume we are pointing to BEFORE the first row |
372 | // rs.next() points to next row and returns true |
373 | // or false if there is no next row, which breaks the loop |
374 | for (; rs.next();) { |
375 | for (i = 0; i < colmax; ++i) { |
376 | o = rs.getObject(i + 1); // Is SQL the first column is indexed |
377 | |
378 | // with 1 not 0 |
379 | System.out.print(o.toString() + " "); |
380 | } |
381 | |
382 | log.info(" "); |
383 | } |
384 | } //void dump( ResultSet rs ) |
385 | |
386 | /** |
387 | * @param db |
388 | * @throws SQLException |
389 | */ |
390 | public void executeCreateIdGenerator() throws SQLException { |
391 | try { |
392 | if(!isDB2()) |
393 | update(" create table das_id_generator (id_space_name varchar(60) not null," |
394 | + "seed numeric(19,0) not null, batch_size integer not null, prefix varchar(10) null," |
395 | + " suffix varchar(10) null, primary key (id_space_name)) "); |
396 | else |
397 | update(" create table das_id_generator (id_space_name varchar(60) not null," |
398 | + "seed numeric(19,0) not null, batch_size numeric(19) not null, prefix varchar(10) default null," |
399 | + " suffix varchar(10) default null, primary key (id_space_name)) "); |
400 | } catch (SQLException e) { |
401 | // drop and try again |
402 | log.info("DROPPING DAS_ID_GENERATOR"); |
403 | try { |
404 | update("drop table das_id_generator"); |
405 | } catch (SQLException ex) { |
406 | |
407 | } |
408 | if(!isDB2()) |
409 | update(" create table das_id_generator (id_space_name varchar(60) not null," |
410 | + "seed numeric(19,0) not null, batch_size integer not null, prefix varchar(10) null," |
411 | + " suffix varchar(10) null, primary key (id_space_name)) "); |
412 | else |
413 | update(" create table das_id_generator (id_space_name varchar(60) not null," |
414 | + "seed numeric(19,0) not null, batch_size numeric(19) not null, prefix varchar(10) default null," |
415 | + " suffix varchar(10) default null, primary key (id_space_name)) "); |
416 | |
417 | } |
418 | } |
419 | |
420 | public void executeSQLFile(File pFile) { |
421 | log.info("Attemping to execute " + pFile); |
422 | SQLFileParser parser = new SQLFileParser(); |
423 | Collection<String> c = parser.parseSQLFile(pFile.getAbsolutePath()); |
424 | Iterator<String> cmds = c.iterator(); |
425 | while (cmds.hasNext()) { |
426 | String cmd = cmds.next(); |
427 | try { |
428 | if ("Oracle".equals(mDatabaseType)) { |
429 | cmd = StringUtils.replace(cmd, "numeric", "NUMBER"); |
430 | cmd = StringUtils.replace(cmd, "varchar ", "VARCHAR2 "); |
431 | cmd = StringUtils.replace(cmd, "varchar(", "VARCHAR2("); |
432 | cmd = StringUtils.replace(cmd, "binary", "RAW (250)"); |
433 | } |
434 | log.info("Executing " + cmd); |
435 | update(cmd); |
436 | } |
437 | catch (SQLException e) { |
438 | log.info(e.getMessage()); |
439 | } |
440 | } |
441 | } |
442 | |
443 | public File createFakeXADataSource(File pRoot) throws IOException{ |
444 | return GSATestUtils.createFakeXADataSource(pRoot, mJDBCProperties, null); |
445 | } |
446 | |
447 | public File createFakeXADataSource(File pRoot, String pName) throws IOException{ |
448 | |
449 | return GSATestUtils.createFakeXADataSource(pRoot, mJDBCProperties, pName); |
450 | |
451 | } |
452 | |
453 | // --------------------------------- |
454 | /** |
455 | * @param pRoot |
456 | * @throws IOException |
457 | */ |
458 | public static File createJTDataSource(File pRoot) throws IOException { |
459 | return GSATestUtils.createJTDataSource(pRoot, null,null); |
460 | } |
461 | |
462 | // ------------------------------------ |
463 | /** |
464 | * Creates a new JTDataSource component. The name of the component may |
465 | * be specified by passing in a non null value for pName. |
466 | * Also the name of the FakeXADataSource may be specified by passing in a non null name. |
467 | * Otherwise the defaults are JTDataSource and FakeXADataSource. |
468 | * |
469 | * @param pRoot |
470 | * @param pName |
471 | * @param pFakeXAName |
472 | * @return |
473 | * @throws IOException |
474 | */ |
475 | public static File createJTDataSource(File pRoot, String pName, String pFakeXAName) |
476 | throws IOException { |
477 | return GSATestUtils.createJTDataSource(pRoot, pName, pFakeXAName); |
478 | } |
479 | |
480 | /** |
481 | * @param pProps |
482 | * @return |
483 | */ |
484 | public static boolean isOracle(Properties pProps) { |
485 | return pProps.get("driver").toString().toLowerCase().indexOf("oracle") != -1; |
486 | } |
487 | |
488 | /** |
489 | * @param pProps |
490 | * @return |
491 | */ |
492 | public static boolean isSybase(Properties pProps) { |
493 | return pProps.get("driver").toString().toLowerCase().indexOf("sybase") != -1; |
494 | } |
495 | |
496 | /** |
497 | * @param pProps |
498 | * @return |
499 | */ |
500 | public static boolean isMSSQLServer(Properties pProps) { |
501 | return pProps.get("driver").equals( "com.inet.tds.TdsDriver"); |
502 | } |
503 | |
504 | /** |
505 | * @param pProps |
506 | * @return |
507 | */ |
508 | public static boolean isDB2(Properties pProps) { |
509 | return pProps.get("driver").toString().indexOf("DB2") != -1; |
510 | } |
511 | |
512 | |
513 | /** |
514 | * @param pProps |
515 | * @return |
516 | */ |
517 | public boolean isOracle() { |
518 | return DBUtils.isMSSQLServer(mJDBCProperties); |
519 | } |
520 | |
521 | /** |
522 | * @param pProps |
523 | * @return |
524 | */ |
525 | public boolean isSybase() { |
526 | return DBUtils.isMSSQLServer(mJDBCProperties); |
527 | } |
528 | |
529 | /** |
530 | * @param pProps |
531 | * @return |
532 | */ |
533 | public boolean isMSSQLServer() { |
534 | return DBUtils.isMSSQLServer(mJDBCProperties); |
535 | } |
536 | |
537 | /** |
538 | * @param pProps |
539 | * @return |
540 | */ |
541 | public boolean isDB2() { |
542 | return DBUtils.isDB2(mJDBCProperties); |
543 | } |
544 | } |