001 package railo.runtime.net.smtp; 002 003 import java.util.HashMap; 004 import java.util.Iterator; 005 import java.util.Map; 006 import java.util.Map.Entry; 007 import java.util.Properties; 008 import java.util.Stack; 009 010 import javax.mail.Authenticator; 011 import javax.mail.MessagingException; 012 import javax.mail.NoSuchProviderException; 013 import javax.mail.Session; 014 import javax.mail.Transport; 015 016 public class SMTPConnectionPool { 017 018 private static final long MAX_AGE = 5*60*1000; 019 private static Map<String,Stack<SessionAndTransport>> sessions=new HashMap<String, Stack<SessionAndTransport>>(); 020 021 022 public static SessionAndTransport getSessionAndTransport(Properties props, Authenticator auth) throws MessagingException{ 023 String key=""+props.hashCode(); 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 048 public static void closeSessions() { 049 Iterator<Entry<String, Stack<SessionAndTransport>>> it = sessions.entrySet().iterator(); 050 Entry<String, Stack<SessionAndTransport>> entry; 051 Stack<SessionAndTransport> oldStack; 052 Stack<SessionAndTransport> newStack; 053 while(it.hasNext()){ 054 entry = it.next(); 055 oldStack = entry.getValue(); 056 if(oldStack.isEmpty()) continue; 057 newStack=new Stack<SMTPConnectionPool.SessionAndTransport>(); 058 entry.setValue(newStack); 059 closeSessions(oldStack,newStack); 060 } 061 } 062 063 private static void closeSessions(Stack<SessionAndTransport> oldStack,Stack<SessionAndTransport> newStack) { 064 SessionAndTransport sat; 065 while((sat=pop(oldStack))!=null){ 066 if(sat.lastAccess+MAX_AGE<System.currentTimeMillis()) { 067 disconnect(sat.transport); 068 } 069 else 070 newStack.add(sat); 071 } 072 } 073 074 private static void disconnect(Transport transport) { 075 if(transport!=null && transport.isConnected()) { 076 try { 077 transport.close(); 078 } catch (MessagingException e) {} 079 } 080 } 081 082 083 084 085 086 087 088 089 090 091 092 093 094 private static synchronized Stack<SessionAndTransport> getSATStack(String key) { 095 Stack<SessionAndTransport> stack=sessions.get(key); 096 if(stack==null) { 097 stack=new Stack<SessionAndTransport>(); 098 sessions.put(key, stack); 099 } 100 return stack; 101 } 102 103 private static Session createSession(String key,Properties props, Authenticator auth) { 104 if(auth!=null)return Session.getInstance(props,auth); 105 return Session.getInstance(props); 106 } 107 108 109 private static SessionAndTransport pop(Stack<SessionAndTransport> satStack) { 110 try{ 111 return satStack.pop(); 112 } 113 catch(Throwable t){} 114 return null; 115 } 116 117 118 public static class SessionAndTransport { 119 public final Session session; 120 public final Transport transport; 121 public final String key; 122 private long lastAccess; 123 124 private SessionAndTransport(String key, Properties props,Authenticator auth) throws NoSuchProviderException { 125 this.key=key; 126 this.session=createSession(key, props, auth); 127 this.transport=session.getTransport("smtp"); 128 touch(); 129 } 130 131 private SessionAndTransport touch() { 132 this.lastAccess=System.currentTimeMillis(); 133 return this; 134 } 135 } 136 137 138 139 }