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
021package org.granite.messaging.webapp;
022
023import java.io.BufferedReader;
024import java.io.IOException;
025import java.io.PrintWriter;
026import java.io.UnsupportedEncodingException;
027import java.security.Principal;
028import java.util.AbstractMap;
029import java.util.Collection;
030import java.util.Enumeration;
031import java.util.HashMap;
032import java.util.HashSet;
033import java.util.Hashtable;
034import java.util.Locale;
035import java.util.Map;
036import java.util.Set;
037
038import javax.servlet.AsyncContext;
039import javax.servlet.DispatcherType;
040import javax.servlet.RequestDispatcher;
041import javax.servlet.ServletContext;
042import javax.servlet.ServletException;
043import javax.servlet.ServletInputStream;
044import javax.servlet.ServletOutputStream;
045import javax.servlet.ServletRequest;
046import javax.servlet.ServletResponse;
047import javax.servlet.http.Cookie;
048import javax.servlet.http.HttpServletRequest;
049import javax.servlet.http.HttpServletResponse;
050import javax.servlet.http.HttpSession;
051import javax.servlet.http.Part;
052
053import org.granite.clustering.TransientReference;
054import org.granite.clustering.TransientReferenceHolder;
055import org.granite.config.GraniteConfig;
056import org.granite.config.GraniteConfigListener;
057import org.granite.config.flex.ServicesConfig;
058import org.granite.context.GraniteContext;
059
060/**
061 * @author Franck WOLFF
062 */
063public 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
589abstract 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
656class 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
696class 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
749class 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