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.util.AbstractMap;
024    import java.util.Enumeration;
025    import java.util.HashSet;
026    import java.util.Map;
027    import java.util.Set;
028    
029    import javax.servlet.ServletContext;
030    import javax.servlet.http.HttpServletRequest;
031    import javax.servlet.http.HttpServletResponse;
032    import javax.servlet.http.HttpSession;
033    
034    import org.granite.clustering.TransientReference;
035    import org.granite.clustering.TransientReferenceHolder;
036    import org.granite.config.GraniteConfig;
037    import org.granite.config.flex.ServicesConfig;
038    import org.granite.context.GraniteContext;
039    
040    /**
041     * @author Franck WOLFF
042     */
043    public class HttpGraniteContext extends GraniteContext {
044    
045            private static final String SESSION_LOCK_KEY = HttpGraniteContext.class.getName() + ".LOCK";
046            
047        private final ServletContext context;
048        private final HttpServletRequest request;
049        private final HttpServletResponse response;
050    
051        private InitialisationMap initialisationMap = null;
052        private ApplicationMap applicationMap = null;
053        private SessionMap sessionMap = null;
054        private RequestMap requestMap = null;
055    
056    
057        public static HttpGraniteContext createThreadIntance(
058            GraniteConfig graniteConfig,
059            ServicesConfig servicesConfig,
060            ServletContext context,
061            HttpServletRequest request,
062            HttpServletResponse response) {
063    
064            HttpGraniteContext graniteContext = new HttpGraniteContext(graniteConfig, servicesConfig, context, request, response);
065            setCurrentInstance(graniteContext);
066            return graniteContext;
067        }
068    
069    
070        private HttpGraniteContext(
071            GraniteConfig graniteConfig,
072            ServicesConfig servicesConfig,
073            ServletContext context,
074            HttpServletRequest request,
075            HttpServletResponse response) {
076    
077            super(graniteConfig, servicesConfig);
078            this.context = context;
079            this.request = request;
080            this.response = response;
081        }
082    
083        public ServletContext getServletContext() {
084            return context;
085        }
086    
087        public HttpServletRequest getRequest() {
088            return request;
089        }
090    
091        public HttpServletResponse getResponse() {
092            return response;
093        }
094    
095        public HttpSession getSession(boolean create) {
096            return request.getSession(create);
097        }
098    
099        public HttpSession getSession() {
100            return request.getSession(true);
101        }
102    
103        @Override
104            public synchronized Object getSessionLock() {
105                    Object lock = request.getSession(true).getAttribute(SESSION_LOCK_KEY);
106                    if (lock == null) {
107                            lock = new Boolean(true);
108                            request.getSession(true).setAttribute(SESSION_LOCK_KEY, lock);
109                    }
110                    return lock;
111            }
112    
113    
114            @Override
115        public Map<String, String> getInitialisationMap() {
116            if (initialisationMap == null)
117                initialisationMap = new InitialisationMap(context);
118            return initialisationMap;
119        }
120    
121        @Override
122        public Map<String, Object> getApplicationMap() {
123            if (applicationMap == null)
124                applicationMap = new ApplicationMap(context);
125            return applicationMap;
126        }
127    
128            @Override
129        public Map<String, Object> getSessionMap() {
130                    return getSessionMap(true);
131        }
132        @Override
133            public Map<String, Object> getSessionMap(boolean create) {
134            if (sessionMap == null && (create || request.getSession(false) != null))
135                sessionMap = new SessionMap(request);
136            return sessionMap;
137            }
138    
139        @Override
140        public Map<String, Object> getRequestMap() {
141            if (requestMap == null)
142                requestMap = new RequestMap(request);
143            return requestMap;
144        }
145    }
146    
147    abstract class BaseContextMap<T,U> extends AbstractMap<T,U> {
148    
149        protected static final String KEY_STRING_ERROR = "Key should be a non null String: ";
150    
151        @Override
152        public void clear() {
153            throw new UnsupportedOperationException();
154        }
155    
156        @Override
157        public void putAll(Map<? extends T, ? extends U> t) {
158            throw new UnsupportedOperationException();
159        }
160    
161        @Override
162        public U remove(Object key) {
163            throw new UnsupportedOperationException();
164        }
165    
166        static class Entry<T,U> implements Map.Entry<T,U> {
167    
168            private final T key;
169            private final U value;
170    
171            Entry(T key, U value) {
172                this.key = key;
173                this.value = value;
174            }
175    
176            public T getKey() {
177                return key;
178            }
179    
180            public U getValue() {
181                return value;
182            }
183    
184            public U setValue(U value) {
185                throw new UnsupportedOperationException();
186            }
187    
188            @Override
189            public int hashCode() {
190                return ((key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()));
191            }
192    
193            @Override
194            public boolean equals(Object obj) {
195                if (obj == this)
196                    return true;
197    
198                if (obj == null || !(obj instanceof Map.Entry<?, ?>))
199                    return false;
200    
201                Map.Entry<?, ?> input = (Map.Entry<?, ?>)obj;
202                Object inputKey = input.getKey();
203                Object inputValue = input.getValue();
204    
205                if (inputKey == key || (inputKey != null && inputKey.equals(key))) {
206                    if (inputValue == value || (inputValue != null && inputValue.equals(value)))
207                        return true;
208                }
209                return false;
210            }
211        }
212    }
213    
214    class InitialisationMap extends BaseContextMap<String, String> {
215    
216        private ServletContext servletContext = null;
217    
218        InitialisationMap(ServletContext servletContext) {
219            if (servletContext == null)
220                throw new NullPointerException("servletContext is null");
221            this.servletContext = servletContext;
222        }
223    
224        @Override
225        public String get(Object key) {
226            if (!(key instanceof String))
227                return null;
228            return servletContext.getInitParameter(key.toString());
229        }
230    
231        @Override
232        public String put(String key, String value) {
233            throw new UnsupportedOperationException();
234        }
235    
236        @Override
237        public Set<Map.Entry<String, String>> entrySet() {
238            Set<Map.Entry<String, String>> entries = new HashSet<Map.Entry<String, String>>();
239            for (Enumeration<?> e = servletContext.getInitParameterNames(); e.hasMoreElements();) {
240                String key = (String)e.nextElement();
241                entries.add(new Entry<String, String>(key, servletContext.getInitParameter(key)));
242            }
243            return entries;
244        }
245    
246        @Override
247        public boolean equals(Object obj) {
248            if (obj == null || !(obj instanceof InitialisationMap))
249                return false;
250            return super.equals(obj);
251        }
252    }
253    
254    class ApplicationMap extends BaseContextMap<String, Object> {
255    
256        private ServletContext servletContext = null;
257    
258        ApplicationMap(ServletContext servletContext) {
259            if (servletContext == null)
260                throw new NullPointerException("servletContext is null");
261            this.servletContext = servletContext;
262        }
263    
264        @Override
265        public Object get(Object key) {
266            if (!(key instanceof String))
267                return null;
268           return servletContext.getAttribute(key.toString());
269        }
270    
271        @Override
272        public Object put(String key, Object value) {
273            if (key == null)
274                throw new IllegalArgumentException(KEY_STRING_ERROR + key);
275            Object result = servletContext.getAttribute(key);
276            servletContext.setAttribute(key, value);
277            return (result);
278        }
279    
280        @Override
281        public Object remove(Object key) {
282            if (!(key instanceof String))
283                return null;
284            Object result = servletContext.getAttribute(key.toString());
285            servletContext.removeAttribute(key.toString());
286            return result;
287        }
288    
289        @Override
290        public Set<Map.Entry<String, Object>> entrySet() {
291            Set<Map.Entry<String, Object>> entries = new HashSet<Map.Entry<String, Object>>();
292            for (Enumeration<?> e = servletContext.getAttributeNames(); e.hasMoreElements();) {
293                String key = (String)e.nextElement();
294                entries.add(new Entry<String, Object>(key, servletContext.getAttribute(key)));
295            }
296            return entries;
297        }
298    
299        @Override
300        public boolean equals(Object obj) {
301            if (obj == null || !(obj instanceof ApplicationMap))
302                return false;
303            return super.equals(obj);
304        }
305    }
306    
307    class SessionMap extends BaseContextMap<String, Object> {
308    
309        private HttpServletRequest request = null;
310    
311        SessionMap(HttpServletRequest request) {
312            if (request == null)
313                throw new NullPointerException("request is null");
314            this.request = request;
315        }
316    
317        @Override
318        public Object get(Object key) {
319            if (!(key instanceof String))
320                return null;
321            Object value = getSession().getAttribute(key.toString());
322            if (value instanceof TransientReferenceHolder)
323                    return ((TransientReferenceHolder)value).get();
324            return value;
325        }
326    
327        @Override
328        public Object put(String key, Object value) {
329            if (key == null)
330                throw new IllegalArgumentException(KEY_STRING_ERROR + key);
331            HttpSession session = getSession();
332            Object result = session.getAttribute(key);
333            if (result instanceof TransientReferenceHolder)
334                    result = ((TransientReferenceHolder)result).get();
335            if (value != null && value.getClass().isAnnotationPresent(TransientReference.class))
336                    value = new TransientReferenceHolder(value);
337            session.setAttribute(key, value);
338            return result;
339        }
340    
341        @Override
342        public Object remove(Object key) {
343            if (!(key instanceof String))
344                return null;
345            HttpSession session = getSession();
346            Object result = session.getAttribute(key.toString());
347            if (result instanceof TransientReferenceHolder)
348                    result = ((TransientReferenceHolder)result).get();
349            session.removeAttribute(key.toString());
350            return result;
351        }
352    
353        @Override
354        public Set<Map.Entry<String, Object>> entrySet() {
355            Set<Map.Entry<String, Object>> entries = new HashSet<Map.Entry<String, Object>>();
356            HttpSession session = getSession();
357            for (Enumeration<?> e = session.getAttributeNames(); e.hasMoreElements(); ) {
358                String key = (String)e.nextElement();
359                Object value = session.getAttribute(key);
360                if (value instanceof TransientReferenceHolder)
361                    value = ((TransientReferenceHolder)value).get();
362                entries.add(new Entry<String, Object>(key, value));
363            }
364            return entries;
365        }
366    
367        @Override
368        public boolean equals(Object obj) {
369            if (obj == null || !(obj instanceof SessionMap))
370                return false;
371            return super.equals(obj);
372        }
373    
374        private HttpSession getSession() {
375            return request.getSession(true);
376        }
377    }
378    
379    class RequestMap extends BaseContextMap<String, Object> {
380    
381        private HttpServletRequest request = null;
382    
383        RequestMap(HttpServletRequest request) {
384            if (request == null)
385                throw new NullPointerException("request is null");
386            this.request = request;
387        }
388    
389        @Override
390        public Object get(Object key) {
391            if (!(key instanceof String))
392                return null;
393            return request.getAttribute(key.toString());
394        }
395    
396        @Override
397        public Object put(String key, Object value) {
398            if (key == null)
399                throw new IllegalArgumentException(KEY_STRING_ERROR + key);
400            Object result = request.getAttribute(key);
401            request.setAttribute(key, value);
402            return result;
403        }
404    
405        @Override
406        public Object remove(Object key) {
407            if (!(key instanceof String))
408                return null;
409            Object result = request.getAttribute(key.toString());
410            request.removeAttribute(key.toString());
411            return result;
412        }
413    
414        @Override
415        public Set<Map.Entry<String, Object>> entrySet() {
416            Set<Map.Entry<String, Object>> entries = new HashSet<Map.Entry<String, Object>>();
417            for (Enumeration<?> e = request.getAttributeNames(); e.hasMoreElements();) {
418                String key = (String)e.nextElement();
419                entries.add(new Entry<String, Object>(key, request.getAttribute(key)));
420            }
421            return entries;
422        }
423    
424        @Override
425        public boolean equals(Object obj) {
426            if (obj == null || !(obj instanceof RequestMap))
427                return false;
428            return super.equals(obj);
429        }
430    }