mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85521 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
318 lines
10 KiB
Java
318 lines
10 KiB
Java
/*
|
|
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.repo.mail;
|
|
|
|
import javax.mail.Address;
|
|
import javax.mail.Message;
|
|
import javax.mail.MessagingException;
|
|
import javax.mail.NoSuchProviderException;
|
|
import javax.mail.Session;
|
|
import javax.mail.Transport;
|
|
import javax.mail.URLName;
|
|
|
|
import org.alfresco.util.PropertyCheck;
|
|
import org.apache.commons.pool.KeyedPoolableObjectFactory;
|
|
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
|
|
|
|
|
/**
|
|
* This class extends Spring's {@link JavaMailSenderImpl} to pool the {@link Transport}s used to send emails.
|
|
*
|
|
* This is to overcome problems reported in CLOUD-313.
|
|
*
|
|
* @author Alex Miller
|
|
*/
|
|
public class AlfrescoJavaMailSender extends JavaMailSenderImpl
|
|
{
|
|
private static final long DEAFULT_TIME_BETWEEN_EVICTION_RUNS = 30000l;
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(AlfrescoJavaMailSender.class);
|
|
|
|
/**
|
|
* {@link KeyedPoolableObjectFactory} which uses the {@link Session} returned by {@link JavaMailSenderImpl.getSession()} to create a new
|
|
* {@link Transport}.
|
|
*/
|
|
private final class TransportFactory implements KeyedPoolableObjectFactory
|
|
{
|
|
/**
|
|
* Create a new {@link Transport} using the {@link Session} returned by {@link JavaMailSenderImpl#getSession() getSession()}.
|
|
*
|
|
* @param key A {@link URLName} containing the connection details
|
|
* @return A new {@link Transport}
|
|
*/
|
|
@Override
|
|
public Object makeObject(Object key) throws Exception
|
|
{
|
|
if ((key instanceof URLName) == false)
|
|
{
|
|
throw new IllegalArgumentException("Invlid key type");
|
|
}
|
|
log.debug("Creating new Transport");
|
|
URLName urlName = (URLName) key;
|
|
Transport transport = getSession().getTransport(urlName.getProtocol());
|
|
transport.connect(urlName.getHost(), urlName.getPort(), urlName.getUsername(), urlName.getPassword());
|
|
return transport;
|
|
}
|
|
|
|
/**
|
|
* Disconnects the pooled {@link Transport} object.
|
|
*
|
|
* @param key {@link URLName} containing the connection details.
|
|
* @param object Pooled {@link Transport}
|
|
*/
|
|
@Override
|
|
public void destroyObject(Object key, Object object) throws Exception
|
|
{
|
|
if (object instanceof Transport == false)
|
|
{
|
|
throw new IllegalArgumentException("Unexpected object type");
|
|
}
|
|
log.debug("Destroying Transpaort");
|
|
Transport transport = (Transport)object;
|
|
transport.close();
|
|
}
|
|
|
|
/**
|
|
* Checks to see if the pooled {@link Transport} is still connected.
|
|
*
|
|
* @param key {@link URLName} containing the connection details.
|
|
* @param object Pooled {@link Transport}
|
|
*
|
|
* @return true if the pooled transport is still connected, or false, otherwise.
|
|
*/
|
|
@Override
|
|
public boolean validateObject(Object key, Object object)
|
|
{
|
|
if (object instanceof Transport == false)
|
|
{
|
|
throw new IllegalArgumentException("Unexpected object type");
|
|
}
|
|
log.debug("Validating transport");
|
|
Transport transport = (Transport)object;
|
|
return transport.isConnected();
|
|
}
|
|
|
|
/**
|
|
* Do nothing
|
|
*/
|
|
@Override
|
|
public void activateObject(Object key, Object obj) throws Exception
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Do Noting
|
|
*/
|
|
@Override
|
|
public void passivateObject(Object key, Object obj) throws Exception
|
|
{
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrapper implementation of {@link Transport}, which borrows from a pool on connection, and returns to the pool on close.
|
|
*
|
|
* @see AlfrescoJavaMailSender#getTranport(Session)
|
|
*/
|
|
private static class PooledTransportWrapper extends Transport
|
|
{
|
|
private Transport wrapped = null;
|
|
private String protocol;
|
|
private GenericKeyedObjectPool pool;
|
|
|
|
/**
|
|
* Default constructor.
|
|
*
|
|
* @param transportPool Pool to borrow/return transports to/from.
|
|
* @param session {@link Session} used to create new transports.
|
|
* @param protocol Mail protocol for transport.
|
|
*/
|
|
private PooledTransportWrapper(GenericKeyedObjectPool transportPool, Session session, String protocol)
|
|
{
|
|
super(session, new URLName(protocol, null, 0, null, null, null));
|
|
this.pool = transportPool;
|
|
this.protocol = protocol;
|
|
}
|
|
|
|
/**
|
|
* Send a message, using the borrowed {@link Transport}.
|
|
*/
|
|
@Override
|
|
public void sendMessage(Message message, Address[] addresses) throws MessagingException
|
|
{
|
|
if (wrapped == null)
|
|
{
|
|
throw new IllegalStateException ("Not connected!");
|
|
}
|
|
wrapped.sendMessage(message, addresses);
|
|
}
|
|
|
|
/**
|
|
* Return the borrowed {@link Transport} to the pool.
|
|
*/
|
|
@Override
|
|
public synchronized void close() throws MessagingException
|
|
{
|
|
if (this.wrapped == null ||
|
|
isConnected() == false)
|
|
{
|
|
throw new IllegalStateException("Already closed");
|
|
}
|
|
try
|
|
{
|
|
log.debug("Returning transport to pool");
|
|
pool.returnObject(getURLName(), wrapped);
|
|
wrapped = null;
|
|
}
|
|
catch (Exception error)
|
|
{
|
|
throw new MessagingException("Unexpected exception returning transport to pool", error);
|
|
}
|
|
finally
|
|
{
|
|
super.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Borrow a transport from the pool.
|
|
*/
|
|
@Override
|
|
protected boolean protocolConnect(String host, int port, String username, String password) throws MessagingException
|
|
{
|
|
URLName name = new URLName(protocol, host, port, null, username, password);
|
|
try
|
|
{
|
|
log.debug("Borrowing object from pool");
|
|
wrapped = (Transport) pool.borrowObject(name);
|
|
return true;
|
|
}
|
|
catch (MessagingException ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new MessagingException("Unexpected exception borrwoing connection from pool", ex);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private GenericKeyedObjectPool transportPool = new GenericKeyedObjectPool(new TransportFactory());
|
|
|
|
public AlfrescoJavaMailSender()
|
|
{
|
|
transportPool.setMaxActive(-1);
|
|
transportPool.setTestOnBorrow(true);
|
|
transportPool.setTestOnReturn(true);
|
|
transportPool.setTimeBetweenEvictionRunsMillis(DEAFULT_TIME_BETWEEN_EVICTION_RUNS);
|
|
transportPool.setMinEvictableIdleTimeMillis(DEAFULT_TIME_BETWEEN_EVICTION_RUNS);
|
|
}
|
|
|
|
/**
|
|
* @return A new {@link PooledTransportWrapper} which borrows a pooled {@link Transport} on connect, and returns it to
|
|
* the pool on close.
|
|
*/
|
|
@Override
|
|
protected Transport getTransport(Session session) throws NoSuchProviderException
|
|
{
|
|
return new PooledTransportWrapper(transportPool, session, getProtocol());
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the maximum number of active transports, managed by the pool. Use a negative value for no limit. Default is -1.
|
|
*/
|
|
public void setMaxActive(int maxActive)
|
|
{
|
|
transportPool.setMaxActive(maxActive);
|
|
}
|
|
|
|
/**
|
|
* Set the maximum number of transports that can sit idle in the pool. Use a negative value for no limit. Default is 8.
|
|
*/
|
|
public void setMaxIdle(int maxIdle)
|
|
{
|
|
transportPool.setMaxIdle(maxIdle);
|
|
}
|
|
|
|
/**
|
|
* Set the maximum amount of time (in milliseconds) to wait for a transport to be returned from the pool.
|
|
* Set to 0 or less to block indefinitely.
|
|
*/
|
|
public void setMaxWait(long maxWait)
|
|
{
|
|
transportPool.setMaxWait(maxWait);
|
|
}
|
|
|
|
/**
|
|
* Set the time (in milliseconds) between runs of the idle object eviction thread. Set to non-positive for no eviction.
|
|
* Default value is 30 seconds.
|
|
*/
|
|
public void setTimeBetweenEvictionRuns(long time)
|
|
{
|
|
transportPool.setTimeBetweenEvictionRunsMillis(time);
|
|
}
|
|
|
|
/**
|
|
* Set the minimum amount of time a transport may sit idle, before it is eligible for eviction. Set to non positive prevent
|
|
* eviction based on idle time.
|
|
*
|
|
* This value has no affect if timeBetweenEvictionRuns is non positive.
|
|
*
|
|
* Default value is 30 seconds.
|
|
*/
|
|
public void setMinEvictableIdleTime(long time)
|
|
{
|
|
transportPool.setMinEvictableIdleTimeMillis(time);
|
|
}
|
|
|
|
@Override
|
|
public void setUsername(String userName)
|
|
{
|
|
if (PropertyCheck.isValidPropertyString(userName))
|
|
{
|
|
super.setUsername(userName);
|
|
}
|
|
else
|
|
{
|
|
super.setUsername(null);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setPassword(String password)
|
|
{
|
|
if (PropertyCheck.isValidPropertyString(password))
|
|
{
|
|
super.setPassword(password);
|
|
}
|
|
else
|
|
{
|
|
super.setPassword(null);
|
|
}
|
|
}
|
|
}
|