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: ****************************************************************/package org.apache.james.transport.mailets;
019:
020: import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector;
021: import org.apache.avalon.excalibur.datasource.DataSourceComponent;
022: import org.apache.avalon.framework.service.ServiceManager;
023: import org.apache.james.Constants;
024: import org.apache.james.util.JDBCUtil;
025: import org.apache.mailet.MailAddress;
026: import org.apache.mailet.MailetException;
027:
028: import javax.mail.MessagingException;
029: import javax.mail.internet.ParseException;
030:
031: import java.sql.Connection;
032: import java.sql.DatabaseMetaData;
033: import java.sql.PreparedStatement;
034: import java.sql.ResultSet;
035: import java.sql.SQLException;
036: import java.sql.Statement;
037: import java.util.Collection;
038: import java.util.Vector;
039:
040: /**
041: * Rewrites recipient addresses based on a database table. The connection
042: * is configured by passing the URL to a conn definition. You need to set
043: * the table name to check (or view) along with the source and target columns
044: * to use. For example,
045: * <mailet match="All" class="JDBCListserv">
046: * <data_source>maildb</datasource>
047: * <listserv_id>mylistserv</listserv_id>
048: * <listserv_table>source_email_address</listserv_table>
049: * <members_table>target_email_address</members_table>
050: * </mailet>
051: *
052: * This mailet will cache the settings available when first initialized. If you wish
053: * it to reload for each message, add the init parameter
054: * <cache_settings>false</cache_settings>
055: *
056: */
057: public class JDBCListserv extends GenericListserv {
058:
059: protected DataSourceComponent datasource;
060: protected String listservID = null;
061: protected String listservTable = null;
062: protected String membersTable = null;
063: protected boolean cacheSettings = true;
064:
065: //Settings for this listserv
066: protected Collection members = null;
067: protected boolean membersOnly = true;
068: protected boolean attachmentsAllowed = true;
069: protected boolean replyToList = true;
070: protected MailAddress listservAddress = null;
071: protected String subjectPrefix = null;
072:
073: //Queries to DB
074: protected String listservQuery = null;
075: protected String membersQuery = null;
076:
077: /**
078: * The JDBCUtil helper class
079: */
080: private final JDBCUtil theJDBCUtil = new JDBCUtil() {
081: protected void delegatedLog(String logString) {
082: log("JDBCListserv: " + logString);
083: }
084: };
085:
086: /**
087: * Initialize the mailet
088: */
089: public void init() throws MessagingException {
090: if (getInitParameter("data_source") == null) {
091: throw new MailetException(
092: "data_source not specified for JDBCListserv");
093: }
094: if (getInitParameter("listserv_id") == null) {
095: throw new MailetException(
096: "listserv_id not specified for JDBCListserv");
097: }
098: if (getInitParameter("listserv_table") == null) {
099: throw new MailetException(
100: "listserv_table not specified for JDBCListserv");
101: }
102: if (getInitParameter("members_table") == null) {
103: throw new MailetException(
104: "members_table not specified for JDBCListserv");
105: }
106:
107: String datasourceName = getInitParameter("data_source");
108: listservID = getInitParameter("listserv_id");
109: listservTable = getInitParameter("listserv_table");
110: membersTable = getInitParameter("members_table");
111:
112: if (getInitParameter("cache_settings") != null) {
113: try {
114: cacheSettings = new Boolean(
115: getInitParameter("cache_settings"))
116: .booleanValue();
117: } catch (Exception e) {
118: //ignore error
119: }
120: }
121:
122: Connection conn = null;
123:
124: try {
125: ServiceManager componentManager = (ServiceManager) getMailetContext()
126: .getAttribute(Constants.AVALON_COMPONENT_MANAGER);
127: // Get the DataSourceSelector service
128: DataSourceSelector datasources = (DataSourceSelector) componentManager
129: .lookup(DataSourceSelector.ROLE);
130: // Get the data-source required.
131: datasource = (DataSourceComponent) datasources
132: .select(datasourceName);
133:
134: conn = datasource.getConnection();
135:
136: // Check if the required listserv table exists. If not, complain.
137: DatabaseMetaData dbMetaData = conn.getMetaData();
138: // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
139: // Try UPPER, lower, and MixedCase, to see if the table is there.
140: if (!(theJDBCUtil.tableExists(dbMetaData, listservTable))) {
141: StringBuffer exceptionBuffer = new StringBuffer(128)
142: .append("Could not find table '").append(
143: listservTable).append(
144: "' in datasource '").append(
145: datasourceName).append("'");
146: throw new MailetException(exceptionBuffer.toString());
147: }
148:
149: // Check if the required members table exists. If not, complain.
150: // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
151: // Try UPPER, lower, and MixedCase, to see if the table is there.
152: if (!(theJDBCUtil.tableExists(dbMetaData, membersTable))) {
153: StringBuffer exceptionBuffer = new StringBuffer(128)
154: .append("Could not find table '").append(
155: membersTable).append(
156: "' in datasource '").append(
157: datasourceName).append("'");
158: throw new MailetException(exceptionBuffer.toString());
159: }
160:
161: StringBuffer queryBuffer = new StringBuffer(256)
162: .append(
163: "SELECT members_only, attachments_allowed, reply_to_list, subject_prefix, list_address FROM ")
164: .append(listservTable).append(
165: " WHERE listserv_id = ?");
166: listservQuery = queryBuffer.toString();
167: queryBuffer = new StringBuffer(128).append(
168: "SELECT member FROM ").append(membersTable).append(
169: " WHERE listserv_id = ?");
170: membersQuery = queryBuffer.toString();
171:
172: //Always load settings at least once... if we aren't caching, we will load at each getMembers() call
173: loadSettings();
174: } catch (MailetException me) {
175: throw me;
176: } catch (Exception e) {
177: throw new MessagingException(
178: "Error initializing JDBCListserv", e);
179: } finally {
180: theJDBCUtil.closeJDBCConnection(conn);
181: }
182: }
183:
184: /**
185: * Returns a Collection of MailAddress objects of members to receive this email
186: */
187: public Collection getMembers() throws MessagingException {
188: if (!cacheSettings) {
189: loadSettings();
190: }
191:
192: return members;
193: }
194:
195: /**
196: * Returns whether this list should restrict to senders only
197: */
198: public boolean isMembersOnly() throws MessagingException {
199: return membersOnly;
200: }
201:
202: /**
203: * Returns whether this listserv allow attachments
204: */
205: public boolean isAttachmentsAllowed() throws MessagingException {
206: return attachmentsAllowed;
207: }
208:
209: /**
210: * Returns whether listserv should add reply-to header
211: *
212: * @return whether listserv should add a reply-to header
213: */
214: public boolean isReplyToList() throws MessagingException {
215: return replyToList;
216: }
217:
218: /**
219: * The email address that this listserv processes on. If returns null, will use the
220: * recipient of the message, which hopefully will be the correct email address assuming
221: * the matcher was properly specified.
222: */
223: public MailAddress getListservAddress() throws MessagingException {
224: return listservAddress;
225: }
226:
227: /**
228: * An optional subject prefix which will be surrounded by [].
229: */
230: public String getSubjectPrefix() throws MessagingException {
231: return subjectPrefix;
232: }
233:
234: /**
235: * Loads the configuration settings for this mailet from the database.
236: *
237: * @throws MessagingException if a problem occurs while accessing the database or
238: * the required parameters are not present
239: */
240: protected void loadSettings() throws MessagingException {
241: Connection conn = null;
242: PreparedStatement stmt = null;
243: ResultSet rs = null;
244:
245: try {
246: //Load members
247: conn = datasource.getConnection();
248: try {
249: stmt = conn.prepareStatement(membersQuery);
250: stmt.setString(1, listservID);
251: rs = stmt.executeQuery();
252: Collection tmpMembers = new Vector();
253: while (rs.next()) {
254: String address = rs.getString(1);
255: try {
256: MailAddress mailAddress = new MailAddress(
257: address);
258: tmpMembers.add(mailAddress);
259: } catch (ParseException pe) {
260: //don't stop... just log and continue
261: StringBuffer exceptionBuffer = new StringBuffer(
262: 64).append("error parsing address '")
263: .append(address).append(
264: "' in listserv '").append(
265: listservID).append("'");
266: log(exceptionBuffer.toString());
267: }
268: }
269: members = tmpMembers;
270: } finally {
271: ResultSet localRS = rs;
272: // Clear reference to result set
273: rs = null;
274: theJDBCUtil.closeJDBCResultSet(localRS);
275: Statement localStmt = stmt;
276: // Clear reference to statement
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 = new StringBuffer(64)
286: .append("Could not find listserv record for '")
287: .append(listservID).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: //log and ignore
302: StringBuffer logBuffer = new StringBuffer(128)
303: .append("invalid listserv address '")
304: .append(listservAddress).append(
305: "' for listserv '").append(
306: listservID).append("'");
307: log(logBuffer.toString());
308: listservAddress = null;
309: }
310: }
311: } catch (SQLException sqle) {
312: throw new MailetException("Problem loading settings", sqle);
313: } finally {
314: theJDBCUtil.closeJDBCResultSet(rs);
315: theJDBCUtil.closeJDBCStatement(stmt);
316: theJDBCUtil.closeJDBCConnection(conn);
317: }
318: }
319:
320: /**
321: * Return a string describing this mailet.
322: *
323: * @return a string describing this mailet
324: */
325: public String getMailetInfo() {
326: return "JDBC listserv mailet";
327: }
328: }
|