Monday, March 22, 2010

Nested tables With DisplayTag

I've been using DisplayTag for a long time but never cover its all functions. Today I've to list a collection of ojects with a List property also need to be iterated. DisplayTag's nested table display is what I need.


http://displaytag.homeip.net/displaytag-examples-1.2/img/displaytag.png

The display tag library is an open source suite of custom tags that provide high-level web presentation patterns which will work in an MVC model. The library provides a significant amount of functionality while still being easy to use.

I followed the nested tables example you can find at here. However, this example does not go through after I copy paste. I think there is a mistake in the nesting EL expressions

The difficulty is how to pass the child List property to the nested table, since :
You can't use page attributes created by the parent table for iteration in the nested table (for example if you have a parent table with id="parent" you can't use name="pageScope.parent" as source for the nested table).

the table's data is, let's say "projectList", the nested table's data is "projectList[rowIndex].developers". Since the "rowIndex" is obtained from DisplayTag's implicit objects, nesting EL expressions is used.
//DisplayTag's implicit objects, get the row's number, start from 1.
${projectList_rowNum} 
//In Java, the index begin at 0, so need to minus 1

//use the square brackets notation to get row's projectList
${projectList[rowIndex].developers} 

In their example, they define:

${nestedName} will get a String value, not the List.

The full example as following:


  
  
  

  

  

   
  
  
 
  



Sunday, March 21, 2010

JQuery UI Autocomplete widget with customize JSON data and Spring MVC

One of my favorite newly added widget in jQuery UI 1.8, is Autocomplete. However, it took me a long time to figure it out how to use customized JSON data. So I wrote this as supplementary for you to use your own format JSON data.


The Default JSON Data Format

The Autocomplete widget will looking for an Array of object with label, value property pair, for example, data from jQury UI's remote datasource example.
[ { "id": "Dromas ardeola", "label": "Crab-Plover", "value": "Crab-Plover" }, { "id": "Larus sabini", "label": "Sabine`s Gull", "value": "Sabine`s Gull" }, { "id": "Vanellus gregarius", "label": "Sociable Lapwing", "value": "Sociable Lapwing" }, { "id": "Oenanthe isabellina", "label": "Isabelline Wheatear", "value": "Isabelline Wheatear" } ]

Customized JSON Data

But my country name JSON data looks like this:
 {"countries":[{"name":"Australia","id":14},{"name":"Austria","id":15},{"name":"Guinea-bissau","id":96},{"name":"Macau","id":133},{"name":"Mauritania","id":143},{"name":"Mauritius","id":144},{"name":"Nauru","id":157},{"name":"Palau","id":172},{"name":"Saudi Arabia","id":197},{"name":"Tokelau","id":224}]}

In order to adapt our country names' for auto complete widget, we need to process it at first in "source" callback function:
source: function(request, response) {
  $.ajax({
   url: "countries/",//request url
   dataType: "json",
   data: {
                term: request.term //this will enable countires?term=au
               
            },
   success: function(data) {
    response($.map(data.countries, function(item) {
     return {
      label: item.name,
      value: item.name
     }
    }))
   }
  })
 },

The Complete Example





Saturday, March 20, 2010

Formatting time with PrettyTime JSP Tag

In Web 2.0 applictions, timestamp is no longer displayed in the pattern "yyyy-MM-dd hh:mm:ss", such as 2010-03-20 13:38:20". Instead, it is formmated as so called "pretty time", such as "5 Minutes ago". In Java world, there is an open source library called PrettyTime to implement that.

PrettyTime is an OpenSource time formatting library. Completely customizable, PrettyTime creates human readable, relative timestamps like those seen on Digg, Twitter, and Facebook. It’s simple, get started “right now!”

To use PrettyTime in Java code, it's petty simple:
public String getPretty(Date date) {
  PrettyTime p = new PrettyTime();
  String prettier = p.format(date);
  return prettier;

 }

It is generally a good practice to render date prettier in display layer, that is, JSP file. Therefore, we will create a simple JSP Tag to make our date or time display in a fashion way. And the tag will implement in JSP Tag Files, which was introduced in JSP 2.0.

Preparation

Add PrettyTime in your project's building path, I use Maven:

 com.ocpsoft
 ocpsoft-pretty-time
 1.0.5


prettyTime.tag

This JSP Tag File will be placed at:
webapp/WEB-INF/tags/prettyTime.tag
This tag will require one Date attribute, the date you want to format. The prettyTime.tag as following:

<%@ tag import="com.ocpsoft.pretty.time.PrettyTime"  import="java.util.Date"%>
<%@ attribute name="date" required="true" type="java.util.Date" %>
 
<%
 PrettyTime p = new PrettyTime();
    String prettier = p.format(date);
 out.println(prettier);
%>


Usage in JSP file

It is very easy to use prettyTime tag in your JSP file. You need to declare our tag at first.
<%@ taglib prefix="kc" tagdir="/WEB-INF/tags"%>

Ordered:


Wednesday, March 17, 2010

Australian Money rounding in Java and JavaScript

Money rounding is a little bit difficult in Australia, since the smallest coin is 5 cent and HALF_EVEN is not enough. It requires rounding to nearest 5 cents for Australian businesses. For example, $5.96 rounds to $5.95.
$5.98 goes to $6, kinds of ONE_FOURTH_EVEN.

