001/**************************************************************** 002 * Licensed to the Apache Software Foundation (ASF) under one * 003 * or more contributor license agreements. See the NOTICE file * 004 * distributed with this work for additional information * 005 * regarding copyright ownership. The ASF licenses this file * 006 * to you under the Apache License, Version 2.0 (the * 007 * "License"); you may not use this file except in compliance * 008 * with the License. You may obtain a copy of the License at * 009 * * 010 * http://www.apache.org/licenses/LICENSE-2.0 * 011 * * 012 * Unless required by applicable law or agreed to in writing, * 013 * software distributed under the License is distributed on an * 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * 015 * KIND, either express or implied. See the License for the * 016 * specific language governing permissions and limitations * 017 * under the License. * 018 ****************************************************************/ 019package org.apache.james.rrt.jdbc; 020 021import java.io.InputStream; 022import java.sql.Connection; 023import java.sql.DatabaseMetaData; 024import java.sql.PreparedStatement; 025import java.sql.ResultSet; 026import java.sql.SQLException; 027import java.util.ArrayList; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031 032import javax.annotation.PostConstruct; 033import javax.inject.Inject; 034import javax.sql.DataSource; 035 036import org.apache.commons.configuration.ConfigurationException; 037import org.apache.commons.configuration.HierarchicalConfiguration; 038import org.apache.james.filesystem.api.FileSystem; 039import org.apache.james.rrt.api.RecipientRewriteTableException; 040import org.apache.james.rrt.lib.AbstractRecipientRewriteTable; 041import org.apache.james.rrt.lib.Mappings; 042import org.apache.james.rrt.lib.MappingsImpl; 043import org.apache.james.util.sql.JDBCUtil; 044import org.apache.james.util.sql.SqlResources; 045 046/** 047 * Class responsible to implement the Virtual User Table in database with JDBC 048 * access. 049 * 050 * @deprecated use JPARecipientRewriteTable 051 */ 052@Deprecated 053public class JDBCRecipientRewriteTable extends AbstractRecipientRewriteTable { 054 055 private DataSource dataSource = null; 056 057 private String tableName = "RecipientRewriteTable"; 058 059 /** 060 * Contains all of the sql strings for this component. 061 */ 062 private SqlResources sqlQueries; 063 064 /** 065 * The name of the SQL configuration file to be used to configure this 066 * repository. 067 */ 068 private String sqlFileName; 069 070 private FileSystem fileSystem; 071 072 /** 073 * The JDBCUtil helper class 074 */ 075 private final JDBCUtil theJDBCUtil = new JDBCUtil() { 076 protected void delegatedLog(String logString) { 077 getLogger().debug("JDBCRecipientRewriteTable: " + logString); 078 } 079 }; 080 081 @PostConstruct 082 public void init() throws Exception { 083 084 StringBuffer logBuffer; 085 if (getLogger().isDebugEnabled()) { 086 getLogger().debug(this.getClass().getName() + ".initialize()"); 087 } 088 089 // Test the connection to the database, by getting the DatabaseMetaData. 090 Connection conn = dataSource.getConnection(); 091 PreparedStatement createStatement = null; 092 093 try { 094 // Initialise the sql strings. 095 096 InputStream sqlFile; 097 098 try { 099 sqlFile = fileSystem.getResource(sqlFileName); 100 } catch (Exception e) { 101 getLogger().error(e.getMessage(), e); 102 throw e; 103 } 104 105 if (getLogger().isDebugEnabled()) { 106 logBuffer = new StringBuffer(128).append("Reading SQL resources from file: ").append(sqlFileName).append(", section ").append(this.getClass().getName()).append("."); 107 getLogger().debug(logBuffer.toString()); 108 } 109 110 // Build the statement parameters 111 Map<String, String> sqlParameters = new HashMap<String, String>(); 112 if (tableName != null) { 113 sqlParameters.put("table", tableName); 114 } 115 116 sqlQueries = new SqlResources(); 117 sqlQueries.init(sqlFile, this.getClass().getName(), conn, sqlParameters); 118 119 // Check if the required table exists. If not, create it. 120 DatabaseMetaData dbMetaData = conn.getMetaData(); 121 122 // Need to ask in the case that identifiers are stored, ask the 123 // DatabaseMetaInfo. 124 // Try UPPER, lower, and MixedCase, to see if the table is there. 125 if (!(theJDBCUtil.tableExists(dbMetaData, tableName))) { 126 127 // Users table doesn't exist - create it. 128 createStatement = conn.prepareStatement(sqlQueries.getSqlString("createTable", true)); 129 createStatement.execute(); 130 131 if (getLogger().isInfoEnabled()) { 132 logBuffer = new StringBuffer(64).append("JdbcVirtalUserTable: Created table '").append(tableName).append("'."); 133 getLogger().info(logBuffer.toString()); 134 } 135 } 136 137 } finally { 138 theJDBCUtil.closeJDBCStatement(createStatement); 139 theJDBCUtil.closeJDBCConnection(conn); 140 } 141 } 142 143 @Inject 144 public void setFileSystem(FileSystem fileSystem) { 145 this.fileSystem = fileSystem; 146 } 147 148 @Inject 149 public void setDataSource(DataSource dataSource) { 150 this.dataSource = dataSource; 151 } 152 153 protected void doConfigure(HierarchicalConfiguration conf) throws ConfigurationException { 154 155 String destination = conf.getString("[@destinationURL]", null); 156 157 if (destination == null) { 158 throw new ConfigurationException("destinationURL must configured"); 159 } 160 161 // normalize the destination, to simplify processing. 162 if (!destination.endsWith("/")) { 163 destination += "/"; 164 } 165 // Parse the DestinationURL for the name of the datasource, 166 // the table to use, and the (optional) repository Key. 167 // Split on "/", starting after "db://" 168 List<String> urlParams = new ArrayList<String>(); 169 int start = 5; 170 171 int end = destination.indexOf('/', start); 172 while (end > -1) { 173 urlParams.add(destination.substring(start, end)); 174 start = end + 1; 175 end = destination.indexOf('/', start); 176 } 177 178 // Build SqlParameters and get datasource name from URL parameters 179 if (urlParams.size() == 0) { 180 String exceptionBuffer = "Malformed destinationURL - Must be of the format '" + "db://<data-source>'. Was passed " + conf.getString("[@destinationURL]"); 181 throw new ConfigurationException(exceptionBuffer); 182 } 183 184 if (urlParams.size() >= 2) { 185 tableName = urlParams.get(1); 186 } 187 188 if (getLogger().isDebugEnabled()) { 189 String logBuffer = "Parsed URL: table = '" + tableName + "'"; 190 getLogger().debug(logBuffer); 191 } 192 193 sqlFileName = conf.getString("sqlFile"); 194 195 } 196 197 /** 198 * @throws RecipientRewriteTableException 199 * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#addMappingInternal(String, 200 * String, String) 201 */ 202 protected void addMappingInternal(String user, String domain, String regex) throws RecipientRewriteTableException { 203 String fixedUser = getFixedUser(user); 204 String fixedDomain = getFixedDomain(domain); 205 Mappings map = getUserDomainMappings(fixedUser, fixedDomain); 206 if (map != null && map.size() != 0) { 207 Mappings updatedMappings = MappingsImpl.from(map).add(regex).build(); 208 doUpdateMapping(fixedUser, fixedDomain, updatedMappings.serialize()); 209 } 210 doAddMapping(fixedUser, fixedDomain, regex); 211 } 212 213 /** 214 * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#mapAddressInternal(java.lang.String, 215 * java.lang.String) 216 */ 217 protected String mapAddressInternal(String user, String domain) throws RecipientRewriteTableException { 218 Connection conn = null; 219 PreparedStatement mappingStmt = null; 220 try { 221 conn = dataSource.getConnection(); 222 mappingStmt = conn.prepareStatement(sqlQueries.getSqlString("selectMappings", true)); 223 224 ResultSet mappingRS = null; 225 try { 226 mappingStmt.setString(1, user); 227 mappingStmt.setString(2, domain); 228 mappingRS = mappingStmt.executeQuery(); 229 if (mappingRS.next()) { 230 return mappingRS.getString(1); 231 } 232 } finally { 233 theJDBCUtil.closeJDBCResultSet(mappingRS); 234 } 235 236 } catch (SQLException sqle) { 237 getLogger().error("Error accessing database", sqle); 238 throw new RecipientRewriteTableException("Error accessing database", sqle); 239 } finally { 240 theJDBCUtil.closeJDBCStatement(mappingStmt); 241 theJDBCUtil.closeJDBCConnection(conn); 242 } 243 return null; 244 } 245 246 /** 247 * @throws RecipientRewriteTableException 248 * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#mapAddress(java.lang.String, 249 * java.lang.String) 250 */ 251 protected Mappings getUserDomainMappingsInternal(String user, String domain) throws RecipientRewriteTableException { 252 Connection conn = null; 253 PreparedStatement mappingStmt = null; 254 try { 255 conn = dataSource.getConnection(); 256 mappingStmt = conn.prepareStatement(sqlQueries.getSqlString("selectUserDomainMapping", true)); 257 ResultSet mappingRS = null; 258 try { 259 mappingStmt.setString(1, user); 260 mappingStmt.setString(2, domain); 261 mappingRS = mappingStmt.executeQuery(); 262 if (mappingRS.next()) { 263 return MappingsImpl.fromRawString(mappingRS.getString(1)); 264 } 265 } finally { 266 theJDBCUtil.closeJDBCResultSet(mappingRS); 267 } 268 } catch (SQLException sqle) { 269 getLogger().error("Error accessing database", sqle); 270 throw new RecipientRewriteTableException("Error accessing database", sqle); 271 } finally { 272 theJDBCUtil.closeJDBCStatement(mappingStmt); 273 theJDBCUtil.closeJDBCConnection(conn); 274 } 275 return null; 276 } 277 278 /** 279 * @throws RecipientRewriteTableException 280 * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#getAllMappingsInternal() 281 */ 282 protected Map<String, Mappings> getAllMappingsInternal() throws RecipientRewriteTableException { 283 Connection conn = null; 284 PreparedStatement mappingStmt = null; 285 Map<String, Mappings> mapping = new HashMap<String, Mappings>(); 286 try { 287 conn = dataSource.getConnection(); 288 mappingStmt = conn.prepareStatement(sqlQueries.getSqlString("selectAllMappings", true)); 289 ResultSet mappingRS = null; 290 try { 291 mappingRS = mappingStmt.executeQuery(); 292 while (mappingRS.next()) { 293 String user = mappingRS.getString(1); 294 String domain = mappingRS.getString(2); 295 String map = mappingRS.getString(3); 296 mapping.put(user + "@" + domain, MappingsImpl.fromRawString(map)); 297 } 298 if (mapping.size() > 0) 299 return mapping; 300 } finally { 301 theJDBCUtil.closeJDBCResultSet(mappingRS); 302 } 303 304 } catch (SQLException sqle) { 305 getLogger().error("Error accessing database", sqle); 306 throw new RecipientRewriteTableException("Error accessing database", sqle); 307 } finally { 308 theJDBCUtil.closeJDBCStatement(mappingStmt); 309 theJDBCUtil.closeJDBCConnection(conn); 310 } 311 return null; 312 } 313 314 /** 315 * @throws RecipientRewriteTableException 316 * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#removeMappingInternal(String, 317 * String, String) 318 */ 319 protected void removeMappingInternal(String user, String domain, String mapping) throws RecipientRewriteTableException { 320 String fixedUser = getFixedUser(user); 321 String fixedDomain = getFixedDomain(domain); 322 Mappings map = getUserDomainMappings(fixedUser, fixedDomain); 323 if (map != null && map.size() > 1) { 324 Mappings updatedMappings = map.remove(mapping); 325 doUpdateMapping(fixedUser, fixedDomain, updatedMappings.serialize()); 326 } else { 327 doRemoveMapping(fixedUser, fixedDomain, mapping); 328 } 329 } 330 331 /** 332 * Update the mapping for the given user and domain 333 * 334 * @param user 335 * the user 336 * @param domain 337 * the domain 338 * @param mapping 339 * the mapping 340 * @return true if update was successfully 341 * @throws RecipientRewriteTableException 342 */ 343 private void doUpdateMapping(String user, String domain, String mapping) throws RecipientRewriteTableException { 344 Connection conn = null; 345 PreparedStatement mappingStmt = null; 346 347 try { 348 conn = dataSource.getConnection(); 349 mappingStmt = conn.prepareStatement(sqlQueries.getSqlString("updateMapping", true)); 350 351 ResultSet mappingRS = null; 352 try { 353 mappingStmt.setString(1, mapping); 354 mappingStmt.setString(2, user); 355 mappingStmt.setString(3, domain); 356 357 if (mappingStmt.executeUpdate() < 1) { 358 throw new RecipientRewriteTableException("Mapping not found"); 359 } 360 } finally { 361 theJDBCUtil.closeJDBCResultSet(mappingRS); 362 } 363 364 } catch (SQLException sqle) { 365 getLogger().error("Error accessing database", sqle); 366 throw new RecipientRewriteTableException("Error accessing database", sqle); 367 } finally { 368 theJDBCUtil.closeJDBCStatement(mappingStmt); 369 theJDBCUtil.closeJDBCConnection(conn); 370 } 371 } 372 373 /** 374 * Remove a mapping for the given user and domain 375 * 376 * @param user 377 * the user 378 * @param domain 379 * the domain 380 * @param mapping 381 * the mapping 382 * @return true if succesfully 383 * @throws RecipientRewriteTableException 384 */ 385 private void doRemoveMapping(String user, String domain, String mapping) throws RecipientRewriteTableException { 386 Connection conn = null; 387 PreparedStatement mappingStmt = null; 388 389 try { 390 conn = dataSource.getConnection(); 391 mappingStmt = conn.prepareStatement(sqlQueries.getSqlString("deleteMapping", true)); 392 393 ResultSet mappingRS = null; 394 try { 395 mappingStmt.setString(1, user); 396 mappingStmt.setString(2, domain); 397 mappingStmt.setString(3, mapping); 398 if (mappingStmt.executeUpdate() < 1) { 399 throw new RecipientRewriteTableException("Mapping not found"); 400 } 401 } finally { 402 theJDBCUtil.closeJDBCResultSet(mappingRS); 403 } 404 405 } catch (SQLException sqle) { 406 getLogger().error("Error accessing database", sqle); 407 } finally { 408 theJDBCUtil.closeJDBCStatement(mappingStmt); 409 theJDBCUtil.closeJDBCConnection(conn); 410 } 411 } 412 413 /** 414 * Add mapping for given user and domain 415 * 416 * @param user 417 * the user 418 * @param domain 419 * the domain 420 * @param mapping 421 * the mapping 422 * @return true if successfully 423 * @throws RecipientRewriteTableException 424 */ 425 private void doAddMapping(String user, String domain, String mapping) throws RecipientRewriteTableException { 426 Connection conn = null; 427 PreparedStatement mappingStmt = null; 428 429 try { 430 conn = dataSource.getConnection(); 431 mappingStmt = conn.prepareStatement(sqlQueries.getSqlString("addMapping", true)); 432 433 ResultSet mappingRS = null; 434 try { 435 mappingStmt.setString(1, user); 436 mappingStmt.setString(2, domain); 437 mappingStmt.setString(3, mapping); 438 439 if (mappingStmt.executeUpdate() < 1) { 440 throw new RecipientRewriteTableException("Mapping not found"); 441 } 442 } finally { 443 theJDBCUtil.closeJDBCResultSet(mappingRS); 444 } 445 446 } catch (SQLException sqle) { 447 getLogger().error("Error accessing database", sqle); 448 } finally { 449 theJDBCUtil.closeJDBCStatement(mappingStmt); 450 theJDBCUtil.closeJDBCConnection(conn); 451 } 452 } 453 454}