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.MailAddress;
26 import org.apache.mailet.MailetException;
27
28 import javax.mail.MessagingException;
29 import javax.mail.internet.ParseException;
30
31 import java.sql.Connection;
32 import java.sql.DatabaseMetaData;
33 import java.sql.PreparedStatement;
34 import java.sql.ResultSet;
35 import java.sql.SQLException;
36 import java.sql.Statement;
37 import java.util.Collection;
38 import java.util.Vector;
39
40 /***
41 * Rewrites recipient addresses based on a database table. The connection
42 * is configured by passing the URL to a conn definition. You need to set
43 * the table name to check (or view) along with the source and target columns
44 * to use. For example,
45 * <mailet match="All" class="JDBCListserv">
46 * <data_source>maildb</datasource>
47 * <listserv_id>mylistserv</listserv_id>
48 * <listserv_table>source_email_address</listserv_table>
49 * <members_table>target_email_address</members_table>
50 * </mailet>
51 *
52 * This mailet will cache the settings available when first initialized. If you wish
53 * it to reload for each message, add the init parameter
54 * <cache_settings>false</cache_settings>
55 *
56 */
57 public class JDBCListserv extends GenericListserv {
58
59 protected DataSourceComponent datasource;
60 protected String listservID = null;
61 protected String listservTable = null;
62 protected String membersTable = null;
63 protected boolean cacheSettings = true;
64
65
66 protected Collection members = null;
67 protected boolean membersOnly = true;
68 protected boolean attachmentsAllowed = true;
69 protected boolean replyToList = true;
70 protected MailAddress listservAddress = null;
71 protected String subjectPrefix = null;
72
73
74 protected String listservQuery = null;
75 protected String membersQuery = null;
76
77 /***
78 * The JDBCUtil helper class
79 */
80 private final JDBCUtil theJDBCUtil =
81 new JDBCUtil() {
82 protected void delegatedLog(String logString) {
83 log("JDBCListserv: " + logString);
84 }
85 };
86
87 /***
88 * Initialize the mailet
89 */
90 public void init() throws MessagingException {
91 if (getInitParameter("data_source") == null) {
92 throw new MailetException("data_source not specified for JDBCListserv");
93 }
94 if (getInitParameter("listserv_id") == null) {
95 throw new MailetException("listserv_id not specified for JDBCListserv");
96 }
97 if (getInitParameter("listserv_table") == null) {
98 throw new MailetException("listserv_table not specified for JDBCListserv");
99 }
100 if (getInitParameter("members_table") == null) {
101 throw new MailetException("members_table not specified for JDBCListserv");
102 }
103
104 String datasourceName = getInitParameter("data_source");
105 listservID = getInitParameter("listserv_id");
106 listservTable = getInitParameter("listserv_table");
107 membersTable = getInitParameter("members_table");
108
109 if (getInitParameter("cache_settings") != null) {
110 try {
111 cacheSettings = new Boolean(getInitParameter("cache_settings")).booleanValue();
112 } catch (Exception e) {
113
114 }
115 }
116
117 Connection conn = null;
118
119 try {
120 ServiceManager componentManager = (ServiceManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
121
122 DataSourceSelector datasources = (DataSourceSelector)componentManager.lookup(DataSourceSelector.ROLE);
123
124 datasource = (DataSourceComponent)datasources.select(datasourceName);
125
126 conn = datasource.getConnection();
127
128
129 DatabaseMetaData dbMetaData = conn.getMetaData();
130
131
132 if (!(theJDBCUtil.tableExists(dbMetaData, listservTable))) {
133 StringBuffer exceptionBuffer =
134 new StringBuffer(128)
135 .append("Could not find table '")
136 .append(listservTable)
137 .append("' in datasource '")
138 .append(datasourceName)
139 .append("'");
140 throw new MailetException(exceptionBuffer.toString());
141 }
142
143
144
145
146 if (!( theJDBCUtil.tableExists(dbMetaData, membersTable))) {
147 StringBuffer exceptionBuffer =
148 new StringBuffer(128)
149 .append("Could not find table '")
150 .append(membersTable)
151 .append("' in datasource '")
152 .append(datasourceName)
153 .append("'");
154 throw new MailetException(exceptionBuffer.toString());
155 }
156
157 StringBuffer queryBuffer =
158 new StringBuffer(256)
159 .append("SELECT members_only, attachments_allowed, reply_to_list, subject_prefix, list_address FROM ")
160 .append(listservTable)
161 .append(" WHERE listserv_id = ?");
162 listservQuery = queryBuffer.toString();
163 queryBuffer =
164 new StringBuffer(128)
165 .append("SELECT member FROM ")
166 .append(membersTable)
167 .append(" WHERE listserv_id = ?");
168 membersQuery = queryBuffer.toString();
169
170
171 loadSettings();
172 } catch (MailetException me) {
173 throw me;
174 } catch (Exception e) {
175 throw new MessagingException("Error initializing JDBCListserv", e);
176 } finally {
177 theJDBCUtil.closeJDBCConnection(conn);
178 }
179 }
180
181 /***
182 * Returns a Collection of MailAddress objects of members to receive this email
183 */
184 public Collection getMembers() throws MessagingException {
185 if (!cacheSettings) {
186 loadSettings();
187 }
188
189 return members;
190 }
191
192 /***
193 * Returns whether this list should restrict to senders only
194 */
195 public boolean isMembersOnly() throws MessagingException {
196 return membersOnly;
197 }
198
199 /***
200 * Returns whether this listserv allow attachments
201 */
202 public boolean isAttachmentsAllowed() throws MessagingException {
203 return attachmentsAllowed;
204 }
205
206 /***
207 * Returns whether listserv should add reply-to header
208 *
209 * @return whether listserv should add a reply-to header
210 */
211 public boolean isReplyToList() throws MessagingException {
212 return replyToList;
213 }
214
215 /***
216 * The email address that this listserv processes on. If returns null, will use the
217 * recipient of the message, which hopefully will be the correct email address assuming
218 * the matcher was properly specified.
219 */
220 public MailAddress getListservAddress() throws MessagingException {
221 return listservAddress;
222 }
223
224 /***
225 * An optional subject prefix which will be surrounded by [].
226 */
227 public String getSubjectPrefix() throws MessagingException {
228 return subjectPrefix;
229 }
230
231 /***
232 * Loads the configuration settings for this mailet from the database.
233 *
234 * @throws MessagingException if a problem occurs while accessing the database or
235 * the required parameters are not present
236 */
237 protected void loadSettings() throws MessagingException {
238 Connection conn = null;
239 PreparedStatement stmt = null;
240 ResultSet rs = null;
241
242 try {
243
244 conn = datasource.getConnection();
245 try {
246 stmt = conn.prepareStatement(membersQuery);
247 stmt.setString(1, listservID);
248 rs = stmt.executeQuery();
249 Collection tmpMembers = new Vector();
250 while (rs.next()) {
251 String address = rs.getString(1);
252 try {
253 MailAddress mailAddress = new MailAddress(address);
254 tmpMembers.add(mailAddress);
255 } catch (ParseException pe) {
256
257 StringBuffer exceptionBuffer =
258 new StringBuffer(64)
259 .append("error parsing address '")
260 .append(address)
261 .append("' in listserv '")
262 .append(listservID)
263 .append("'");
264 log(exceptionBuffer.toString());
265 }
266 }
267 members = tmpMembers;
268 } finally {
269 ResultSet localRS = rs;
270
271 rs = null;
272 theJDBCUtil.closeJDBCResultSet(localRS);
273 Statement localStmt = stmt;
274
275 stmt = null;
276 theJDBCUtil.closeJDBCStatement(localStmt);
277 }
278
279 stmt = conn.prepareStatement(listservQuery);
280 stmt.setString(1, listservID);
281 rs = stmt.executeQuery();
282 if (!rs.next()) {
283 StringBuffer exceptionBuffer =
284 new StringBuffer(64)
285 .append("Could not find listserv record for '")
286 .append(listservID)
287 .append("'");
288 throw new MailetException(exceptionBuffer.toString());
289 }
290 membersOnly = rs.getBoolean("members_only");
291 attachmentsAllowed = rs.getBoolean("attachments_allowed");
292 replyToList = rs.getBoolean("reply_to_list");
293 subjectPrefix = rs.getString("subject_prefix");
294 String address = rs.getString("list_address");
295 if (address == null) {
296 listservAddress = null;
297 } else {
298 try {
299 listservAddress = new MailAddress(address);
300 } catch (ParseException pe) {
301
302 StringBuffer logBuffer =
303 new StringBuffer(128)
304 .append("invalid listserv address '")
305 .append(listservAddress)
306 .append("' for listserv '")
307 .append(listservID)
308 .append("'");
309 log(logBuffer.toString());
310 listservAddress = null;
311 }
312 }
313 } catch (SQLException sqle) {
314 throw new MailetException("Problem loading settings", sqle);
315 } finally {
316 theJDBCUtil.closeJDBCResultSet(rs);
317 theJDBCUtil.closeJDBCStatement(stmt);
318 theJDBCUtil.closeJDBCConnection(conn);
319 }
320 }
321
322 /***
323 * Return a string describing this mailet.
324 *
325 * @return a string describing this mailet
326 */
327 public String getMailetInfo() {
328 return "JDBC listserv mailet";
329 }
330 }