Wednesday, September 24, 2008

The Mysterious Ways of SchedulerFactoryBean

Using Spring framework and Quartz, I wanted to make some dynamic Jobs and triggers. After banging my head and some accidents I finally understood how to use it. The API docs say:

"For dynamic registration of jobs at runtime, use a bean reference to this SchedulerFactoryBean to get direct access to the Quartz Scheduler (org.quartz.Scheduler). This allows you to create new jobs and triggers, and also to control and monitor the entire Scheduler."

What the hell that means, I couldn't figure. Hunting for some examples on the web didn't help either. In one of my posts I have given a link to fine tune SchedulerFactoryBean for static jobs. Picking from there, let us assume you have a Stocks Alert Manager to which you wish to give a spring managed scheduler using your very own SchedulerFactoryBean . Let us assume your stockAlertsManager looks like this:


Then your bean config should look something like this:

If you have not noticed, the scheduler property of StockAlertsManager is of type org.quartz.impl.StdScheduler but in the bean config I have set it to the reference of our all-powerful SchedulerFactoryBean. Despite of the mismatch in types your spring application will not complain and initialize the scheduler property nicely. Even when SchedulerFactoryBean does not in any way extend StdScheduler or implement Scheduler . Wierd, counter-intuitive but works. Re-visiting the API doc:

"For dynamic registration of jobs at runtime, use a bean reference to this SchedulerFactoryBean to get direct access to the Quartz Scheduler (org.quartz.Scheduler). This allows you to create new jobs and triggers, and also to control and monitor the entire Scheduler."

Well, they literally meant it! Who would have thought?!

Tuesday, September 23, 2008

Using Autowiring for Testing RMI Services in Spring

Scehduling can be a common requirement in many applications. However testing such an application that used RMI with JUnit and JMock in a Spring-Maven environment turned out to be a little tricky for me. Thanks to the help of a colleague (thanks Mudassir!) and some head banging, I was able to find a way: Autowiring.

Generally my basic JUnit test cases have the following features:
1. The whole class annotated by @RunWith(JMock.class) - org.junit.runner.RunWith;
2. A set up method (the init method) annotated with @Before - org.junit.Before
3. The test cases annotated @Test - org.junit.Test
4. JUnit4Mockery used to mock relevant interfaces - org.jmock.integration.junit4.JUnit4Mockery
5. The usual expectatons and assertions
6. Spring adds punch with ability to mock request, response, sessions - org.springframework.mock.web.*

A Simple Test Case

Works fine for most things. Now picture this: you are developing application that needs to check stock prices every five minutes and send alerts to registered users if need be. Lets say there are three modules being developed for it: the user interface using which a user may register for an alert for stock price, the scheduler that keeps track of these alerts and the workflow engine that takes care of the alerts once fired. A classic MVC approach so far.

The controller accepts alerts from user interface and schedules Jobs that forward all information to the workflow. Let us assume these three modules are being developed by three different teams sitting in three corners of the world (ok, may be three corners of the office or just three different/independent machines/servers).

Now, when you are making the controller, you are essentially dependent on view for input and on the model for feedback (if any) for your input. We can provide access to our controller using any RMI strategy. For our example, we consider Spring's HttpInvoker. We intend to write a a test case to test the controller module.

Our controller has a remote service running in a spring environment. If it had been a simple servlet listening to ordinary post/get requests, writing a test case with MockHttpRequest would be a piece of cake. However when it is an RMI service, what mock up to use? An answer can be a test class looking something like this:

A Test Case For RMI Service


The answer lies in using SpringJUnit4ClassRunner and then auto-wiring the HttpInvokerService. ContextConfiguration points to the locations for the config xml. In the current case you should put it in "myPackage. If you are using Maven, the resources folder would be the right place to put it. The config file may look like:

Autowiring Config


If you are using Maven, don't forget to add the following dependencies:

Maven Dependencies

A few tweaks may be needed to suit your case but this should give you a general idea about using autowiring for your test cases in JUnit, JMock, Spring, Maven environment.

Friday, September 12, 2008

Maven Blues

Was facing a strange problem where Maven (version 2) would say something like "generics are not supported in -source 1.3" for Java 5 features. Adding the following the Plugins element in the pom helped:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugins>

Wednesday, September 3, 2008

Quartz and Spring

For scheduling purposes one can use Quartz with Spring. The basic usage can be learnt by going through the quartz tutorial and spring documentation on scheduling .

However when it came to using advanced usage like configuring job stores, I had a little difficulty finding stuff. A particular entry in the spring forum was really useful. These three resources were able to take care of my reasonably complex needs for scheduling. Hope they are of some use to you too.

Thursday, August 28, 2008

Splitting a Project into Modules in Maven

The beauty of Maven and Idea is the ease with which they allow you to manage, build and test your applications. Let us suppose we have a project that we wish to build in modules. For sake of simplicity we assume that the project has two basic modules: a webapp module and a core module.

Make a folder on the system for your project. In the folder make two folders by name "core" and "webapp". Also put a pom.xml which should look like:

parent pom

Notable things are the modules node and that the packaging is pom.

In the "core" folder make a folder "src" and put a pom.xml something like:

core pom

