1 /************************************************************************
2 * Copyright (c) 2000-2006 The Apache Software Foundation. *
3 * All rights reserved. *
4 * ------------------------------------------------------------------- *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you *
6 * may not use this file except in compliance with the License. You *
7 * may obtain a copy of the License at: *
8 * *
9 * http://www.apache.org/licenses/LICENSE-2.0 *
10 * *
11 * Unless required by applicable law or agreed to in writing, software *
12 * distributed under the License is distributed on an "AS IS" BASIS, *
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14 * implied. See the License for the specific language governing *
15 * permissions and limitations under the License. *
16 ***********************************************************************/
17
18 package org.apache.james.transport.mailets;
19
20 import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector;
21 import org.apache.avalon.excalibur.datasource.DataSourceComponent;
22 import org.apache.avalon.framework.service.ServiceManager;
23 import org.apache.james.Constants;
24 import org.apache.james.util.JDBCUtil;
25 import org.apache.mailet.GenericMailet;
26 import org.apache.mailet.Mail;
27 import org.apache.mailet.MailAddress;
28 import org.apache.mailet.MailetException;
29
30 import javax.mail.MessagingException;
31 import javax.mail.internet.ParseException;
32
33 import java.sql.Connection;
34 import java.sql.DatabaseMetaData;
35 import java.sql.PreparedStatement;
36 import java.sql.ResultSet;
37 import java.sql.SQLException;
38 import java.util.Collection;
39 import java.util.Iterator;
40 import java.util.Vector;
41
42 /***
43 * Rewrites recipient addresses based on a database table. The connection
44 * is configured by passing the URL to a conn definition. You need to set
45 * the table name to check (or view) along with the source and target columns
46 * to use. For example,
47 * <mailet match="All" class="JDBCAlias">
48 * <mappings>db://maildb/Aliases</mappings>
49 * <source_column>source_email_address</source_column>
50 * <target_column>target_email_address</target_column>
51 * </mailet>
52 *
53 */
54 public class JDBCAlias extends GenericMailet {
55
56 protected DataSourceComponent datasource;
57 protected String query = null;
58
59
60 private final JDBCUtil theJDBCUtil =
61 new JDBCUtil() {
62 protected void delegatedLog(String logString) {
63 log("JDBCAlias: " + logString);
64 }
65 };
66
67 /***
68 * Initialize the mailet
69 */
70 public void init() throws MessagingException {
71 String mappingsURL = getInitParameter("mappings");
72
73 String datasourceName = mappingsURL.substring(5);
74 int pos = datasourceName.indexOf("/");
75 String tableName = datasourceName.substring(pos + 1);
76 datasourceName = datasourceName.substring(0, pos);
77
78 Connection conn = null;
79 if (getInitParameter("source_column") == null) {
80 throw new MailetException("source_column not specified for JDBCAlias");
81 }
82 if (getInitParameter("target_column") == null) {
83 throw new MailetException("target_column not specified for JDBCAlias");
84 }
85 try {
86 ServiceManager componentManager = (ServiceManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
87
88 DataSourceSelector datasources = (DataSourceSelector)componentManager.lookup(DataSourceSelector.ROLE);
89
90 datasource = (DataSourceComponent)datasources.select(datasourceName);
91
92 conn = datasource.getConnection();
93
94
95 DatabaseMetaData dbMetaData = conn.getMetaData();
96
97
98 if (!(theJDBCUtil.tableExists(dbMetaData, tableName))) {
99 StringBuffer exceptionBuffer =
100 new StringBuffer(128)
101 .append("Could not find table '")
102 .append(tableName)
103 .append("' in datasource '")
104 .append(datasourceName)
105 .append("'");
106 throw new MailetException(exceptionBuffer.toString());
107 }
108
109
110 StringBuffer queryBuffer =
111 new StringBuffer(128)
112 .append("SELECT ")
113 .append(getInitParameter("target_column"))
114 .append(" FROM ")
115 .append(tableName)
116 .append(" WHERE ")
117 .append(getInitParameter("source_column"))
118 .append(" = ?");
119 query = queryBuffer.toString();
120 } catch (MailetException me) {
121 throw me;
122 } catch (Exception e) {
123 throw new MessagingException("Error initializing JDBCAlias", e);
124 } finally {
125 theJDBCUtil.closeJDBCConnection(conn);
126 }
127 }
128
129 public void service(Mail mail) throws MessagingException {
130
131
132 Connection conn = null;
133 PreparedStatement mappingStmt = null;
134 ResultSet mappingRS = null;
135
136 Collection recipients = mail.getRecipients();
137 Collection recipientsToRemove = new Vector();
138 Collection recipientsToAdd = new Vector();
139 try {
140 conn = datasource.getConnection();
141 mappingStmt = conn.prepareStatement(query);
142
143
144 for (Iterator i = recipients.iterator(); i.hasNext(); ) {
145 try {
146 MailAddress source = (MailAddress)i.next();
147 mappingStmt.setString(1, source.toString());
148 mappingRS = mappingStmt.executeQuery();
149 if (!mappingRS.next()) {
150
151 continue;
152 }
153 try {
154 String targetString = mappingRS.getString(1);
155 MailAddress target = new MailAddress(targetString);
156
157
158 recipientsToRemove.add(source);
159 recipientsToAdd.add(target);
160 } catch (ParseException pe) {
161
162 StringBuffer exceptionBuffer =
163 new StringBuffer(128)
164 .append("There is an invalid alias from ")
165 .append(source)
166 .append(" to ")
167 .append(mappingRS.getString(1));
168 log(exceptionBuffer.toString());
169 continue;
170 }
171 } finally {
172 ResultSet localRS = mappingRS;
173
174 mappingRS = null;
175 theJDBCUtil.closeJDBCResultSet(localRS);
176 }
177 }
178 } catch (SQLException sqle) {
179 throw new MessagingException("Error accessing database", sqle);
180 } finally {
181 theJDBCUtil.closeJDBCStatement(mappingStmt);
182 theJDBCUtil.closeJDBCConnection(conn);
183 }
184
185 recipients.removeAll(recipientsToRemove);
186 recipients.addAll(recipientsToAdd);
187 }
188
189 /***
190 * Return a string describing this mailet.
191 *
192 * @return a string describing this mailet
193 */
194 public String getMailetInfo() {
195 return "JDBC aliasing mailet";
196 }
197
198 }