Archive

Posts Tagged ‘Java’

Dynamic Forms with Map-backed ActionForms in Struts 1

September 14, 2010 4 comments

A project that I work on uses Struts 1 and I came across a problem where I intended to create a page that could have any number of text fields (number of fields would be increased by a button click). The idea was to have a way to have name – value text input boxes whose content would be saved in a properties database table when the form was submitted. After some blind google searches I came across “Map-backed” and “List-backed” properties in struts. This write-up is a summary of using Map-backed properties to achieve that goal. This article does not show how to save the values in the database however… it just logs the values received on the server.

As a first step we will create a blank Struts application with maven. Look at this article to create a blank application.
The next step is to create a page that will have our dynamic form. Here is the page(dynamicTextEntry.jsp)..

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>

<html:html>
<head>
<script type="text/javascript">
	function add(){
		var element1 = document.createElement("input");
		var element2 = document.createElement("input");
		var elementCount = parseInt(document.getElementById("count").value);

		element1.setAttribute("type","text");
		element1.setAttribute("value","Enter Name");
		element1.setAttribute("name","value(name"+ elementCount +")");

		element2.setAttribute("type","text");
		element2.setAttribute("value","Enter Value");
		element2.setAttribute("name","value(value"+ elementCount +")");

		var spanBody = document.getElementById("textBoxes");
		spanBody.appendChild(element1);
		spanBody.appendChild(element2);
		var breakElement = document.createElement('br');
		spanBody.appendChild(breakElement);
		
		document.getElementById("count").value = elementCount + parseInt(1);
	}
</script>
<title>Dynamic Entry Form</title>
<html:base/>
</head>
<body bgcolor="white">

<html:form action="setDynamicTextEntry.do" >
<html:hidden property="count" styleId="count" value="0"/>
<input type="button" value="Add Field (+)" onclick="add()"/>
</br>
<span id="textBoxes"></span>

<html:submit property="submit"> Submit</html:submit>

</html:form>
</body>
</html:html>

We will create two actions in struts-config.xml as follows… the action class is shown later…

	<action
            path="/dynamicInputs"
            forward="/pages/dynamicTextEntry.jsp"/>
		
	<action
            path="/setDynamicTextEntry"
            type="com.wordpress.codesilo.controller.SetDynamicTextEntryAction"
            name="dyamicTextEntryForm"
            scope="request"
            validate="true"
            input="/pages/dynamicTextEntry.jsp">
            <forward name="success" path="/pages/success.jsp"/>
        </action>

We will also add form bean to struts-config.xml

<form-bean name="dyamicTextEntryForm" type="com.wordpress.codesilo.model.DyamicTextEntryForm"></form-bean>

The action class is as follows…

public class SetDynamicTextEntryAction extends Action {

	
	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		
		DyamicTextEntryForm dynform = (DyamicTextEntryForm)form;
		Map dynformValues = dynform.getValues();
		int count = dynformValues.size()/2;
		
		System.out.println("Map Size: " + dynformValues.size());
		for(int i =0; i<count ; i++){
			String name = (String)dynformValues.get("name"+i);
			String value = (String)dynformValues.get("value"+i);
			System.out.println("Name:" + name + " Value:" + value);
		}
		return mapping.findForward("success");
	}
}

The form is as follows…

public class DyamicTextEntryForm extends ActionForm {

	private final Map values = new HashMap();
	private int count;
	
	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	public Map getValues(){
		return values;
	}
	
	public void setValue(String key, Object value){
		values.put(key, value);
	}
	
	public Object getValue(String key){
		return values.get(key);
	}
	
}

Add a success page that is forwarded to once the form is submitted and we are ready to try out the code.
The page looks as follows… (Every time to click the add button a new pair of text boxes are added)
When we add/change text in the boxes and click submit, the values entered in the text boxes are displayed in the console.


Explanation:
The javascript in the jsp adds text boxes to the existing dom in pairs. The elements added would look like the following when rendered in HTML

<input type="text" value="Enter Name" name="value(name0)">
<input type="text" value="Enter Value" name="value(value0)">

Every time the button is clicked the count increments and new text boxes are added. So, on the second click the following elements are added…

<input type="text" value="Enter Name" name="value(name1)">
<input type="text" value="Enter Value" name="value(value1)">

