1   /*
2    * Copyright (c) 2003 by Atlassian Software Systems Pty. Ltd.
3    * All rights reserved.
4    */
5   package com.atlassian.config.db;
6   
7   import com.atlassian.config.ConfigurationException;
8   import com.atlassian.core.util.PropertyUtils;
9   import org.apache.commons.lang.StringUtils;
10  import org.slf4j.Logger;
11  import org.slf4j.LoggerFactory;
12  
13  import java.util.ArrayList;
14  import java.util.Enumeration;
15  import java.util.List;
16  import java.util.Properties;
17  
18  public class DatabaseDetails
19  {
20      private static final Logger log = LoggerFactory.getLogger(DatabaseDetails.class);
21  
22      private String driverClassName;
23      private String databaseUrl;
24      private String userName;
25      private String password;
26      private int poolSize;
27      private String dialect;
28      private Properties configProps;
29      private List dbNotes = new ArrayList();
30      private Properties extraHibernateProperties = new Properties();
31  
32      public String getDatabaseUrl()
33      {
34          return databaseUrl;
35      }
36  
37      public void setDatabaseUrl(String databaseUrl)
38      {
39          // CONFIG-20 - trailing whitespace causes issues with mysql
40          this.databaseUrl = nullSafeTrim(databaseUrl);
41      }
42  
43      public int getPoolSize()
44      {
45          return poolSize;
46      }
47  
48      public void setPoolSize(int poolSize)
49      {
50          this.poolSize = poolSize;
51      }
52  
53      public String getDriverClassName()
54      {
55          return driverClassName;
56      }
57  
58      public void setDriverClassName(String driverClassName)
59      {
60          this.driverClassName = nullSafeTrim(driverClassName);
61      }
62  
63      public String getUserName()
64      {
65          return userName;
66      }
67  
68      public void setUserName(String userName)
69      {
70          this.userName = nullSafeTrim(userName);
71      }
72  
73      public String getPassword()
74      {
75          return password;
76      }
77  
78      public void setPassword(String password)
79      {
80          this.password = password;
81      }
82  
83      public String getDialect()
84      {
85          return dialect;
86      }
87  
88      public void setDialect(String dialect)
89      {
90          this.dialect = nullSafeTrim(dialect);
91      }
92  
93      public List getDbNotes()
94      {
95          return dbNotes;
96      }
97  
98      public void setDbNotes(List dbNotes)
99      {
100         this.dbNotes = dbNotes;
101     }
102 
103     public String toString()
104     {
105         StringBuffer str = new StringBuffer();
106         str = str.append(getDriverClassName()).append("\n");
107         str = str.append(getDatabaseUrl()).append("\n");
108         str = str.append(getDialect()).append("\n");
109         str = str.append(getUserName()).append("\n");
110         str = str.append(getPassword()).append("\n");
111 
112         return str.toString();
113     }
114 
115     public Properties getConfigProps()
116     {
117         return configProps;
118     }
119 
120     /**
121      * This method will set the dialect, pool size, and configuration properties based on a given database name.
122      */
123     public void setupForDatabase(String database)
124     {
125         int poolSizeToSet = 10;
126 
127         if (database.equals("other"))
128         {
129             setPoolSize(poolSizeToSet);
130             return;
131         }
132 
133         Properties props = getConfigProperties(database);
134         setDialect(props.getProperty("dialect"));
135 
136         try
137         {
138             poolSizeToSet = Integer.parseInt(props.getProperty("poolSize"));
139         }
140         catch (NumberFormatException e)
141         {
142             log.error("Could find a property for poolSize; nonetheless, defaulting to 10.");
143         }
144 
145         setPoolSize(poolSizeToSet);
146 
147         this.configProps = props;
148 
149         storeHibernateProperties(props);
150 
151     }
152 
153     /**
154      * Looks for properties prefixed with "hibernate." in a given properties file
155      * and bundles them into exextraHibernateProperties, for use in the hibernate connection.
156      */
157     private void storeHibernateProperties(Properties props)
158     {
159         //now look for errata hibernate properties, which might have been passed within the properties file
160         Enumeration enu = props.keys();
161 
162         while (enu.hasMoreElements())
163         {
164             String key = (String) enu.nextElement();
165 
166             if (key.matches("hibernate.*") && props.getProperty(key) != null)
167             {
168                 extraHibernateProperties.put(key, props.getProperty(key));
169             }
170             else if (props.getProperty(key) == null) //it's helpful to output any nulls, which might be problematic when
171             {                                       //playing with a connection at the back end
172                 log.warn("database hibernate property present but set to null: [" + key + "] = [" + props.getProperty(key) + "]. Setting this property anyway." );
173                 extraHibernateProperties.put(key, props.getProperty(key));
174             }
175         }
176     }
177 
178     static Properties getConfigProperties(String databaseName)
179     {
180         return PropertyUtils.getProperties("database-defaults/" + databaseName.toLowerCase() + ".properties", DatabaseDetails.class);
181     }
182 
183     /**
184      * Constructs a default db config instance based upon the contents of a properties file,
185      * expected to look something like:
186      * <p/>
187      * driverClassName=oracle.jdbc.OracleDriver
188      * databaseUrl=jdbc:oracle:thin:@localhost:1521:SID
189      * userName=
190      * password=
191      * poolSize= 10
192      * dialect=net.sf.hibernate.dialect.HSQLDialect
193      * <p/>
194      * and be within the pwd/actions dir..
195      *
196      * @param databaseName
197      */
198     public static DatabaseDetails getDefaults(String databaseName) throws ConfigurationException
199     {
200         DatabaseDetails defaults = new DatabaseDetails();
201 
202         if ("other".equals(databaseName.toLowerCase()))
203             return defaults;
204 
205         Properties props = getConfigProperties(databaseName);
206         if (props == null)
207         {
208             throw new ConfigurationException("The default values for '" + databaseName + "' not found. Check that properties file exists in your database-defaults directory");
209         }
210 
211         defaults.setDriverClassName(props.getProperty("driverClassName"));
212         defaults.setDatabaseUrl(props.getProperty("databaseUrl"));
213         defaults.setUserName(props.getProperty("userName"));
214         defaults.setPassword(props.getProperty("password"));
215 
216         defaults.storeHibernateProperties(props);
217 
218         // load notes
219         List dbNotes = new ArrayList();
220         int i = 1;
221 
222         while (StringUtils.isNotEmpty(props.getProperty("note" + i)))
223         {
224             dbNotes.add(props.getProperty("note" + i));
225             i++;
226         }
227 
228         defaults.setDbNotes(dbNotes);
229 
230         try
231         {
232             defaults.setPoolSize(Integer.parseInt(props.getProperty("poolSize")));
233         }
234         catch (NumberFormatException e)
235         {
236             log.error("Bad number within poolSize field in " + databaseName + ".");
237             throw new ConfigurationException(e.getMessage(), e);
238         }
239 
240         return defaults;
241     }
242 
243     public Properties getExtraHibernateProperties()
244     {
245         return extraHibernateProperties;
246     }
247 
248     /**
249      *
250      * @return boolean - whether driver exists in class path.
251      */
252     public boolean checkDriver()
253     {
254         try
255         {
256             Class.forName(getDriverClassName());
257             return true;
258         }
259         catch (ClassNotFoundException e)
260         {
261             return false;
262         }
263     }
264 
265     private static String nullSafeTrim(String str) {
266         return str != null ? str.trim() : null;
267     }
268 }