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    }