View Javadoc

1   /*
2    *  jDTAUS Core RI Servlet Container
3    *  Copyright (C) 2005 Christian Schulte
4    *  <cs@schulte.it>
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19   *
20   */
21  package org.jdtaus.core.container.ri.servlet;
22  
23  import java.io.IOException;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.util.Locale;
27  import javax.servlet.Filter;
28  import javax.servlet.FilterChain;
29  import javax.servlet.FilterConfig;
30  import javax.servlet.ServletContext;
31  import javax.servlet.ServletException;
32  import javax.servlet.ServletRequest;
33  import javax.servlet.ServletResponse;
34  import javax.servlet.http.HttpServletRequest;
35  import javax.servlet.http.HttpSession;
36  import org.jdtaus.core.container.ContainerFactory;
37  import org.jdtaus.core.container.Context;
38  import org.jdtaus.core.container.ContextFactory;
39  import org.jdtaus.core.container.ModelFactory;
40  
41  /**
42   * jDTAUS webapp integration filter.
43   * <p>This filter needs to be setup in each application's {@code web.xml}
44   * descriptor like:<pre>
45   * &lt;filter&gt;
46   *   &lt;filter-name&gt;jDTAUS Integration Filter&lt;/filter-name&gt;
47   *   &lt;filter-class&gt;org.jdtaus.core.container.ri.servlet.ServletFilter&lt;/filter-class&gt;
48   * &lt;/filter&gt;</pre></p>
49   *
50   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
51   * @version $JDTAUS: ServletFilter.java 8641 2012-09-27 06:45:17Z schulte $
52   *
53   * @see #init(FilterConfig)
54   */
55  public class ServletFilter implements Filter
56  {
57      //--ServletFilter-----------------------------------------------------------
58  
59      /** Holds thread local {@code ServletContext}s. */
60      private static final ThreadLocal CONTEXTS = new ThreadLocal();
61  
62      /** Holds thread local {@code HttpSession}s. */
63      private static final ThreadLocal SESSIONS = new ThreadLocal();
64  
65      /** Holds thread local {@code Locale}s. */
66      private static final ThreadLocal LOCALES = new ThreadLocal();
67  
68      /** Holds the {@code ServletContext} the filter got initialized with. */
69      private ServletContext servletContext;
70  
71      /**
72       * Gets the thread local servlet context.
73       *
74       * @return the thread local servlet context.
75       *
76       * @throws ContextLostException if no servlet context is bound to the
77       * current thread of execution.
78       */
79      public static ServletContext getServletContext()
80      {
81          final ServletContext context = (ServletContext) CONTEXTS.get();
82  
83          if ( context == null )
84          {
85              throw new ContextLostException( getLocale(),
86                                              Thread.currentThread() );
87  
88          }
89  
90          return context;
91      }
92  
93      /**
94       * Gets the thread local HTTP session.
95       *
96       * @return the thread local HTTP session.
97       *
98       * @throws SessionLostException if no session is bound to the current
99       * thread of execution or if the requesting {@code ServletRequest} is not
100      * an instance of {@code HttpServletRequest}.
101      */
102     public static HttpSession getHttpSession()
103     {
104         final HttpSession session = (HttpSession) SESSIONS.get();
105 
106         if ( session == null )
107         {
108             throw new SessionLostException( getLocale(),
109                                             Thread.currentThread() );
110 
111         }
112 
113         return session;
114     }
115 
116     /**
117      * Gets the thread local locale.
118      *
119      * @return the thread local locale.
120      */
121     public static Locale getLocale()
122     {
123         Locale locale = (Locale) LOCALES.get();
124         return locale == null ? Locale.getDefault() : locale;
125     }
126 
127     //-----------------------------------------------------------ServletFilter--
128     //--Filter------------------------------------------------------------------
129 
130     /**
131      * Initializes the filter by configuring {@code ContainerFactory},
132      * {@code ModelFactory} and {@code ContextFactory} to use the
133      * {@code ServletContextFactories} implementation.
134      *
135      * @see ServletContextFactories
136      */
137     public void init( FilterConfig filterConfig ) throws ServletException
138     {
139         this.servletContext = filterConfig.getServletContext();
140 
141         // Initialize system properties if nothing is provided.
142         if ( System.getProperty( ContainerFactory.class.getName() ) == null )
143         {
144             System.setProperty( ContainerFactory.class.getName(),
145                                 ServletContextFactories.class.getName() );
146 
147             filterConfig.getServletContext().log( this.getSystemPropertyMessage(
148                 Locale.getDefault(), ContainerFactory.class.getName(),
149                 ServletContextFactories.class.getName() ) );
150 
151         }
152         if ( System.getProperty( ContextFactory.class.getName() ) == null )
153         {
154             System.setProperty( ContextFactory.class.getName(),
155                                 ServletContextFactories.class.getName() );
156 
157             filterConfig.getServletContext().log( this.getSystemPropertyMessage(
158                 Locale.getDefault(), ContextFactory.class.getName(),
159                 ServletContextFactories.class.getName() ) );
160 
161         }
162         if ( System.getProperty( ModelFactory.class.getName() ) == null )
163         {
164             System.setProperty( ModelFactory.class.getName(),
165                                 ServletContextFactories.class.getName() );
166 
167             filterConfig.getServletContext().log( this.getSystemPropertyMessage(
168                 Locale.getDefault(), ModelFactory.class.getName(),
169                 ServletContextFactories.class.getName() ) );
170 
171         }
172         if ( System.getProperty( Context.class.getName() ) == null )
173         {
174             System.setProperty( Context.class.getName(),
175                                 HttpSessionContext.class.getName() );
176 
177             filterConfig.getServletContext().log( this.getSystemPropertyMessage(
178                 Locale.getDefault(), Context.class.getName(),
179                 ServletContextFactories.class.getName() ) );
180 
181         }
182     }
183 
184     /**
185      * Attaches the request's {@code HttpSession} with corresponding
186      * {@code ServletContext} to the current thread of execution.
187      *
188      * @see #getServletContext()
189      * @see #getHttpSession()
190      */
191     public void doFilter( final ServletRequest req, final ServletResponse rsp,
192                           final FilterChain chain )
193         throws IOException, ServletException
194     {
195         try
196         {
197             if ( req instanceof HttpServletRequest )
198             {
199                 final HttpServletRequest request = (HttpServletRequest) req;
200                 final HttpSession session = request.getSession( true );
201 
202                 CONTEXTS.set( session.getServletContext() );
203                 SESSIONS.set( session );
204             }
205             else
206             {
207                 CONTEXTS.set( this.servletContext );
208                 SESSIONS.set( null );
209             }
210 
211             LOCALES.set( req.getLocale() );
212             chain.doFilter( req, rsp );
213         }
214         finally
215         {
216             this.removeThreadLocal( CONTEXTS );
217             this.removeThreadLocal( SESSIONS );
218             this.removeThreadLocal( LOCALES );
219         }
220     }
221 
222     public void destroy()
223     {
224         this.servletContext = null;
225     }
226 
227     //------------------------------------------------------------------Filter--
228     //--ServletFilter-----------------------------------------------------------
229 
230     private void removeThreadLocal( final ThreadLocal threadLocal )
231     {
232         try
233         {
234             // Try remove method introduced in JDK 1.5.
235             final Method removeMethod = threadLocal.getClass().
236                 getDeclaredMethod( "remove", new Class[ 0 ] );
237 
238             removeMethod.invoke( threadLocal, null );
239         }
240         catch ( IllegalAccessException e )
241         {
242             threadLocal.set( null );
243             this.servletContext.log( e.getMessage(), e );
244         }
245         catch ( IllegalArgumentException e )
246         {
247             threadLocal.set( null );
248             this.servletContext.log( e.getMessage(), e );
249         }
250         catch ( InvocationTargetException e )
251         {
252             threadLocal.set( null );
253             this.servletContext.log( e.getMessage(), e );
254         }
255         catch ( NoSuchMethodException e )
256         {
257             threadLocal.set( null );
258         }
259     }
260 
261     //-----------------------------------------------------------ServletFilter--
262     //--Messages----------------------------------------------------------------
263 
264 // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages
265     // This section is managed by jdtaus-container-mojo.
266 
267     /**
268      * Gets the text of message <code>systemProperty</code>.
269      * <blockquote><pre>System Eigenschaft {0} auf {1} gesetzt.</pre></blockquote>
270      * <blockquote><pre>System property {0} set to {1}.</pre></blockquote>
271      *
272      * @param locale The locale of the message instance to return.
273      * @param propertyName Name of the updated system property.
274      * @param value Value the system property got updated to.
275      *
276      * @return Information about an updated system property.
277      */
278     private String getSystemPropertyMessage( final Locale locale,
279             final java.lang.String propertyName,
280             final java.lang.String value )
281     {
282         return ContainerFactory.getContainer().
283             getMessage( this, "systemProperty", locale,
284                 new Object[]
285                 {
286                     propertyName,
287                     value
288                 });
289 
290     }
291 
292 // </editor-fold>//GEN-END:jdtausMessages
293 
294     //----------------------------------------------------------------Messages--
295 }