1 2 Previous Next 15 Replies Latest reply on Sep 22, 2009 1:43 AM by Stuart Douglas

    Outjecting session-scope object from servlet filter

    Roger Goldman Newbie

      Hi everyone.




      Over the past several days, I've attempted to cause an APPLICATION-scoped Seam-enabled servlet filter to outject a session scope object.  After many attempts and hours of searching the web and reading seam-related posts and documentation, I seem to have exhausted my options (and possibly patience).


      I'm hoping someone with expertise in this particular area can assist me in getting over this hurdle.  Please note that we have been successfully using seam for the past 4 months developing this application and I suspect that my problem stems from a lack of understanding of how Seam's framework was designed to deal with Servlet Filters.


      Some facts about my environment




      • Tomcat 6.0.14

      • Seam 2.0.3.CR1 (although we had the same problems with 2.0.2.SP1 and 2.1.0.BETA1)

      • Persistence settings



      components.xml




           <transaction:entity-transaction entity-manager="#{entityManager}" />
           <persistence:entity-manager-factory name="MyDatabase" />
           <persistence:managed-persistence-context name="entityManager"
                auto-create="true" scope="conversation"
                entity-manager-factory="#{MyDatabase}" />




      persistence.xml



         <persistence-unit name="MyDatabase" transaction-type="RESOURCE_LOCAL">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <jta-data-source>java:comp/env/jdbc/TestDB</jta-data-source>
            <properties>
               <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
               <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
               <property name="hibernate.show_sql" value="true"/>
               <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/>
            </properties>
         </persistence-unit>
      




      The Seam-enabled Servlet Filter




      @Startup
      @Scope(ScopeType.APPLICATION)
      @Name("userAuthenticationFilter")
      @Filter(within="org.jboss.seam.servlet.SeamFilter")
      public class UserAuthenticationFilter implements javax.servlet.Filter {
           @Out(scope=ScopeType.SESSION)
           private User user;
           
           @SuppressWarnings("unchecked")
           public void init(FilterConfig filterConfig) throws ServletException {
           }
      
           public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {
      
                      user = detectUser();
                chain.doFilter(request, response );
           }
      
           public void destroy() {
           }
      
              private User detectUser() {
                      ...
              }
      }
      




      The Problem



      The problem I'm encountering is the following exception when the init() method is called:


      INFO: Initializing filter: userAuthenticationFilter
      Sep 12, 2008 3:20:44 PM org.apache.catalina.core.StandardContext filterStart
      SEVERE: Exception starting filter Seam Filter
      java.lang.IllegalStateException: No session context active
           at org.jboss.seam.ScopeType.getContext(ScopeType.java:132)
           at org.jboss.seam.Component.outjectAttribute(Component.java:1667)
           at org.jboss.seam.Component.outjectAttributes(Component.java:1620)
           at org.jboss.seam.Component.outject(Component.java:1473)
           at org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:47)
           at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
           at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
           at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
           at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
           at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:166)
           at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:102)
           at test.UserAuthenticationFilter_$$_javassist_0.init(UserAuthenticationFilter_$$_javassist_0.java)
           at org.jboss.seam.servlet.SeamFilter.init(SeamFilter.java:97)
           at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
           at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
           at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:108)
           at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3696)
           at org.apache.catalina.core.StandardContext.start(StandardContext.java:4343)
           at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
           at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
           at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
           at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
           at org.apache.catalina.core.StandardService.start(StandardService.java:516)
           at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
           at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           at java.lang.reflect.Method.invoke(Method.java:585)
           at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
           at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
      Sep 12, 2008 3:20:44 PM org.apache.catalina.core.StandardContext start
      SEVERE: Error filterStart



      Call for Help



      I can understand the error message: the init() method runs while there is only an APPLICATION context active.  OK, but I'm not trying to outject the User object in the init() method.  I'm trying to do the outjection in the doFilter() method, which runs while servicing a REQUEST -- therefore both REQUEST and SESSION contexts should be active, no?


      If Seam doesn't support this kind of situation and I need to take an entirely different approach that would be OK with me.  Would you please help me understand the right way of doing something like this is with the Seam framework.


      Many thanks in advance.

        • 1. Re: Outjecting session-scope object from servlet filter
          Hans Schlegel Newbie

          Hi Roger


          Did you try it the standard way...



               public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
          
                          user = detectUser();
                          request.getSession().setAttribute("user", user);
                    chain.doFilter(request, response );
               }
          



          • 2. Re: Outjecting session-scope object from servlet filter
            Roger Goldman Newbie

            Thanks.  I tried your suggestion and it seems to get further along.  Unfortunately, requests aren't making their entire way through the filter, and get a NullPointerException here:


            Daemon Thread [http-8080-1] (Suspended (breakpoint at line 241 in Contexts))     
                 Contexts.destroy(Context) line: 241     
                 Lifecycle.endCall() line: 95     
                 JavaBeanInterceptor(RootInterceptor).invoke(InvocationContext, EventType) line: 122     
                 JavaBeanInterceptor.interceptInvocation(Method, Object[]) line: 166     
                 JavaBeanInterceptor.invoke(Object, Method, Method, Object[]) line: 102     
                 UserAuthenticationFilter_$$_javassist_0.doFilter(ServletRequest, ServletResponse, FilterChain) line: not available     
                 SeamFilter$FilterChainImpl.doFilter(ServletRequest, ServletResponse) line: 78     
                 SeamFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 158     
                 ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235     
                 ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206     
                 NtlmHttpFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 118     
                 ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235     
                 ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206     
                 StandardWrapperValve.invoke(Request, Response) line: 233     
                 StandardContextValve.invoke(Request, Response) line: 175     
                 StandardHostValve.invoke(Request, Response) line: 128     
                 ErrorReportValve.invoke(Request, Response) line: 102     
                 StandardEngineValve.invoke(Request, Response) line: 109     
                 CoyoteAdapter.service(Request, Response) line: 263     
                 Http11Processor.process(Socket) line: 844     
                 Http11Protocol$Http11ConnectionHandler.process(Socket) line: 584     
                 JIoEndpoint$Worker.run() line: 447     
                 Thread.run() line: 595     
            



            The problem is that the Contexts.destroy() method is being called with a null context from Lifecycle.endCall() which apparently thinks that a session context should exist.


            public static void endCall()
               {
                  try
                  {
                     Contexts.destroy( Contexts.getSessionContext() );   // Can the session context ever be null here???
                     Contexts.flushAndDestroyContexts();
                     if ( Manager.instance().isLongRunningConversation() )
                     {
                        throw new IllegalStateException("Do not start long-running conversations in direct calls to EJBs");
                     }
                  }
                  finally
                  {
                     clearThreadlocals();
                     log.debug( "<<< End call" );
                  }
               }
            



            If a Session context should exists here, when should it have been created?  Or should call to Contexts.destroy() be guarded?  This is a probably question for one of the Seam developers.


            Thanks.


            /rag
             

            • 3. Re: Outjecting session-scope object from servlet filter
              Roger Goldman Newbie

              I did a quick test to see if guarding the call to Contexts.destroy( Contexts.getSessionContext() ); with an if statement would fix things, but it didn't.


              The problem shifts to the call to Manager.instance().isLongRunningConversation() which expects to have an Event context, which apparently also doesn't exists in this case.


              Can someone from the core team answer the question of whether what I am trying to do is supported, and if so, what the correct way of doing it is?


              Many thanks.


              /rag

              • 4. Re: Outjecting session-scope object from servlet filter
                Robert Yokota Newbie

                Try

                @Filter(within="org.jboss.seam.web.ajax4jsfFilter")

                instead of

                @Filter(within="org.jboss.seam.servlet.SeamFilter")

                • 5. Re: Outjecting session-scope object from servlet filter
                  Roger Goldman Newbie

                  Same thing happens with the ajex4jsfFilter.


                  Anybody have any other ideas?  Is this even supported?  Has anyone been able to do this successfully?


                  • 6. Re: Outjecting session-scope object from servlet filter
                    Pete Muir Master

                    Use the context filter or a ContextualHttpServletRequest - RTM :p

                    • 7. Re: Outjecting session-scope object from servlet filter
                      Roger Goldman Newbie

                      Hi Pete,


                      Are you referring to the Seam Reference document (A Framework for Enterprise Java) and, more specifically section 26.1.4.7 of version 2.0.2.SP1?  If so, yes, I've RTM several times, as well as many other Seam-related online articles. :-)  (By the way, there appears to be no mention of the ContextualHttpServletRequest in that reference manual, although some information is available elsewhere online).


                      I have a Seam application already built and simply need to intercept each Seam request, do some preliminary work (possibly outjecting some stuff into the Session scope), and then simply let the regular Seam request lifecycle proceed normally.


                      From what I've read, I don't see how context-filters or ContextualHttpServletRequests could help me, as I actually need to manipulate requests that would normally get handled by Seam.  The documentation


                      I essentially need the equivalent of a ServletFilter, but one which has access to the Seam contexts for the currently executing request.


                      I imagine there are all kinds of other people wanting to achieve something similar to what I'm doing.  I'd hate to have to hack something in place to make it work -- I'd rather do it the right way, if Seam has built-in support for this use case.






                      /rag

                      • 8. Re: Outjecting session-scope object from servlet filter
                        Christian Lauer Newbie

                        Hi Roger,


                        I had a similar same problem like yours.
                        I found a trick to solve it by disabling interceptors using @BypassInterceptors on the filter class. This disables bijection, which makes your outjection not work anymore.
                        This can be solved by calling another seam component from the filter.
                        What you need to do is get this component within the init method of the filter, as you don't have access to the application context from within the doFilter method (can anyone tell me why???).


                        Here's a simple example:



                        @Startup
                        @AutoCreate
                        @Name("testFilter")
                        @Scope(ScopeType.APPLICATION)
                        @BypassInterceptors
                        @Filter(within="org.jboss.seam.servlet.SeamFilter")
                        public class TestFilter implements javax.servlet.Filter {
                        
                          private TestComponent testComponent;
                          
                          public void init(FilterConfig filterConfig) throws ServletException {
                            System.out.println("INITIALIZING FILTER ...");
                            try {
                              this.testComponent = (TestComponent) Component.getInstance("testComponent");
                              System.out.println("GOT TEST COMPONENT!!!!");
                            } catch (Throwable ex) {
                              ex.printStackTrace();
                            }
                          }
                          
                          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                            throws IOException, ServletException {
                        
                            System.out.println("FILTER called!!!!");
                            try {
                              testComponent.invoke(((HttpServletRequest) request).getRequestURI());
                            } catch (Throwable ex) {
                              ex.printStackTrace();
                            }
                            chain.doFilter(request, response);
                          }
                        
                          public void destroy() {
                            System.out.println("FILTER DESTROYED!!!!");
                          }
                        
                        }
                        



                        The used component has to be application scoped and auto created as well:



                        @Name("testComponent")
                        @AutoCreate
                        @Scope(ScopeType.APPLICATION)
                        public class TestComponent {
                        
                          @Create
                          public void onCreate() {
                            System.out.println("TEST COMPONENT CREATED!");
                          }
                          
                          public void invoke(String path) {
                            System.out.println("TEST COMPONENT CALLED for path '" + path + "'!");
                          }
                          
                        }
                        



                        Hope this helps,
                        Christian

                        • 9. Re: Outjecting session-scope object from servlet filter
                          Julien Kronegg Novice

                          The used component has to be application scoped and auto created as well

                          This would probably not work for Roger, as he wants to put the User in session (i.e. not with application scope).


                          By the way, I have the same problem: my GET request contains a SSO string parameter that I want to use to create the Identity: when using a ServletRequestListener with ContextualHttpServletRequest, I'm not yet in the session scope, so the ContextualHttpServletRequest creates a new session which holds the initialized Identity. But at the next HTTP request, a new session seems to be created (with an uninitialized Identity).


                          I'm still looking for a solution...

                          • 10. Re: Outjecting session-scope object from servlet filter
                            Ronald van Kuijk Apprentice

                            This is for conversation-scope but I think it would work for session as well (since a conversation is in a session)


                            (you need the extra layer, seam seems to do it with all gwt, wicket servlet/filters as well)

                            • 11. Re: Outjecting session-scope object from servlet filter
                              Julien Kronegg Novice

                              I found the solution for my SSO problem: session cookies was not allowed on the browser, thus Seam was starting a new session at each HTTP request.


                              This is the solution I use (i.e. ServletRequestListener + ContextualHttpServletRequest):


                              public class MyRequestListener implements javax.servlet.ServletRequestListener {
                                public void requestInitialized(ServletRequestEvent e) {
                                  final HttpServletRequest request = (HttpServletRequest)e.getServletRequest();
                                  new ContextualHttpServletRequest(request) throws Exception {
                                    public void process() {
                                      String sso_id = request.getParameter("SSO_ID");
                                      MyIdentity identity = (MyIdentity)Component.getInstance(MyIdentity.class);
                              
                                      identity.doSomeActionWithSsoId(sso_id);
                                      // this method must at least: initialize the username and
                                      // password with fake values to tell Seam the user is logged on
                                    }
                                  }.run();
                                }
                                public void requestDestroyed(ServletRequestEvent e) {}
                              }
                              



                              You also need to define your ServletRequestListener in the web.xml:


                              ...
                              <listener>
                                <listener-class>my.package.MyRequestListener</listener-class>
                              </listener>
                              ...
                              



                              I think it is a better solution than the Servlet filter because we do not modify the ServletResponse.

                              • 12. Re: Outjecting session-scope object from servlet filter
                                Diana Gomez Newbie

                                Another way to get Identy component in a filter..


                                HttpSession session = ((HttpServletRequest) request).getSession(false);
                                                if (session!=null)
                                                {
                                                   Object attribute =    session.getAttribute("org.jboss.seam.security.identity");
                                                   if (attribute instanceof Identity) 
                                                   {
                                                      identity = (Identity) attribute;
                                                    }



                                • 13. Re: Outjecting session-scope object from servlet filter
                                  Diana Gomez Newbie

                                  Another way to get Identity component




                                  HttpSession session = ((HttpServletRequest) request).getSession(false);
                                                  if (session!=null)
                                                  {
                                                     Object attribute = session.getAttribute("org.jboss.seam.security.identity");
                                                     if (attribute instanceof Identity) 
                                                     {
                                                        identity = (Identity) attribute;
                                  }



                                  • 14. Re: Outjecting session-scope object from servlet filter
                                    Diana Gomez Newbie

                                    another way to get Identity




                                    HttpSession session = ((HttpServletRequest) request).getSession(false);
                                                    if (session!=null)
                                                    {
                                                       Object attribute = session.getAttribute("org.jboss.seam.security.identity");
                                                       if (attribute instanceof Identity) 
                                                       {
                                                          identity = (Identity) attribute;
                                                        }
                                                     }



                                    1 2 Previous Next