Once the form is submitted, the setValue(String key, Object value) on the form is called for each of these text boxes. The key will be the names we provide (name0, value0, name1, value1 etc) and the value is the value from the text boxes.

Rest is self explanatory. đŸ™‚

References:
http://struts.apache.org/1.x/userGuide/building_controller.html
http://www.manning-sandbox.com/message.jspa?messageID=26953

Sun JDK6 on Lucid

June 20, 2010 1 comment

In one of my earlier posts I had shown how to install Sun Java6 on Ubuntu(Karmic). When I upgraded to Lucid recently, that version of JDK was removed and Open JDK was the only one that was present. I had to google a bit to realize that sun-java6 was no longer present in the repositories. The release notes on Ubuntu’s wiki state the same. However, following the instructions on the release notes did not help me. Two reasons… First, the link is incorrect and secondly, the sources.list needs to have two entries one for deb and another for deb-src. The command on the wiki just adds the line with deb on the sources.list.
I found this blog that has a better explanation of the steps to be followed to fix the problem.

Summary,
Edit /etc/apt/sources.list
Uncomment the following two lines.
deb http://archive.canonical.com/ubuntu lucid partner
deb-src http://archive.canonical.com/ubuntu lucid partner

Run the following commands

sudo aptitude update
sudo apt-get install sun-java6-bin sun-java6-jre sun-java6-jdk
sudo update-java-alternatives -s java-6-sun

Scheduling using Quartz

June 8, 2010 2 comments

Many times we need to perform repetitive jobs in our applications. One common way is to use Thread.sleep method but if you need to synchronize the start of the job based on clock cycles , using a Quartz scheduler is way simpler. Cron triggers can be used to schedule the time that the job starts. We will take a look at how to use Quartz in the non-spring and spring way.

Without Spring…
Get the Quartz 1.8.0 download from here. Add the slf4j jars to the classpath.
My main class looks like this…

public class Main {

 public static void main(String[] args) throws SchedulerException, ParseException {
 Main main = new Main();
 main.scheduleJobs();
 }

 public void scheduleJobs() throws SchedulerException, ParseException {
 SchedulerFactory factory = new StdSchedulerFactory();
 Scheduler sch = factory.getScheduler();
 JobDetail jobDetail = new JobDetail("testJob", null, MyTestJob.class);
 CronTrigger cron = new CronTrigger("testCron", null , "* * * * * ?");
 sch.scheduleJob(jobDetail, cron);
 sch.start();
 }
}

What we have done here is that we have created a scheduler by using SchedulerFactory. JobDetail is the definition of the job that will be run once the trigger fires. “testJob” is the name we give to the job detail, its group is “null” and the class that implements Job is MyTestJob. Similarly, the CronTrigger has the name “testCron”, belongs to group “null” and has a cron expression that fires every second.

The MyTestJob class is as follows…

public class MyTestJob implements Job {

 @Override
 public void execute(JobExecutionContext arg0) throws JobExecutionException {
 System.out.println("In my job.");
 }
}

If we run the program we will see some log messages and then the following output will be printed on the console.. one line every second…
In my job.
In my job.
In my job.
In my job.

Using Spring..
We first create a basic Spring project with Maven… see my older post to get an idea.
The dependencies on my pom.xml file are as follows…

<dependencies>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-jdbc</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>3.8.1</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.quartz-scheduler</groupId>
 <artifactId>quartz</artifactId>
 <version>1.8.0</version>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context-support</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 </dependencies>

We will create the beans.xml file in the resources dir. It looks like this….

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 <bean name="exampleJob">
 <property name="jobClass" value="com.wordpress.codesilo.ExampleJob" />
 </bean>

 <bean id="cronTrigger">
 <property name="jobDetail" ref="exampleJob" />
 <property name="cronExpression" value="* * * * * ?" />
 </bean>

 <bean id="scheduleFactory">
 <property name="triggers">
 <list>
 <ref bean="cronTrigger" />
 </list>
 </property>
 </bean>
</beans>

The ExampleJob class if the class that will run once the trigger fires. It looks like this..

public class ExampleJob extends QuartzJobBean {
 @Override
 protected void executeInternal(JobExecutionContext arg0)
 throws JobExecutionException {
 System.out.println("In the job");
 }
}

