001package org.javasimon.jdbcx4; 002 003import java.io.PrintWriter; 004import java.lang.reflect.Method; 005import java.sql.SQLException; 006import java.util.Properties; 007 008import org.javasimon.jdbc4.SimonConnectionConfiguration; 009 010/** 011 * SimonCommonDataSource is parent for all three datasource implementation classes. 012 * <p/> 013 * It contains getters and setters for basic properties which all three datasource types 014 * needs to implement. 015 * 016 * @author Radovan Sninsky 017 * @author <a href="mailto:virgo47@gmail.com">Richard "Virgo" Richter</a> 018 * @since 2.4 019 */ 020public abstract class AbstractSimonDataSource { 021 protected transient PrintWriter logWriter; 022 protected SimonConnectionConfiguration configuration; 023 private String user; 024 private String password; 025 private int loginTimeout; 026 027 private String realDataSourceClassName; 028 private String prefix; 029 /** 030 * Properties specific to the real datasource 031 */ 032 private Properties properties; 033 034 /** 035 * Retrieves the log writer for this <code>DataSource</code> object. 036 * 037 * @return the log writer for this data source or null if logging is disabled 038 * @throws java.sql.SQLException if a database access error occurs 039 * @see javax.sql.DataSource#getLogWriter() 040 * @see #setLogWriter(java.io.PrintWriter) 041 */ 042 public final PrintWriter getLogWriter() throws SQLException { 043 return logWriter; 044 } 045 046 /** 047 * Sets the log writer for this <code>DataSource</code> object to the given <code>java.io.PrintWriter</code> object. 048 * 049 * @param out the new log writer; to disable logging, set to null 050 * @throws java.sql.SQLException if a database access error occurs 051 * @see javax.sql.DataSource#setLogWriter(java.io.PrintWriter) 052 * @see #getLogWriter 053 */ 054 public final void setLogWriter(PrintWriter out) throws SQLException { 055 this.logWriter = out; 056 } 057 058 /** 059 * Returns JDBC connection URL. 060 * 061 * @return JDBC connection URL 062 */ 063 public final String getUrl() { 064 return configuration == null ? null : configuration.getSimonUrl(); 065 } 066 067 /** 068 * Setter for URL property. 069 * 070 * @param url JDBC connection URL 071 */ 072 public final void setUrl(String url) { 073 this.configuration = new SimonConnectionConfiguration(url); 074 } 075 076 /** 077 * Returns real JDBC connection URL. 078 * 079 * @return real JDBC connection URL 080 */ 081 public final String getRealUrl() { 082 return configuration == null ? null : configuration.getRealUrl(); 083 } 084 085 /** 086 * Returns database user to authenticate connection. 087 * 088 * @return database user 089 */ 090 public final String getUser() { 091 return user; 092 } 093 094 /** 095 * Setter for user property. 096 * 097 * @param user database user 098 */ 099 public final void setUser(String user) { 100 this.user = user; 101 } 102 103 /** 104 * Returns database password to authenticate connection. 105 * 106 * @return database password 107 */ 108 public final String getPassword() { 109 return password; 110 } 111 112 /** 113 * Setter for password property. 114 * 115 * @param password database password 116 */ 117 public final void setPassword(String password) { 118 this.password = password; 119 } 120 121 /** 122 * Sets the maximum time in seconds that this data source will wait 123 * while attempting to connect to a database. A value of zero 124 * specifies that the timeout is the default system timeout 125 * if there is one; otherwise, it specifies that there is no timeout. 126 * When a {@code DataSource} object is created, the login timeout is 127 * initially zero. 128 * 129 * @param seconds the data source login time limit 130 * @throws java.sql.SQLException if a database access error occurs. 131 * @see #getLoginTimeout 132 */ 133 public final void setLoginTimeout(int seconds) throws SQLException { 134 this.loginTimeout = seconds; 135 } 136 137 /** 138 * Gets the maximum time in seconds that this data source can wait 139 * while attempting to connect to a database. A value of zero 140 * means that the timeout is the default system timeout 141 * if there is one; otherwise, it means that there is no timeout. 142 * When a {@code DataSource} object is created, the login timeout is 143 * initially zero. 144 * 145 * @return the data source login time limit 146 * @throws java.sql.SQLException if a database access error occurs. 147 * @see #setLoginTimeout 148 */ 149 public final int getLoginTimeout() throws SQLException { 150 return loginTimeout; 151 } 152 153 /** 154 * Returns real datasource class name. 155 * 156 * @return real datasource class name 157 */ 158 public final String getRealDataSourceClassName() { 159 if ((realDataSourceClassName == null || realDataSourceClassName.isEmpty()) && (configuration != null)) { 160 realDataSourceClassName = doGetRealDataSourceClassName(); 161 } 162 return realDataSourceClassName; 163 } 164 165 /** 166 * Setter for realDataSourceClassName property. 167 * 168 * @param className class name of real datasource 169 */ 170 public final void setRealDataSourceClassName(String className) { 171 this.realDataSourceClassName = className; 172 } 173 174 /** 175 * Instantiates the DataSource. 176 * 177 * @param dataSourceClass Expected DataSource class 178 * @param <T> DataSource type 179 * @return Create DataSource 180 * @throws SQLException 181 */ 182 protected final <T> T createDataSource(Class<T> dataSourceClass) throws SQLException { 183 if (getRealDataSourceClassName() == null) { 184 throw new SQLException("Property realDataSourceClassName is not set"); 185 } 186 try { 187 T ds = dataSourceClass.cast(Class.forName(realDataSourceClassName).newInstance()); 188 for (Method m : ds.getClass().getMethods()) { 189 String methodName = m.getName(); 190 if (methodName.startsWith("set") && m.getParameterTypes().length == 1) { 191 final Object propertyValue; 192 if (methodName.equals("setUser")) { 193 propertyValue = getUser(); 194 } else if (methodName.equals("setPassword")) { 195 propertyValue = getPassword(); 196 } else if (methodName.equalsIgnoreCase("setUrl")) { 197 propertyValue = getRealUrl(); 198 } else if (methodName.equals("setLogWriter")) { 199 propertyValue = getLogWriter(); 200 } else if (methodName.equals("setLoginTimeout")) { 201 propertyValue = getLoginTimeout(); 202 } else { 203 String propertyName = methodName.substring(3, 4).toLowerCase(); 204 if (methodName.length() > 4) { 205 propertyName += methodName.substring(4); 206 } 207 final Class<?> propertyType = m.getParameterTypes()[0]; 208 propertyValue = getPropertyAs(propertyName, propertyType); 209 } 210 if (propertyValue != null) { 211 m.invoke(ds, propertyValue); 212 } 213 } 214 } 215 return ds; 216 217 } catch (Exception e) { 218 throw new SQLException(e); 219 } 220 } 221 222 /** 223 * Reads DataSource class name from configuration. 224 */ 225 protected abstract String doGetRealDataSourceClassName(); 226 227 /** 228 * Returns Simon prefix for constructing names of Simons. 229 * 230 * @return Simon prefix 231 */ 232 public final String getPrefix() { 233 if ((prefix == null || prefix.isEmpty()) && (configuration != null)) { 234 prefix = configuration.getPrefix(); 235 } 236 return prefix; 237 } 238 239 /** 240 * Sets Simon prefix for constructing names of Simons. 241 * 242 * @param prefix Simon prefix 243 */ 244 public final void setPrefix(String prefix) { 245 this.prefix = prefix; 246 } 247 248 /** 249 * Get properties specific to the real datasource. 250 * 251 * @return Properties 252 */ 253 public Properties getProperties() { 254 return properties; 255 } 256 257 /** 258 * Set properties specific to the real datasource. 259 */ 260 public void setProperties(Properties properties) { 261 this.properties = properties; 262 } 263 264 /** 265 * Returns property from {@link #properties} and convert it to given type. 266 * 267 * @param <T> property type 268 * @param propertyName property name 269 * @param propertyType property type 270 * @return property value 271 */ 272 @SuppressWarnings("unchecked") 273 private <T> T getPropertyAs(String propertyName, Class<T> propertyType) { 274 final String sValue = properties == null ? null : properties.getProperty(propertyName); 275 final T value; 276 if (sValue == null) { 277 value = null; 278 } else if (propertyType.equals(String.class)) { 279 value = propertyType.cast(sValue); 280 } else if (propertyType.equals(Integer.class)) { 281 value = propertyType.cast(Integer.valueOf(sValue)); 282 } else if (propertyType.equals(int.class)) { 283 value = (T) Integer.valueOf(sValue); 284 } else if (propertyType.equals(Long.class)) { 285 value = propertyType.cast(Long.valueOf(sValue)); 286 } else if (propertyType.equals(long.class)) { 287 value = (T) Long.valueOf(sValue); 288 } else if (propertyType.equals(Boolean.class)) { 289 value = propertyType.cast(Boolean.valueOf(sValue)); 290 } else if (propertyType.equals(boolean.class)) { 291 value = (T) Boolean.valueOf(sValue); 292 } else { 293 value = null; 294 } 295 return value; 296 } 297}