5 Replies Latest reply on Oct 16, 2009 9:07 PM by walterjwhite

    Filters with EntityManager and loss of StatusMessages

    dhinojosa

      I have a strange situation. I created a filter that persists an entity to the database via the EntityManager about the request and it's headers.  Everything works well except the statusMessages are gone when the next page is displayed.  Here is my filter:


      @Startup
      @Scope(ScopeType.APPLICATION)
      @Name("requestDataCellFilter")
      @BypassInterceptors
      @Filter(within="org.jboss.seam.web.ajax4jsfFilter")
      public class RequestFilter extends AbstractFilter {
      
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                  throws IOException, ServletException {
              if (servletRequest instanceof HttpServletRequest) {
                  final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
                  if (
                          (!(httpServletRequest.getServletPath().endsWith(".html")))
                          ) {
                      filterChain.doFilter(servletRequest, servletResponse);
                      return;
                  }
                  new ContextualHttpServletRequest(httpServletRequest) {
                      @SuppressWarnings({"unchecked"})
                      public void process() throws ServletException {
                          final Request request = new Request();  //Request object is an entity.
                          request.setLocalAddr(httpServletRequest.getLocalAddr());
                          request.setRemoteAddr(httpServletRequest.getRemoteAddr());
                          request.setRemoteHost(httpServletRequest.getRemoteHost());
                          request.setRemotePort(httpServletRequest.getRemotePort());
                          request.setAuthType(httpServletRequest.getAuthType());
                          request.setContextPath(httpServletRequest.getContextPath());
                          request.setMethod(httpServletRequest.getMethod());
                          request.setPathInfo(httpServletRequest.getPathInfo());
                          request.setPathTranslated(httpServletRequest.getPathTranslated());
                          request.setQueryString(httpServletRequest.getQueryString());
                          request.setRemoteUser(httpServletRequest.getRemoteUser());
                          request.setRequestedSessionId(httpServletRequest.getRequestedSessionId());
                          request.setRequestURI(httpServletRequest.getRequestURI());
                          request.setRequestURL(httpServletRequest.getRequestURL().toString());
                          request.setServletPath(httpServletRequest.getServletPath());
      
                          Enumeration<String> enumeration = (Enumeration<String>) httpServletRequest.getHeaderNames();
                          while (enumeration.hasMoreElements()) {
                              String name = enumeration.nextElement();
                              String value = httpServletRequest.getHeader(name);
                              Header header = new Header(name, value);
                              request.addHeader(header);
                          }
                          UserTransaction transaction = (UserTransaction) Component
                                  .getInstance("org.jboss.seam.transaction.transaction");
                          try {
                              transaction.begin();
                              EntityManager entityManager =
                                      (EntityManager)
                                              Component.getInstance("entityManager");
      
                              Calendar calendar =
                                      (Calendar)
                                              Component.getInstance("currentCalendar");  //This is a GregorianCalendar component that I use.
                              request.setCreatedDate(calendar);
                              entityManager.persist(request);
                              entityManager.flush();
                              transaction.commit();
                          } catch (Exception e) {
                              try {
                                  transaction.rollback();
                              } catch (SystemException e1) {
                                  throw new ServletException(e1);
                              }
                          }
                      }
                  }.run();
              }
      
              filterChain.doFilter(servletRequest, servletResponse);
          }
      }
      
      


      So, for example, if someone creates an entity with EntityHome the createdMessage doesn't display because of this filter.  As always, your help is appreciated.


        • 1. Re: Filters with EntityManager and loss of StatusMessages
          walterjwhite

          Dan,


          Cool - I actually do a very similar thing to capture the input and output.


          Just curious, do you log the response as well?



          My approach differs slightly from yours - I think you might have issues wrapping that in a ContextualHttpServletRequest since you are already only listening for .html pages. I am guessing the FacesServlet is responding to those requests (depends on your configuration).  I would try removing that wrapping and seeing what happens.


          You also you specify what urls you want your filter to listen to in the component declaration (components.xml).


          • 2. Re: Filters with EntityManager and loss of StatusMessages
            walterjwhite

            It looks like my response got messed up ...


            I was saying that you can specify what URLs you want that servlet filter to listen to like other seam servlet filters.


            components.xml


            url-pattern="*.html"


            Make sure you declare a package-info.java with the namespace and import it at the top of your components.xml.  You can then configure any properties you need for that component.



            Walter

            • 3. Re: Filters with EntityManager and loss of StatusMessages
              dhinojosa

              No Application Context Available exception is the result if I don't wrap it around a ContextualHttpServletRequest(httpServletRequest).  For this particular filter I just want to log the request and all works great, it's just that certain exception just disappear along the way. ;)

              • 4. Re: Filters with EntityManager and loss of StatusMessages
                dhinojosa

                Ooops, meant to say: it's just that certain status messages just disappear along the way. ;)

                • 5. Re: Filters with EntityManager and loss of StatusMessages
                  walterjwhite

                  Dan,


                  I also capture the request/response but don't appear to have issues with messages.


                  I have a contact action that notifies the user we received their message okay:


                  facesMessages.add( ...)



                  I also try to notify the user of events that happen asynchronously using a servlet filter.  I have an application-scoped component that processes events and stores them referencing the appropriate session id (key-value pair type deal).  The servlet filter then gets that component and then messages for the session id (if any).  My logs indicate that there are messages being added, but I never see those (the ones added from the servlet filter).


                  In the servlet filter, I'm doing the same thing:


                  FacesMessages facesMessages = FacesMessages.instance();
                  facesMessages.add( ... );



                  1. Where are you adding your messages from (another servlet filter or another component with support for bijection?
                  2. Are you sure there aren't any exceptions being thrown?
                  3. Where is the FacesServlet configured to listen (if anywhere)?


                  I still think it has something to do with wrapping the request.  That would probably overwrite any existing faces context / messages.


                  The way that I wrap everything in a context is simple.


                  1. implement your own ContextFilter that wraps all URLs. <custom:filter/> (I don't install my components by default, this is just for installation)
                  2. if a context is already active, then don't wrap the request, if it is not, then wrap the request.
                  3. put that in a try-catch.



                  Walter