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    }