Creating a Web Event Calendar Using the Struts Framework

This tutorial shows you how to use the JavaPlanner library with the Struts framework. You will create a simple web application with the planner populated with data from a database and able to save changes back on the server.

This is the second tutorial of the trilogy saying about using JavaPlanner with the Java frameworks:

The tutorial isn’t intended for beginners and assume that you have the basic knowledge of the Struts framework and the JavaPlanner library.

All files related to the tutorial can be downloaded here.

Step 1. New project

Create a new dynamic project and name it 'demoapp'.

Step 2. Required code files

After setting up a new project, add the required code files into build path. They are:

  • Struts framework jar files;
  • Hibernate jar files;
  • dhtmlxScheduler library files (it’s a client-side library that provides creating JavaPlanner on the page);
  • javaplanner.jar file (you can download it here).

You can find all the mentioned files in the supplied package.

Step 3. Data to load

In the tutorials we will use data from the demoapp_struts.sql dump file (the file resides in the root folder of the supplied package). You can create a local copy of this database by importing an demoapp_struts.sql dump file or use any available database. But note, if you use a custom database you will need to adapt the code stated in the tutorial by yourself.

Step 4. Web application descriptor

On this step we should declare the FilterDispatcher and configure it.
The FilterDispatcher initializes the Struts framework and treats client requests. It's declared in the web.xml file.

  • Alter the content of a web.xml file to make it look like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
id="WebApp_ID" version="2.5">
<display-name>Scheduler.java + Struts demoapp</display-name>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
 
	<welcome-file-list>
		<welcome-file>/demoapp_struts/01_simple_init.action</welcome-file>
	</welcome-file-list>
 
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

Step 5. The mapping file

In our app we will use the Hibernate library to store and retrieve data from the server.
And as our next step, we will create a hibernate mapping file. This file defines how a Java class is mapped with the database table and acts like a bridge between Java types and database data types.

  • In the 'src' folder of your project directory, create an Event.hbm.xml file with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
        <class name="com.dhtmlx.planner.DHXEvent" table="events">
                <id column="event_id" name="id" type="java.lang.Integer">
                        <generator class="increment"/>
                </id>
                <property column="start_date" name="start_date" type="timestamp"/>
                <property column="end_date" name="end_date" type="timestamp"/>
                <property column="event_name" name="text" type="java.lang.String"/>
        </class>
</hibernate-mapping>

Step 6. Configuring Hibernate

As Hibernate is not the subject of our tutorial we won’t detail using this library and assume that you know how to configure Hibernate.

If you’re not, please refer to the Hibernate documentation at http://www.hibernate.org/docs or check out the hibernate.cfg.xml file (demoapp_struts/src/hibernate.cfg.xml) in the supplied package.

Step 7. The HibernateUtil Helper Class

This helper class is required to get Hibernate up and running.

  • Create the org.apache.struts.demoapp.util package;
  • In the newly-created package, create a HibernateUtil.java file with the following code:
package org.apache.struts.demoapp.util;
 
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class HibernateUtil {
	private static final SessionFactory sessionFactory = buildSessionFactory();
	@SuppressWarnings("deprecation")
	private static SessionFactory buildSessionFactory() {
		try {
			return new Configuration().configure().buildSessionFactory();
		}
		catch (Throwable ex) {
			System.err.println("Initial SessionFactory creation failed." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}
 
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
}

Step 8. Loading and storing data

As Hibernate files for our application are ready, let's create a class that will handle the Hibernate facilities. In JavaPlanner there is a special class for managing data - DHXEventsManager. It defines logic for data loading and processing.

  • Create the org.apache.struts.demoapp.action package;
  • In the package, create a CustomEventsManager.java file and extend it from DHXEventsManager as in:
package org.apache.struts.demoapp.model;
 
import javax.servlet.http.HttpServletRequest;
 
import org.apache.struts.demoapp.util.HibernateUtil;
import org.hibernate.Session;
 
import com.dhtmlx.planner.DHXEvent;
import com.dhtmlx.planner.DHXStatus;
import com.dhtmlx.planner.DHXEv;
import com.dhtmlx.planner.DHXEventsManager;
 
import java.util.ArrayList;
import java.util.List;
 
public class CustomEventsManager extends DHXEventsManager {
 
	public CustomEventsManager(HttpServletRequest request) {
		super(request);
	}
 
	public Iterable<DHXEv> getEvents() {
		HibernateUtil.getSessionFactory();
		Session session = HibernateUtil.getSessionFactory().openSession();
		List<DHXEv> evs = new ArrayList<DHXEv>();
		try {
			session = HibernateUtil.getSessionFactory().openSession();
			evs = session.createCriteria(DHXEvent.class).list();
		} catch (RuntimeException e) {
			e.printStackTrace();
		} finally{
			session.flush();
			session.close();
		}
 
    	return evs;
	}
 
	@Override
	public DHXStatus saveEvent(DHXEv event, DHXStatus status) {
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			session = HibernateUtil.getSessionFactory().openSession();
			session.beginTransaction();
 
			if (status == DHXStatus.UPDATE)
				session.update(event);
			else if (status == DHXStatus.DELETE)
				session.delete(event);
			else if (status == DHXStatus.INSERT)
				session.save(event);
 
			session.getTransaction().commit();
		} catch (RuntimeException e) {
			e.printStackTrace();
		} finally{
			session.flush();
			session.close();
		}
		return status;
	}
 
	@Override
	public DHXEv createEvent(String id, DHXStatus status) {
		return new DHXEvent();
	}
}
  • getEvents() method answers for data loading;
  • saveEvent() method manages the update/insert/delete operations;
  • createEvent() method provide creating new events in the planer.

For a deeper learning of loading and processing data in the planner, read:

Step 9. Model class ‘MessageStore.java’

Next, create a model class - MessageStore.java. This special class allows us to define public set/get methods for accessing private attributes used in the controller.

  • Create the org.apache.struts.demoapp.model package;
  • In the newly-created package, create a MessageStore.java file with the following code:
//MessageStore.java
package org.apache.struts.demoapp.model;
 
public class MessageStore {
 
	private String planner;
        private String data;
 
	public String getPlanner() {
		return planner;
	}
	public void setPlanner(String planner) {
		this.planner = planner;
	}
 
	public String getData() {
		return data;
	}
	public void setData(String data) {
		this.data = data;
	}	
}

Step 10. A controller class

Once the data is prepared we move to creating an action class that will act as a controller.

  • In the 'action' folder of your project directory, create a SavingAction.java file with the following content:
package org.apache.struts.demoapp.action;
 
import org.apache.struts.demoapp.model.CustomEventsManager;
import org.apache.struts.demoapp.model.MessageStore;
import org.apache.struts2.ServletActionContext;
 
import com.dhtmlx.planner.DHXPlanner;
import com.dhtmlx.planner.DHXSkin;
import com.dhtmlx.planner.data.DHXDataFormat;
import com.opensymphony.xwork2.ActionSupport;
 
public class LoadingAction extends ActionSupport {
 
	private static final long serialVersionUID = 1L;
	private MessageStore messageStore = new MessageStore();
 
	public MessageStore getMessageStore() {
		return messageStore;
	}
 
	public void setMessageStore(MessageStore messageStore) {
		this.messageStore = messageStore;
	}
 
	public String initializingPlanner() throws Exception {
	//creates and configures a planner instance
		DHXPlanner p = new DHXPlanner("./codebase/", DHXSkin.TERRACE);
		p.setWidth(900);
		p.setInitialDate(2013, 1, 7);
		p.config.setScrollHour( 8 );
		p.load("events", DHXDataFormat.JSON);
 
		messageStore.setPlanner(p.render());
		return SUCCESS;
	}
 
	public String events() throws Exception {
		CustomEventsManager evs = new CustomEventsManager(ServletActionContext.getRequest());
		messageStore.setData(evs.run());
		return SUCCESS;
	}
}
  • In the initializing() function we use a standard code initializing JavaPlanner.
  • The events() function instantiates the CustomEventsManager class and retrieve data.

If you doubt what one or another method makes, refer to the following documentation:

Step 11. A view file

Next, we need a page to present the scheduler (stored in the model class MessageStore) in the browser.

  • Create a view file and name it 'article.jsp' (this name we used in our controller to refer to the view).
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
   <body>
      <div class="content" id="content">
         <div id="planner">
            <s:property escape="false" value="messageStore.planner" />
         </div>
      </div>
   </body>
</html>

Step 12. Struts configuration

We need a mapping to tie the controller and the view together.

  • In the 'src' folder of your project directory, create the configuration file 'struts.xml' and make it look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
	<constant name="struts.devMode" value="true" />
	<constant name="struts.action.excludePattern" value=".*/static/.*" />
	<package name="test" extends="struts-default">
		<action name="initializingPlanner" 
                   class="org.apache.struts.demoapp.action.LoadingAction" method="initializingPlanner">
			<result name="success">/article.jsp</result>
		</action>
		<action name="events" class="org.apache.struts.demoapp.action.LoadingAction" method="events">
			<result name="success">/data.jsp</result>
		</action>
	</package>
</struts>



That’s it. You have a ready-to-use planner application created with the help of the Struts framework and JavaPlanner library. The application can be a good start point for creating custom planner web applications.

All related files can be downloaded here.