Our main class will have this only..

 public static void main(String[] args) throws SchedulerException {
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 }

If we run main , we will see the following …
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
In the job
In the job
……..

We will initialize log4j by adding the following log4j.xml file in the resources dir.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 <appender name="console">
 <param name="Target" value="System.out"/>
 <layout>
 <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
 </layout>
 </appender>

 <root>
 <priority value ="debug" />
 <appender-ref ref="console" />
 </root>

</log4j:configuration>

Now, we will see all the debug messages along with out System.out message …”In the job”

In order to inject a bean in the job class we change the exampleJob declaration in beans.xml to the following and declare the “injectedBean” …

<bean name="exampleJob">
 <property name="jobClass" value="com.wordpress.codesilo.ExampleJob" />
 <property name="jobDataAsMap">
 <map>
 <entry key="injectedBean" value-ref="injectedBean" />
 </map>
 </property>
 </bean>

 <bean id="injectedBean"/>

We will have a simple method that displays a message in the InjectedBean class

 public void execute(){
 System.out.println("In injected bean execute method");
 }

and call this method from the ExampleJob class.
Now, if we run main we should see the following output (after removing the debug logs)
In the job
In injected bean execute method
In the job
In injected bean execute method

Stateful Job and Concurrency

In order that the job is not fired concurrently we can have two approaches …

a) Make the job stateful.  All we need here is to implement StatefulJob when creating the ExampleJob class. So, the ExampleJob class declaration now looks like this..

 public class ExampleJob extends QuartzJobBean implements StatefulJob {
 ......
 ......
 }

Read more about it here.

b) Use “MethodInvokingJobDetailFactoryBean” and set the concurrent flag to false. Here is a section from the docs

By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with each other. If you specify two triggers for the same JobDetail, it might be possible that before the first job has finished, the second one will start. If JobDetail classes implement the Stateful interface, this won’t happen. The second job will not start before the first one has finished. To make jobs resulting from the MethodInvokingJobDetailFactoryBean non-concurrent, set the concurrent flag to false.

 <bean id="jobDetail">
 <property name="targetObject" ref="exampleBusinessObject" />
 <property name="targetMethod" value="doIt" />
 <property name="concurrent" value="false" />
 </bean>

Setting up Ubuntu for development

February 2, 2010 1 comment

I had to reinstall Ubuntu recently and this blog is a summary of setting Ubuntu up for development.

Installing Maven:

sudo apt-get install maven2

In the .bash_profile file in the $HOME directory set the MAVEN_REPO variable and export it. Add this line in the file : export MAVEN_REPO=$HOME/.m2/repository

Installing Sun JDK:

sudo apt-get install sun-java6-bin sun-java6-jre sun-java6-jdk
sudo update-java-alternatives -l
sudo update-java-alternatives -s java-6-sun

In the .bash_profile file again, add these lines —
export JAVA_HOME=/usr/lib/jvm/java-6-sun
export PATH=$PATH:$JAVA_HOME/bin

Update: For installing JDK on Lucid Lynx read this post.

Installing MySql Server:

sudo apt-get install mysql-server

Set the root password when prompted.

Installing Samba:

sudo apt-get install samba smbfs

Installing openssh:

sudo apt-get install openssh-server openssh-client


Installing Ruby and RoR:
This link is a very good summary of doing that in Karmic Koala.

Installing Subversion:

sudo apt-get install subversion

Installing Client for Subversion:
RapidSVN is a very good tool for Ubuntu but recently I tried  RabbitVCS. This is in active development and is very close to TortoiseSVN in Windows.
To install RabbitVCS you need to download the deb package from their website and and install it using the following command (rabbitvcs_0.12.1-2~karmic_all.deb is the downloaded file)

sudo dpkg -i rabbitvcs_0.12.1-2~karmic_all.deb

Installing Eclipse, SpringIDE and Maven Plugin for Eclipse:
Eclipse can be easily installed by using package manager but I ran into some problems with the maven plugin when I used the eclipse that came with Karmic. When I used the Eclipse from their download site ,I did not have the problems.
Get SpringIDE plugin by providing this site in the “install new software” option in Eclipse: http://springide.org/updatesite. The ADJT features were giving problems when installing this plugin so I deselected them.
Get maven plugin from here : http://m2eclipse.sonatype.org/update