1 17 18 package org.apache.james.userrepository; 19 20 import org.apache.avalon.cornerstone.services.datasource.DataSourceSelector; 21 import org.apache.avalon.excalibur.datasource.DataSourceComponent; 22 import org.apache.avalon.framework.CascadingRuntimeException; 23 import org.apache.avalon.framework.activity.Initializable; 24 import org.apache.avalon.framework.component.Component; 25 import org.apache.avalon.framework.component.ComponentException; 26 import org.apache.avalon.framework.component.ComponentManager; 27 import org.apache.avalon.framework.component.Composable; 28 import org.apache.avalon.framework.configuration.Configurable; 29 import org.apache.avalon.framework.configuration.Configuration; 30 import org.apache.avalon.framework.configuration.ConfigurationException; 31 import org.apache.avalon.framework.context.Context; 32 import org.apache.avalon.framework.context.ContextException; 33 import org.apache.avalon.framework.context.Contextualizable; 34 import org.apache.james.context.AvalonContextUtilities; 35 import org.apache.james.services.User; 36 import org.apache.james.util.JDBCUtil; 37 import org.apache.james.util.SqlResources; 38 39 import java.io.File ; 40 import java.sql.*; 41 import java.util.*; 42 43 65 public abstract class AbstractJdbcUsersRepository extends AbstractUsersRepository 66 implements Contextualizable, Composable, Configurable, Initializable 67 { 68 71 protected Context context; 72 73 protected Map m_sqlParameters; 74 75 private String m_sqlFileName; 76 77 private String m_datasourceName; 78 79 private DataSourceSelector m_datasources; 80 81 private DataSourceComponent m_datasource; 82 83 private String m_getUsersSql; 85 86 private String m_userByNameCaseInsensitiveSql; 88 89 private String m_insertUserSql; 92 private String m_updateUserSql; 93 private String m_deleteUserSql; 94 95 private String m_createUserTableSql; 97 98 private JDBCUtil theJDBCUtil; 100 101 104 public void contextualize(final Context context) 105 throws ContextException { 106 this.context = context; 107 } 108 109 112 public void compose( final ComponentManager componentManager ) 113 throws ComponentException 114 { 115 StringBuffer logBuffer = null; 116 if (getLogger().isDebugEnabled()) 117 { 118 logBuffer = 119 new StringBuffer (64) 120 .append(this.getClass().getName()) 121 .append(".compose()"); 122 getLogger().debug( logBuffer.toString() ); 123 } 124 125 m_datasources = 126 (DataSourceSelector)componentManager.lookup( DataSourceSelector.ROLE ); 127 } 128 129 146 public void configure(Configuration configuration) throws ConfigurationException 147 { 148 StringBuffer logBuffer = null; 149 if (getLogger().isDebugEnabled()) { 150 logBuffer = 151 new StringBuffer (64) 152 .append(this.getClass().getName()) 153 .append(".configure()"); 154 getLogger().debug( logBuffer.toString() ); 155 } 156 157 String destUrl = configuration.getAttribute("destinationURL"); 160 if ( ! destUrl.endsWith("/") ) { 162 destUrl += "/"; 163 } 164 List urlParams = new ArrayList(); 166 int start = 5; 167 int end = destUrl.indexOf('/', start); 168 while ( end > -1 ) { 169 urlParams.add(destUrl.substring(start, end)); 170 start = end + 1; 171 end = destUrl.indexOf('/', start); 172 } 173 174 m_sqlParameters = new HashMap(); 176 switch ( urlParams.size() ) { 177 case 3: 178 m_sqlParameters.put("key", urlParams.get(2)); 179 case 2: 180 m_sqlParameters.put("table", urlParams.get(1)); 181 case 1: 182 m_datasourceName = (String )urlParams.get(0); 183 break; 184 default: 185 throw new ConfigurationException 186 ("Malformed destinationURL - " + 187 "Must be of the format \"db://<data-source>[/<table>[/<key>]]\"."); 188 } 189 190 if (getLogger().isDebugEnabled()) { 191 logBuffer = 192 new StringBuffer (128) 193 .append("Parsed URL: table = '") 194 .append(m_sqlParameters.get("table")) 195 .append("', key = '") 196 .append(m_sqlParameters.get("key")) 197 .append("'"); 198 getLogger().debug(logBuffer.toString()); 199 } 200 201 m_sqlFileName = configuration.getChild("sqlFile", true).getValue(); 203 if (!m_sqlFileName.startsWith("file://")) { 204 throw new ConfigurationException 205 ("Malformed sqlFile - Must be of the format \"file://<filename>\"."); 206 } 207 208 Configuration sqlParamsConfig = configuration.getChild("sqlParameters"); 211 String [] paramNames = sqlParamsConfig.getAttributeNames(); 212 for (int i = 0; i < paramNames.length; i++ ) { 213 String paramName = paramNames[i]; 214 String paramValue = sqlParamsConfig.getAttribute(paramName); 215 m_sqlParameters.put(paramName, paramValue); 216 } 217 } 218 219 229 public void initialize() throws Exception 230 { 231 StringBuffer logBuffer = null; 232 if (getLogger().isDebugEnabled()) { 233 logBuffer = 234 new StringBuffer (128) 235 .append(this.getClass().getName()) 236 .append(".initialize()"); 237 getLogger().debug( logBuffer.toString() ); 238 } 239 240 theJDBCUtil = 241 new JDBCUtil() { 242 protected void delegatedLog(String logString) { 243 AbstractJdbcUsersRepository.this.getLogger().warn("AbstractJdbcUsersRepository: " + logString); 244 } 245 }; 246 247 m_datasource = (DataSourceComponent)m_datasources.select(m_datasourceName); 249 250 Connection conn = openConnection(); 252 try{ 253 DatabaseMetaData dbMetaData = conn.getMetaData(); 254 255 File sqlFile = null; 256 257 try { 258 sqlFile = AvalonContextUtilities.getFile(context, m_sqlFileName); 259 } catch (Exception e) { 260 getLogger().fatalError(e.getMessage(), e); 261 throw e; 262 } 263 264 if (getLogger().isDebugEnabled()) { 265 logBuffer = 266 new StringBuffer (256) 267 .append("Reading SQL resources from file: ") 268 .append(sqlFile.getAbsolutePath()) 269 .append(", section ") 270 .append(this.getClass().getName()) 271 .append("."); 272 getLogger().debug(logBuffer.toString()); 273 } 274 275 SqlResources sqlStatements = new SqlResources(); 276 sqlStatements.init(sqlFile, this.getClass().getName(), 277 conn, m_sqlParameters); 278 279 m_getUsersSql = sqlStatements.getSqlString("select", true); 282 283 m_userByNameCaseInsensitiveSql = 286 sqlStatements.getSqlString("selectByLowercaseName"); 287 288 m_insertUserSql = sqlStatements.getSqlString("insert", true); 291 m_updateUserSql = sqlStatements.getSqlString("update", true); 292 m_deleteUserSql = sqlStatements.getSqlString("delete", true); 293 294 m_createUserTableSql = sqlStatements.getSqlString("createTable", true); 296 297 String tableName = sqlStatements.getSqlString("tableName", true); 300 301 313 314 if (! theJDBCUtil.tableExists(dbMetaData, tableName)) 316 { 317 PreparedStatement createStatement = null; 319 try { 320 createStatement = 321 conn.prepareStatement(m_createUserTableSql); 322 createStatement.execute(); 323 } finally { 324 theJDBCUtil.closeJDBCStatement(createStatement); 325 } 326 327 logBuffer = 328 new StringBuffer (128) 329 .append(this.getClass().getName()) 330 .append(": Created table \'") 331 .append(tableName) 332 .append("\'."); 333 getLogger().info(logBuffer.toString()); 334 } else { 335 if (getLogger().isDebugEnabled()) { 336 getLogger().debug("Using table: " + tableName); 337 } 338 } 339 340 } 341 finally { 342 theJDBCUtil.closeJDBCConnection( conn ); 343 } 344 } 345 346 351 protected List listUserNames() { 352 Collection users = getAllUsers(); 353 List userNames = new ArrayList(users.size()); 354 for (Iterator it = users.iterator(); it.hasNext(); ) { 355 userNames.add(((User)it.next()).getUserName()); 356 } 357 users.clear(); 358 return userNames; 359 } 360 361 368 protected Iterator listAllUsers() { 369 return getAllUsers().iterator(); 370 } 371 372 376 private Collection getAllUsers() { 377 List userList = new ArrayList(); 379 Connection conn = openConnection(); 380 PreparedStatement getUsersStatement = null; 381 ResultSet rsUsers = null; 382 try { 383 getUsersStatement = 385 conn.prepareStatement(m_getUsersSql); 386 rsUsers = getUsersStatement.executeQuery(); 387 388 while ( rsUsers.next() ) { 390 User user = readUserFromResultSet(rsUsers); 391 userList.add(user); 392 } 393 } 394 catch ( SQLException sqlExc) { 395 throw new CascadingRuntimeException("Error accessing database", sqlExc); 396 } 397 finally { 398 theJDBCUtil.closeJDBCResultSet(rsUsers); 399 theJDBCUtil.closeJDBCStatement(getUsersStatement); 400 theJDBCUtil.closeJDBCConnection(conn); 401 } 402 403 return userList; 404 } 405 406 412 protected void doAddUser(User user) { 413 Connection conn = openConnection(); 414 PreparedStatement addUserStatement = null; 415 416 try { 418 addUserStatement = 420 conn.prepareStatement(m_insertUserSql); 421 422 setUserForInsertStatement(user, addUserStatement); 423 424 addUserStatement.execute(); 425 } 426 catch ( SQLException sqlExc) { 427 throw new CascadingRuntimeException("Error accessing database", sqlExc); 428 } finally { 429 theJDBCUtil.closeJDBCStatement(addUserStatement); 430 theJDBCUtil.closeJDBCConnection(conn); 431 } 432 } 433 434 441 protected void doRemoveUser(User user) { 442 String username = user.getUserName(); 443 444 Connection conn = openConnection(); 445 PreparedStatement removeUserStatement = null; 446 447 try { 449 removeUserStatement = conn.prepareStatement(m_deleteUserSql); 450 removeUserStatement.setString(1, username); 451 removeUserStatement.execute(); 452 } 453 catch ( SQLException sqlExc ) { 454 throw new CascadingRuntimeException("Error accessing database", sqlExc); 455 } finally { 456 theJDBCUtil.closeJDBCStatement(removeUserStatement); 457 theJDBCUtil.closeJDBCConnection(conn); 458 } 459 } 460 461 466 protected void doUpdateUser(User user) 467 { 468 Connection conn = openConnection(); 469 PreparedStatement updateUserStatement = null; 470 471 try { 473 updateUserStatement = conn.prepareStatement(m_updateUserSql); 474 setUserForUpdateStatement(user, updateUserStatement); 475 updateUserStatement.execute(); 476 } 477 catch ( SQLException sqlExc ) { 478 throw new CascadingRuntimeException("Error accessing database", sqlExc); 479 } finally { 480 theJDBCUtil.closeJDBCStatement(updateUserStatement); 481 theJDBCUtil.closeJDBCConnection(conn); 482 } 483 } 484 485 496 protected User getUserByName(String name, boolean ignoreCase) 497 { 498 if ( m_userByNameCaseInsensitiveSql == null ) { 501 return super.getUserByName(name, ignoreCase); 502 } 503 504 Connection conn = openConnection(); 507 PreparedStatement getUsersStatement = null; 508 ResultSet rsUsers = null; 509 try { 510 String sql = m_userByNameCaseInsensitiveSql; 512 getUsersStatement = conn.prepareStatement(sql); 513 514 getUsersStatement.setString(1, name.toLowerCase(Locale.US)); 515 516 rsUsers = getUsersStatement.executeQuery(); 517 518 User user = null; 520 while ( rsUsers.next() ) { 521 User rowUser = readUserFromResultSet(rsUsers); 522 String actualName = rowUser.getUserName(); 523 524 if ( ignoreCase || actualName.equals(name) ) { 526 user = rowUser; 527 break; 528 } 529 } 530 return user; 531 } 532 catch ( SQLException sqlExc ) { 533 throw new CascadingRuntimeException("Error accessing database", sqlExc); 534 } 535 finally { 536 theJDBCUtil.closeJDBCResultSet(rsUsers); 537 theJDBCUtil.closeJDBCStatement(getUsersStatement); 538 theJDBCUtil.closeJDBCConnection(conn); 539 } 540 } 541 542 543 554 protected abstract User readUserFromResultSet(ResultSet rsUsers) 555 throws SQLException; 556 557 569 protected abstract void setUserForInsertStatement(User user, 570 PreparedStatement userInsert) 571 throws SQLException; 572 573 585 protected abstract void setUserForUpdateStatement(User user, 586 PreparedStatement userUpdate) 587 throws SQLException; 588 589 595 private Connection openConnection() 596 { 597 try { 598 return m_datasource.getConnection(); 599 } 600 catch (SQLException sqle) { 601 throw new CascadingRuntimeException( 602 "An exception occurred getting a database connection.", sqle); 603 } 604 } 605 } 606 607 608 | Popular Tags |