001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.jetty.cluster;
019    
020    import java.io.BufferedReader;
021    import java.io.IOException;
022    import java.io.UnsupportedEncodingException;
023    import java.security.Principal;
024    import java.util.Enumeration;
025    import java.util.Locale;
026    import java.util.Map;
027    
028    import javax.servlet.RequestDispatcher;
029    import javax.servlet.ServletInputStream;
030    import javax.servlet.http.Cookie;
031    import javax.servlet.http.HttpServletRequest;
032    import javax.servlet.http.HttpSession;
033    
034    import org.apache.geronimo.clustering.SessionAlreadyExistException;
035    import org.apache.geronimo.clustering.SessionListener;
036    import org.apache.geronimo.clustering.SessionManager;
037    import org.mortbay.jetty.servlet.AbstractSessionManager;
038    
039    
040    /**
041     *
042     * @version $Rev$ $Date$
043     */
044    public class ClusteredSessionManager extends AbstractSessionManager {
045        private static final Object ALL_SESSION_PLACEHOLDER = new Object();
046        
047        private final SessionManager sessionManager;
048        
049        public ClusteredSessionManager(SessionManager sessionManager) {
050            this.sessionManager = sessionManager;
051    
052            String workerName = sessionManager.getNode().getName();
053            workerName = workerName.replaceAll(" ", "");
054            setWorkerName(workerName);
055            // implementation note: enables cross context session id such that a mock HttpServletRequest having a defined 
056            // requestedSessionId attribute can be used to re-create an HttpSession with a defined session ID in this
057            // manager.
058            setCrossContextSessionIDs(true);
059            
060            sessionManager.registerListener(new MigrationListener());
061    
062            // sessions are not removed by this manager. They are invalidated via a callback mechanism
063            setMaxInactiveInterval(-1);
064        }
065    
066        protected Session newSession(HttpServletRequest request) {
067            return new ClusteredSession(request);
068        }
069    
070        private class MigrationListener implements SessionListener {
071            
072            public void notifyInboundSessionMigration(org.apache.geronimo.clustering.Session session) {
073                String sessionId = session.getSessionId();
074                synchronized (__allSessions) {
075                    if (__allSessions.containsKey(sessionId)) {
076                        throw new IllegalStateException("ID [" + sessionId + "] is already defined.");
077                    }
078                    __allSessions.add(sessionId, ALL_SESSION_PLACEHOLDER);
079                    newHttpSession(new RequestWithBoundSession(session));
080                    __allSessions.removeValue(sessionId, ALL_SESSION_PLACEHOLDER);
081                }
082            }
083            
084            public void notifyOutboundSessionMigration(org.apache.geronimo.clustering.Session session) {
085                String sessionId = session.getSessionId();
086                synchronized (__allSessions) {
087                    __allSessions.remove(sessionId);
088                }
089    
090                synchronized (_sessions) {
091                    _sessions.remove(sessionId);
092                } 
093            }
094        }
095    
096        protected class ClusteredSession extends Session {
097            private static final String FORCE_SET_VALUES = "$$$JETTY_FORCE_SET_VALUES$$$"; 
098    
099            private final org.apache.geronimo.clustering.Session session;
100    
101            protected ClusteredSession(HttpServletRequest request) {
102                super(request);
103                
104                if (request instanceof RequestWithBoundSession) {
105                    this.session = ((RequestWithBoundSession) request).session;
106                    // implementation note: set a dummy attribute such that the underlying attribute map is initialized
107                    // with the state of the inbound session.
108                    setAttribute(FORCE_SET_VALUES, FORCE_SET_VALUES);
109                } else {
110                    try {
111                        this.session = sessionManager.createSession(getId());
112                    } catch (SessionAlreadyExistException e) {
113                        throw (IllegalStateException) new IllegalStateException().initCause(e);
114                    }
115                }
116            }
117            
118            protected Map newAttributeMap() {
119                return session.getState();
120            }
121        }
122    
123        /**
124         * Implementation note: this is a mock HttpServletRequest which is used to create an HttpSession with the same
125         * session ID than the wrapped Session.
126         */
127        private class RequestWithBoundSession implements HttpServletRequest {
128            private final org.apache.geronimo.clustering.Session session;
129    
130            public RequestWithBoundSession(org.apache.geronimo.clustering.Session session) {
131                this.session = session;
132            }
133    
134            public void setAttribute(String arg0, Object arg1) {
135            }
136    
137            public Object getAttribute(String arg0) {
138                return null;
139            }
140    
141            public String getRequestedSessionId() {
142                return session.getSessionId();
143            }
144    
145            public String getAuthType() {
146                throw new UnsupportedOperationException();
147            }
148    
149            public String getContextPath() {
150                throw new UnsupportedOperationException();
151            }
152    
153            public Cookie[] getCookies() {
154                throw new UnsupportedOperationException();
155            }
156    
157            public long getDateHeader(String arg0) {
158                throw new UnsupportedOperationException();
159            }
160    
161            public String getHeader(String arg0) {
162                throw new UnsupportedOperationException();
163            }
164    
165            public Enumeration getHeaderNames() {
166                throw new UnsupportedOperationException();
167            }
168    
169            public Enumeration getHeaders(String arg0) {
170                throw new UnsupportedOperationException();
171            }
172    
173            public int getIntHeader(String arg0) {
174                throw new UnsupportedOperationException();
175            }
176    
177            public String getMethod() {
178                throw new UnsupportedOperationException();
179            }
180    
181            public String getPathInfo() {
182                throw new UnsupportedOperationException();
183            }
184    
185            public String getPathTranslated() {
186                throw new UnsupportedOperationException();
187            }
188    
189            public String getQueryString() {
190                throw new UnsupportedOperationException();
191            }
192    
193            public String getRemoteUser() {
194                throw new UnsupportedOperationException();
195            }
196    
197            public String getRequestURI() {
198                throw new UnsupportedOperationException();
199            }
200    
201            public StringBuffer getRequestURL() {
202                throw new UnsupportedOperationException();
203            }
204    
205            public String getServletPath() {
206                throw new UnsupportedOperationException();
207            }
208    
209            public HttpSession getSession() {
210                throw new UnsupportedOperationException();
211            }
212    
213            public HttpSession getSession(boolean arg0) {
214                throw new UnsupportedOperationException();
215            }
216    
217            public Principal getUserPrincipal() {
218                throw new UnsupportedOperationException();
219            }
220    
221            public boolean isRequestedSessionIdFromCookie() {
222                throw new UnsupportedOperationException();
223            }
224    
225            public boolean isRequestedSessionIdFromURL() {
226                throw new UnsupportedOperationException();
227            }
228    
229            public boolean isRequestedSessionIdFromUrl() {
230                throw new UnsupportedOperationException();
231            }
232    
233            public boolean isRequestedSessionIdValid() {
234                throw new UnsupportedOperationException();
235            }
236    
237            public boolean isUserInRole(String arg0) {
238                throw new UnsupportedOperationException();
239            }
240    
241            public Enumeration getAttributeNames() {
242                throw new UnsupportedOperationException();
243            }
244    
245            public String getCharacterEncoding() {
246                throw new UnsupportedOperationException();
247            }
248    
249            public int getContentLength() {
250                throw new UnsupportedOperationException();
251            }
252    
253            public String getContentType() {
254                throw new UnsupportedOperationException();
255            }
256    
257            public ServletInputStream getInputStream() throws IOException {
258                throw new UnsupportedOperationException();
259            }
260    
261            public String getLocalAddr() {
262                throw new UnsupportedOperationException();
263            }
264    
265            public String getLocalName() {
266                throw new UnsupportedOperationException();
267            }
268    
269            public int getLocalPort() {
270                throw new UnsupportedOperationException();
271            }
272    
273            public Locale getLocale() {
274                throw new UnsupportedOperationException();
275            }
276    
277            public Enumeration getLocales() {
278                throw new UnsupportedOperationException();
279            }
280    
281            public String getParameter(String arg0) {
282                throw new UnsupportedOperationException();
283            }
284    
285            public Map getParameterMap() {
286                throw new UnsupportedOperationException();
287            }
288    
289            public Enumeration getParameterNames() {
290                throw new UnsupportedOperationException();
291            }
292    
293            public String[] getParameterValues(String arg0) {
294                throw new UnsupportedOperationException();
295            }
296    
297            public String getProtocol() {
298                throw new UnsupportedOperationException();
299            }
300    
301            public BufferedReader getReader() throws IOException {
302                throw new UnsupportedOperationException();
303            }
304    
305            public String getRealPath(String arg0) {
306                throw new UnsupportedOperationException();
307            }
308    
309            public String getRemoteAddr() {
310                throw new UnsupportedOperationException();
311            }
312    
313            public String getRemoteHost() {
314                throw new UnsupportedOperationException();
315            }
316    
317            public int getRemotePort() {
318                throw new UnsupportedOperationException();
319            }
320    
321            public RequestDispatcher getRequestDispatcher(String arg0) {
322                throw new UnsupportedOperationException();
323            }
324    
325            public String getScheme() {
326                throw new UnsupportedOperationException();
327            }
328    
329            public String getServerName() {
330                throw new UnsupportedOperationException();
331            }
332    
333            public int getServerPort() {
334                throw new UnsupportedOperationException();
335            }
336    
337            public boolean isSecure() {
338                throw new UnsupportedOperationException();
339            }
340    
341            public void removeAttribute(String arg0) {
342                throw new UnsupportedOperationException();
343            }
344    
345            public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException {
346                throw new UnsupportedOperationException();
347            }
348        }
349    }