1 package com.atlassian.config.bootstrap;
2
3 import com.atlassian.config.ApplicationConfiguration;
4 import com.atlassian.config.ConfigurationException;
5 import com.atlassian.config.HomeLocator;
6 import com.atlassian.config.db.DatabaseDetails;
7 import com.atlassian.config.db.HibernateConfig;
8 import com.atlassian.config.db.HibernateConfigurator;
9 import com.atlassian.config.setup.SetupPersister;
10 import org.apache.commons.lang.StringUtils;
11 import org.apache.log4j.Logger;
12
13 import javax.naming.InitialContext;
14 import javax.naming.NamingException;
15 import javax.sql.DataSource;
16 import java.sql.Connection;
17 import java.sql.DriverManager;
18 import java.sql.SQLException;
19 import java.sql.Statement;
20 import java.util.*;
21
22
23
24
25 public class DefaultAtlassianBootstrapManager implements AtlassianBootstrapManager
26 {
27 public static final Logger log = Logger.getLogger(DefaultAtlassianBootstrapManager.class);
28
29
30
31 protected boolean bootstrapped;
32 protected String bootstrapFailureReason;
33
34
35
36 private String operation;
37
38
39 private List tables;
40
41
42 protected ApplicationConfiguration applicationConfig;
43 protected SetupPersister setupPersister;
44 protected HomeLocator homeLocator;
45 protected HibernateConfigurator hibernateConfigurator;
46 protected HibernateConfig hibernateConfig;
47
48
49
50
51 public void init() throws BootstrapException
52 {
53
54
55
56
57
58 try
59 {
60 if (StringUtils.isNotEmpty(homeLocator.getHomePath()))
61 {
62 applicationConfig.setApplicationHome(homeLocator.getHomePath());
63 applicationConfig.setConfigurationFileName(homeLocator.getConfigFileName());
64
65 if (applicationConfig.configFileExists())
66 {
67 applicationConfig.load();
68 }
69
70 afterConfigurationLoaded();
71
72 setupPersister.setSetupType(applicationConfig.getSetupType());
73 if (SetupPersister.SETUP_STATE_COMPLETE.equals(setupPersister.getCurrentStep()))
74 {
75
76 if (!performPersistenceUpgrade())
77 {
78 return;
79 }
80
81 applicationConfig.setSetupComplete(true);
82 publishConfiguration();
83 }
84 }
85 else
86 {
87
88
89 log.warn("Unable to set up application config: no home set");
90 }
91
92 finishBootstrapInitialisation();
93
94 bootstrapped = true;
95 }
96 catch (ConfigurationException e)
97 {
98 log.error("Home is not configured properly: " + e);
99 bootstrapped = false;
100 bootstrapFailureReason = e.getMessage();
101 }
102 }
103
104 public void publishConfiguration()
105 {
106
107 }
108
109
110
111
112
113
114 public Object getProperty(String key)
115 {
116 Object o = null;
117 try
118 {
119 o = applicationConfig.getProperty(key);
120 }
121 catch (NullPointerException e)
122 {
123 log.error("BootstrapManager was asked to fetch property (" + key + ") and found a NullPointer");
124 }
125
126 return o;
127 }
128
129
130
131
132 public void setProperty(String key, Object value)
133 {
134 if (value == null)
135 {
136 applicationConfig.removeProperty(key);
137 }
138 else
139 {
140 applicationConfig.setProperty(key, value);
141 }
142 if (isSetupComplete())
143 {
144 publishConfiguration();
145 }
146 }
147
148 public boolean isPropertyTrue(String prop)
149 {
150 return "true".equals(getString(prop));
151 }
152
153
154
155
156 public void removeProperty(String key)
157 {
158 applicationConfig.removeProperty(key);
159 }
160
161
162
163
164 public String getString(String key)
165 {
166 return (String) applicationConfig.getProperty(key);
167 }
168
169 public String getFilePathProperty(String key)
170 {
171 return getString(key);
172 }
173
174
175
176
177 public Collection getPropertyKeys()
178 {
179 return applicationConfig.getProperties().keySet();
180 }
181
182
183
184
185 public Map getPropertiesWithPrefix(String prefix)
186 {
187 return applicationConfig.getPropertiesWithPrefix(prefix);
188 }
189
190 public void save() throws ConfigurationException
191 {
192 applicationConfig.save();
193 }
194
195 public String getConfiguredApplicationHome()
196 {
197 return homeLocator.getHomePath();
198 }
199
200
201
202
203
204
205 public boolean isSetupComplete()
206 {
207 return isBootstrapped() && applicationConfig.isSetupComplete();
208 }
209
210 public void setSetupComplete(boolean complete)
211 {
212 applicationConfig.setSetupComplete(complete);
213 }
214
215
216 public String getBuildNumber()
217 {
218 return applicationConfig.getBuildNumber();
219 }
220
221 public void setBuildNumber(String buildNumber)
222 {
223 applicationConfig.setBuildNumber(buildNumber);
224 }
225
226
227
228
229
230
231
232
233
234 public Properties getHibernateProperties()
235 {
236 Properties props = new Properties();
237 props.putAll(applicationConfig.getPropertiesWithPrefix("hibernate."));
238 return props;
239 }
240
241
242
243
244
245
246
247
248 public void bootstrapDatabase(DatabaseDetails dbDetails, boolean embedded)
249 throws BootstrapException
250 {
251 try
252 {
253 hibernateConfigurator.configureDatabase(dbDetails, embedded);
254 }
255 catch (ConfigurationException e)
256 {
257 log.fatal("Could not successfully configure database: \n db: " + dbDetails + " \n embedded = " + embedded);
258 log.fatal("ConfigurationException reads thus: " + e);
259 hibernateConfigurator.unconfigureDatabase();
260 throw new BootstrapException(e);
261 }
262
263 Connection conn = null;
264 try
265 {
266 conn = getTestDatabaseConnection(dbDetails);
267 if (!databaseContainsExistingData(conn))
268 {
269 throw new BootstrapException("Schema creation complete, but database tables don't seem to exist.");
270 }
271 }
272 finally
273 {
274 try
275 {
276 if (conn != null) conn.close();
277 }
278 catch (SQLException e)
279 {
280
281 }
282 }
283
284 postBootstrapDatabase();
285 }
286
287
288
289
290
291
292
293
294
295
296
297 public void bootstrapDatasource(String datasourceName, String hibernateDialect)
298 throws BootstrapException
299 {
300 try
301 {
302 hibernateConfigurator.configureDatasource(datasourceName, hibernateDialect);
303 }
304 catch (ConfigurationException e)
305 {
306 log.fatal("Could not successfully configure datasource: \n db: " + datasourceName + " \n dialect = "
307 + hibernateDialect);
308 log.fatal("ConfigurationException reads thus: " + e);
309 hibernateConfigurator.unconfigureDatabase();
310 throw new BootstrapException(e);
311 }
312 Connection connection = null;
313 try
314 {
315 connection = getTestDatasourceConnection(datasourceName);
316 if (!databaseContainsExistingData(connection))
317 {
318 throw new BootstrapException("Schema creation complete, but tables could not be found.");
319 }
320 }
321 finally
322 {
323 try
324 {
325 if (connection != null) connection.close();
326 }
327 catch (SQLException e)
328 {
329
330 }
331 }
332 postBootstrapDatabase();
333 }
334
335
336
337
338
339
340
341 public Connection getTestDatabaseConnection(DatabaseDetails databaseDetails) throws BootstrapException
342 {
343 Connection conn = null;
344 try
345 {
346 Class.forName(databaseDetails.getDriverClassName());
347 conn = DriverManager.getConnection(getDbUrl(databaseDetails),
348 databaseDetails.getUserName(),
349 databaseDetails.getPassword());
350 if (conn == null)
351 {
352 throw new BootstrapException("Connection was null. We could not successfully connect to the specified database!");
353 }
354 return conn;
355 }
356 catch (SQLException e)
357 {
358 log.error("Could not successfully test your database: ", e);
359 throw new BootstrapException(e);
360 }
361 catch (ClassNotFoundException e)
362 {
363 log.error("Could not successfully test your database: ", e);
364 throw new BootstrapException(e);
365 }
366 }
367
368
369
370
371
372
373
374 public Connection getTestDatasourceConnection(String datasourceName) throws BootstrapException
375 {
376 DataSource dsrc;
377
378 log.debug("datasource is " + datasourceName);
379
380 try
381 {
382 InitialContext ctx = new InitialContext();
383 dsrc = (DataSource) ctx.lookup(datasourceName);
384
385 if (dsrc == null)
386 {
387 throw new NamingException("Could not locate " + datasourceName);
388 }
389 }
390 catch (NamingException e)
391 {
392 log.error("Could not locate datasource: " + datasourceName, e);
393 throw new BootstrapException("Could not locate datasource: " + datasourceName, e);
394 }
395 catch (ClassCastException e)
396 {
397 log.error("Couldn't locate Datasource (" + datasourceName + ") in the initial context. An object was bound to this name but whatever we found, it wasn't a Datasource: " + e);
398 throw new BootstrapException("Couldn't locate Datasource (" + datasourceName + ") in the initial context. An object was bound to this name but whatever we found, it wasn't a Datasource: ", e);
399 }
400
401 try
402 {
403 Connection conn = dsrc.getConnection();
404 conn.createStatement();
405 return conn;
406 }
407 catch (SQLException e)
408 {
409 log.error("Couldn't open a connection on Datasource (" + datasourceName + "): " + e);
410 throw new BootstrapException("Couldn't open a connection on Datasource (" + datasourceName + "): ", e);
411 }
412 catch (NullPointerException e)
413 {
414 log.error("Couldn't open a connection on Datasource (" + datasourceName + "): " + e);
415 throw new BootstrapException("Couldn't open a connection on Datasource (" + datasourceName + "): ", e);
416 }
417 }
418
419
420
421
422
423
424
425 public boolean databaseContainsExistingData(Connection connection)
426 {
427 for (Iterator iterator = getTables().iterator(); iterator.hasNext();)
428 {
429 String table = (String) iterator.next();
430 if (tableExists(connection, table))
431 return true;
432 }
433 return false;
434 }
435
436 private boolean tableExists(Connection conn, String table)
437 {
438 Statement st = null;
439 try
440 {
441 st = conn.createStatement();
442 st.executeQuery("select count(*) from " + table);
443 return true;
444 }
445 catch (SQLException e)
446 {
447 return false;
448 }
449 finally
450 {
451 if (st != null)
452 {
453 try
454 {
455 st.close();
456 }
457 catch (SQLException e)
458 {
459
460 }
461 }
462 }
463 }
464
465
466 public boolean isApplicationHomeValid()
467 {
468 return applicationConfig.isApplicationHomeValid();
469 }
470
471
472
473
474
475
476
477 protected boolean performPersistenceUpgrade()
478 {
479
480 return true;
481 }
482
483
484
485
486
487
488 protected void finishBootstrapInitialisation() throws ConfigurationException
489 {
490
491 }
492
493
494
495
496
497
498 protected String getDbUrl(DatabaseDetails dbDetails)
499 {
500 return dbDetails.getDatabaseUrl();
501 }
502
503
504
505
506 protected void postBootstrapDatabase()
507 {
508
509 }
510
511
512
513
514 protected void afterConfigurationLoaded() throws ConfigurationException
515 {
516
517 }
518
519
520
521
522 public void setApplicationConfig(ApplicationConfiguration applicationConfig)
523 {
524 this.applicationConfig = applicationConfig;
525 }
526
527 public void setHomeLocator(HomeLocator homeLocator)
528 {
529 this.homeLocator = homeLocator;
530 }
531
532 public void setSetupPersister(SetupPersister setupPersister)
533 {
534 this.setupPersister = setupPersister;
535 }
536
537 public HomeLocator getHomeLocator()
538 {
539 return homeLocator;
540 }
541
542 public ApplicationConfiguration getApplicationConfig()
543 {
544 return applicationConfig;
545 }
546
547 public String getApplicationHome()
548 {
549 return applicationConfig.getApplicationHome();
550 }
551
552 public SetupPersister getSetupPersister()
553 {
554 return setupPersister;
555 }
556
557
558
559
560 public boolean isBootstrapped()
561 {
562 return bootstrapped;
563 }
564
565 public String getOperation()
566 {
567 return operation;
568 }
569
570 public void setOperation(String operation)
571 {
572 this.operation = operation;
573 }
574
575 public HibernateConfigurator getHibernateConfigurator()
576 {
577 return hibernateConfigurator;
578 }
579
580 public void setHibernateConfigurator(HibernateConfigurator hibernateConfigurator)
581 {
582 this.hibernateConfigurator = hibernateConfigurator;
583 }
584
585 public HibernateConfig getHibernateConfig()
586 {
587 return hibernateConfig;
588 }
589
590 public void setHibernateConfig(HibernateConfig hibernateConfig)
591 {
592 this.hibernateConfig = hibernateConfig;
593 }
594
595 public String getBootstrapFailureReason()
596 {
597 return bootstrapFailureReason;
598 }
599
600 public List getTables()
601 {
602 return tables;
603 }
604
605 public void setTables(List tables)
606 {
607 this.tables = tables;
608 }
609 }