PeriodicTask Tutorial
Resin 3.0

Features
Installation
Configuration
Web Applications
IOC/AOP
Resources
JSP
Quercus
Servlets and Filters
Databases
Admin (JMX)
CMP
EJB
Amber
EJB 3.0
Security
XML and XSLT
XTP
JMS
Performance
Protocols
Third-party
Troubleshooting/FAQ

Overview
Deploy
Tutorials
FAQ
Scrapbook

Periodic Task
Tutorials
Tutorials
FAQ

Find this tutorial in: /usr/local/resin/webapps/resin-doc/webapp/tutorial/periodictask
Try the Tutorial

This tutorial demonstrates the creation of a PeriodicTask that performs a task at intervals and collects statistics on it's performance. An administration interface to the task is provided, and while the task is active the user is shown a "temporarily unavailable" page.

The code for this tutorial provides a full featured example that can be used as a cut-and-paste source for solving real problems. The PeriodicTask keeps detailed statistics, an administration interface is provided with a servlet, and the task can be executed either manually or automatically at timed intervals.

  1. Files in this tutorial
  2. Resource Configuration
  3. Using PeriodicTask for real work
    1. Extend PeriodicTask
  4. Jmx: a management interface for the resource
  5. CronResource: timed execution of the PeriodicTask
  6. Filter: redirecting users when the task is running
  7. PeriodicTaskServlet: an administration interface
  8. Dependency Injection/Inversion of Control
  9. See Also

Files in this tutorial

WEB-INF/classes/example/PeriodicTask.java The implementation of the class that performs the task
WEB-INF/classes/example/PeriodicTaskMBean.java The Jmx MBean interface to the class that performs the task
WEB-INF/classes/example/PeriodicTaskServlet.java An administrators view of the PeriodicTask.
WEB-INF/classes/example/PeriodicTaskFilter.java A filter that responds with a "temporarily unavailable" page when the task is running.
WEB-INF/web.xml web-app configuration
index.jsp A page representative of any page in the application.
unavailable.jsp A page to show when the web application is unavailable because the task is active.

Resource Configuration

The <resource> tag is used to configure an instance of PeriodicTask, and store it with a JNDI name.

PeriodicTask is implemented as a regular Java object that follows the JavaBeans convention for setters and getters. The configuration of the object occurs in the web.xml, using Resin's Bean-style initialization .

See it in: WEB-INF/web.xml
  <resource type="example.PeriodicTask" jndi-name="PeriodicTask">
    <init>
      <estimated-average-time>5</estimated-average-time>
    </init>
  </resource>

If only this step were performed, the object would sit in the JVM memory, performing no function. The rest of this tutorial details various ways that the PeriodicTask can be utilized.

Using PeriodicTask for real work

This tutorial performs no real work in it's task, it sleeps for 10 seconds to imitate a task that takes ten seconds. The code can be used without modification to perform real tasks for your web application. All of the statistics gathering and other functionality is available for the derived class.

Extend PeriodicTask

The following example extends PeriodicTask to create a task that vacuum's a postgress database.

WEB-INF/classes/example/VacuumTask.java
package example;

import java.util.logging.Level;
import java.util.logging.Logger;

import java.sql.*;
import javax.sql.*;

public class VacuumTask extends PeriodicTask {
  static protected final Logger log = 
    Logger.getLogger(VacuumTask.class.getName());

  private DataSource _dataSource;

  public void setDataSource(DataSource dataSource)
  { 
    _dataSource = dataSource;
  }

  public void init()
    throws Exception
  {
    if (_dataSource == null)
      throw new Exception("`data-source' is required.");
  }

  protected void performTask()
    throws Exception
  {
    Connection conn = null;
    try {
      conn = _dataSource.getConnection();

      Statement stmt = conn.createStatement();
      stmt.executeUpdate("VACUUM FULL ANALYZE;");
      stmt.close();
    } finally {
      try {
        if (conn != null)
          conn.close();
      } catch (SQLException ex) {
        log.warning(ex.toString());
      }
    }
  }
}

The VacuumTask is configured to run automatically every night at midnight. Since the database is integral to the application, the PeriodicTaskFilter is used to redirect users to an "unavailable" page while the task active. The PeriodicTaskServlet is used to provide an administration interface to the task at the url /admin/example/vacuum.

A <security-constraint> is used to limit access to the /admin/ portion of the website. An <authenticator> is used to specify the user names and passwords.

