Sunday, April 1, 2012

ZK Flow Control: Detect inactive time and do notify before logout.

This post is about how to detect the last access time and notify user before automatically logout in ZK.

The Files

web.xml


<?xml version="1.0" encoding="UTF-8"?>

<!-- web.xml
    Purpose:
        
    Description:
        
    History:
        Wed Dec 29 12:13:00     2004, Created by tomyeh

Copyright (C) 2004 Potix Corporation. All Rights Reserved.
-->

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> 

    <description><![CDATA[My ZK Application]]></description>
    <display-name>MyApp</display-name>

    <!-- //// -->
    <!-- ZK -->
    <listener>
        <description>ZK listener for session cleanup</description>
        <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
    </listener>
    <servlet>
        <description>ZK loader for ZUML pages</description>
        <servlet-name>zkLoader</servlet-name>
        <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>

        <!-- Must. Specifies URI of the update engine (DHtmlUpdateServlet).
        It must be the same as <url-pattern> for the update engine.
        -->
        <init-param>
            <param-name>update-uri</param-name>
            <param-value>/zkau</param-value>
        </init-param>
        <!-- Optional. Specifies whether to compress the output
        of the ZK loader. It speeds up the transmission over slow Internet.
        However, if you configure a filter to post-processing the
        output, you might have to disable it.

        Default: true
        <init-param>
            <param-name>compress</param-name>
            <param-value>true</param-value>
        </init-param>
        -->
        <!-- Optional. Specifies the default log level: OFF, ERROR, WARNING,
            INFO, DEBUG and FINER. If not specified, the system default is used.
        <init-param>
            <param-name>log-level</param-name>
            <param-value>OFF</param-value>
        </init-param>
        -->
        <load-on-startup>1</load-on-startup><!-- Must -->
    </servlet>
    <servlet-mapping>
        <servlet-name>zkLoader</servlet-name>
        <url-pattern>*.zul</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>zkLoader</servlet-name>
        <url-pattern>*.zhtml</url-pattern>
    </servlet-mapping>
    <!-- Optional. Uncomment it if you want to use richlets.
    <servlet-mapping>
        <servlet-name>zkLoader</servlet-name>
        <url-pattern>/zk/*</url-pattern>
    </servlet-mapping>
    -->
    <servlet>
        <description>The asynchronous update engine for ZK</description>
        <servlet-name>auEngine</servlet-name>
        <servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>

        <!-- [Optional] Specifies whether to compress the output
        of the ZK loader. It speeds up the transmission over slow Internet.
        However, if your server will do the compression, you might have to disable it.

        Default: true
        <init-param>
            <param-name>compress</param-name>
            <param-value>true</param-value>
        </init-param>
        -->
        <!-- [Optional] Specifies the AU extension for particular prefix.
        <init-param>
            <param-name>extension0</param-name>
            <param-value>/upload=com.my.MyUploader</param-value>
        </init-param>
        -->
    </servlet>
    <servlet-mapping>
        <servlet-name>auEngine</servlet-name>
        <url-pattern>/zkau/*</url-pattern>
    </servlet-mapping>

    <!-- The filter put the real last access time into session -->
    <filter>
        <filter-name>lastAccessFilter</filter-name>
        <filter-class>test.LastAccessFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>lastAccessFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- Uncomment if you want to use the ZK filter to post process the HTML output
    generated by other technology, such as JSP and velocity.
    <filter>
        <filter-name>zkFilter</filter-name>
        <filter-class>org.zkoss.zk.ui.http.DHtmlLayoutFilter</filter-class>
        <init-param>
            <param-name>extension</param-name>
            <param-value>html</param-value>
        </init-param>
        <init-param>
            <param-name>compress</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>zkFilter</filter-name>
        <url-pattern>/test/filter.dsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>zkFilter</filter-name>
        <url-pattern>/test/filter2.dsp</url-pattern>
    </filter-mapping>
    -->
    <!-- //// -->

    <!-- /////////// -->
    <!-- Timeout in 60 minutes (3600 seconds) -->
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>

    <!-- MIME mapping -->
    <mime-mapping>
        <extension>doc</extension>
        <mime-type>application/vnd.ms-word</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>gif</extension>
        <mime-type>image/gif</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>htm</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>html</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>jpeg</extension>
        <mime-type>image/jpeg</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>jpg</extension>
        <mime-type>image/jpeg</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>js</extension>
        <mime-type>text/javascript</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>pdf</extension>
        <mime-type>application/pdf</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>png</extension>
        <mime-type>image/png</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>txt</extension>
        <mime-type>text/plain</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>xls</extension>
        <mime-type>application/vnd.ms-excel</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>xml</extension>
        <mime-type>text/xml</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>zhtml</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>zul</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>

    <welcome-file-list>
        <welcome-file>index.zul</welcome-file>
        <welcome-file>index.zhtml</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
    </welcome-file-list>
</web-app>

In web.xml, we specify a filter called lastAccessFilter,
which will put the real last access time into session.

We also specify the session will timeout in 60 minutes,
i.e., session.getMaxInactiveInterval() will return 3600 (seconds).

LastAccessFilter.java


package test;

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class LastAccessFilter implements Filter {
    public void init(FilterConfig fc) {}
    public void doFilter (ServletRequest req, ServletResponse resp, FilterChain chain) {
        HttpServletRequest hreq = (HttpServletRequest)req;
        HttpSession sess = hreq.getSession();
        String checker_id = (String)sess.getAttribute("checker_id");
        String componentId = hreq.getParameter("uuid_0");

        if (componentId == null || !componentId.equals(checker_id)) {

            // only do if not request by check timer
            long last = sess.getLastAccessedTime();
            sess.setAttribute("real_last", last);
        } else if (sess.getAttribute("real_last") == null) {
            // need the initiate however
            long last = sess.getLastAccessedTime();
            sess.setAttribute("real_last", last);
        }
        try {
            chain.doFilter(req, resp);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }
    public void destroy() {}
}

No comments:

Post a Comment