To implement Australian dollar rounding, I use a kind of stupid solution, introducing an rounding map.
roundingMap.put(1, new BigDecimal("-0.01"));
  roundingMap.put(2, new BigDecimal("-0.02"));
  roundingMap.put(3, new BigDecimal("0.02"));
  roundingMap.put(4, new BigDecimal("0.01"));
  roundingMap.put(6, new BigDecimal("-0.01"));
  roundingMap.put(7, new BigDecimal("-0.02"));
  roundingMap.put(8, new BigDecimal("0.02"));
  roundingMap.put(9, new BigDecimal("0.01"));
This map contains number 1,2,3,4,6,7,8,9 which need to be rounded. To round a amount, simply get the last digital and get the rounding value.

for example, the last digital for $5.96 is 6. The rounding value for key 6 is -0.01. the final result is $5.96-0.01=5.95.

This implementation is not very smart but it's the best I can figure out.

Here is the full solution.
In JAVA:
The Rounding Class:
import java.math.BigDecimal;
import java.util.HashMap;

/**
 * Rounding to nearest 5 cents for Australian businesses
 * 
 * @author Ke CAI
 */
public class MoneyRounding {
 static HashMap roundingMap = new HashMap();
 static {
  roundingMap.put(1, new BigDecimal("-0.01"));
  roundingMap.put(2, new BigDecimal("-0.02"));
  roundingMap.put(3, new BigDecimal("0.02"));
  roundingMap.put(4, new BigDecimal("0.01"));
  roundingMap.put(6, new BigDecimal("-0.01"));
  roundingMap.put(7, new BigDecimal("-0.02"));
  roundingMap.put(8, new BigDecimal("0.02"));
  roundingMap.put(9, new BigDecimal("0.01"));

 }

 public static BigDecimal getRounding(BigDecimal bd) {
  int decimalDigit = bd.movePointRight(2).intValue() % 10;
  BigDecimal mappedVal = (BigDecimal) roundingMap.get(decimalDigit);
  if (mappedVal == null)
   return BigDecimal.ZERO;
  return mappedVal;
 }

}


Unit test and how to use Rounding Test:
import static org.junit.Assert.assertEquals;

import java.math.BigDecimal;

import org.junit.Test;

public class RoundingTest {

 @Test
 public void testRounding() {
  
  BigDecimal amout = new BigDecimal("15.58");

  BigDecimal rounding = MoneyRounding.getRounding(amout);
  assertEquals(rounding, new BigDecimal("0.02"));
  
  BigDecimal amout1 = new BigDecimal("15.56");

  BigDecimal rounding1 = MoneyRounding.getRounding(amout1);
  assertEquals(rounding1, new BigDecimal("-0.01"));
  
 }

}

The following is how to implement it in JavaScript:
var Rounding = function( ){
 function getRounding(amount){
 var roundingMap={1:-0.01,2:-0.02,3:0.02,4:0.01,6:-0.01,7:-0.02,8:0.02,9:0.01};
 var  decimalDigit =amount*100%10;
 return roundingMap[decimalDigit];
}

//test
var amount=15.59;
alert(getRounding(amount));

Tuesday, March 9, 2010

Coding anywhere with Dropbox Eclipse Maven

There are several Java projects that I like to work on when I have some free time. My pain is, the “free time” is from different locations, different computers and different Operating Systems. In work, my computer is a Dell PC installed Windows Vista. At home, I use a PC with Windows 7 and my sweet heart, Macbook Air with Snow Leopard.

The precious “free time” cannot be wasted on copy paste project via USB stick. And you know, Mac keeps generating .DS_Store, .trash files which are annoying. Then I started to use Subversion, commit my changes before I left company and update when I get home. Yes, as you predicted, what if the codes haven't passed test or even with compile errors? Therefore, subversion does not fit my multi-locations development scenario.

I have heard DropBox for a long time and I found it's perfect for me to code in different computer. I am Java developer, Eclipse and Maven are the most frequently IDE and build tools I used. A Maven's project in Eclipse workspace looks like that:

The key to use DropBox to synchronize maven project between different computers is to copy the three folders I selected(src,sql, pom.xml) into DropBox folder and create symbolic link to those in your eclipse workspace. The rest folder or file is only for your local computer and should be avoided to synchronize(Similar to import project into Subversion repository). I will show you how to do it in Windows and Mac.
In Windows
The symbolic link requires another software. I recommend Link Shell Extension . It provides enough documents for you to do the symbolic link.
Firstly of all, copy the Maven project into your DropBox folder (only src, sql, pom.xml) either in Mac or Windows.
Secondly, create a folder in your eclipse workspce. Then do the symbolic link.
In Windows,
open DropBox folder and browse to the project folder, right click on "src" folder, select "Pick Link Source".

Go into your eclipse workspace project folder, right click, select "Drop As..."->"SymbolicLink". Do the same to "sql" folder if you have.

The "pom.xml" file is a litte bit different, after you selected By "Pick Link Source", simply select "Symbolic link".
In Mac, life is much easier, open "Terminal", "cd" into your eclipse workspace folder, and use the following command:

ln -s ~/Dropbox/myproject/src src
ln -s ~/Dropbox/myproject/sql sql
ln -s ~/Dropbox/myproject/pom.xml pom.xml
Now projects in all your computers will linked to the project in DropBox's cloud. The DropBox will synchronize your project for you between different places.

Fire up "cmd" or "terminal", "cd" into your project folder within eclipse workspce,

Use "mvn eclipse:eclipse" to generate eclipse project descriptor and import it into your eclipse.
Note: In Mac, maven eclipse plugin might not work well with symbolic link folder. The source folders are pointed to the incomplete path to Dropbox. It's not hard to fix maully.
Wherever you modify your code, the other place will be synchronized. Amazing,Happy Coding:)