/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. * **/ package lucee.runtime.net.smtp; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Stack; import javax.mail.Authenticator; import javax.mail.MessagingException; import javax.mail.NoSuchProviderException; import javax.mail.Session; import javax.mail.Transport; import lucee.commons.lang.ExceptionUtil; public class SMTPConnectionPool { private static Map<String,Stack<SessionAndTransport>> sessions=new HashMap<String, Stack<SessionAndTransport>>(); public static SessionAndTransport getSessionAndTransport(Properties props, String key, Authenticator auth, long lifeTimespan, long idleTimespan) throws MessagingException{ // Session SessionAndTransport sat=null; Stack<SessionAndTransport> satStack = getSATStack(key); sat=pop(satStack); // when sat still valid return it if(sat!=null) { if(isValid(sat,lifeTimespan,idleTimespan)) { return sat.touch(); } disconnect(sat.transport); } return new SessionAndTransport(key, props, auth,lifeTimespan,idleTimespan); } private static boolean isValid(SessionAndTransport sat, long lifeTimespan, long idleTimespan) { return (idleTimespan<=0 || sat.lastAccess+idleTimespan>System.currentTimeMillis()) && (lifeTimespan<=0 || sat.created+lifeTimespan>System.currentTimeMillis()); } public static void releaseSessionAndTransport(SessionAndTransport sat) { getSATStack(sat.key).add(sat.touch()); } public static String listSessions() { Iterator<Entry<String, Stack<SessionAndTransport>>> it = sessions.entrySet().iterator(); Entry<String, Stack<SessionAndTransport>> entry; Stack<SessionAndTransport> stack; StringBuilder sb=new StringBuilder(); while(it.hasNext()){ entry = it.next(); sb.append(entry.getKey()).append('\n'); stack = entry.getValue(); if(stack.isEmpty()) continue; listSessions(sb,stack); } return sb.toString(); } private static void listSessions(StringBuilder sb, Stack<SessionAndTransport> stack) { Iterator<SessionAndTransport> it = stack.iterator(); while(it.hasNext()){ SessionAndTransport sat = it.next(); sb.append("- "+sat.key+":"+new Date(sat.lastAccess)).append('\n'); } } public static void closeSessions() { Iterator<Entry<String, Stack<SessionAndTransport>>> it = sessions.entrySet().iterator(); Entry<String, Stack<SessionAndTransport>> entry; Stack<SessionAndTransport> oldStack; Stack<SessionAndTransport> newStack; while(it.hasNext()){ entry = it.next(); oldStack = entry.getValue(); if(oldStack.isEmpty()) continue; newStack=new Stack<SMTPConnectionPool.SessionAndTransport>(); entry.setValue(newStack); closeSessions(oldStack,newStack); } } private static void closeSessions(Stack<SessionAndTransport> oldStack,Stack<SessionAndTransport> newStack) { SessionAndTransport sat; while((sat=pop(oldStack))!=null){ if(!isValid(sat, sat.lifeTimespan, sat.idleTimespan)) { disconnect(sat.transport); } else newStack.add(sat); } } static void disconnect(Transport transport) { if(transport!=null && transport.isConnected()) { try { transport.close(); } catch (MessagingException e) {} } } private static synchronized Stack<SessionAndTransport> getSATStack(String key) { Stack<SessionAndTransport> stack=sessions.get(key); if(stack==null) { stack=new Stack<SessionAndTransport>(); sessions.put(key, stack); } return stack; } private static Session createSession(String key,Properties props, Authenticator auth) { if(auth!=null)return Session.getInstance(props,auth); return Session.getInstance(props); } private static SessionAndTransport pop(Stack<SessionAndTransport> satStack) { try{ return satStack.pop(); } catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);} return null; } public static class SessionAndTransport { public final Session session; public final Transport transport; public final String key; private long lastAccess; public final long created; public final long lifeTimespan; public final long idleTimespan; SessionAndTransport(String key, Properties props,Authenticator auth, long lifeTimespan, long idleTimespan) throws NoSuchProviderException { this.key=key; this.session=createSession(key, props, auth); this.transport=session.getTransport("smtp"); this.created=System.currentTimeMillis(); this.lifeTimespan=lifeTimespan; this.idleTimespan=idleTimespan; touch(); } private SessionAndTransport touch() { this.lastAccess=System.currentTimeMillis(); return this; } } }