001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of the Granite Data Services Platform.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or
008     *   modify it under the terms of the GNU Lesser General Public
009     *   License as published by the Free Software Foundation; either
010     *   version 2.1 of the License, or (at your option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful,
013     *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015     *   General Public License for more details.
016     *
017     *   You should have received a copy of the GNU Lesser General Public
018     *   License along with this library; if not, write to the Free Software
019     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020     *   USA, or see <http://www.gnu.org/licenses/>.
021     */
022    package org.granite.messaging.webapp;
023    
024    import java.io.BufferedReader;
025    import java.io.IOException;
026    import java.io.PrintWriter;
027    import java.io.UnsupportedEncodingException;
028    import java.security.Principal;
029    import java.util.AbstractMap;
030    import java.util.Collection;
031    import java.util.Enumeration;
032    import java.util.HashMap;
033    import java.util.HashSet;
034    import java.util.Hashtable;
035    import java.util.Locale;
036    import java.util.Map;
037    import java.util.Set;
038    
039    import javax.servlet.AsyncContext;
040    import javax.servlet.DispatcherType;
041    import javax.servlet.RequestDispatcher;
042    import javax.servlet.ServletContext;
043    import javax.servlet.ServletException;
044    import javax.servlet.ServletInputStream;
045    import javax.servlet.ServletOutputStream;
046    import javax.servlet.ServletRequest;
047    import javax.servlet.ServletResponse;
048    import javax.servlet.http.Cookie;
049    import javax.servlet.http.HttpServletRequest;
050    import javax.servlet.http.HttpServletResponse;
051    import javax.servlet.http.HttpSession;
052    import javax.servlet.http.Part;
053    
054    import org.granite.clustering.TransientReference;
055    import org.granite.clustering.TransientReferenceHolder;
056    import org.granite.config.GraniteConfig;
057    import org.granite.config.GraniteConfigListener;
058    import org.granite.config.flex.ServicesConfig;
059    import org.granite.context.GraniteContext;
060    
061    /**
062     * @author Franck WOLFF
063     */
064    public class ServletGraniteContext extends GraniteContext {
065    
066        private final ServletContext servletContext;
067    
068        protected InitialisationMap initialisationMap = null;
069        protected ApplicationMap applicationMap = null;
070        protected SessionMap sessionMap = null;
071        protected HttpServletRequest request = null;
072        protected HttpServletResponse response = null;
073        protected HttpSession session = null;
074    
075    
076        public static ServletGraniteContext createThreadInstance(
077            GraniteConfig graniteConfig,
078            ServicesConfig servicesConfig,
079            ServletContext context,
080            String sessionId,
081            String clientType) {
082    
083            ServletGraniteContext graniteContext = new ServletGraniteContext(graniteConfig, servicesConfig, context, sessionId, clientType);
084            setCurrentInstance(graniteContext);
085            return graniteContext;
086        }
087        
088        public static ServletGraniteContext createThreadInstance(
089            GraniteConfig graniteConfig,
090            ServicesConfig servicesConfig,
091            ServletContext context,
092            HttpSession session,
093            String clientType) {
094    
095            ServletGraniteContext graniteContext = new ServletGraniteContext(graniteConfig, servicesConfig, context, session, clientType);
096            setCurrentInstance(graniteContext);
097            return graniteContext;
098        }
099    
100    
101        protected ServletGraniteContext(
102            GraniteConfig graniteConfig,
103            ServicesConfig servicesConfig,
104            ServletContext servletContext,
105            String sessionId,
106            String clientType) {
107    
108            super(graniteConfig, servicesConfig, sessionId, clientType);
109            this.servletContext = servletContext;
110        }
111        
112        protected ServletGraniteContext(
113            GraniteConfig graniteConfig,
114            ServicesConfig servicesConfig,
115            ServletContext servletContext,
116            HttpSession session,
117            String clientType) {
118    
119            super(graniteConfig, servicesConfig, session.getId(), clientType);
120            this.servletContext = servletContext;
121            this.session = session;
122        }
123    
124        public ServletContext getServletContext() {
125            return servletContext;
126        }
127        
128        public HttpServletRequest getRequest() {
129            if (request == null)
130                    request = new BasicRequest();
131            return request;
132        }
133        
134        public HttpServletResponse getResponse() {
135            if (response == null)
136                    response = new BasicResponse();
137            return response;
138        }
139        
140        public HttpSession getSession(boolean create) {
141            return getSession();
142        }
143    
144        public HttpSession getSession() {
145            if (session != null)
146                    return session;
147            
148            if (getSessionId() == null)
149                    return null;
150            
151            // Lookup session in session map when using embedded Jetty
152            @SuppressWarnings("unchecked")
153                    Map<String, HttpSession> sessionMap = (Map<String, HttpSession>)servletContext.getAttribute(GraniteConfigListener.GRANITE_SESSION_MAP);
154            return sessionMap != null ? sessionMap.get(getSessionId()) : null;
155        }
156    
157        @Override
158            public Object getSessionLock() {
159                    return null;
160            }
161    
162    
163            @Override
164        public Map<String, String> getInitialisationMap() {
165            if (initialisationMap == null)
166                initialisationMap = new InitialisationMap(servletContext);
167            return initialisationMap;
168        }
169    
170        @Override
171        public Map<String, Object> getApplicationMap() {
172            if (applicationMap == null)
173                applicationMap = new ApplicationMap(servletContext);
174            return applicationMap;
175        }
176    
177            @Override
178        public Map<String, Object> getSessionMap() {
179                    return null;
180        }
181        @Override
182            public Map<String, Object> getSessionMap(boolean create) {
183            if (sessionMap == null && getSession() != null)
184                sessionMap = new SessionMap(getSession());
185            return sessionMap;
186            }
187    
188        @Override
189        public Map<String, Object> getRequestMap() {
190            return null;
191        }
192        
193        
194        private class BasicRequest implements HttpServletRequest {
195            
196            private Map<String, Object> attributes = new HashMap<String, Object>();
197            
198            public ServletContext getServletContext() {
199                    return servletContext;
200            }
201    
202            public Object getAttribute(String key) {
203                    return attributes.get(key);
204            }
205    
206            public void removeAttribute(String key) {
207                    attributes.remove(key);
208            }
209    
210            public void setAttribute(String key, Object value) {
211                    attributes.put(key, value);
212            }
213    
214            public Enumeration<String> getAttributeNames() {
215                    return new Hashtable<String, Object>(attributes).keys();
216            }
217    
218            public HttpSession getSession() {
219                    return ServletGraniteContext.this.getSession();
220            }
221    
222            public HttpSession getSession(boolean create) {
223                    return ServletGraniteContext.this.getSession(create);
224            }
225    
226            public String getRequestedSessionId() {
227                    return null;
228            }
229    
230            public boolean isRequestedSessionIdFromCookie() {
231                    return false;
232            }
233    
234            public boolean isRequestedSessionIdFromURL() {
235                    return false;
236            }
237    
238            public boolean isRequestedSessionIdFromUrl() {
239                    return false;
240            }
241    
242            public boolean isRequestedSessionIdValid() {
243                    return false;
244            }
245    
246            public Principal getUserPrincipal() {
247                    return null;
248            }
249    
250            public boolean isUserInRole(String arg0) {
251                    return false;
252            }
253    
254            public void login(String arg0, String arg1) throws ServletException {
255            }
256    
257            public void logout() throws ServletException {
258            }
259            
260            public String getCharacterEncoding() {
261                    return null;
262            }
263    
264            public int getContentLength() {
265                    return 0;
266            }
267    
268            public String getContentType() {
269                    return null;
270            }
271    
272            public DispatcherType getDispatcherType() {
273                    return null;
274            }
275    
276            public ServletInputStream getInputStream() throws IOException {
277                    return null;
278            }
279    
280            public String getLocalAddr() {
281                    return null;
282            }
283    
284            public String getLocalName() {
285                    return null;
286            }
287    
288            public int getLocalPort() {
289                    return 0;
290            }
291    
292            public Locale getLocale() {
293                    return null;
294            }
295    
296            public Enumeration<Locale> getLocales() {
297                    return null;
298            }
299    
300            public String getParameter(String arg0) {
301                    return null;
302            }
303    
304            public Map<String, String[]> getParameterMap() {
305                    return null;
306            }
307    
308            public Enumeration<String> getParameterNames() {
309                    return null;
310            }
311    
312            public String[] getParameterValues(String arg0) {
313                    return null;
314            }
315    
316            public String getProtocol() {
317                    return null;
318            }
319    
320            public BufferedReader getReader() throws IOException {
321                    return null;
322            }
323    
324            public String getRealPath(String arg0) {
325                    return null;
326            }
327    
328            public String getRemoteAddr() {
329                    return null;
330            }
331    
332            public String getRemoteHost() {
333                    return null;
334            }
335    
336            public int getRemotePort() {
337                    return 0;
338            }
339    
340            public RequestDispatcher getRequestDispatcher(String arg0) {
341                    return null;
342            }
343    
344            public String getScheme() {
345                    return null;
346            }
347    
348            public String getServerName() {
349                    return null;
350            }
351    
352            public int getServerPort() {
353                    return 0;
354            }
355    
356            public AsyncContext getAsyncContext() {
357                    return null;
358            }
359    
360            public boolean isAsyncStarted() {
361                    return false;
362            }
363    
364            public boolean isAsyncSupported() {
365                    return false;
366            }
367    
368            public boolean isSecure() {
369                    return false;
370            }
371    
372            public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException {
373            }
374    
375            public AsyncContext startAsync() throws IllegalStateException {
376                    return null;
377            }
378    
379            public AsyncContext startAsync(ServletRequest request, ServletResponse response) throws IllegalStateException {
380                    return null;
381            }
382    
383            public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
384                    return false;
385            }
386    
387            public String getAuthType() {
388                    return null;
389            }
390    
391            public String getContextPath() {
392                    return null;
393            }
394    
395            public Cookie[] getCookies() {
396                    return null;
397            }
398    
399            public long getDateHeader(String name) {
400                    return 0;
401            }
402    
403            public String getHeader(String name) {
404                    return null;
405            }
406    
407            public Enumeration<String> getHeaderNames() {
408                    return null;
409            }
410    
411            public Enumeration<String> getHeaders(String name) {
412                    return null;
413            }
414    
415            public int getIntHeader(String name) {
416                    return 0;
417            }
418    
419            public String getMethod() {
420                    return null;
421            }
422    
423            public Part getPart(String name) throws IOException, ServletException {
424                    return null;
425            }
426    
427            public Collection<Part> getParts() throws IOException, ServletException {
428                    return null;
429            }
430    
431            public String getPathInfo() {
432                    return null;
433            }
434    
435            public String getPathTranslated() {
436                    return null;
437            }
438    
439            public String getQueryString() {
440                    return null;
441            }
442    
443            public String getRemoteUser() {
444                    return null;
445            }
446    
447            public String getRequestURI() {
448                    return null;
449            }
450    
451            public StringBuffer getRequestURL() {
452                    return null;
453            }
454    
455            public String getServletPath() {
456                    return null;
457            }    
458        }
459        
460        private class BasicResponse implements HttpServletResponse {
461    
462                    public void flushBuffer() throws IOException {
463                    }
464    
465                    public int getBufferSize() {
466                            return 0;
467                    }
468    
469                    public String getCharacterEncoding() {
470                            return null;
471                    }
472    
473                    public String getContentType() {
474                            return null;
475                    }
476    
477                    public Locale getLocale() {
478                            return null;
479                    }
480    
481                    public ServletOutputStream getOutputStream() throws IOException {
482                            return null;
483                    }
484    
485                    public PrintWriter getWriter() throws IOException {
486                            return null;
487                    }
488    
489                    public boolean isCommitted() {
490                            return false;
491                    }
492    
493                    public void reset() {
494                    }
495    
496                    public void resetBuffer() {
497                    }
498    
499                    public void setBufferSize(int size) {
500                    }
501    
502                    public void setCharacterEncoding(String charset) {
503                    }
504    
505                    public void setContentLength(int length) {
506                    }
507    
508                    public void setContentType(String contentType) {
509                    }
510    
511                    public void setLocale(Locale locale) {
512                    }
513    
514                    public void addCookie(Cookie cookie) {
515                    }
516    
517                    public void addDateHeader(String name, long value) {
518                    }
519    
520                    public void addHeader(String name, String value) {
521                    }
522    
523                    public void addIntHeader(String name, int value) {
524                    }
525    
526                    public boolean containsHeader(String name) {
527                            return false;
528                    }
529    
530                    public String encodeRedirectURL(String url) {
531                            return null;
532                    }
533    
534                    public String encodeRedirectUrl(String url) {
535                            return null;
536                    }
537    
538                    public String encodeURL(String url) {
539                            return null;
540                    }
541    
542                    public String encodeUrl(String url) {
543                            return null;
544                    }
545    
546                    public String getHeader(String name) {
547                            return null;
548                    }
549    
550                    public Collection<String> getHeaderNames() {
551                            return null;
552                    }
553    
554                    public Collection<String> getHeaders(String name) {
555                            return null;
556                    }
557    
558                    public int getStatus() {
559                            return 0;
560                    }
561    
562                    public void sendError(int code) throws IOException {
563                    }
564    
565                    public void sendError(int code, String msg) throws IOException {
566                    }
567    
568                    public void sendRedirect(String url) throws IOException {
569                    }
570    
571                    public void setDateHeader(String name, long value) {
572                    }
573    
574                    public void setHeader(String name, String value) {
575                    }
576    
577                    public void setIntHeader(String name, int value) {
578                    }
579    
580                    public void setStatus(int code) {
581                    }
582    
583                    public void setStatus(int code, String msg) {
584                    }
585            
586        }
587    }
588    
589    
590    abstract class BaseContextMap<T,U> extends AbstractMap<T,U> {
591    
592        protected static final String KEY_STRING_ERROR = "Key should be a non null String: ";
593    
594        @Override
595        public void clear() {
596            throw new UnsupportedOperationException();
597        }
598    
599        @Override
600        public void putAll(Map<? extends T, ? extends U> t) {
601            throw new UnsupportedOperationException();
602        }
603    
604        @Override
605        public U remove(Object key) {
606            throw new UnsupportedOperationException();
607        }
608    
609        static class Entry<T,U> implements Map.Entry<T,U> {
610    
611            private final T key;
612            private final U value;
613    
614            Entry(T key, U value) {
615                this.key = key;
616                this.value = value;
617            }
618    
619            public T getKey() {
620                return key;
621            }
622    
623            public U getValue() {
624                return value;
625            }
626    
627            public U setValue(U value) {
628                throw new UnsupportedOperationException();
629            }
630    
631            @Override
632            public int hashCode() {
633                return ((key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()));
634            }
635    
636            @Override
637            public boolean equals(Object obj) {
638                if (obj == this)
639                    return true;
640    
641                if (obj == null || !(obj instanceof Map.Entry<?, ?>))
642                    return false;
643    
644                Map.Entry<?, ?> input = (Map.Entry<?, ?>)obj;
645                Object inputKey = input.getKey();
646                Object inputValue = input.getValue();
647    
648                if (inputKey == key || (inputKey != null && inputKey.equals(key))) {
649                    if (inputValue == value || (inputValue != null && inputValue.equals(value)))
650                        return true;
651                }
652                return false;
653            }
654        }
655    }
656    
657    class InitialisationMap extends BaseContextMap<String, String> {
658    
659        private ServletContext servletContext = null;
660    
661        InitialisationMap(ServletContext servletContext) {
662            if (servletContext == null)
663                throw new NullPointerException("servletContext is null");
664            this.servletContext = servletContext;
665        }
666    
667        @Override
668        public String get(Object key) {
669            if (!(key instanceof String))
670                return null;
671            return servletContext.getInitParameter(key.toString());
672        }
673    
674        @Override
675        public String put(String key, String value) {
676            throw new UnsupportedOperationException();
677        }
678    
679        @Override
680        public Set<Map.Entry<String, String>> entrySet() {
681            Set<Map.Entry<String, String>> entries = new HashSet<Map.Entry<String, String>>();
682            for (Enumeration<?> e = servletContext.getInitParameterNames(); e.hasMoreElements();) {
683                String key = (String)e.nextElement();
684                entries.add(new Entry<String, String>(key, servletContext.getInitParameter(key)));
685            }
686            return entries;
687        }
688    
689        @Override
690        public boolean equals(Object obj) {
691            if (obj == null || !(obj instanceof InitialisationMap))
692                return false;
693            return super.equals(obj);
694        }
695    }
696    
697    class ApplicationMap extends BaseContextMap<String, Object> {
698    
699        private ServletContext servletContext = null;
700    
701        ApplicationMap(ServletContext servletContext) {
702            if (servletContext == null)
703                throw new NullPointerException("servletContext is null");
704            this.servletContext = servletContext;
705        }
706    
707        @Override
708        public Object get(Object key) {
709            if (!(key instanceof String))
710                return null;
711           return servletContext.getAttribute(key.toString());
712        }
713    
714        @Override
715        public Object put(String key, Object value) {
716            if (key == null)
717                throw new IllegalArgumentException(KEY_STRING_ERROR + key);
718            Object result = servletContext.getAttribute(key);
719            servletContext.setAttribute(key, value);
720            return (result);
721        }
722    
723        @Override
724        public Object remove(Object key) {
725            if (!(key instanceof String))
726                return null;
727            Object result = servletContext.getAttribute(key.toString());
728            servletContext.removeAttribute(key.toString());
729            return result;
730        }
731    
732        @Override
733        public Set<Map.Entry<String, Object>> entrySet() {
734            Set<Map.Entry<String, Object>> entries = new HashSet<Map.Entry<String, Object>>();
735            for (Enumeration<?> e = servletContext.getAttributeNames(); e.hasMoreElements();) {
736                String key = (String)e.nextElement();
737                entries.add(new Entry<String, Object>(key, servletContext.getAttribute(key)));
738            }
739            return entries;
740        }
741    
742        @Override
743        public boolean equals(Object obj) {
744            if (obj == null || !(obj instanceof ApplicationMap))
745                return false;
746            return super.equals(obj);
747        }
748    }
749    
750    class SessionMap extends BaseContextMap<String, Object> {
751    
752        private HttpServletRequest request = null;
753        private HttpSession session = null;
754    
755        SessionMap(HttpSession session) {
756            if (session == null)
757                throw new NullPointerException("session is null");
758            this.session = session;
759        }
760        
761        SessionMap(HttpServletRequest request) {
762            if (request == null)
763                throw new NullPointerException("request is null");
764            this.request = request;
765        }
766    
767        @Override
768        public Object get(Object key) {
769            if (!(key instanceof String))
770                return null;
771            Object value = getSession().getAttribute(key.toString());
772            if (value instanceof TransientReferenceHolder)
773                    return ((TransientReferenceHolder)value).get();
774            return value;
775        }
776    
777        @Override
778        public Object put(String key, Object value) {
779            if (key == null)
780                throw new IllegalArgumentException(KEY_STRING_ERROR + key);
781            HttpSession session = getSession();
782            Object result = session.getAttribute(key);
783            if (result instanceof TransientReferenceHolder)
784                    result = ((TransientReferenceHolder)result).get();
785            if (value != null && value.getClass().isAnnotationPresent(TransientReference.class))
786                    value = new TransientReferenceHolder(value);
787            session.setAttribute(key, value);
788            return result;
789        }
790    
791        @Override
792        public Object remove(Object key) {
793            if (!(key instanceof String))
794                return null;
795            HttpSession session = getSession();
796            Object result = session.getAttribute(key.toString());
797            if (result instanceof TransientReferenceHolder)
798                    result = ((TransientReferenceHolder)result).get();
799            session.removeAttribute(key.toString());
800            return result;
801        }
802    
803        @Override
804        public Set<Map.Entry<String, Object>> entrySet() {
805            Set<Map.Entry<String, Object>> entries = new HashSet<Map.Entry<String, Object>>();
806            HttpSession session = getSession();
807            for (Enumeration<?> e = session.getAttributeNames(); e.hasMoreElements(); ) {
808                String key = (String)e.nextElement();
809                Object value = session.getAttribute(key);
810                if (value instanceof TransientReferenceHolder)
811                    value = ((TransientReferenceHolder)value).get();
812                entries.add(new Entry<String, Object>(key, value));
813            }
814            return entries;
815        }
816    
817        @Override
818        public boolean equals(Object obj) {
819            if (obj == null || !(obj instanceof SessionMap))
820                return false;
821            return super.equals(obj);
822        }
823    
824        private HttpSession getSession() {
825            if (request != null)
826                    return request.getSession(true);
827            return session;
828        }
829    }
830