001 package railo.runtime.net.smtp; 002 003 import java.util.Date; 004 import java.util.HashMap; 005 import java.util.Iterator; 006 import java.util.Map; 007 import java.util.Map.Entry; 008 import java.util.Properties; 009 import java.util.Stack; 010 011 import javax.mail.Authenticator; 012 import javax.mail.MessagingException; 013 import javax.mail.NoSuchProviderException; 014 import javax.mail.Session; 015 import javax.mail.Transport; 016 017 public class SMTPConnectionPool { 018 019 private static final long MAX_AGE = 5*60*1000; 020 private static Map<String,Stack<SessionAndTransport>> sessions=new HashMap<String, Stack<SessionAndTransport>>(); 021 022 023 public static SessionAndTransport getSessionAndTransport(Properties props, String key, Authenticator auth) throws MessagingException{ 024 025 // Session 026 SessionAndTransport sat=null; 027 Stack<SessionAndTransport> satStack = getSATStack(key); 028 sat=pop(satStack); 029 030 // when sat still valid return it 031 if(sat!=null) { 032 if(sat.lastAccess+MAX_AGE>System.currentTimeMillis()) { 033 return sat.touch(); 034 } 035 disconnect(sat.transport); 036 } 037 038 return new SessionAndTransport(key, props, auth); 039 } 040 041 042 public static void releaseSessionAndTransport(SessionAndTransport sat) { 043 044 getSATStack(sat.key).add(sat.touch()); 045 } 046 047 public static String listSessions() { 048 Iterator<Entry<String, Stack<SessionAndTransport>>> it = sessions.entrySet().iterator(); 049 Entry<String, Stack<SessionAndTransport>> entry; 050 Stack<SessionAndTransport> stack; 051 StringBuilder sb=new StringBuilder(); 052 while(it.hasNext()){ 053 entry = it.next(); 054 sb.append(entry.getKey()).append('\n'); 055 stack = entry.getValue(); 056 if(stack.isEmpty()) continue; 057 listSessions(sb,stack); 058 } 059 return sb.toString(); 060 } 061 062 private static void listSessions(StringBuilder sb, Stack<SessionAndTransport> stack) { 063 Iterator<SessionAndTransport> it = stack.iterator(); 064 while(it.hasNext()){ 065 SessionAndTransport sat = it.next(); 066 sb.append("- "+sat.key+":"+new Date(sat.lastAccess)).append('\n'); 067 } 068 } 069 070 071 public static void closeSessions() { 072 Iterator<Entry<String, Stack<SessionAndTransport>>> it = sessions.entrySet().iterator(); 073 Entry<String, Stack<SessionAndTransport>> entry; 074 Stack<SessionAndTransport> oldStack; 075 Stack<SessionAndTransport> newStack; 076 while(it.hasNext()){ 077 entry = it.next(); 078 oldStack = entry.getValue(); 079 if(oldStack.isEmpty()) continue; 080 newStack=new Stack<SMTPConnectionPool.SessionAndTransport>(); 081 entry.setValue(newStack); 082 closeSessions(oldStack,newStack); 083 } 084 } 085 086 private static void closeSessions(Stack<SessionAndTransport> oldStack,Stack<SessionAndTransport> newStack) { 087 SessionAndTransport sat; 088 while((sat=pop(oldStack))!=null){ 089 if(sat.lastAccess+MAX_AGE<System.currentTimeMillis()) { 090 disconnect(sat.transport); 091 } 092 else 093 newStack.add(sat); 094 } 095 } 096 097 private static void disconnect(Transport transport) { 098 if(transport!=null && transport.isConnected()) { 099 try { 100 transport.close(); 101 } catch (MessagingException e) {} 102 } 103 } 104 105 106 107 108 109 110 111 112 113 114 115 116 117 private static synchronized Stack<SessionAndTransport> getSATStack(String key) { 118 Stack<SessionAndTransport> stack=sessions.get(key); 119 if(stack==null) { 120 stack=new Stack<SessionAndTransport>(); 121 sessions.put(key, stack); 122 } 123 return stack; 124 } 125 126 private static Session createSession(String key,Properties props, Authenticator auth) { 127 if(auth!=null)return Session.getInstance(props,auth); 128 return Session.getInstance(props); 129 } 130 131 132 private static SessionAndTransport pop(Stack<SessionAndTransport> satStack) { 133 try{ 134 return satStack.pop(); 135 } 136 catch(Throwable t){} 137 return null; 138 } 139 140 141 public static class SessionAndTransport { 142 public final Session session; 143 public final Transport transport; 144 public final String key; 145 private long lastAccess; 146 147 private SessionAndTransport(String key, Properties props,Authenticator auth) throws NoSuchProviderException { 148 this.key=key; 149 this.session=createSession(key, props, auth); 150 this.transport=session.getTransport("smtp"); 151 touch(); 152 } 153 154 private SessionAndTransport touch() { 155 this.lastAccess=System.currentTimeMillis(); 156 return this; 157 } 158 } 159 160 161 162 }