Index: core-library/src/main/java/org/apache/james/mailrepository/clean/CleanMailRepositoryService.java =================================================================== --- core-library/src/main/java/org/apache/james/mailrepository/clean/CleanMailRepositoryService.java (revision 0) +++ core-library/src/main/java/org/apache/james/mailrepository/clean/CleanMailRepositoryService.java (revision 0) @@ -0,0 +1,143 @@ +/**************************************************************** + * 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.mailrepository.clean; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector; +import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger; +import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler; +import org.apache.avalon.framework.activity.Disposable; +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.container.ContainerUtil; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.Serviceable; + +public class CleanMailRepositoryService + extends AbstractLogEnabled implements Serviceable, Configurable, Initializable, Disposable{ + + /** + * Configuration object for this service + */ + private Configuration conf; + + private DataSourceSelector datasources; + + private String datasourceName; + + /** + * The service manager that allows access to the system services + */ + private ServiceManager manager; + + /** + * The scheduler service that is used to trigger fetch tasks. + */ + private TimeScheduler scheduler; + + /** + * Whether this service is enabled. + */ + private volatile boolean enabled = false; + + private List taskNames = new ArrayList(); + + public void setScheduler(TimeScheduler ts) { + scheduler = ts; + } + + public void service(ServiceManager m) throws ServiceException { + manager = m; + } + + public void configure(Configuration c) throws ConfigurationException { + conf = c; + Configuration config = c.getChild( "repositoryPath" ); + String destination = config.getValue(); + // 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); + } + datasourceName = (String)urlParams.get(0); + } + + public void initialize() throws Exception { + //set if enabled in config + enabled = conf.getAttributeAsBoolean( "enabled", false ); + if( enabled ) { + TimeScheduler scheduler = (TimeScheduler) manager.lookup( TimeScheduler.ROLE ); + datasources = (DataSourceSelector) manager.lookup( DataSourceSelector.ROLE ); + setScheduler( scheduler ); + + Configuration[] confs = conf.getChildren( "cleanup" ); + for(int i=0; i + + + + + + 1.0 + + + + + + + + + + + + + + \ No newline at end of file Index: core-library/src/main/java/org/apache/james/mailrepository/clean/MailCleaner.java =================================================================== --- core-library/src/main/java/org/apache/james/mailrepository/clean/MailCleaner.java (revision 0) +++ core-library/src/main/java/org/apache/james/mailrepository/clean/MailCleaner.java (revision 0) @@ -0,0 +1,116 @@ +/**************************************************************** + * 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.mailrepository.clean; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.Date; + +import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector; +import org.apache.avalon.cornerstone.services.scheduler.Target; +import org.apache.avalon.excalibur.datasource.DataSourceComponent; +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.logger.AbstractLogEnabled; +import org.apache.james.util.JDBCUtil; + +public class MailCleaner extends AbstractLogEnabled implements Configurable, Target { + + private boolean cleaning; + private int delay; + private String schema; + private String table; + private DataSourceSelector datasources; + private String dataSourceName; + private DataSourceComponent dataSourceComponent; + + public MailCleaner() { + super(); + } + + public void configure(Configuration conf) throws ConfigurationException { + try { + setDataSourceComponent( (DataSourceComponent) datasources.select( dataSourceName ) ); + } catch(Exception e) { + throw new ConfigurationException( e.getMessage() ); + } + Configuration mConf = conf.getChild( "mail-cleaner" ); + delay = mConf.getAttributeAsInteger( "delay" ); + schema = mConf.getAttribute( "schema" ); + table = mConf.getAttribute( "table" ); + } + + public void targetTriggered(String arg0) { + if( isCleaning() ) + return; + + setCleaning( true ); + getLogger().info( "Cleaning..." ); + + Connection con = null; + //take X days off today + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DAY_OF_MONTH, -delay); + Timestamp lastUpdated = new Timestamp( cal.getTimeInMillis() ); + try { + con = dataSourceComponent.getConnection(); + PreparedStatement ps = con.prepareStatement( + "DELETE FROM "+schema+"."+table+" t WHERE t.last_updated < ?" + ); + ps.setTimestamp(1, lastUpdated); + ps.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + new JDBCUtil(){ + protected void delegatedLog(String errorString){ + return; + } + }.closeJDBCConnection( con ); + + setCleaning( false ); + } + } + + public boolean isCleaning() { + return cleaning; + } + + public void setCleaning(boolean cleaning) { + this.cleaning = cleaning; + } + + public void setDatasources(DataSourceSelector dss) { + datasources = dss; + } + + public void setDataSourceName(String datasourceName) { + this.dataSourceName = datasourceName; + } + + public void setDataSourceComponent(DataSourceComponent dataSourceComponent) { + this.dataSourceComponent = dataSourceComponent; + } +} \ No newline at end of file Index: core-library/src/main/java/org/apache/james/mailrepository/clean/CleanMailRepositoryService.java =================================================================== --- core-library/src/main/java/org/apache/james/mailrepository/clean/CleanMailRepositoryService.java (revision 0) +++ core-library/src/main/java/org/apache/james/mailrepository/clean/CleanMailRepositoryService.java (revision 0) @@ -0,0 +1,143 @@ +/**************************************************************** + * 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.mailrepository.clean; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector; +import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger; +import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler; +import org.apache.avalon.framework.activity.Disposable; +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.container.ContainerUtil; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.Serviceable; + +public class CleanMailRepositoryService + extends AbstractLogEnabled implements Serviceable, Configurable, Initializable, Disposable{ + + /** + * Configuration object for this service + */ + private Configuration conf; + + private DataSourceSelector datasources; + + private String datasourceName; + + /** + * The service manager that allows access to the system services + */ + private ServiceManager manager; + + /** + * The scheduler service that is used to trigger fetch tasks. + */ + private TimeScheduler scheduler; + + /** + * Whether this service is enabled. + */ + private volatile boolean enabled = false; + + private List taskNames = new ArrayList(); + + public void setScheduler(TimeScheduler ts) { + scheduler = ts; + } + + public void service(ServiceManager m) throws ServiceException { + manager = m; + } + + public void configure(Configuration c) throws ConfigurationException { + conf = c; + Configuration config = c.getChild( "repositoryPath" ); + String destination = config.getValue(); + // 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); + } + datasourceName = (String)urlParams.get(0); + } + + public void initialize() throws Exception { + //set if enabled in config + enabled = conf.getAttributeAsBoolean( "enabled", false ); + if( enabled ) { + TimeScheduler scheduler = (TimeScheduler) manager.lookup( TimeScheduler.ROLE ); + datasources = (DataSourceSelector) manager.lookup( DataSourceSelector.ROLE ); + setScheduler( scheduler ); + + Configuration[] confs = conf.getChildren( "cleanup" ); + for(int i=0; i + + + + + + 1.0 + + + + + + + + + + + + + + \ No newline at end of file Index: core-library/src/main/java/org/apache/james/mailrepository/clean/MailCleaner.java =================================================================== --- core-library/src/main/java/org/apache/james/mailrepository/clean/MailCleaner.java (revision 0) +++ core-library/src/main/java/org/apache/james/mailrepository/clean/MailCleaner.java (revision 0) @@ -0,0 +1,116 @@ +/**************************************************************** + * 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.mailrepository.clean; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.Date; + +import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector; +import org.apache.avalon.cornerstone.services.scheduler.Target; +import org.apache.avalon.excalibur.datasource.DataSourceComponent; +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.logger.AbstractLogEnabled; +import org.apache.james.util.JDBCUtil; + +public class MailCleaner extends AbstractLogEnabled implements Configurable, Target { + + private boolean cleaning; + private int delay; + private String schema; + private String table; + private DataSourceSelector datasources; + private String dataSourceName; + private DataSourceComponent dataSourceComponent; + + public MailCleaner() { + super(); + } + + public void configure(Configuration conf) throws ConfigurationException { + try { + setDataSourceComponent( (DataSourceComponent) datasources.select( dataSourceName ) ); + } catch(Exception e) { + throw new ConfigurationException( e.getMessage() ); + } + Configuration mConf = conf.getChild( "mail-cleaner" ); + delay = mConf.getAttributeAsInteger( "delay" ); + schema = mConf.getAttribute( "schema" ); + table = mConf.getAttribute( "table" ); + } + + public void targetTriggered(String arg0) { + if( isCleaning() ) + return; + + setCleaning( true ); + getLogger().info( "Cleaning..." ); + + Connection con = null; + //take X days off today + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DAY_OF_MONTH, -delay); + Timestamp lastUpdated = new Timestamp( cal.getTimeInMillis() ); + try { + con = dataSourceComponent.getConnection(); + PreparedStatement ps = con.prepareStatement( + "DELETE FROM "+schema+"."+table+" t WHERE t.last_updated < ?" + ); + ps.setTimestamp(1, lastUpdated); + ps.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + new JDBCUtil(){ + protected void delegatedLog(String errorString){ + return; + } + }.closeJDBCConnection( con ); + + setCleaning( false ); + } + } + + public boolean isCleaning() { + return cleaning; + } + + public void setCleaning(boolean cleaning) { + this.cleaning = cleaning; + } + + public void setDatasources(DataSourceSelector dss) { + datasources = dss; + } + + public void setDataSourceName(String datasourceName) { + this.dataSourceName = datasourceName; + } + + public void setDataSourceComponent(DataSourceComponent dataSourceComponent) { + this.dataSourceComponent = dataSourceComponent; + } +} \ No newline at end of file Index: mordred-library/src/main/java/org/apache/james/util/mordred/PoolConnEntry.java =================================================================== --- mordred-library/src/main/java/org/apache/james/util/mordred/PoolConnEntry.java (revision 578062) +++ mordred-library/src/main/java/org/apache/james/util/mordred/PoolConnEntry.java (working copy) @@ -33,6 +33,7 @@ /** * An entry in a connection pool. + * * */ public class PoolConnEntry implements java.sql.Connection{ @@ -426,4 +427,4 @@ throw new SQLException("This is not a Jdbc 3.0 Compliant Connection"); } -} +} \ No newline at end of file Index: phoenix-deployment/src/conf/james-server.xml =================================================================== --- phoenix-deployment/src/conf/james-server.xml (revision 578062) +++ phoenix-deployment/src/conf/james-server.xml (working copy) @@ -122,6 +122,9 @@ + + + @@ -347,6 +350,17 @@ + + ${app.home}/logs/mailclean + %{time:dd/MM/yy HH:mm:ss} %5.5{priority} %{category}: %{message}\n%{throwable} + true + + + dd + 10485760 + + +