A great answer to the "What is Agile?" question

My friend David Draper has just posted a great response that he gave to a potential client recently in answer to the dreaded question "what, in a nutshell, does agile mean?"

Check out David's blog for his answer.

Technorati Tags: , ,

Better Java Dates, Times & Calendars with Joda-Time

Anyone who has used Java to manipulate Dates will know that it's one of the most frustrating parts of the core APIs - it should just be so easy!

As an example, here is one way to create a 'date of birth' Date - in this object we want the time part of the Date to be all zeros (midnight):

import java.util.Calendar;
import java.util.Date;

Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(2004, Calendar.JULY, 10);
Date dob = calendar.getTime();
There are a few gotchas to be aware of here, first is that you can't specify the month value as just "7" or "07" as that would give the month as August (as month 0 = January!) and the other is that without the call to clear() the time part will be set to the time when the Calendar.getInstance() was called.

Now compare this to creating a 'date of birth' Date object using Joda-Time:
import org.joda.time.DateMidnight;

Date dob = new DateMidnight(2004, 07, 10).toDate();
The DateMidnight class indicates that the time part will be zeros (more explicit than the "clear()" method) and you don't have to use any constants to build up the months.

The Joda-Time package is rammed full of useful bits like this, including instants, periods, intervals, durations, etc. as well as full calendar support and the ability to 'freeze time' (very useful for unit testing).

It's a fantastic package and should be considered a replacement for the cumbersome java.util.Calendar class.

Technorati Tags: , , , ,

The next Manchester Spring User Group meetup is 11th August

Following on from an excellent gathering in June, Guy Remond (MD of Cake Solutions) has announced the details of August's meeting:

"Introducing Spring Batch 2.0 plus Spring Framework 3.0 update" by Dave Syer:

Well known as lead committer to the Spring Batch project as well as having a major influence throughout SpringSource, Dave will be sharing insight into the use of Spring Batch, showing some demonstrations and unveiling enhancements (scalability, XML config, Java 5…) within Spring Batch 2.0. In addition he has promised some interesting thoughts on the long awaited Spring Framework 3.0.
There was a brief mention of Spring Batch at the last SUG meeting so I'm looking forward to finding out more...

Oh, don't forget to register for the August meeting over on the Spring User Group website.

Technorati Tags: , , , , ,

Supporting the Oracle XMLTYPE datatype via JPA (Spring, Hibernate & JDBC)

On a recent project I was tasked with developing two domain objects which mapped via JPA to a couple of tables. This would have been easy apart from one table used the the Oracle-specific XMLTYPE data type:

create table PERSON
(
P_ID number not null,
P_NAME varchar2(50),
P_UPDATED date,
P_XML xmltype
);
The XMLTYPE datatype is not supported by JPA (or any Hibernate-specific annotations) and so I had to use a different approach. I created the JPA-based Person class as normal, adding @Column annotations to the class, ignoring the P_XML column. I then added the following bit of code to be a placeholder for the XML:
@Transient
// required so that JPA doesn't try to persist it, we need JDBC for that
private String xml;
I then developed the JpaPersonDao as normal, using the getJpaTemplate() methods to select, insert and update the database. This handles all the columns except the XMLTYPE one - you need to use JDBC for that one due to the way in which Oracle expects the column to be filled and read.

My approach was to use the JPA-based DAO to perform most of the work loading and saving the rows, but hook in a JDBC-based DAO behind the scenes to handle the XMLTYPE column. By hiding it in the DAO, the users of the PersonDao will not have to worry about the special nature of the XMLTYPE column.

This is the JdbcPersonDao performing access to the XMLTYPE-based column only:
public class JdbcPersonDao extends JdbcDaoSupport {

private static final String SELECT_XML_SQL = "select p.P_XML.getClobVal() from PERSON p where P_ID = ?";
private static final String UPDATE_XML_SQL = "update PERSON set P_XML = xmltype(?) where P_ID = ?";

public String getXml(Integer id) {
Object[] args = { new Integer(id) };
int[] argTypes = new int[] { Types.INTEGER };
return (String) getJdbcTemplate().queryForObject(SELECT_XML_SQL, args, argTypes, String.class);
}

public void setXml(Integer id, String xml) {
OracleLobHandler lobHandler = new OracleLobHandler();
lobHandler.setNativeJdbcExtractor(new CommonsDbcpNativeJdbcExtractor());

Object[] args = { new SqlLobValue(xml, lobHandler), new Integer(id) };
int[] argTypes = new int[] { Types.CLOB, Types.INTEGER };
getJdbcTemplate().update(UPDATE_XML_SQL, args, argTypes);
}
}
And here are the important bits of the JpaPersonDao hooking into the JDBC-based one to ensure that the data stays consistent, both accesses to the database are within the same transaction and so are atomic:
public class JpaPersonDao extends JpaDaoSupport implements PersonDao {

@Autowired
private JdbcPersonDao jdbcPersonDao; // deals with the xmltype clob

public Person getPersonById(Integer id) {
Person person = getJpaTemplate().find(Person.class, id);

if (person != null) {
person.setXml(jdbcPersonDao.getXml(id));
}

return person;
}

public void savePerson(Person person) {
getJpaTemplate().persist(person);
getJpaTemplate().flush(); // forces the generation of an ID, required in the saveXml call
saveXml(person);
}

public Person updatePerson(Person person) {
// put the xml to one side as the merge clears out the transient field
String xml = person.getXml();
Person updatedPerson = getJpaTemplate().merge(person);
updatedPerson.setXml(xml);
saveXml(updatedPerson);

return updatedPerson;
}

private void saveXml(Person person) {
if (person.getXml() != null) {
jdbcPersonDao.setXml(person.getId(), person.getXml());
}
}
}
Not the most elegant solution, but at least with the use of the @Autowired JDBC-based DAO the mess is hidden from the caller...

Technorati Tags: , , , , , , ,

MP3 purchase comparison between Amazon.co.uk & Play.com

My first foray into purchasing MP3 was from Amazon.co.uk some months back. It was a smooth experience much like buying anything else from Amazon and it's quirky MP3 downloader popped the nicely named MP3 files into my music folder in the normal directory structure of Artist name/Album name/track number & name.

This week I purchased an album from Play.com's MP3 catalogue due to it being a little cheap than Amazon. It's download format was a large zip file that had to be saved to the desktop, it's content was just the tracks - no artist/album directory structure, no track numbers. Because I don't have an iPod I had to look up the track listing on the net and rename the files just to put them in the right album order!

Next time I want to buy some music online I think I will be skipping Play.com's offering completely and paying the little more that Amazon.co.uk was charging - it will be worth it to just have my music just download straight into the right place rather than messing around with zip file and renames...

Technorati Tags: , , ,

A new way to label in GMail (and the end of Right-Sided Labels)

Back in March I blogged about my favourite GMail labs. One of them has died today - Right-side Labels.

Google are grouping labels together with Inbox, Drafts, Chats and other system labels, and so putting the labels over on the right-hand side doesn't make sense anymore.

The problem is, my GMail's not been updated yet so I can't play with the new features! :)

Technorati Tags: , , ,