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