1 /*****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20 package org.apache.james.transport.mailets;
21
22 import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector;
23 import org.apache.avalon.excalibur.datasource.DataSourceComponent;
24 import org.apache.avalon.framework.service.ServiceManager;
25 import org.apache.james.Constants;
26 import org.apache.james.util.JDBCUtil;
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.sql.Statement;
39 import java.util.Collection;
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="JDBCListserv">
48 * <data_source>maildb</datasource>
49 * <listserv_id>mylistserv</listserv_id>
50 * <listserv_table>source_email_address</listserv_table>
51 * <members_table>target_email_address</members_table>
52 * </mailet>
53 *
54 * This mailet will cache the settings available when first initialized. If you wish
55 * it to reload for each message, add the init parameter
56 * <cache_settings>false</cache_settings>
57 *
58 */
59 public class JDBCListserv extends GenericListserv {
60
61 protected DataSourceComponent datasource;
62 protected String listservID = null;
63 protected String listservTable = null;
64 protected String membersTable = null;
65 protected boolean cacheSettings = true;
66
67
68 protected Collection members = null;
69 protected boolean membersOnly = true;
70 protected boolean attachmentsAllowed = true;
71 protected boolean replyToList = true;
72 protected MailAddress listservAddress = null;
73 protected String subjectPrefix = null;
74
75
76 protected String listservQuery = null;
77 protected String membersQuery = null;
78
79 /***
80 * The JDBCUtil helper class
81 */
82 private final JDBCUtil theJDBCUtil =
83 new JDBCUtil() {
84 protected void delegatedLog(String logString) {
85 log("JDBCListserv: " + logString);
86 }
87 };
88
89 /***
90 * Initialize the mailet
91 */
92 public void init() throws MessagingException {
93 if (getInitParameter("data_source") == null) {
94 throw new MailetException("data_source not specified for JDBCListserv");
95 }
96 if (getInitParameter("listserv_id") == null) {
97 throw new MailetException("listserv_id not specified for JDBCListserv");
98 }
99 if (getInitParameter("listserv_table") == null) {
100 throw new MailetException("listserv_table not specified for JDBCListserv");
101 }
102 if (getInitParameter("members_table") == null) {
103 throw new MailetException("members_table not specified for JDBCListserv");
104 }
105
106 String datasourceName = getInitParameter("data_source");
107 listservID = getInitParameter("listserv_id");
108 listservTable = getInitParameter("listserv_table");
109 membersTable = getInitParameter("members_table");
110
111 if (getInitParameter("cache_settings") != null) {
112 try {
113 cacheSettings = new Boolean(getInitParameter("cache_settings")).booleanValue();
114 } catch (Exception e) {
115
116 }
117 }
118
119 Connection conn = null;
120
121 try {
122 ServiceManager componentManager = (ServiceManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
123
124 DataSourceSelector datasources = (DataSourceSelector)componentManager.lookup(DataSourceSelector.ROLE);
125
126 datasource = (DataSourceComponent)datasources.select(datasourceName);
127
128 conn = datasource.getConnection();
129
130
131 DatabaseMetaData dbMetaData = conn.getMetaData();
132
133
134 if (!(theJDBCUtil.tableExists(dbMetaData, listservTable))) {
135 StringBuffer exceptionBuffer =
136 new StringBuffer(128)
137 .append("Could not find table '")
138 .append(listservTable)
139 .append("' in datasource '")
140 .append(datasourceName)
141 .append("'");
142 throw new MailetException(exceptionBuffer.toString());
143 }
144
145
146
147
148 if (!( theJDBCUtil.tableExists(dbMetaData, membersTable))) {
149 StringBuffer exceptionBuffer =
150 new StringBuffer(128)
151 .append("Could not find table '")
152 .append(membersTable)
153 .append("' in datasource '")
154 .append(datasourceName)
155 .append("'");
156 throw new MailetException(exceptionBuffer.toString());
157 }
158
159 StringBuffer queryBuffer =
160 new StringBuffer(256)
161 .append("SELECT members_only, attachments_allowed, reply_to_list, subject_prefix, list_address FROM ")
162 .append(listservTable)
163 .append(" WHERE listserv_id = ?");
164 listservQuery = queryBuffer.toString();
165 queryBuffer =
166 new StringBuffer(128)
167 .append("SELECT member FROM ")
168 .append(membersTable)
169 .append(" WHERE listserv_id = ?");
170 membersQuery = queryBuffer.toString();
171
172
173 loadSettings();
174 } catch (MailetException me) {
175 throw me;
176 } catch (Exception e) {
177 throw new MessagingException("Error initializing JDBCListserv", e);
178 } finally {
179 theJDBCUtil.closeJDBCConnection(conn);
180 }
181 }
182
183 /***
184 * Returns a Collection of MailAddress objects of members to receive this email
185 */
186 public Collection getMembers() throws MessagingException {
187 if (!cacheSettings) {
188 loadSettings();
189 }
190
191 return members;
192 }
193
194 /***
195 * Returns whether this list should restrict to senders only
196 */
197 public boolean isMembersOnly() throws MessagingException {
198 return membersOnly;
199 }
200
201 /***
202 * Returns whether this listserv allow attachments
203 */
204 public boolean isAttachmentsAllowed() throws MessagingException {
205 return attachmentsAllowed;
206 }
207
208 /***
209 * Returns whether listserv should add reply-to header
210 *
211 * @return whether listserv should add a reply-to header
212 */
213 public boolean isReplyToList() throws MessagingException {
214 return replyToList;
215 }
216
217 /***
218 * The email address that this listserv processes on. If returns null, will use the
219 * recipient of the message, which hopefully will be the correct email address assuming
220 * the matcher was properly specified.
221 */
222 public MailAddress getListservAddress() throws MessagingException {
223 return listservAddress;
224 }
225
226 /***
227 * An optional subject prefix which will be surrounded by [].
228 */
229 public String getSubjectPrefix() throws MessagingException {
230 return subjectPrefix;
231 }
232
233 /***
234 * Loads the configuration settings for this mailet from the database.
235 *
236 * @throws MessagingException if a problem occurs while accessing the database or
237 * the required parameters are not present
238 */
239 protected void loadSettings() throws MessagingException {
240 Connection conn = null;
241 PreparedStatement stmt = null;
242 ResultSet rs = null;
243
244 try {
245
246 conn = datasource.getConnection();
247 try {
248 stmt = conn.prepareStatement(membersQuery);
249 stmt.setString(1, listservID);
250 rs = stmt.executeQuery();
251 Collection tmpMembers = new Vector();
252 while (rs.next()) {
253 String address = rs.getString(1);
254 try {
255 MailAddress mailAddress = new MailAddress(address);
256 tmpMembers.add(mailAddress);
257 } catch (ParseException pe) {
258
259 StringBuffer exceptionBuffer =
260 new StringBuffer(64)
261 .append("error parsing address '")
262 .append(address)
263 .append("' in listserv '")
264 .append(listservID)
265 .append("'");
266 log(exceptionBuffer.toString());
267 }
268 }
269 members = tmpMembers;
270 } finally {
271 ResultSet localRS = rs;
272
273 rs = null;
274 theJDBCUtil.closeJDBCResultSet(localRS);
275 Statement localStmt = stmt;
276
277 stmt = null;
278 theJDBCUtil.closeJDBCStatement(localStmt);
279 }
280
281 stmt = conn.prepareStatement(listservQuery);
282 stmt.setString(1, listservID);
283 rs = stmt.executeQuery();
284 if (!rs.next()) {
285 StringBuffer exceptionBuffer =
286 new StringBuffer(64)
287 .append("Could not find listserv record for '")
288 .append(listservID)
289 .append("'");
290 throw new MailetException(exceptionBuffer.toString());
291 }
292 membersOnly = rs.getBoolean("members_only");
293 attachmentsAllowed = rs.getBoolean("attachments_allowed");
294 replyToList = rs.getBoolean("reply_to_list");
295 subjectPrefix = rs.getString("subject_prefix");
296 String address = rs.getString("list_address");
297 if (address == null) {
298 listservAddress = null;
299 } else {
300 try {
301 listservAddress = new MailAddress(address);
302 } catch (ParseException pe) {
303
304 StringBuffer logBuffer =
305 new StringBuffer(128)
306 .append("invalid listserv address '")
307 .append(listservAddress)
308 .append("' for listserv '")
309 .append(listservID)
310 .append("'");
311 log(logBuffer.toString());
312 listservAddress = null;
313 }
314 }
315 } catch (SQLException sqle) {
316 throw new MailetException("Problem loading settings", sqle);
317 } finally {
318 theJDBCUtil.closeJDBCResultSet(rs);
319 theJDBCUtil.closeJDBCStatement(stmt);
320 theJDBCUtil.closeJDBCConnection(conn);
321 }
322 }
323
324 /***
325 * Return a string describing this mailet.
326 *
327 * @return a string describing this mailet
328 */
329 public String getMailetInfo() {
330 return "JDBC listserv mailet";
331 }
332 }