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