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.GenericMailet;
026: import org.apache.mailet.Mail;
027: import org.apache.mailet.MailAddress;
028: import org.apache.mailet.MailetException;
029:
030: import javax.mail.MessagingException;
031: import javax.mail.internet.ParseException;
032:
033: import java.sql.Connection;
034: import java.sql.DatabaseMetaData;
035: import java.sql.PreparedStatement;
036: import java.sql.ResultSet;
037: import java.sql.SQLException;
038: import java.util.Collection;
039: import java.util.Iterator;
040: import java.util.Vector;
041:
042: /**
043: * Rewrites recipient addresses based on a database table. The connection
044: * is configured by passing the URL to a conn definition. You need to set
045: * the table name to check (or view) along with the source and target columns
046: * to use. For example,
047: * <mailet match="All" class="JDBCAlias">
048: * <mappings>db://maildb/Aliases</mappings>
049: * <source_column>source_email_address</source_column>
050: * <target_column>target_email_address</target_column>
051: * </mailet>
052: *
053: */
054: public class JDBCAlias extends GenericMailet {
055:
056: protected DataSourceComponent datasource;
057: protected String query = null;
058:
059: // The JDBCUtil helper class
060: private final JDBCUtil theJDBCUtil = new JDBCUtil() {
061: protected void delegatedLog(String logString) {
062: log("JDBCAlias: " + logString);
063: }
064: };
065:
066: /**
067: * Initialize the mailet
068: */
069: public void init() throws MessagingException {
070: String mappingsURL = getInitParameter("mappings");
071:
072: String datasourceName = mappingsURL.substring(5);
073: int pos = datasourceName.indexOf("/");
074: String tableName = datasourceName.substring(pos + 1);
075: datasourceName = datasourceName.substring(0, pos);
076:
077: Connection conn = null;
078: if (getInitParameter("source_column") == null) {
079: throw new MailetException(
080: "source_column not specified for JDBCAlias");
081: }
082: if (getInitParameter("target_column") == null) {
083: throw new MailetException(
084: "target_column not specified for JDBCAlias");
085: }
086: try {
087: ServiceManager componentManager = (ServiceManager) getMailetContext()
088: .getAttribute(Constants.AVALON_COMPONENT_MANAGER);
089: // Get the DataSourceSelector service
090: DataSourceSelector datasources = (DataSourceSelector) componentManager
091: .lookup(DataSourceSelector.ROLE);
092: // Get the data-source required.
093: datasource = (DataSourceComponent) datasources
094: .select(datasourceName);
095:
096: conn = datasource.getConnection();
097:
098: // Check if the required table exists. If not, complain.
099: DatabaseMetaData dbMetaData = conn.getMetaData();
100: // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
101: // Try UPPER, lower, and MixedCase, to see if the table is there.
102: if (!(theJDBCUtil.tableExists(dbMetaData, tableName))) {
103: StringBuffer exceptionBuffer = new StringBuffer(128)
104: .append("Could not find table '").append(
105: tableName).append("' in datasource '")
106: .append(datasourceName).append("'");
107: throw new MailetException(exceptionBuffer.toString());
108: }
109:
110: //Build the query
111: StringBuffer queryBuffer = new StringBuffer(128).append(
112: "SELECT ")
113: .append(getInitParameter("target_column")).append(
114: " FROM ").append(tableName).append(
115: " WHERE ").append(
116: getInitParameter("source_column")).append(
117: " = ?");
118: query = queryBuffer.toString();
119: } catch (MailetException me) {
120: throw me;
121: } catch (Exception e) {
122: throw new MessagingException(
123: "Error initializing JDBCAlias", e);
124: } finally {
125: theJDBCUtil.closeJDBCConnection(conn);
126: }
127: }
128:
129: public void service(Mail mail) throws MessagingException {
130: //Then loop through each address in the recipient list and try to map it according to the alias table
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: for (Iterator i = recipients.iterator(); i.hasNext();) {
144: try {
145: MailAddress source = (MailAddress) i.next();
146: mappingStmt.setString(1, source.toString());
147: mappingRS = mappingStmt.executeQuery();
148: if (!mappingRS.next()) {
149: //This address was not found
150: continue;
151: }
152: try {
153: String targetString = mappingRS.getString(1);
154: MailAddress target = new MailAddress(
155: targetString);
156:
157: //Mark this source address as an address to remove from the recipient list
158: recipientsToRemove.add(source);
159: recipientsToAdd.add(target);
160: } catch (ParseException pe) {
161: //Don't alias this address... there's an invalid address mapping here
162: StringBuffer exceptionBuffer = new StringBuffer(
163: 128).append(
164: "There is an invalid alias from ")
165: .append(source).append(" to ").append(
166: mappingRS.getString(1));
167: log(exceptionBuffer.toString());
168: continue;
169: }
170: } finally {
171: ResultSet localRS = mappingRS;
172: // Clear reference to result set
173: mappingRS = null;
174: theJDBCUtil.closeJDBCResultSet(localRS);
175: }
176: }
177: } catch (SQLException sqle) {
178: throw new MessagingException("Error accessing database",
179: 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: }
|