Author: norman Date: Fri Oct 13 07:11:36 2006 New Revision: 463685 URL: http://svn.apache.org/viewvc?view=rev&rev=463685 Log: First steps for VUT Service. See JAMES-582
Added: james/server/trunk/src/java/org/apache/james/services/VirtualUserTable.java (with props) james/server/trunk/src/java/org/apache/james/services/VirtualUserTableManagement.java (with props) james/server/trunk/src/java/org/apache/james/vut/ james/server/trunk/src/java/org/apache/james/vut/AbstractVirtualUserTable.java (with props) james/server/trunk/src/java/org/apache/james/vut/ErrorMappingException.java (with props) james/server/trunk/src/java/org/apache/james/vut/InvalidMappingException.java (with props) james/server/trunk/src/java/org/apache/james/vut/JDBCVirtualUserTable.java (with props) james/server/trunk/src/test/org/apache/james/vut/ james/server/trunk/src/test/org/apache/james/vut/AbstractVirtualUserTableTest.java (with props) james/server/trunk/src/test/org/apache/james/vut/JDBCVirtualUserTableTest.java (with props) Modified: james/server/trunk/src/conf/sqlResources.xml james/server/trunk/src/java/org/apache/james/util/VirtualUserTableUtil.java Modified: james/server/trunk/src/conf/sqlResources.xml URL: http://svn.apache.org/viewvc/james/server/trunk/src/conf/sqlResources.xml?view=diff&rev=463685&r1=463684&r2=463685 ============================================================================== --- james/server/trunk/src/conf/sqlResources.xml (original) +++ james/server/trunk/src/conf/sqlResources.xml Fri Oct 13 07:11:36 2006 @@ -984,7 +984,100 @@ PRIMARY KEY (ipaddress,sender,recip) ) </sql> +</sqlDefs> +<!-- SQL statements for the JdbcVirtualUserTable --> +<sqlDefs name="org.apache.james.vut.JDBCVirtualUserTable"> + + <!-- Statements used to check whether a particular message exists in this repository. --> + <sql name="selectMappings">select VirtualUserTable.target_address from VirtualUserTable, VirtualUserTable as VUTDomains +where ((VirtualUserTable."user") like ? or (VirtualUserTable."user") like '\%') +and (VirtualUserTable.domain like ? +or (VirtualUserTable.domain like '\%' and VUTDomains.domain like ?)) </sql> + <sql name="deleteMapping">delete from VirtualUserTable where VirtualUserTable."user" = ? and VirtualUserTable.domain = ? and VirtualUserTable.target_address = ?</sql> + <sql name="updateMapping">update VirtualUserTable set VirtualUserTable.target_address = ? where VirtualUserTable."user" = ? and VirtualUserTable.domain = ? </sql> + <sql name="addMapping">insert into VirtualUserTable values(?,?,?) </sql> + <!-- Statements used to create the table associated with this class. --> + <sql name="createTable" db="mysql"> + CREATE TABLE VirtualUserTable ( + user varchar(64) NOT NULL default '', + domain varchar(255) NOT NULL default '', + target_address varchar(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="hypersonic"> + CREATE CACHED TABLE VirtualUserTable ( + user varchar(64) NOT NULL default '', + domain varchar(255) NOT NULL default '', + target_address varchar(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="hsqldb"> + CREATE CACHED TABLE VirtualUserTable ( + user varchar(64) NOT NULL default '', + domain varchar(255) NOT NULL default '', + target_address varchar(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="mssql"> + CREATE TABLE [VirtualUserTable] ( + [user] [varchar] (64) NOT NULL default '', + [domain] [varchar] (255) NOT NULL default '', + [target_address] [varchar] (255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="oracle"> + CREATE TABLE VirtualUserTable ( + user varchar2(64) NOT NULL default '', + domain varchar2(255) NOT NULL default '', + target_address varchar2(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="postgresql"> + CREATE TABLE VirtualUserTable ( + user varchar(64) NOT NULL default '', + domain varchar(255) NOT NULL default '', + target_address varchar(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="sapdb"> + CREATE TABLE VirtualUserTable ( + user varchar(64) NOT NULL default '', + domain varchar(255) NOT NULL default '', + target_address varchar(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="db2"> + CREATE TABLE VirtualUserTable ( + user varchar(64) NOT NULL default '', + domain varchar(255) NOT NULL default '', + target_address varchar(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="ingres"> + CREATE TABLE VirtualUserTable ( + user varchar(64) NOT NULL default '', + domain varchar(255) NOT NULL default '', + target_address varchar(255) NOT NULL default '', + PRIMARY KEY (user,domain) + ) + </sql> + <sql name="createTable" db="derby"> + CREATE TABLE VirtualUserTable ( + "user" varchar (64) NOT NULL default '', + domain varchar (255) NOT NULL default '', + target_address varchar (255) NOT NULL default '', + PRIMARY KEY ("user",domain) + ) + </sql> </sqlDefs> </sqlResources> Added: james/server/trunk/src/java/org/apache/james/services/VirtualUserTable.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/services/VirtualUserTable.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/java/org/apache/james/services/VirtualUserTable.java (added) +++ james/server/trunk/src/java/org/apache/james/services/VirtualUserTable.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,41 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + + + +package org.apache.james.services; + +import java.util.Collection; + +import org.apache.james.vut.ErrorMappingException; + +public interface VirtualUserTable { + + public static final String ROLE = "org.apache.james.services.VirtualUserTable"; + + /** + * Return the mapped MailAddress for the given address. Return null if no + * matched mapping was found + * + * @param mailaddress the MailAddress + * @return the mapped mailAddress + * @throws ErrorMappingException + */ + public Collection getMappings(String user, String domain) throws ErrorMappingException; +} Propchange: james/server/trunk/src/java/org/apache/james/services/VirtualUserTable.java ------------------------------------------------------------------------------ svn:eol-style = native Added: james/server/trunk/src/java/org/apache/james/services/VirtualUserTableManagement.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/services/VirtualUserTableManagement.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/java/org/apache/james/services/VirtualUserTableManagement.java (added) +++ james/server/trunk/src/java/org/apache/james/services/VirtualUserTableManagement.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,36 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + + + +package org.apache.james.services; + +import org.apache.james.vut.InvalidMappingException; + +public interface VirtualUserTableManagement extends VirtualUserTable{ + + public static final String ROLE = "org.apache.james.services.VirtualUserTableManagement"; + + public boolean addRegexMapping(String user, String domain, String regex) throws InvalidMappingException; + public boolean removeRegexMapping(String user,String domain, String regex); + public boolean addAddressMapping(String user, String domain, String address) throws InvalidMappingException; + public boolean removeAddressMapping(String user,String domain, String address); + public boolean addErrorMapping(String user, String domain, String error) throws InvalidMappingException; + public boolean removeErrorMapping(String user,String domain, String error); +} Propchange: james/server/trunk/src/java/org/apache/james/services/VirtualUserTableManagement.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: james/server/trunk/src/java/org/apache/james/util/VirtualUserTableUtil.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/util/VirtualUserTableUtil.java?view=diff&rev=463685&r1=463684&r2=463685 ============================================================================== --- james/server/trunk/src/java/org/apache/james/util/VirtualUserTableUtil.java (original) +++ james/server/trunk/src/java/org/apache/james/util/VirtualUserTableUtil.java Fri Oct 13 07:11:36 2006 @@ -21,6 +21,8 @@ package org.apache.james.util; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; @@ -56,6 +58,7 @@ String result = null; + //TODO: Throw exception on invalid syntax ? int msgPos = targetString.indexOf(':', "regex:".length() + 1); // log("regex: targetString = " + targetString); @@ -143,4 +146,22 @@ } return mappings; } + + + /** + * Return a Collection which holds the extracted mappings of the given String + * + * @param rawMapping + * @return + */ + public static Collection getMappings(String rawMapping) { + ArrayList map = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(rawMapping, + VirtualUserTableUtil.getSeparator(rawMapping)); + + while (tokenizer.hasMoreTokens()) { + map.add(tokenizer.nextToken().trim()); + } + return map; + } } Added: james/server/trunk/src/java/org/apache/james/vut/AbstractVirtualUserTable.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/vut/AbstractVirtualUserTable.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/java/org/apache/james/vut/AbstractVirtualUserTable.java (added) +++ james/server/trunk/src/java/org/apache/james/vut/AbstractVirtualUserTable.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,294 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + + + +package org.apache.james.vut; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.StringTokenizer; + +import javax.mail.internet.ParseException; + +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.james.services.VirtualUserTable; +import org.apache.james.services.VirtualUserTableManagement; +import org.apache.james.util.VirtualUserTableUtil; +import org.apache.mailet.MailAddress; +import org.apache.oro.text.regex.MalformedPatternException; +import org.apache.oro.text.regex.Perl5Compiler; + +public abstract class AbstractVirtualUserTable extends AbstractLogEnabled + implements VirtualUserTable, VirtualUserTableManagement { + + /** + * @see org.apache.james.services.VirtualUserTable#getMapping(org.apache.mailet.MailAddress) + */ + public Collection getMappings(String user,String domain) throws ErrorMappingException { + Collection mappings = new ArrayList(); + + String targetString = mapAddress(user, domain); + + + // Only non-null mappings are translated + if (targetString != null) { + if (targetString.startsWith("error:")) { + throw new ErrorMappingException(targetString.substring("error:".length())); + + } else { + Iterator map= VirtualUserTableUtil.getMappings(targetString).iterator(); + + while (map.hasNext()) { + String target; + String targetAddress = map.next().toString(); + + if (targetAddress.startsWith("regex:")) { + try { + targetAddress = VirtualUserTableUtil.regexMap(new MailAddress(user,domain), targetAddress); + } catch (MalformedPatternException e) { + getLogger().error("Exception during regexMap processing: ", e); + } catch (ParseException e) { + // should never happen + } + + if (targetAddress == null) continue; + } + + if (targetAddress.indexOf('@') < 0) { + target = targetAddress + "@localhost"; + } else { + target = targetAddress; + } + + // add mapping + mappings.add(target); + + StringBuffer buf = new StringBuffer().append("Valid virtual user mapping ") + .append(user).append("@").append(domain) + .append(" to ").append(targetAddress); + getLogger().debug(buf.toString()); + + } + } + } + return mappings; + } + + /** + * @see org.apache.james.services.VirtualUserTableManagement#addRegexMapping(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean addRegexMapping(String user, String domain, String regex) throws InvalidMappingException { + // TODO: More logging + + if (validUserString(user) == false) { + throw new InvalidMappingException("Invalid user: " + user); + } + if(validDomainString(domain) == false) { + throw new InvalidMappingException("Invalid domain: " + domain); + } + + try { + new Perl5Compiler().compile(regex); + } catch (MalformedPatternException e) { + throw new InvalidMappingException("Invalid regex: " + regex); + } + return addMappingInternal(user,domain,"regex:" + regex); + } + + + /** + * @see org.apache.james.services.VirtualUserTableManagement#removeRegexMapping(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean removeRegexMapping(String user, String domain, String regex) { + // TODO: More logging + + return removeMappingInternal(user,domain,"regex:" + regex); + } + + /** + * @see org.apache.james.services.VirtualUserTableManagement#addAddressMapping(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean addAddressMapping(String user, String domain, String address) throws InvalidMappingException { + // TODO: More logging + + if (validUserString(user) == false) { + throw new InvalidMappingException("Invalid user: " + user); + } + if(validDomainString(domain) == false) { + throw new InvalidMappingException("Invalid domain: " + domain); + } + + if (address.indexOf('@') < 0) { + address = address + "@localhost"; + } + try { + new MailAddress(address); + } catch (ParseException e) { + throw new InvalidMappingException("Invalid emailAddress: " + address); + } + return addMappingInternal(user,domain, address); + } + + /** + * @see org.apache.james.services.VirtualUserTableManagement#removeAddressMapping(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean removeAddressMapping(String user, String domain, String address) { + // TODO: More logging + + if (address.indexOf('@') < 0) { + address = address + "@localhost"; + } + return removeMappingInternal(user,domain,address); + } + + /** + * @throws InvalidMappingException + * @see org.apache.james.services.VirtualUserTableManagement#addErrorMapping(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean addErrorMapping(String user, String domain, String error) throws InvalidMappingException { + // TODO: More logging + + if (validUserString(user) == false) { + throw new InvalidMappingException("Invalid user: " + user); + } + if(validDomainString(domain) == false) { + throw new InvalidMappingException("Invalid domain: " + domain); + } + + return addMappingInternal(user,domain, "error:" + error); + } + + /** + * @see org.apache.james.services.VirtualUserTableManagement#removeErrorMapping(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean removeErrorMapping(String user, String domain, String error) { + // TODO: More logging + + return removeMappingInternal(user,domain,"error:" + error); + } + + + /** + * Convert a raw mapping String to a Collection + * + * @param rawMapping the mapping Strin + * @return map a collection which holds all mappings + */ + protected ArrayList mappingToColletion(String rawMapping) { + ArrayList map = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(rawMapping, + VirtualUserTableUtil.getSeparator(rawMapping)); + + while (tokenizer.hasMoreTokens()) { + map.add(tokenizer.nextToken().trim()); + } + return map; + } + + + /** + * Convert a Collection which holds mappings to a raw mapping String + * + * @param map the Collection + * @return mapping the mapping String + */ + protected String CollectionToMapping(Collection map) { + StringBuffer mapping = new StringBuffer(); + + Iterator mappings = map.iterator(); + + while (mappings.hasNext()) { + mapping.append(mappings.next()); + + if (mappings.hasNext()) { + mapping.append(";"); + } + } + + return mapping.toString(); + + } + + /** + * Return true if the userString is valid + * TODO: More checkin ? + * + * @param user the userString + * @return true of false + */ + private boolean validUserString(String user) { + if(user.endsWith("@%") || user.indexOf("@") < 0) { + return true; + } + return false; + } + + /** + * Return true if the domainString is valid + * TODO: More checkin ? + * + * @param domain the domainString + * @return true of false + */ + private boolean validDomainString(String domain) { + if (domain.startsWith("%@") || domain.indexOf("@") < 0) { + return true; + } + return false; + } + + + /** + * Override to map virtual recipients to real recipients, both local and non-local. + * Each key in the provided map corresponds to a potential virtual recipient, stored as + * a <code>MailAddress</code> object. + * + * Translate virtual recipients to real recipients by mapping a string containing the + * address of the real recipient as a value to a key. Leave the value <code>null<code> + * if no mapping should be performed. Multiple recipients may be specified by delineating + * the mapped string with commas, semi-colons or colons. + * + * @param recipient the mapping of virtual to real recipients, as + * <code>MailAddress</code>es to <code>String</code>s. + */ + protected abstract String mapAddress(String user, String domain); + + /** + * Add new mapping + * + * @param user the user + * @param domain the domain + * @param mapping the mapping + * @return true if successfully + */ + public abstract boolean addMappingInternal(String user, String domain, String mapping); + + /** + * Remove mapping + * + * @param user the user + * @param domain the domain + * @param mapping the mapping + * @return true if successfully + */ + public abstract boolean removeMappingInternal(String user, String domain, String mapping); + +} Propchange: james/server/trunk/src/java/org/apache/james/vut/AbstractVirtualUserTable.java ------------------------------------------------------------------------------ svn:eol-style = native Added: james/server/trunk/src/java/org/apache/james/vut/ErrorMappingException.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/vut/ErrorMappingException.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/java/org/apache/james/vut/ErrorMappingException.java (added) +++ james/server/trunk/src/java/org/apache/james/vut/ErrorMappingException.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,29 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + + +package org.apache.james.vut; + +public class ErrorMappingException extends Exception { + + public ErrorMappingException(String string) { + super(string); + } + +} Propchange: james/server/trunk/src/java/org/apache/james/vut/ErrorMappingException.java ------------------------------------------------------------------------------ svn:eol-style = native Added: james/server/trunk/src/java/org/apache/james/vut/InvalidMappingException.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/vut/InvalidMappingException.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/java/org/apache/james/vut/InvalidMappingException.java (added) +++ james/server/trunk/src/java/org/apache/james/vut/InvalidMappingException.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,30 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + + + +package org.apache.james.vut; + +public class InvalidMappingException extends Exception { + + public InvalidMappingException(String string) { + super(string); + } + +} Propchange: james/server/trunk/src/java/org/apache/james/vut/InvalidMappingException.java ------------------------------------------------------------------------------ svn:eol-style = native Added: james/server/trunk/src/java/org/apache/james/vut/JDBCVirtualUserTable.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/vut/JDBCVirtualUserTable.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/java/org/apache/james/vut/JDBCVirtualUserTable.java (added) +++ james/server/trunk/src/java/org/apache/james/vut/JDBCVirtualUserTable.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,413 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + + + + +package org.apache.james.vut; + +import java.io.File; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector; +import org.apache.avalon.excalibur.datasource.DataSourceComponent; +import org.apache.avalon.framework.activity.Initializable; +import org.apache.avalon.framework.configuration.Configurable; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.Serviceable; +import org.apache.james.services.FileSystem; +import org.apache.james.util.JDBCUtil; +import org.apache.james.util.SqlResources; + +public class JDBCVirtualUserTable extends AbstractVirtualUserTable implements Configurable,Serviceable, Initializable{ + + private DataSourceSelector datasources = null; + private DataSourceComponent dataSourceComponent = null; + private String tableName = null; + private String dataSourceName = null; + + /** + * Contains all of the sql strings for this component. + */ + protected SqlResources sqlQueries; + + /** + * The name of the SQL configuration file to be used to configure this repository. + */ + private String sqlFileName; + + private FileSystem fileSystem; + + protected String datasourceName; + + + /** + * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) + */ + public void service(ServiceManager arg0) throws ServiceException { + datasources = (DataSourceSelector)arg0.lookup(DataSourceSelector.ROLE); + setFileSystem((FileSystem) arg0.lookup(FileSystem.ROLE)); + } + + /** + * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) + */ + public void configure(Configuration arg0) throws ConfigurationException { + String destination = arg0.getAttribute("destinationURL"); + // normalize the destination, to simplify processing. + if ( ! destination.endsWith("/") ) { + destination += "/"; + } + // Parse the DestinationURL for the name of the datasource, + // the table to use, and the (optional) repository Key. + // Split on "/", starting after "db://" + List urlParams = new ArrayList(); + int start = 5; + + int end = destination.indexOf('/', start); + while ( end > -1 ) { + urlParams.add(destination.substring(start, end)); + start = end + 1; + end = destination.indexOf('/', start); + } + + // Build SqlParameters and get datasource name from URL parameters + if (urlParams.size() == 0) { + StringBuffer exceptionBuffer = + new StringBuffer(256) + .append("Malformed destinationURL - Must be of the format '") + .append("db://<data-source>[/<table>[/<repositoryName>]]'. Was passed ") + .append(arg0.getAttribute("destinationURL")); + throw new ConfigurationException(exceptionBuffer.toString()); + } + if (urlParams.size() >= 1) { + dataSourceName = (String)urlParams.get(0); + } + if (urlParams.size() >= 2) { + tableName = (String)urlParams.get(1); + } + + + if (getLogger().isDebugEnabled()) { + StringBuffer logBuffer = + new StringBuffer(128) + .append("Parsed URL: table = '") + .append(tableName) + .append("'"); + getLogger().debug(logBuffer.toString()); + } + + sqlFileName = arg0.getChild("sqlFile").getValue(); + if (!sqlFileName.startsWith("file://")) { + throw new ConfigurationException + ("Malformed sqlFile - Must be of the format 'file://<filename>'."); + } + } + + /** + * @see org.apache.avalon.framework.activity.Initializable#initialize() + */ + public void initialize() throws Exception { + + setDataSourceComponent((DataSourceComponent) datasources.select(dataSourceName)); + + StringBuffer logBuffer = null; + if (getLogger().isDebugEnabled()) { + getLogger().debug(this.getClass().getName() + ".initialize()"); + } + + // Test the connection to the database, by getting the DatabaseMetaData. + Connection conn = dataSourceComponent.getConnection(); + PreparedStatement createStatement = null; + + try { + // Initialise the sql strings. + + File sqlFile = null; + try { + sqlFile = fileSystem.getFile(sqlFileName); + sqlFileName = null; + } catch (Exception e) { + getLogger().fatalError(e.getMessage(), e); + throw e; + } + + if (getLogger().isDebugEnabled()) { + logBuffer = + new StringBuffer(128) + .append("Reading SQL resources from file: ") + .append(sqlFile.getAbsolutePath()) + .append(", section ") + .append(this.getClass().getName()) + .append("."); + getLogger().debug(logBuffer.toString()); + } + + // Build the statement parameters + Map sqlParameters = new HashMap(); + if (tableName != null) { + sqlParameters.put("table", tableName); + } + + sqlQueries = new SqlResources(); + sqlQueries.init(sqlFile, this.getClass().getName(), + conn, sqlParameters); + + // Check if the required table exists. If not, create it. + DatabaseMetaData dbMetaData = conn.getMetaData(); + // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo. + // Try UPPER, lower, and MixedCase, to see if the table is there. + + if (!(theJDBCUtil.tableExists(dbMetaData, tableName))) { + + // Users table doesn't exist - create it. + createStatement = + conn.prepareStatement(sqlQueries.getSqlString("createTable", true)); + createStatement.execute(); + + if (getLogger().isInfoEnabled()) { + logBuffer = + new StringBuffer(64) + .append("JdbcVirtalUserTable: Created table '") + .append(tableName) + .append("'."); + getLogger().info(logBuffer.toString()); + } + } + + + } finally { + theJDBCUtil.closeJDBCStatement(createStatement); + theJDBCUtil.closeJDBCConnection(conn); + } + } + + /** + * The JDBCUtil helper class + */ + private final JDBCUtil theJDBCUtil = new JDBCUtil() { + protected void delegatedLog(String logString) { + getLogger().debug("JDBCVirtualUserTable: " + logString); + } + }; + + + public void setDataSourceComponent(DataSourceComponent dataSourceComponent) { + this.dataSourceComponent = dataSourceComponent; + } + + + public void setFileSystem(FileSystem fileSystem) { + this.fileSystem = fileSystem; + } + + /** + * @see org.apache.james.vut.AbstractVirtualUserTable#mapAddress(java.lang.String, java.lang.String) + */ + public String mapAddress(String user, String domain) { + Connection conn = null; + PreparedStatement mappingStmt = null; + try { + conn = dataSourceComponent.getConnection(); + mappingStmt = conn.prepareStatement(sqlQueries.getSqlString("selectMappings", true)); + + ResultSet mappingRS = null; + try { + mappingStmt.setString(1, user); + mappingStmt.setString(2, domain); + mappingStmt.setString(3, domain); + mappingRS = mappingStmt.executeQuery(); + if (mappingRS.next()) { + return mappingRS.getString(1); + } + } finally { + theJDBCUtil.closeJDBCResultSet(mappingRS); + } + + } catch (SQLException sqle) { + System.out.println("SSQL:"+ sqlQueries.getSqlString("selectMappings", true)); + getLogger().error("Error accessing database", sqle); + } finally { + theJDBCUtil.closeJDBCStatement(mappingStmt); + theJDBCUtil.closeJDBCConnection(conn); + } + return null; + } + + /** + * @see org.apache.james.vut.AbstractVirtualUserTable#removeRegexMappingInternal(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean removeMappingInternal(String user, String domain, String regex) { + String mapping = mapAddress(user,domain); + if (mapping != null) { + ArrayList map = mappingToColletion(mapping); + map.remove(regex); + + if (map.size() == 0) { + return removeMapping(user,domain,regex); + } else { + return updateMapping(user,domain,CollectionToMapping(map)); + } + } + return false; + } + + + /** + * @see org.apache.james.vut.AbstractVirtualUserTable#addRegexMappingInternal(java.lang.String, java.lang.String, java.lang.String) + */ + public boolean addMappingInternal(String user, String domain, String regex) { + String mapping = mapAddress(user,domain); + if (mapping != null) { + ArrayList map = mappingToColletion(mapping); + map.add(regex); + + return updateMapping(user,domain,CollectionToMapping(map)); + } + return addMapping(user,domain,regex); + } + + /** + * Update the mapping for the given user and domain + * + * @param user the user + * @param domain the domain + * @param mapping the mapping + * @return true if update was successfully + */ + private boolean updateMapping(String user, String domain, String mapping) { + Connection conn = null; + PreparedStatement mappingStmt = null; + + try { + conn = dataSourceComponent.getConnection(); + mappingStmt = conn.prepareStatement(sqlQueries.getSqlString( + "updateMapping", true)); + + ResultSet mappingRS = null; + try { + mappingStmt.setString(1, mapping); + mappingStmt.setString(2, user); + mappingStmt.setString(3, domain); + if (mappingStmt.executeUpdate()> 0) { + return true; + } + } finally { + theJDBCUtil.closeJDBCResultSet(mappingRS); + } + + } catch (SQLException sqle) { + getLogger().error("Error accessing database", sqle); + } finally { + theJDBCUtil.closeJDBCStatement(mappingStmt); + theJDBCUtil.closeJDBCConnection(conn); + } + return false; + } + + + /** + * Remove a mapping for the given user and domain + * + * @param user the user + * @param domain the domain + * @param mapping the mapping + * @return true if succesfully + */ + private boolean removeMapping(String user, String domain, String mapping) { + Connection conn = null; + PreparedStatement mappingStmt = null; + + try { + conn = dataSourceComponent.getConnection(); + mappingStmt = conn.prepareStatement(sqlQueries.getSqlString( + "deleteMapping", true)); + + ResultSet mappingRS = null; + try { + mappingStmt.setString(1, user); + mappingStmt.setString(2, domain); + mappingStmt.setString(3, mapping); + if(mappingStmt.executeUpdate() > 0) { + return true; + } + } finally { + theJDBCUtil.closeJDBCResultSet(mappingRS); + } + + } catch (SQLException sqle) { + getLogger().error("Error accessing database", sqle); + } finally { + theJDBCUtil.closeJDBCStatement(mappingStmt); + theJDBCUtil.closeJDBCConnection(conn); + } + return false; + } + + /** + * Add mapping for given user and domain + * + * @param user the user + * @param domain the domain + * @param mapping the mapping + * @return true if successfully + */ + private boolean addMapping(String user, String domain, String mapping) { + Connection conn = null; + PreparedStatement mappingStmt = null; + + try { + conn = dataSourceComponent.getConnection(); + mappingStmt = conn.prepareStatement(sqlQueries.getSqlString( + "addMapping", true)); + + ResultSet mappingRS = null; + try { + mappingStmt.setString(1, user); + mappingStmt.setString(2, domain); + mappingStmt.setString(3, mapping); + if(mappingStmt.executeUpdate() >0) { + return true; + } + } finally { + theJDBCUtil.closeJDBCResultSet(mappingRS); + } + + } catch (SQLException sqle) { + getLogger().error("Error accessing database", sqle); + } finally { + theJDBCUtil.closeJDBCStatement(mappingStmt); + theJDBCUtil.closeJDBCConnection(conn); + } + return false; + } + +} + Propchange: james/server/trunk/src/java/org/apache/james/vut/JDBCVirtualUserTable.java ------------------------------------------------------------------------------ svn:eol-style = native Added: james/server/trunk/src/test/org/apache/james/vut/AbstractVirtualUserTableTest.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/test/org/apache/james/vut/AbstractVirtualUserTableTest.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/test/org/apache/james/vut/AbstractVirtualUserTableTest.java (added) +++ james/server/trunk/src/test/org/apache/james/vut/AbstractVirtualUserTableTest.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,142 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + + + +package org.apache.james.vut; + +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.container.ContainerUtil; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.james.services.VirtualUserTableManagement; + +import junit.framework.TestCase; + +public abstract class AbstractVirtualUserTableTest extends TestCase { + + protected VirtualUserTableManagement virtualUserTable; + protected void setUp() throws Exception { + try { + virtualUserTable = getVirtalUserTable(); + } catch (Exception e) { + tearDown(); + throw new Exception(e); + } + } + + protected void tearDown() throws Exception { + super.tearDown(); + ContainerUtil.dispose(virtualUserTable); + } + + protected abstract VirtualUserTableManagement getVirtalUserTable() throws ServiceException, ConfigurationException, Exception; + + public void testStoreAndRetrieveRegexMapping() throws ErrorMappingException { + + String user = "test"; + String domain = "localhost"; + String regex = "(.*):[EMAIL PROTECTED]"; + String regex2 = "(.+):[EMAIL PROTECTED]"; + String invalidRegex = ".*):"; + boolean catched = false; + try { + + assertTrue("No mapping",virtualUserTable.getMappings(user, domain).isEmpty()); + + assertTrue("Added virtual mapping", virtualUserTable.addRegexMapping(user, domain, regex)); + assertTrue("Added virtual mapping", virtualUserTable.addRegexMapping(user, domain, regex2)); + + assertTrue("Two mappings",virtualUserTable.getMappings(user, domain).size() == 2); + + assertTrue("remove virtual mapping", virtualUserTable.removeRegexMapping(user, domain, regex)); + + try { + assertTrue("Added virtual mapping", virtualUserTable.addRegexMapping(user, domain, invalidRegex)); + } catch (InvalidMappingException e) { + catched = true; + } + assertTrue("Invalid Mapping throw exception" , catched); + + assertTrue("remove virtual mapping", virtualUserTable.removeRegexMapping(user, domain, regex2)); + } catch (InvalidMappingException e) { + fail("Storing failed"); + } + + } + + public void testStoreAndRetrieveAddressMapping() throws ErrorMappingException { + + String user = "test"; + String domain = "localhost"; + String address = "[EMAIL PROTECTED]"; + String address2 = "[EMAIL PROTECTED]"; + String invalidAddress= "[EMAIL PROTECTED]:"; + boolean catched = false; + try { + + assertTrue("No mapping",virtualUserTable.getMappings(user, domain).isEmpty()); + + assertTrue("Added virtual mapping", virtualUserTable.addAddressMapping(user, domain, address)); + assertTrue("Added virtual mapping", virtualUserTable.addAddressMapping(user, domain, address2)); + + assertTrue("Two mappings",virtualUserTable.getMappings(user, domain).size() == 2); + + assertTrue("remove virtual mapping", virtualUserTable.removeAddressMapping(user, domain, address)); + + try { + assertTrue("Added virtual mapping", virtualUserTable.addAddressMapping(user, domain, invalidAddress)); + } catch (InvalidMappingException e) { + catched = true; + } + assertTrue("Invalid Mapping throw exception" , catched); + + assertTrue("remove virtual mapping", virtualUserTable.removeAddressMapping(user, domain, address2)); + } catch (InvalidMappingException e) { + fail("Storing failed"); + } + + } + + public void testStoreAndRetrieveErrorMapping() throws ErrorMappingException { + + String user = "test"; + String domain = "localhost"; + String error = "Bounce!"; + boolean catched = false; + try { + + assertTrue("No mapping",virtualUserTable.getMappings(user, domain).isEmpty()); + + assertTrue("Added virtual mapping", virtualUserTable.addErrorMapping(user, domain, error)); + + try { + virtualUserTable.getMappings(user, domain); + } catch (ErrorMappingException e) { + catched = true; + } + assertTrue("Error Mapping throw exception" , catched); + + assertTrue("remove virtual mapping", virtualUserTable.removeErrorMapping(user, domain, error)); + } catch (InvalidMappingException e) { + fail("Storing failed"); + } + + } + +} Propchange: james/server/trunk/src/test/org/apache/james/vut/AbstractVirtualUserTableTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: james/server/trunk/src/test/org/apache/james/vut/JDBCVirtualUserTableTest.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/test/org/apache/james/vut/JDBCVirtualUserTableTest.java?view=auto&rev=463685 ============================================================================== --- james/server/trunk/src/test/org/apache/james/vut/JDBCVirtualUserTableTest.java (added) +++ james/server/trunk/src/test/org/apache/james/vut/JDBCVirtualUserTableTest.java Fri Oct 13 07:11:36 2006 @@ -0,0 +1,37 @@ +package org.apache.james.vut; + +import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.configuration.DefaultConfiguration; +import org.apache.avalon.framework.service.DefaultServiceManager; +import org.apache.avalon.framework.service.ServiceException; + +import org.apache.james.services.FileSystem; + +import org.apache.james.services.VirtualUserTableManagement; +import org.apache.james.test.mock.avalon.MockLogger; + +import org.apache.james.test.mock.james.MockFileSystem; +import org.apache.james.test.mock.util.AttrValConfiguration; +import org.apache.james.test.util.Util; + +public class JDBCVirtualUserTableTest extends AbstractVirtualUserTableTest { + + protected VirtualUserTableManagement getVirtalUserTable() throws ServiceException, ConfigurationException, Exception { + DefaultServiceManager serviceManager = new DefaultServiceManager(); + serviceManager.put(FileSystem.ROLE, new MockFileSystem()); + serviceManager.put(DataSourceSelector.ROLE, Util.getDataSourceSelector()); + JDBCVirtualUserTable mr = new JDBCVirtualUserTable(); + + + mr.enableLogging(new MockLogger()); + DefaultConfiguration defaultConfiguration = new DefaultConfiguration("ReposConf"); + defaultConfiguration.setAttribute("destinationURL","db://maildb/virtualusertable"); + defaultConfiguration.addChild(new AttrValConfiguration("sqlFile","file://conf/sqlResources.xml")); + //defaultConfiguration.setAttribute("type","MAIL"); + mr.service(serviceManager); + mr.configure(defaultConfiguration); + mr.initialize(); + return mr; + } +} Propchange: james/server/trunk/src/test/org/apache/james/vut/JDBCVirtualUserTableTest.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]