Menu

VelocityContext in LeBAH

Developers
2009-08-13
2013-04-16
  • Shamsul Bahrin Abd Mutalib

    There was a serious bugs in the LeBAH main servlet... just read below.

    The velocity engine was initialized during when the servlet is first started.  This was implemented in the lebah.portal.velocity.VServlet init method, as below:

        public void init(ServletConfig config) throws ServletException {
            super.init(config);
            try {
                engine = new VelocityEngine();
                context = new VelocityContext();
                Properties p = loadConfiguration(config);
                engine.init(p);
            } catch ( Exception e ) {
                System.out.println( e.getMessage() );
            }
        }

    The consequence are, this velocity context shall be shared by all user sessions. As a result, whenever one user use the context, like put a reference in the context or modify an existing reference, the effect will be affected to other user sessions currently accessing this portal.  This, sometimes will created an unwanted result on the user's page, like for example, suddenly logged in user are replaced to other user currently logged in at another place!

    THE REMEDY

    To avoid this from happening, do not initialized the velocity engine in the servlet's init method.  But, let's move this initialization codes into it's own method that we can call later.  So, the VServlet codes becomes like this:

        public void init(ServletConfig config) throws ServletException {
            super.init(config);

        }
       
        public void initVelocity(ServletConfig config) throws ServletException {
            try {
                engine = new VelocityEngine();
                context = new VelocityContext();
                Properties p = loadConfiguration(config);
                engine.init(p);
            } catch ( Exception e ) {
                System.out.println( e.getMessage() );
            }
        }

    Now, we want the velocity engine will be initialized during new user session.  So that, every user sessions shall have their own copy of velocity context.

    This is done in the DesktopController servlet.  We can just put this line of code in the doBody method of the DesktopController:

    initVelocity(this.getServletConfig());

    But this will results in the creation of new velocity engine, each time the servlet is called, therefore, everytime there are new velocity context.  This is OK, but not efficient.

    Instead, let's make the creation more efficient by only initialize the engine only when there are new user sessions.  This is done as below:

            if ( session.getAttribute("_context") != null ) {
                context = (org.apache.velocity.VelocityContext)
                               session.getAttribute("_context");
            } else {
                initVelocity(getServletConfig());
                session.setAttribute("_context", context);
            }

    This will make sure that, each user session shall have their own copy of velocity context.

    To make extra cautions, let's make the doBody method as synchronized.

        public synchronized void doBody(HttpServletRequest req, HttpServletResponse res)
                    throws Exception {
            res.setContentType("text/html");
                   PrintWriter out = res.getWriter();
           
            HttpSession session = req.getSession();
           
            if ( session.getAttribute("_context") != null ) {
                context = (org.apache.velocity.VelocityContext) session.getAttribute("_context");
            } else {
                initVelocity(getServletConfig());
                session.setAttribute("_context", context);
            }

    ---- rest of codes...

    SAM.

     
    • Shamsul Bahrin Abd Mutalib

      Instead of synchronized the whole doBody() method, why not just do it only on the part that initialized the VE, as below:

          public void doBody(HttpServletRequest req, HttpServletResponse res) throws Exception {

              res.setContentType("text/html");
              PrintWriter out = res.getWriter();
            
              synchronized(this) {

                  HttpSession session = req.getSession();
                  if ( session.getAttribute("_context") != null ) {
                      context = (org.apache.velocity.VelocityContext) session.getAttribute("_context");
                  } else {
                      //Initialize Velocity Engine for this Session.
                      initVelocity(getServletConfig());
                      //store context in session

                      session.setAttribute("_context", context);
                  }
              }
            

      ..... rest of codes.

       

Log in to post a comment.