1 17 18 package org.apache.james.mailrepository; 19 20 import org.apache.avalon.cornerstone.services.datasource.DataSourceSelector; 21 import org.apache.avalon.cornerstone.services.store.Store; 22 import org.apache.avalon.cornerstone.services.store.StreamRepository; 23 import org.apache.avalon.excalibur.datasource.DataSourceComponent; 24 import org.apache.avalon.framework.activity.Initializable; 25 import org.apache.avalon.framework.component.Component; 26 import org.apache.avalon.framework.component.ComponentException; 27 import org.apache.avalon.framework.component.ComponentManager; 28 import org.apache.avalon.framework.component.Composable; 29 import org.apache.avalon.framework.configuration.Configurable; 30 import org.apache.avalon.framework.configuration.Configuration; 31 import org.apache.avalon.framework.configuration.ConfigurationException; 32 import org.apache.avalon.framework.configuration.DefaultConfiguration; 33 import org.apache.avalon.framework.context.Context; 34 import org.apache.avalon.framework.context.ContextException; 35 import org.apache.avalon.framework.context.Contextualizable; 36 import org.apache.avalon.framework.logger.AbstractLogEnabled; 37 import org.apache.james.context.AvalonContextUtilities; 38 import org.apache.james.core.MailImpl; 39 import org.apache.james.core.MimeMessageWrapper; 40 import org.apache.james.services.MailRepository; 41 import org.apache.james.util.JDBCUtil; 42 import org.apache.james.util.Lock; 43 import org.apache.james.util.SqlResources; 44 import org.apache.mailet.MailAddress; 45 46 import javax.mail.MessagingException ; 47 import javax.mail.internet.MimeMessage ; 48 import java.io.ByteArrayInputStream ; 49 import java.io.ByteArrayOutputStream ; 50 import java.io.File ; 51 import java.io.IOException ; 52 import java.io.ObjectOutputStream ; 53 import java.io.ObjectInputStream ; 54 import java.io.OutputStream ; 55 import java.sql.*; 56 import java.util.*; 57 58 74 public class JDBCMailRepository 75 extends AbstractLogEnabled 76 implements MailRepository, Component, Contextualizable, Composable, Configurable, Initializable { 77 78 81 private static final boolean DEEP_DEBUG = false; 82 83 86 private ComponentManager componentManager; 87 88 91 protected Context context; 92 93 97 private Lock lock; 98 99 101 104 106 109 protected String tableName; 110 111 114 protected String repositoryName; 115 116 119 121 124 private String sqlFileName; 125 126 129 private StreamRepository sr = null; 130 131 133 136 protected DataSourceSelector datasources; 137 138 141 protected DataSourceComponent datasource; 142 143 146 protected String datasourceName; 147 148 151 protected SqlResources sqlQueries; 152 153 156 protected JDBCUtil theJDBCUtil; 157 158 161 protected boolean jdbcMailAttributesReady = false; 162 163 166 public void contextualize(final Context context) 167 throws ContextException { 168 this.context = context; 169 } 170 171 174 public void compose( final ComponentManager componentManager ) 175 throws ComponentException { 176 StringBuffer logBuffer = null; 177 if (getLogger().isDebugEnabled()) { 178 logBuffer = 179 new StringBuffer (64) 180 .append(this.getClass().getName()) 181 .append(".compose()"); 182 getLogger().debug(logBuffer.toString()); 183 } 184 datasources = (DataSourceSelector)componentManager.lookup( DataSourceSelector.ROLE ); 186 this.componentManager = componentManager; 187 188 } 189 190 193 public void configure(Configuration conf) throws ConfigurationException { 194 if (getLogger().isDebugEnabled()) { 195 getLogger().debug(this.getClass().getName() + ".configure()"); 196 } 197 198 String destination = conf.getAttribute("destinationURL"); 199 if ( ! destination.endsWith("/") ) { 201 destination += "/"; 202 } 203 List urlParams = new ArrayList(); 207 int start = 5; 208 if (destination.startsWith("dbfile")) { 209 start += 4; 211 } 212 int end = destination.indexOf('/', start); 213 while ( end > -1 ) { 214 urlParams.add(destination.substring(start, end)); 215 start = end + 1; 216 end = destination.indexOf('/', start); 217 } 218 219 if (urlParams.size() == 0) { 221 StringBuffer exceptionBuffer = 222 new StringBuffer (256) 223 .append("Malformed destinationURL - Must be of the format '") 224 .append("db://<data-source>[/<table>[/<repositoryName>]]'. Was passed ") 225 .append(conf.getAttribute("destinationURL")); 226 throw new ConfigurationException(exceptionBuffer.toString()); 227 } 228 if (urlParams.size() >= 1) { 229 datasourceName = (String )urlParams.get(0); 230 } 231 if (urlParams.size() >= 2) { 232 tableName = (String )urlParams.get(1); 233 } 234 if (urlParams.size() >= 3) { 235 repositoryName = ""; 236 for (int i = 2; i < urlParams.size(); i++) { 237 if (i >= 3) { 238 repositoryName += '/'; 239 } 240 repositoryName += (String )urlParams.get(i); 241 } 242 } 243 244 if (getLogger().isDebugEnabled()) { 245 StringBuffer logBuffer = 246 new StringBuffer (128) 247 .append("Parsed URL: table = '") 248 .append(tableName) 249 .append("', repositoryName = '") 250 .append(repositoryName) 251 .append("'"); 252 getLogger().debug(logBuffer.toString()); 253 } 254 255 String filestore = conf.getChild("filestore").getValue(null); 256 sqlFileName = conf.getChild("sqlFile").getValue(); 257 if (!sqlFileName.startsWith("file://")) { 258 throw new ConfigurationException 259 ("Malformed sqlFile - Must be of the format 'file://<filename>'."); 260 } 261 try { 262 if (filestore != null) { 263 Store store = (Store)componentManager. 264 lookup("org.apache.avalon.cornerstone.services.store.Store"); 265 DefaultConfiguration streamConfiguration 267 = new DefaultConfiguration( "repository", 268 "generated:JDBCMailRepository.configure()" ); 269 270 streamConfiguration.setAttribute( "destinationURL", filestore ); 271 streamConfiguration.setAttribute( "type", "STREAM" ); 272 streamConfiguration.setAttribute( "model", "SYNCHRONOUS" ); 273 sr = (StreamRepository) store.select(streamConfiguration); 274 275 if (getLogger().isDebugEnabled()) { 276 getLogger().debug("Got filestore for JdbcMailRepository: " + filestore); 277 } 278 } 279 280 lock = new Lock(); 281 if (getLogger().isDebugEnabled()) { 282 StringBuffer logBuffer = 283 new StringBuffer (128) 284 .append(this.getClass().getName()) 285 .append(" created according to ") 286 .append(destination); 287 getLogger().debug(logBuffer.toString()); 288 } 289 } catch (Exception e) { 290 final String message = "Failed to retrieve Store component:" + e.getMessage(); 291 getLogger().error(message, e); 292 throw new ConfigurationException(message, e); 293 } 294 } 295 296 306 public void initialize() throws Exception { 307 StringBuffer logBuffer = null; 308 if (getLogger().isDebugEnabled()) { 309 getLogger().debug(this.getClass().getName() + ".initialize()"); 310 } 311 312 theJDBCUtil = 313 new JDBCUtil() { 314 protected void delegatedLog(String logString) { 315 JDBCMailRepository.this.getLogger().warn("JDBCMailRepository: " + logString); 316 } 317 }; 318 datasource = (DataSourceComponent)datasources.select(datasourceName); 320 321 Connection conn = datasource.getConnection(); 323 PreparedStatement createStatement = null; 324 325 try { 326 328 File sqlFile = null; 329 try { 330 sqlFile = AvalonContextUtilities.getFile(context, sqlFileName); 331 sqlFileName = null; 332 } catch (Exception e) { 333 getLogger().fatalError(e.getMessage(), e); 334 throw e; 335 } 336 337 String resourceName = "org.apache.james.mailrepository.JDBCMailRepository"; 338 339 if (getLogger().isDebugEnabled()) { 340 logBuffer = 341 new StringBuffer (128) 342 .append("Reading SQL resources from file: ") 343 .append(sqlFile.getAbsolutePath()) 344 .append(", section ") 345 .append(this.getClass().getName()) 346 .append("."); 347 getLogger().debug(logBuffer.toString()); 348 } 349 350 Map sqlParameters = new HashMap(); 352 if (tableName != null) { 353 sqlParameters.put("table", tableName); 354 } 355 if (repositoryName != null) { 356 sqlParameters.put("repository", repositoryName); 357 } 358 359 sqlQueries = new SqlResources(); 360 sqlQueries.init(sqlFile, this.getClass().getName(), 361 conn, sqlParameters); 362 363 DatabaseMetaData dbMetaData = conn.getMetaData(); 365 if (!(theJDBCUtil.tableExists(dbMetaData, tableName))) { 368 createStatement = 370 conn.prepareStatement(sqlQueries.getSqlString("createTable", true)); 371 createStatement.execute(); 372 373 if (getLogger().isInfoEnabled()) { 374 logBuffer = 375 new StringBuffer (64) 376 .append("JdbcMailRepository: Created table '") 377 .append(tableName) 378 .append("'."); 379 getLogger().info(logBuffer.toString()); 380 } 381 } 382 383 checkJdbcAttributesSupport(dbMetaData); 384 385 } finally { 386 theJDBCUtil.closeJDBCStatement(createStatement); 387 theJDBCUtil.closeJDBCConnection(conn); 388 } 389 } 390 391 399 protected void checkJdbcAttributesSupport(DatabaseMetaData dbMetaData) throws SQLException { 400 String attributesColumnName = "message_attributes"; 401 boolean hasUpdateMessageAttributesSQL = false; 402 boolean hasRetrieveMessageAttributesSQL = false; 403 404 boolean hasMessageAttributesColumn = theJDBCUtil.columnExists(dbMetaData, tableName, attributesColumnName); 405 406 StringBuffer logBuffer = new StringBuffer (64) 407 .append("JdbcMailRepository '" 408 + repositoryName 409 + ", table '" 410 + tableName 411 + "': "); 412 413 String updateMessageAttrSql = 416 sqlQueries.getSqlString("updateMessageAttributesSQL", false); 417 if (updateMessageAttrSql!=null) { 418 hasUpdateMessageAttributesSQL = true; 419 } 420 421 String retrieveMessageAttrSql = 424 sqlQueries.getSqlString("retrieveMessageAttributesSQL", false); 425 if (retrieveMessageAttrSql!=null) { 426 hasRetrieveMessageAttributesSQL = true; 427 } 428 429 if (hasUpdateMessageAttributesSQL && !hasRetrieveMessageAttributesSQL) { 430 logBuffer.append("JDBC Mail Attributes support was activated for update but not for retrieval" 431 + "(found 'updateMessageAttributesSQL' but not 'retrieveMessageAttributesSQL'" 432 + "in table '" 433 + tableName 434 + "')."); 435 getLogger().fatalError(logBuffer.toString()); 436 throw new SQLException(logBuffer.toString()); 437 } 438 if (!hasUpdateMessageAttributesSQL && hasRetrieveMessageAttributesSQL) { 439 logBuffer.append("JDBC Mail Attributes support was activated for retrieval but not for update" 440 + "(found 'retrieveMessageAttributesSQL' but not 'updateMessageAttributesSQL'" 441 + "in table '" 442 + tableName 443 + "'."); 444 getLogger().fatalError(logBuffer.toString()); 445 throw new SQLException(logBuffer.toString()); 446 } 447 if (!hasMessageAttributesColumn 448 && (hasUpdateMessageAttributesSQL || hasRetrieveMessageAttributesSQL) 449 ) { 450 logBuffer.append("JDBC Mail Attributes support was activated but column '" 451 + attributesColumnName 452 + "' is missing in table '" 453 + tableName 454 + "'."); 455 getLogger().fatalError(logBuffer.toString()); 456 throw new SQLException(logBuffer.toString()); 457 } 458 if (hasUpdateMessageAttributesSQL && hasRetrieveMessageAttributesSQL) { 459 jdbcMailAttributesReady = true; 460 if (getLogger().isInfoEnabled()) { 461 logBuffer.append("JDBC Mail Attributes support ready."); 462 getLogger().info(logBuffer.toString()); 463 } 464 } else { 465 jdbcMailAttributesReady = false; 466 logBuffer.append("JDBC Mail Attributes support not activated. " 467 + "Missing both 'updateMessageAttributesSQL' " 468 + "and 'retrieveMessageAttributesSQL' " 469 + "statements for table '" 470 + tableName 471 + "' in sqlResources.xml. " 472 + "Will not persist in the repository '" 473 + repositoryName 474 + "'."); 475 getLogger().warn(logBuffer.toString()); 476 } 477 } 478 479 486 public synchronized boolean unlock(String key) { 487 if (lock.unlock(key)) { 488 if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) { 489 StringBuffer debugBuffer = 490 new StringBuffer (256) 491 .append("Unlocked ") 492 .append(key) 493 .append(" for ") 494 .append(Thread.currentThread().getName()) 495 .append(" @ ") 496 .append(new java.util.Date (System.currentTimeMillis())); 497 getLogger().debug(debugBuffer.toString()); 498 } 499 return true; 501 } else { 502 return false; 503 } 504 } 505 506 513 public synchronized boolean lock(String key) { 514 if (lock.lock(key)) { 515 if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) { 516 StringBuffer debugBuffer = 517 new StringBuffer (256) 518 .append("Locked ") 519 .append(key) 520 .append(" for ") 521 .append(Thread.currentThread().getName()) 522 .append(" @ ") 523 .append(new java.util.Date (System.currentTimeMillis())); 524 getLogger().debug(debugBuffer.toString()); 525 } 526 return true; 527 } else { 528 return false; 529 } 530 } 531 532 536 public void store(MailImpl mc) throws MessagingException { 537 Connection conn = null; 538 try { 539 conn = datasource.getConnection(); 540 541 543 conn.setAutoCommit(false); 545 546 PreparedStatement checkMessageExists = null; 547 ResultSet rsExists = null; 548 boolean exists = false; 549 try { 550 checkMessageExists = 551 conn.prepareStatement(sqlQueries.getSqlString("checkMessageExistsSQL", true)); 552 checkMessageExists.setString(1, mc.getName()); 553 checkMessageExists.setString(2, repositoryName); 554 rsExists = checkMessageExists.executeQuery(); 555 exists = rsExists.next() && rsExists.getInt(1) > 0; 556 } finally { 557 theJDBCUtil.closeJDBCResultSet(rsExists); 558 theJDBCUtil.closeJDBCStatement(checkMessageExists); 559 } 560 561 if (exists) { 562 PreparedStatement updateMessage = null; 564 565 try { 566 updateMessage = 567 conn.prepareStatement(sqlQueries.getSqlString("updateMessageSQL", true)); 568 updateMessage.setString(1, mc.getState()); 569 updateMessage.setString(2, mc.getErrorMessage()); 570 if (mc.getSender() == null) { 571 updateMessage.setNull(3, java.sql.Types.VARCHAR); 572 } else { 573 updateMessage.setString(3, mc.getSender().toString()); 574 } 575 StringBuffer recipients = new StringBuffer (); 576 for (Iterator i = mc.getRecipients().iterator(); i.hasNext(); ) { 577 recipients.append(i.next().toString()); 578 if (i.hasNext()) { 579 recipients.append("\r\n"); 580 } 581 } 582 updateMessage.setString(4, recipients.toString()); 583 updateMessage.setString(5, mc.getRemoteHost()); 584 updateMessage.setString(6, mc.getRemoteAddr()); 585 updateMessage.setTimestamp(7, new java.sql.Timestamp (mc.getLastUpdated().getTime())); 586 updateMessage.setString(8, mc.getName()); 587 updateMessage.setString(9, repositoryName); 588 updateMessage.execute(); 589 } finally { 590 Statement localUpdateMessage = updateMessage; 591 updateMessage = null; 593 theJDBCUtil.closeJDBCStatement(localUpdateMessage); 594 } 595 596 if (jdbcMailAttributesReady && mc.hasAttributes()) { 598 String updateMessageAttrSql = 599 sqlQueries.getSqlString("updateMessageAttributesSQL", false); 600 PreparedStatement updateMessageAttr = null; 601 try { 602 updateMessageAttr = 603 conn.prepareStatement(updateMessageAttrSql); 604 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 605 ObjectOutputStream oos = new ObjectOutputStream (baos); 606 try { 607 oos.writeObject(((MailImpl)mc).getAttributesRaw()); 608 oos.flush(); 609 ByteArrayInputStream attrInputStream = 610 new ByteArrayInputStream (baos.toByteArray()); 611 updateMessageAttr.setBinaryStream(1, attrInputStream, baos.size()); 612 } finally { 613 try { 614 if (oos != null) { 615 oos.close(); 616 } 617 } catch (IOException ioe) { 618 getLogger().debug("JDBCMailRepository: Unexpected exception while closing output stream."); 619 } 620 } 621 updateMessageAttr.setString(2, mc.getName()); 622 updateMessageAttr.setString(3, repositoryName); 623 updateMessageAttr.execute(); 624 } catch (SQLException sqle) { 625 getLogger().info("JDBCMailRepository: Trying to update mail attributes failed.",sqle); 626 627 } finally { 628 theJDBCUtil.closeJDBCStatement(updateMessageAttr); 629 } 630 } 631 632 MimeMessage messageBody = mc.getMessage(); 635 boolean saveBody = false; 636 if (messageBody instanceof MimeMessageWrapper) { 637 MimeMessageWrapper message = (MimeMessageWrapper)messageBody; 638 saveBody = message.isModified(); 639 } else { 640 saveBody = true; 641 } 642 643 if (saveBody) { 644 try { 645 updateMessage = 646 conn.prepareStatement(sqlQueries.getSqlString("updateMessageBodySQL", true)); 647 ByteArrayOutputStream headerOut = new ByteArrayOutputStream (); 648 OutputStream bodyOut = null; 649 try { 650 if (sr == null) { 651 bodyOut = headerOut; 654 } else { 655 bodyOut = sr.put(mc.getName()); 657 } 658 659 MimeMessageWrapper.writeTo(messageBody, headerOut, bodyOut); 661 662 ByteArrayInputStream headerInputStream = 664 new ByteArrayInputStream (headerOut.toByteArray()); 665 updateMessage.setBinaryStream(1, headerInputStream, headerOut.size()); 666 } finally { 667 closeOutputStreams(headerOut, bodyOut); 668 } 669 updateMessage.setString(2, mc.getName()); 670 updateMessage.setString(3, repositoryName); 671 updateMessage.execute(); 672 } finally { 673 theJDBCUtil.closeJDBCStatement(updateMessage); 674 } 675 } 676 } else { 677 PreparedStatement insertMessage = null; 679 try { 680 String insertMessageSQL = sqlQueries.getSqlString("insertMessageSQL", true); 681 int number_of_parameters = getNumberOfParameters (insertMessageSQL); 682 insertMessage = 683 conn.prepareStatement(insertMessageSQL); 684 insertMessage.setString(1, mc.getName()); 685 insertMessage.setString(2, repositoryName); 686 insertMessage.setString(3, mc.getState()); 687 insertMessage.setString(4, mc.getErrorMessage()); 688 if (mc.getSender() == null) { 689 insertMessage.setNull(5, java.sql.Types.VARCHAR); 690 } else { 691 insertMessage.setString(5, mc.getSender().toString()); 692 } 693 StringBuffer recipients = new StringBuffer (); 694 for (Iterator i = mc.getRecipients().iterator(); i.hasNext(); ) { 695 recipients.append(i.next().toString()); 696 if (i.hasNext()) { 697 recipients.append("\r\n"); 698 } 699 } 700 insertMessage.setString(6, recipients.toString()); 701 insertMessage.setString(7, mc.getRemoteHost()); 702 insertMessage.setString(8, mc.getRemoteAddr()); 703 insertMessage.setTimestamp(9, new java.sql.Timestamp (mc.getLastUpdated().getTime())); 704 MimeMessage messageBody = mc.getMessage(); 705 706 ByteArrayOutputStream headerOut = new ByteArrayOutputStream (); 707 OutputStream bodyOut = null; 708 try { 709 if (sr == null) { 710 bodyOut = headerOut; 713 } else { 714 bodyOut = sr.put(mc.getName()); 716 } 717 718 MimeMessageWrapper.writeTo(messageBody, headerOut, bodyOut); 720 721 ByteArrayInputStream headerInputStream = 722 new ByteArrayInputStream (headerOut.toByteArray()); 723 insertMessage.setBinaryStream(10, headerInputStream, headerOut.size()); 724 } finally { 725 closeOutputStreams(headerOut, bodyOut); 726 } 727 729 if (number_of_parameters > 10) { 731 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 732 ObjectOutputStream oos = new ObjectOutputStream (baos); 733 try { 734 oos.writeObject(((MailImpl)mc).getAttributesRaw()); 735 oos.flush(); 736 ByteArrayInputStream attrInputStream = 737 new ByteArrayInputStream (baos.toByteArray()); 738 insertMessage.setBinaryStream(11, attrInputStream, baos.size()); 739 } finally { 740 try { 741 if (oos != null) { 742 oos.close(); 743 } 744 } catch (IOException ioe) { 745 getLogger().debug("JDBCMailRepository: Unexpected exception while closing output stream."); 746 } 747 } 748 } 749 750 insertMessage.execute(); 751 } finally { 752 theJDBCUtil.closeJDBCStatement(insertMessage); 753 } 754 } 755 756 conn.commit(); 757 conn.setAutoCommit(true); 758 759 synchronized (this) { 760 notify(); 762 } 763 } catch (Exception e) { 764 throw new MessagingException ("Exception caught while storing mail Container: " + e); 765 } finally { 766 theJDBCUtil.closeJDBCConnection(conn); 767 } 768 } 769 770 777 public MailImpl retrieve(String key) throws MessagingException { 778 if (DEEP_DEBUG) { 779 System.err.println("retrieving " + key); 780 } 781 Connection conn = null; 782 PreparedStatement retrieveMessage = null; 783 ResultSet rsMessage = null; 784 try { 785 conn = datasource.getConnection(); 786 if (DEEP_DEBUG) { 787 System.err.println("got a conn " + key); 788 } 789 790 retrieveMessage = 791 conn.prepareStatement(sqlQueries.getSqlString("retrieveMessageSQL", true)); 792 retrieveMessage.setString(1, key); 793 retrieveMessage.setString(2, repositoryName); 794 rsMessage = retrieveMessage.executeQuery(); 795 if (DEEP_DEBUG) { 796 System.err.println("ran the query " + key); 797 } 798 if (!rsMessage.next()) { 799 if (getLogger().isDebugEnabled()) { 800 StringBuffer debugBuffer = 801 new StringBuffer (64) 802 .append("Did not find a record ") 803 .append(key) 804 .append(" in ") 805 .append(repositoryName); 806 getLogger().debug(debugBuffer.toString()); 807 } 808 return null; 809 } 810 PreparedStatement retrieveMessageAttr = null; 812 HashMap attributes = null; 813 if (jdbcMailAttributesReady) { 814 String retrieveMessageAttrSql = 815 sqlQueries.getSqlString("retrieveMessageAttributesSQL", false); 816 ResultSet rsMessageAttr = null; 817 try { 818 retrieveMessageAttr = 819 conn.prepareStatement(retrieveMessageAttrSql); 820 821 retrieveMessageAttr.setString(1, key); 822 retrieveMessageAttr.setString(2, repositoryName); 823 rsMessageAttr = retrieveMessageAttr.executeQuery(); 824 825 if (rsMessageAttr.next()) { 826 try { 827 byte[] serialized_attr = null; 828 String getAttributesOption = sqlQueries.getDbOption("getAttributes"); 829 if (getAttributesOption != null && getAttributesOption.equalsIgnoreCase("useBlob")) { 830 Blob b = rsMessageAttr.getBlob(1); 831 serialized_attr = b.getBytes(1, (int)b.length()); 832 } else { 833 serialized_attr = rsMessageAttr.getBytes(1); 834 } 835 if (serialized_attr != null) { 837 ByteArrayInputStream bais = new ByteArrayInputStream (serialized_attr); 838 ObjectInputStream ois = new ObjectInputStream (bais); 839 attributes = (HashMap)ois.readObject(); 840 ois.close(); 841 } 842 } catch (IOException ioe) { 843 if (getLogger().isDebugEnabled()) { 844 StringBuffer debugBuffer = 845 new StringBuffer (64) 846 .append("Exception reading attributes ") 847 .append(key) 848 .append(" in ") 849 .append(repositoryName); 850 getLogger().debug(debugBuffer.toString(), ioe); 851 } 852 } 853 } else { 854 if (getLogger().isDebugEnabled()) { 855 StringBuffer debugBuffer = 856 new StringBuffer (64) 857 .append("Did not find a record (attributes) ") 858 .append(key) 859 .append(" in ") 860 .append(repositoryName); 861 getLogger().debug(debugBuffer.toString()); 862 } 863 } 864 } catch (SQLException sqle) { 865 StringBuffer errorBuffer = new StringBuffer (256) 866 .append("Error retrieving message") 867 .append(sqle.getMessage()) 868 .append(sqle.getErrorCode()) 869 .append(sqle.getSQLState()) 870 .append(sqle.getNextException()); 871 getLogger().error(errorBuffer.toString()); 872 } finally { 873 theJDBCUtil.closeJDBCResultSet(rsMessageAttr); 874 theJDBCUtil.closeJDBCStatement(retrieveMessageAttr); 875 } 876 } 877 878 MailImpl mc = new MailImpl(); 879 mc.setAttributesRaw (attributes); 880 mc.setName(key); 881 mc.setState(rsMessage.getString(1)); 882 mc.setErrorMessage(rsMessage.getString(2)); 883 String sender = rsMessage.getString(3); 884 if (sender == null) { 885 mc.setSender(null); 886 } else { 887 mc.setSender(new MailAddress(sender)); 888 } 889 StringTokenizer st = new StringTokenizer(rsMessage.getString(4), "\r\n", false); 890 Set recipients = new HashSet(); 891 while (st.hasMoreTokens()) { 892 recipients.add(new MailAddress(st.nextToken())); 893 } 894 mc.setRecipients(recipients); 895 mc.setRemoteHost(rsMessage.getString(5)); 896 mc.setRemoteAddr(rsMessage.getString(6)); 897 mc.setLastUpdated(rsMessage.getTimestamp(7)); 898 899 MimeMessageJDBCSource source = new MimeMessageJDBCSource(this, key, sr); 900 MimeMessageWrapper message = new MimeMessageWrapper(source); 901 mc.setMessage(message); 902 return mc; 903 } catch (SQLException sqle) { 904 StringBuffer errorBuffer = new StringBuffer (256) 905 .append("Error retrieving message") 906 .append(sqle.getMessage()) 907 .append(sqle.getErrorCode()) 908 .append(sqle.getSQLState()) 909 .append(sqle.getNextException()); 910 getLogger().error(errorBuffer.toString()); 911 throw new MessagingException ("Exception while retrieving mail: " + sqle.getMessage()); 912 } catch (Exception me) { 913 throw new MessagingException ("Exception while retrieving mail: " + me.getMessage()); 914 } finally { 915 theJDBCUtil.closeJDBCResultSet(rsMessage); 916 theJDBCUtil.closeJDBCStatement(retrieveMessage); 917 theJDBCUtil.closeJDBCConnection(conn); 918 } 919 } 920 921 926 public void remove(MailImpl mail) throws MessagingException { 927 remove(mail.getName()); 928 } 929 930 936 public void remove(Collection mails) throws MessagingException { 937 Iterator delList = mails.iterator(); 938 while (delList.hasNext()) { 939 remove((MailImpl)delList.next()); 940 } 941 } 942 943 948 public void remove(String key) throws MessagingException { 949 if (lock(key)) { 951 Connection conn = null; 952 PreparedStatement removeMessage = null; 953 try { 954 conn = datasource.getConnection(); 955 removeMessage = 956 conn.prepareStatement(sqlQueries.getSqlString("removeMessageSQL", true)); 957 removeMessage.setString(1, key); 958 removeMessage.setString(2, repositoryName); 959 removeMessage.execute(); 960 961 if (sr != null) { 962 sr.remove(key); 963 } 964 } catch (Exception me) { 965 throw new MessagingException ("Exception while removing mail: " + me.getMessage()); 966 } finally { 967 theJDBCUtil.closeJDBCStatement(removeMessage); 968 theJDBCUtil.closeJDBCConnection(conn); 969 unlock(key); 970 } 971 } 972 } 973 974 979 public Iterator list() throws MessagingException { 980 Connection conn = null; 982 PreparedStatement listMessages = null; 983 ResultSet rsListMessages = null; 984 try { 985 conn = datasource.getConnection(); 986 listMessages = 987 conn.prepareStatement(sqlQueries.getSqlString("listMessagesSQL", true)); 988 listMessages.setString(1, repositoryName); 989 rsListMessages = listMessages.executeQuery(); 990 991 List messageList = new ArrayList(); 992 while (rsListMessages.next() && !Thread.currentThread().isInterrupted()) { 993 messageList.add(rsListMessages.getString(1)); 994 } 995 return messageList.iterator(); 996 } catch (Exception me) { 997 throw new MessagingException ("Exception while listing mail: " + me.getMessage()); 998 } finally { 999 theJDBCUtil.closeJDBCResultSet(rsListMessages); 1000 theJDBCUtil.closeJDBCStatement(listMessages); 1001 theJDBCUtil.closeJDBCConnection(conn); 1002 } 1003 } 1004 1005 1011 protected Connection getConnection() throws SQLException { 1012 return datasource.getConnection(); 1013 } 1014 1015 1018 public boolean equals(Object obj) { 1019 if (!(obj instanceof JDBCMailRepository)) { 1020 return false; 1021 } 1022 JDBCMailRepository repository = (JDBCMailRepository)obj; 1025 return ((repository.tableName == tableName) || ((repository.tableName != null) && repository.tableName.equals(tableName))) && 1026 ((repository.repositoryName == repositoryName) || ((repository.repositoryName != null) && repository.repositoryName.equals(repositoryName))); 1027 } 1028 1029 1034 public int hashCode() { 1035 int result = 17; 1036 if (tableName != null) { 1037 result = 37 * tableName.hashCode(); 1038 } 1039 if (repositoryName != null) { 1040 result = 37 * repositoryName.hashCode(); 1041 } 1042 return result; 1043 } 1044 1045 1051 private int getNumberOfParameters (String sqlstring) { 1052 char[] chars = sqlstring.toCharArray(); 1055 int count = 0; 1056 for (int i = 0; i < chars.length; i++) { 1057 count += chars[i]=='?' ? 1 : 0; 1058 } 1059 return count; 1060 } 1061 1062 1069 private void closeOutputStreams(OutputStream headerStream, OutputStream bodyStream) { 1070 try { 1071 if ((headerStream != null) && (headerStream != bodyStream)) { 1074 headerStream.close(); 1075 } 1076 } catch (IOException ioe) { 1077 getLogger().debug("JDBCMailRepository: Unexpected exception while closing output stream."); 1078 } 1079 try { 1080 if (bodyStream != null) { 1081 bodyStream.close(); 1082 } 1083 } catch (IOException ioe) { 1084 getLogger().debug("JDBCMailRepository: Unexpected exception while closing output stream."); 1085 } 1086 } 1087} 1088 | Popular Tags |