WEB-INF/web.xml
<web-app xmlns="http://caucho.com/ns/resin">
  <resource type="example.VacuumTask" jndi-name="example/VacuumTask">
    <init>
      <estimated-average-time>30</estimated-average-time>
    </init>
  </resource>

  <servlet-mapping url-pattern='/admin/example/vacuum'>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${jndi:lookup("example/VacuumTask")}</periodic-task>
    </init>
  </servlet>

  <resource type="com.caucho.resources.CronResource">
    <init>
      <!-- run every day at 0215 local time -->
      <cron>15 2 *</cron>
      <work>${jndi:lookup("example/VacuumTask")}</work>
    </init>
  </resource>

  <filter url-regexp="^(?!/admin)+">
    <filter-class>example.PeriodicTaskFilter</filter-class>
    <init>
      <periodic-task>${jndi:lookup("example/VacuumTask")}</periodic-task>
      <url>/unavailable.jsp</url>
    </init>
  </filter>

  <!-- require 'admin' role -->
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Admin</web-resource-name>
      <url-pattern>/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
    </auth-constraint>
  </security-constraint>

 <authenticator>
    <type>com.caucho.server.security.XmlAuthenticator</type>

    <init>
      <!-- user `admin' with password `excellent' is in admin role -->
      <user>admin:FKT/gZPYJ5TIA5uA434mgA==:admin</user>
    </init>
  </authenticator>
</web-app>

Jmx: a management interface for the resource

Jmx provides a mechanism for management of objects on servers. The PeriodicTask implements the PeriodicTaskMBean interface, the PeriodicTaskMBean interface is the Jmx agent's view of the resource.

Jmx uses a naming scheme to store objects for later retrieval. The Jmx name to store the object under is specified with the <mbean-name> child of <resource> .

See it in: WEB-INF/web.xml
  <resource type="example.PeriodicTask" jndi-name="PeriodicTask"
            mbean-interface="example.PeriodicTaskMBean"
            mbean-name="type=PeriodicTask,name=PeriodicTask">
    <init>
      <estimated-average-time>5</estimated-average-time>
    </init>
  </resource>

A simple Jmx lookup of all type=PeriodicTask objects is done in admin/mbean.jmx:

See it in: admin/mbean.jsp
  ObjectName query = new ObjectName("resin:type=PeriodicTask,*");
  pageContext.setAttribute("mbeans",Jmx.query(query));

  ...

<c:forEach var="mbean" items="${mbeans}">

  estimatedAverageTime ${mbean.estimatedAverageTime}
  ...

CronResource: timed execution of the PeriodicTask

Depending on the nature of the PeriodicTask, it may be appropriate to configure the task to automatically run at a specified time, or at a specified interval.

The CronResource is used to configure the timed execution of the PeriodicTask.

See it in: WEB-INF/web.xml
  <resource type="com.caucho.resources.CronResource">
    <init>
      <cron>*</cron>
      <work>${jndi:lookup("PeriodicTask")}</work>
    </init>
  </resource>

Filter: redirecting users when the task is running

Again depending on the nature of the PeriodicTask, it may be appropriate for access to the web application to be limited while the task is performed. A filter is used to provide this functionality, the filter intercepts requests and if the task is active, redirects to a page giving a "temporarily unavailable" message.

See it in: WEB-INF/web.xml
  <filter>
    <filter-name>PeriodicTaskFilter</filter-name>
    <filter-class>example.PeriodicTaskFilter</filter-class>
    <init>
      <periodic-task>${jndi:lookup("PeriodicTask")}</periodic-task>
      <!-- optional url, if not specified a 503 response is sent. -->
      <url>/unavailable.jsp</url>
    </init>
  </filter>

  <filter-mapping>
    <!-- regexp to match all urls except /admin and /index.xtp-->
    <url-regexp>^(?!/admin|/index.xtp)+</url-regexp>
    <filter-name>PeriodicTaskFilter</filter-name>
  </filter-mapping>

See it in: WEB-INF/classes/example/PeriodicTaskFilter.java
  public void setPeriodicTask(PeriodicTask periodicTask)
  {
    _periodicTask = periodicTask;
  }

See it in: WEB-INF/classes/example/PeriodicTaskFilter.java
  public void doFilter(ServletRequest request,
      ServletResponse response,
      FilterChain chain)
    throws ServletException, IOException
  {
    if (_periodicTask.isActive()) {
      dispatch( (HttpServletRequest) request, (HttpServletResponse) response);
    }
    else {
      chain.doFilter(request,response);
    }
  }

