001/* 002 * jDTAUS Core RI Servlet Container 003 * Copyright (C) 2005 Christian Schulte 004 * <cs@schulte.it> 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 019 * 020 */ 021package org.jdtaus.core.container.ri.servlet; 022 023import java.io.IOException; 024import java.lang.reflect.InvocationTargetException; 025import java.lang.reflect.Method; 026import java.util.Locale; 027import javax.servlet.Filter; 028import javax.servlet.FilterChain; 029import javax.servlet.FilterConfig; 030import javax.servlet.ServletContext; 031import javax.servlet.ServletException; 032import javax.servlet.ServletRequest; 033import javax.servlet.ServletResponse; 034import javax.servlet.http.HttpServletRequest; 035import javax.servlet.http.HttpSession; 036import org.jdtaus.core.container.ContainerFactory; 037import org.jdtaus.core.container.Context; 038import org.jdtaus.core.container.ContextFactory; 039import org.jdtaus.core.container.ModelFactory; 040 041/** 042 * jDTAUS webapp integration filter. 043 * <p>This filter needs to be setup in each application's {@code web.xml} 044 * descriptor like:<pre> 045 * <filter> 046 * <filter-name>jDTAUS Integration Filter</filter-name> 047 * <filter-class>org.jdtaus.core.container.ri.servlet.ServletFilter</filter-class> 048 * </filter></pre></p> 049 * 050 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 051 * @version $JDTAUS: ServletFilter.java 8743 2012-10-07 03:06:20Z schulte $ 052 * 053 * @see #init(FilterConfig) 054 */ 055public class ServletFilter implements Filter 056{ 057 //--ServletFilter----------------------------------------------------------- 058 059 /** Holds thread local {@code ServletContext}s. */ 060 private static final ThreadLocal CONTEXTS = new ThreadLocal(); 061 062 /** Holds thread local {@code HttpSession}s. */ 063 private static final ThreadLocal SESSIONS = new ThreadLocal(); 064 065 /** Holds thread local {@code Locale}s. */ 066 private static final ThreadLocal LOCALES = new ThreadLocal(); 067 068 /** Holds the {@code ServletContext} the filter got initialized with. */ 069 private ServletContext servletContext; 070 071 /** 072 * Gets the thread local servlet context. 073 * 074 * @return the thread local servlet context. 075 * 076 * @throws ContextLostException if no servlet context is bound to the 077 * current thread of execution. 078 */ 079 public static ServletContext getServletContext() 080 { 081 final ServletContext context = (ServletContext) CONTEXTS.get(); 082 083 if ( context == null ) 084 { 085 throw new ContextLostException( getLocale(), 086 Thread.currentThread() ); 087 088 } 089 090 return context; 091 } 092 093 /** 094 * Gets the thread local HTTP session. 095 * 096 * @return the thread local HTTP session. 097 * 098 * @throws SessionLostException if no session is bound to the current 099 * 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 final 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( final 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 /** Creates a new {@code ServletFilter} instance. */ 231 public ServletFilter() 232 { 233 super(); 234 } 235 236 private void removeThreadLocal( final ThreadLocal threadLocal ) 237 { 238 try 239 { 240 // Try remove method introduced in JDK 1.5. 241 final Method removeMethod = threadLocal.getClass(). 242 getDeclaredMethod( "remove", new Class[ 0 ] ); 243 244 removeMethod.invoke( threadLocal, null ); 245 } 246 catch ( final IllegalAccessException e ) 247 { 248 threadLocal.set( null ); 249 this.servletContext.log( e.getMessage(), e ); 250 } 251 catch ( final IllegalArgumentException e ) 252 { 253 threadLocal.set( null ); 254 this.servletContext.log( e.getMessage(), e ); 255 } 256 catch ( final InvocationTargetException e ) 257 { 258 threadLocal.set( null ); 259 this.servletContext.log( e.getMessage(), e ); 260 } 261 catch ( final NoSuchMethodException e ) 262 { 263 threadLocal.set( null ); 264 } 265 } 266 267 //-----------------------------------------------------------ServletFilter-- 268 //--Messages---------------------------------------------------------------- 269 270// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages 271 // This section is managed by jdtaus-container-mojo. 272 273 /** 274 * Gets the text of message <code>systemProperty</code>. 275 * <blockquote><pre>System Eigenschaft {0} auf {1} gesetzt.</pre></blockquote> 276 * <blockquote><pre>System property {0} set to {1}.</pre></blockquote> 277 * 278 * @param locale The locale of the message instance to return. 279 * @param propertyName Name of the updated system property. 280 * @param value Value the system property got updated to. 281 * 282 * @return Information about an updated system property. 283 */ 284 private String getSystemPropertyMessage( final Locale locale, 285 final java.lang.String propertyName, 286 final java.lang.String value ) 287 { 288 return ContainerFactory.getContainer(). 289 getMessage( this, "systemProperty", locale, 290 new Object[] 291 { 292 propertyName, 293 value 294 }); 295 296 } 297 298// </editor-fold>//GEN-END:jdtausMessages 299 300 //----------------------------------------------------------------Messages-- 301}