001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.jetty6.cluster;
018    
019    import java.util.HashMap;
020    import java.util.Map;
021    
022    import javax.servlet.http.HttpServletRequest;
023    import javax.servlet.http.HttpSession;
024    
025    import org.apache.geronimo.clustering.SessionAlreadyExistException;
026    import org.apache.geronimo.clustering.SessionListener;
027    import org.apache.geronimo.clustering.SessionManager;
028    import org.mortbay.jetty.servlet.AbstractSessionManager;
029    import org.mortbay.jetty.servlet.HashSessionIdManager;
030    
031    
032    /**
033     * @version $Rev$ $Date$
034     */
035    public class ClusteredSessionManager extends AbstractSessionManager {
036    
037        private final SessionManager sessionManager;
038        private final Map<String, ClusteredSession> idToSession = new HashMap<String, ClusteredSession>();
039    
040        public ClusteredSessionManager(SessionManager sessionManager) {
041            this.sessionManager = sessionManager;
042    
043            String workerName = sessionManager.getNode().getName();
044            workerName = workerName.replaceAll(" ", "");
045            HashSessionIdManager sessionIdManager = new HashSessionIdManager();
046            sessionIdManager.setWorkerName(workerName);
047            setIdManager(sessionIdManager);
048    
049            sessionManager.registerListener(new MigrationListener());
050        }
051    
052        @Override
053        protected Session newSession(HttpServletRequest request) {
054            return new ClusteredSession(request);
055        }
056    
057        @Override
058        public void complete(HttpSession session) {
059            ClusteredSession clusteredSession = (ClusteredSession) session;
060            clusteredSession.session.onEndAccess();
061        }
062    
063        @Override
064        protected void addSession(Session session) {
065            ClusteredSession clusteredSession = (ClusteredSession) session;
066            synchronized (idToSession) {
067                idToSession.put(clusteredSession.getClusterId(), clusteredSession);
068            }
069        }
070    
071        @Override
072        protected void removeSession(String idInCluster) {
073            synchronized (idToSession) {
074                idToSession.remove(idInCluster);
075            }
076        }
077    
078        @Override
079        public Session getSession(String idInCluster) {
080            synchronized (idToSession) {
081                return idToSession.get(idInCluster);
082            }
083        }
084    
085        @Override
086        public int getSessions() {
087            synchronized (idToSession) {
088                return idToSession.size();
089            }
090        }
091    
092        @Override
093        public Map getSessionMap() {
094            throw new AssertionError("getSessionMap is never used.");
095        }
096    
097        @Override
098        protected void invalidateSessions() {
099            // We do not need to clear idToSession: when the SessionManager GBean is stopped, all the sessions
100            // it defines are migrated to other SessionManagers. These outbound session migrations will remove 
101            // them from idToSession.
102        }
103    
104        private class MigrationListener implements SessionListener {
105    
106            public void notifyInboundSessionMigration(org.apache.geronimo.clustering.Session session) {
107                addSession(new ClusteredSession(session), false);
108            }
109    
110            public void notifyOutboundSessionMigration(org.apache.geronimo.clustering.Session session) {
111                ClusteredSession clusteredSession = getClusteredSession(session);
112                removeSession(clusteredSession, false);
113            }
114    
115            public void notifySessionDestruction(org.apache.geronimo.clustering.Session session) {
116                ClusteredSession clusteredSession = getClusteredSession(session);
117                removeSession(clusteredSession, true);
118            }
119            
120            private ClusteredSession getClusteredSession(org.apache.geronimo.clustering.Session session) throws AssertionError {
121                ClusteredSession clusteredSession;
122                synchronized (idToSession) {
123                    clusteredSession = idToSession.remove(session.getSessionId());
124                }
125                if (null == clusteredSession) {
126                    throw new AssertionError("Session [" + session + "] is undefined");
127                }
128                return clusteredSession;
129            }
130            
131            
132        }
133    
134        public class ClusteredSession extends Session {
135            private final org.apache.geronimo.clustering.Session session;
136    
137            protected ClusteredSession(HttpServletRequest request) {
138                super(request);
139                try {
140                    this.session = sessionManager.createSession(getClusterId());
141                } catch (SessionAlreadyExistException e) {
142                    throw (IllegalStateException) new IllegalStateException().initCause(e);
143                }
144                initValues();
145            }
146    
147            protected ClusteredSession(org.apache.geronimo.clustering.Session session) {
148                super(System.currentTimeMillis(), session.getSessionId());
149                this.session = session;
150                initValues();
151            }
152    
153            @Override
154            protected Map newAttributeMap() {
155                return session.getState();
156            }
157    
158            @Override
159            protected String getClusterId() {
160                return super.getClusterId();
161            }
162    
163            @Override
164            public void invalidate() throws IllegalStateException {
165                super.invalidate();
166                session.release();
167            }
168        }
169    
170    }