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