PeriodicTaskServlet: an administration interface

The PeriodicTaskServlet provides an html interface to the PeriodicTask. It shows the current status of the task, and provides a button to "Run" the task.

The PeriodicTaskServlet needs an instance of PeriodicTask to operate on. The Servlet provides a setter:

See it in: WEB-INF/classes/example/PeriodicTaskServlet.java
  public void setPeriodicTask(PeriodicTask periodicTask)
  {
    _periodicTask = periodicTask;
  }

The configuration of the servlet in web.xml uses the jndi:lookup function to get a reference to the PeriodicTask resource previously stored in jndi with the <resource> configuration.

See it in: WEB-INF/web.xml
  <servlet>
    <servlet-name>PeriodicTaskServlet</servlet-name>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${jndi:lookup("PeriodicTask")}</periodic-task>
    </init>
  </servlet>

  <servlet-mapping>
    <url-pattern>/admin/periodictask</url-pattern>
    <servlet-name>PeriodicTaskServlet</servlet-name>
  </servlet-mapping>

Dependency Injection/Inversion of Control

Dependency injection is a term used to describe a separation between the implementation of an object and the construction of an object it depends on, and the ability for a container (like Resin) to resolve the dependency.

In this tutorial, many components including the administration servlet, the filter, and the CronResource, depend upon a PeriodicTask. Each of these components that depend upon the PeriodidicTask provide a setter:

setter
  PeriodicTask _periodTask;

  public void setPeriodicTask(PeriodicTask periodicTask)
  {
    _periodicTask = periodicTask;
  }

The container (Resin), injects the object.

container injection
  <init>
    <periodic-task>${jndi:lookup("PeriodicTask")}</periodic-task>
  </init>

The simplicity of the code shows immediate benefits. There is no dependency on the environment (needing an application object for example), and no need for cumbersome or error prone code in each component.

There are other benefits as well. Since the container instantiates and sets the object, there is more flexibility in the configuration. The following example shows the use of two distinct periodic tasks.

An example illustrates some of the flexibility of dependency injection.

The first task (Foo) is only run manually, it is not run at a timed interval so the CronResource is not used for it. Neither task causes the application to become unavailable, so the PeriodicTaskFilter is not used.

two distinct periodic tasks
WEB-INF/classes/example/PeriodicTaskFoo.java

public class PeriodicTaskFoo extends PeriodicTask {
  protected void performTask()
    throws Exception
  {
   ...
  }

}

WEB-INF/classes/example/PeriodicTaskBar.java

public class PeriodicTaskBar extends PeriodicTask {
  protected void performTask()
    throws Exception
  {
   ...
  }

}

WEB-INF/web.xml

  <!-- TASK FOO -->

  <resource type="example.PeriodicTaskFoo" jndi-name="PeriodicTaskFoo">
    <init>
      <estimated-average-time>15</estimated-average-time>
    </init>
  </resource>

  <servlet>
    <servlet-name>PeriodicTaskFooServlet</servlet-name>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${jndi:lookup("PeriodicTaskFoo")}</periodic-task>
    </init>
  </servlet>

  <servlet-mapping>
    <url-pattern>/admin/example/foo</url-pattern>
    <servlet-name>PeriodicTaskFooServlet</servlet-name>
  </servlet-mapping>

  <!-- TASK BAR -->

  <resource type="example.PeriodicTaskBar" jndi-name="PeriodicTaskBar">
    <init>
      <estimated-average-time>15</estimated-average-time>
    </init>
  </resource>

  <resource type="example.PeriodicTaskBar" jndi-name="PeriodicTaskBar">
    <init>
      <estimated-average-time>15</estimated-average-time>
    </init>
  </resource>

  <servlet>
    <servlet-name>PeriodicTaskBarServlet</servlet-name>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${jndi:lookup("PeriodicTaskBar")}</periodic-task>
    </init>
  </servlet>

  <servlet-mapping>
    <url-pattern>/admin/example/bar</url-pattern>
    <servlet-name>PeriodicTaskBarServlet</servlet-name>
  </servlet-mapping>

  <!-- bar runs every minute -->
  <resource type="com.caucho.resources.CronResource">
    <init>
      <cron>*</cron>
      <work>${jndi:lookup("PeriodicTaskBar")}</work>
    </init>
  </resource>

See Also

CronResource
Documentation for the usage of CronResource

Try the Tutorial


Tutorials
Tutorials
FAQ
Copyright © 1998-2006 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.