Main things to note about the pom is that packaging is "jar". ID are same as those in the parent pom. In "src" folder make two folders "main" and "test". Put a folder named "java" in each of them.

In the "webapp" folder create same directory structure as "core". The pom.xml here would look like:

webapp pom

Make the directory structure webapp -> src -> main -> webapp -> WEB-INF
in WEB-INF put in a web.xml file

You are good to go now. Now all you need to do is mvn idea:idea or mvn eclipse:eclipse (depending on what you are using) while being in the main folder to create the project with its modules.

Wednesday, August 6, 2008

Alternative to Using Valang Custom Functions


Valang provides a rich set of validation tools and is pretty simple. However in some cases you want more. The most obvious case that we encounter is validating if a date is in future or past wrt the current time on server. I know we can parse and input date to a date object readily using initBinder function of a SimpleFormController. But to compare it with the current date using pure varlang is something I could not find.

Luckily valang has an ability to use custom function. However I found it cumbersome to make one separate class for each function I may need. It would make more sense to allow users to group functions in one class to build a custom library of functions. Not to mention I could not find a proper working example of a custom function. So till I get my hands on one and this implementation improves, I have a simple work around.

Step 1: Define valang validations in the config file


<bean id="webMessageFormValidator"
class="myPackage.validators.FormBeanValidator">
<property name="valang">
<value>
<![CDATA[
{to:? IS NOT BLANK:'Please enter email addresses
for recepients.'}
{subject:? IS NOT BLANK:'Mail can not be blank.'}
{from:(length(?)> 0):'Please specify at least one
address.'}
]]>
</value>
</property>
</bean>


Step 2: Define the validator as follows


package mypackage.validators;

import org.springframework.validation.Errors;
import org.springmodules.validation.valang.ValangValidator;
import mypackage.FormBean;


public class FormBeanValidator extends ValangValidator {

public void validate(Object object, Errors errors) {

FormBean form = (FormBean) object;

//perform all validations and raise error flag
//if you find an error
if(isFutureTime(form.myDate()){
errors.rejectValue("myDate", "error.futureDate"
,"Time cannot be in the future.");
}

//dont forget call to super so as the validations
//defined in XML take place
super.validate(object, errors);
}


private boolean isFutureTime(Date formDate,
int hours, int minutes){
//check if time is in future
return false;
}

Tuesday, July 22, 2008

Problem Statement and Source Files


Theory without examples can be hard to grasp and less useful. So just making a small problem and corresponding files. Lets see
Problem statement: Given an online reporting application. There is a form that posts certain parameters and displays reports accordingly. Let us say that there are two basic parameters: report type and date range. Report type may be word, pdf, text. Date range consists of a from and a to time. Further user has an option to specify current time as the to time. Our form bean would look something like this:

package myPackage;

public class MyFormBean{
private String reportType;
//date in format dd/MM/yyyy HH:mm
privateDate fromDate;
private Date toDate;
private boolean useCurrentTime=true;

//.......
//public getters and setters for fields
//.......
}

Reports are denoted by a simple interface:
package myPackage;

public interface Report{
String getFileUrl();
String getType();
Date getCreationTime();
}
Reports are fetched using this interface:
package myPackage;

public interface DataBaseUtil{
List<Report> getReports(MyFormBean myFormBean);
}
which may have some implementation like:
package myPackage;

public class DataBaseUtilImpl{
private static DataBaseUtilImpl singleInst = new DataBaseUtilImpl();
private DataBaseUtilImpl(){}

public static DataBaseUtilImpl getInstance(){ return singleInst ; }

public List<Report> getReports(MyFormBean myFormBean){
//process command object to get a list of reports
}
}
The controller will be injected something like this in the config file:


 <bean id="reportFormController" class="myPackage.ReportFormController">
<property name "dataBaseUtil" ref="DataBaseUtilBean"/>
<property name="formView" value="reportInput"/>
<property name="bindOnNewForm" value="true"/>
<property name="successView" value="reportOutput"/>
<property name="validator" ref="myValidator"/>
<property name="commandName" value="reportFormBean"/>
<property name="commandClass" value="myPackage.MyFormBean"/>
</bean>
The actual form controller will look something like:

package myPackage;

import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.text.*;

public class ReportFormController extends SimpleFormController {
private DataBaseUtil dataBaseUtil;

public void setDataBaseUtil(DataBaseUtil dbUtil){
this.dataBaseUtil = dbUtil;
}

public DataBaseUtil getDataBaseUtil(){
return this.dataBaseUtil;
}

/*Override so as string inputs in the form bind directly to date in command object*/
@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder dataBinder) throws Exception{
DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
df.setLenient(false);
dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(df,false));
super.initBinder(request,dataBinder);
}


@Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,Object command, BindException bindException)throws Exception{
//handle submit request
ReportFormBean repFormBean = (ReportFormBean ) command;

List<Report> reps ;

if(dataBaseUtil != null)
reps = dataBaseUtil.getReports(repFormBean);
else
reps = new ArrayList<Report>();

ModelAndView mv = showForm(request, response, bindException);

mvmodel.put("REPORTS", reps);

return mv;
}
}
From next post we will start exploring some practical problems using these files as our base.