Using Java 1.5 in real world app

It’s almost sure that the current app we’re developing right
now will use Java 5. That’s the first option and will be used
unless some problem arises. So it was time to remember the Taming the Tiger presentation from Joshua Bloch and Neal Gafter in JavaHispano II. The slides are available from the Denver Java Users Group Archives, and it’s a pity that the link to the video of the session seems broken.

As Joshua and Neal advised the only trouble porting pre 1.5 code to 1.5 is that enum can’t
be used as variable name because it’s a reserved word. And of course
the old code does, so it’s time to refactor that variable names. Seems
that appart from that there won’t be any problem.

BTW I’ve also enjoyed the Still More Java Puzzlers slides.

Hibernate 3 + Annotations + Spring 1.2 + Maven

Today I upgraded a prototype working with Hibernate 2 + Spring 1.1
to the latest Hibernate 3.0.1 + Spring 1.2rc2 + Hibernate annotations
3.0beta1 to avoid writing mapping files and use annotations under Java 5.

To use annotation under Maven you need to add the following properties to project.properties

maven.compile.source=1.5
maven.compile.target=1.5

and these all the dependencies you will need. Note that some of them
are not available at ibiblio yet due to a problem of space that will be
solved soon.

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.0.4</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-hibernate</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-dao</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>1.2-rc2</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.0</version>
            <url>http://jakarta.apache.org/commons/collections</url>
        </dependency>
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>ejb</groupId>
            <artifactId>ejb</artifactId>
            <version>3.0-edr2</version>
        </dependency>
        <dependency>
            <groupId>hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.0beta1</version>
        </dependency>
        <dependency>
            <groupId>jta</groupId>
            <artifactId>jta</artifactId>
            <version>1.0.1B</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <groupId>hibernate</groupId>
            <artifactId>antlr</artifactId>
            <version>2.7.5H3</version>
        </dependency>

Soon with Maven 2 you won’t need all this stuff 😉

As far as the Hibernate 2 to 3 migration as many people have already
said it’s just a matter of renaming the net.sf.hibernate imports to
org.hibernate. About the Hibernate annotations I should give Rick the credit as he has already posted the sample code.

To use Spring with the new Hibernate 3 you need to upgrade to Spring
1.2 (1.2rc2 is the latest version currently available) and change org.springframework.orm.hibernate.LocalSessionFactoryBean to org.springframework.orm.hibernate3.LocalSessionFactoryBean in you applicatin context.

To use Java5 annotations instead of mapping files you need to create a hibernate config file (say hibernate.cfg.xml)
with the classes you want to map (or add them to the one you already
have). The reason you need this file is so the Spring framework doesn’t
depend on JDK 5.

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <mapping class="your.domain.class"/>
        <mapping class="another.domain.class"/>
    </session-factory>
</hibernate-configuration>

And then add to your Spring LocalSessionFactoryBean two properties

<property name="configLocation">
    <value>hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
    <value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>

And that’s all for the moment.

Maven 2.0 Alpha 2 Released

Brett has released the Maven 2.0 Alpha 2 version, thanks!

Download

Maven 2 site

Maven 2 and Continuum slides

Brett Porter has posted a set of very interesting slides about Maven 2.0 and Continuum

https://sydneyjug.dev.java.net/files/documents/922/15554/sjug20050601.pdf

Back from JavaHispano

After many busy days I’m able to post this entry.

Two weeks ago I spent two great days at JavaHispano 2004 (Madrid), where I talked about Acegi Security System for Spring.

There I met many nice guys,

Miguel Valdes-Faura

(ObjectWeb), Alexandre Vasseur (AspectWerkz), Santiago Gala (Apache), Hugo Pinto,

Jes�s Perez (Agile-Spain), and people from the JavaHispano JUG as

Abraham Otero.

There
was very interesting talks. What I liked most were “Taming the Tiger”
by Joshua Bloch and Neal Gafter, and Annotation driven AOP by Alexandre
Vasseur. Other interesting ones were from Sun evangelist Angela Caicedo
about JSF, Miguel Valdes about Middleware and the round table about
Java future, with Reggie Hutcherson, another Sun evangelist.

My presentation was about Acegi Security System for Spring and the
features it provides. I used ONess as example of using it in an
enterprise class application. I didn’t expect too much interest from
the public as it’s a very specific thing, but there were questions, and
nobody fell asleep! 😉

I also talked a lot about Maven and saw that everyone is planning to check it for next projects.

It’s worth to say that the conferences were free, and the room was
always under 200 people, wich made it very familiar and a good place to
meet interesting people working in Java. There’s a fact: the more it
costs the more it’s estimated by people.

What are the ideas I got after these two days: AspectWerkz rocks,
JOnAS (the first open source application server, don’t believe JBoss!),
Java 5 and JSF worth trying. And of course Spring Framework community
is growing faster and faster 😉

Maven vs. Ant + Ivy

There was some interesting discussion lately about Ivy. It started with Colin’s blog entry about Ivy and transitive dependencies.

I think that if you decide to use Ant you’d better use something like Ivy to manage the dependencies in a painless way. If you choose maven just for handling dependencies you may prefer using Ant + Ivy, maven is not about just handling jars, I’d like to think that it’s more than that. As Dion I have to stand up for Maven too. It provides me more productivity than Ant.

You may agree or not but something I find really annoying is people trying to reinvent the wheel. Ivy uses the Maven repository at iBiblio and that’s great, we can collaborate to get a better repository BUT Brett is right about the new Ivy repository with dependency metadata, maven project info is already available under the groupId/poms dir and can be used from Ivy, better improve it than starting from scratch, isn’t it?

I’d like to say that some problem I usually find with that dependency metadata is that projects don’t spend a bit of its time to provide it, I don’t force them to do so just to please me, but many people rant about maven because it doesn’t handle dependency information and they should complain to each project developers, not maven.

N.B. A good idea would be an XSL to pretty print the info from the POM.

I expect that the new maven book written by Vincent Massol will proselytize more users 😉 and more importantly developers!

More than 7000 jars in Maven repository

Today the official Maven repository at iBiblio has reached the 7000 jars. Thanks to everybody who helped to make this happen!

I hope that non maven users also benefit from it, remember that there’s a searching engine at maven.ozacc.com

Tracing an application using AspectJ

Almost a year ago I developed a logging aspect so I could trace the program flow without writting to the log in each method call. Also it can be disabled a compile time, improving the performance. I think it’s worth remember it now:

/*
 * Copyright 2004 Carlos Sanchez.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.sf.oness.common.all.logging;

import org.aspectj.lang.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Aspect that logs method calling and exception throwing
 * using the apache commons logging package with the TRACE
 * facility.
 * Logs every method, avoiding recursion into the aspect and
 * into toString calls, which may lead to infinite recursion
 * and StackOverflowError exceptions
 *
 * @author Carlos Sanchez
 * @version $Revision: 1.4 $
 */
public aspect LoggingAspect {

    /**
     * The logging aspects should have the highest precedence.
     * This	way, the logging aspects before advice executes
     * before any of the other aspects before advice, and the
     * logging aspects after advice executes after the other
     * aspects after advice.
     * This makes the logging aspects dominate all other aspects
     */
    declare precedence : LoggingAspect, *;

    /**
     * Log every method avoiding recursion into the aspect and
     * into toString calls, which may lead to infinite recursion
     * and StackOverflowError exceptions
     */
    protected pointcut traceMethods() : (
        !cflow(execution(String *.toString()))
            && !cflow(within(LoggingAspect))
            && (execution(* *.* (..)))
            || execution(*.new (..)));

    /**
     * This advice logs method entries
     */
    before() : traceMethods() {
        Signature sig = thisJoinPointStaticPart.getSignature();
        Log log = getLog(sig);
        if (log.isTraceEnabled()) {
            log.trace(
                "Entering "
                    + fullName(sig)
                    + createParameterMessage(thisJoinPoint));
        }
    }

    /**
     * This advice logs method leavings
     */
    after() returning : traceMethods() {
        Signature sig = thisJoinPointStaticPart.getSignature();
        Log log = getLog(sig);
        if (log.isTraceEnabled()) {
            log.trace("Leaving " + fullName(sig));
        }
    }

    /**
     * This advice logs exception throwing
     */
    after() throwing(Throwable ex) : traceMethods() {
        Signature sig = thisJoinPointStaticPart.getSignature();
        Log log = getLog(sig);
        if (log.isTraceEnabled()) {
            log.trace("Thrown " + fullName(sig) + "\n\t" + ex);
        }
    }

    /**
     * Find log for current class
     */
    private Log getLog(Signature sig) {
        return LogFactory.getLog(sig.getDeclaringType());
    }

    /**
     * @return String with class name + method name
     */
    private String fullName(Signature sig) {
        return "["
            + sig.getDeclaringType().getName()
            + "."
            + sig.getName()
            + "]";
    }

    /**
     * @return String with current object + arguments
     */
    private String createParameterMessage(JoinPoint joinPoint) {
        StringBuffer paramBuffer = new StringBuffer();

        /*
         * Log the current object except if the method is a getter, setter or
         * constructor
         */
        if (joinPoint.getThis() != null) {
            String name = joinPoint.getStaticPart().getSignature().getName();

            if (!(name.startsWith("get"))
                && !(name.startsWith("set"))
                && !(name.equals("<init>"))) {

                paramBuffer.append("\n\t[This: ");
                paramBuffer.append(joinPoint.getThis());
                paramBuffer.append("]");
            }
        }

        Object[] arguments = joinPoint.getArgs();
        if (arguments.length > 0) {
            paramBuffer.append("\n\t[Args: (");
            for (int length = arguments.length, i = 0; i < length; ++i) {
                Object argument = arguments[i];
                paramBuffer.append(argument);
                if (i != length - 1) {
                    paramBuffer.append(",");
                }
            }
            paramBuffer.append(")]");
        }
        return paramBuffer.toString();
    }
}
  • very important to avoid infinite recursion!
  • avoid logging of getters, setters and constructors (it’d be better to disable it in the traceMethods pointcut)

This aspect will print a line to the log when you enter a method (with all the parameters), when you leave or when an exception is thrown. This is useful when you need to debug an application in an environment where you can’t use a debugger or it’s too complex to get it working.

Configuration can be done in commons-logging.properties file in the classpath to use Log4J for example:

org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

and log4j.properties:

# Global logging configuration
log4j.rootLogger=ERROR, stdout
log4j.logger.net.sf.oness=DEBUG, stdout

# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

With this aspect debugging info can be added to classes not developed by you without needing the sources. Just use the AspectJ ability to weave jars and you’ll get it!

You can also check the Cactus LogAspect which does something similar.

Acegi Security System for Spring 0.8.1 released

The 0.8.1 version of the Acegi Security System for Spring has been released, thanks Ben!

This release fixes a number of non-critical bugs, updates JAR
dependencies to match Spring 1.1.5, and introduces X509
(certificate-based) authentication support.

For Maven users, Acegi Security’s latest JARs are now available from
http://acegisecurity.sourceforge.net/maven/acegisecurity/jars and iBiblio.

Spring and iBATIS 2

Lately I was refactoring a application that acceses DB. Due it was using plain JDBC I decided to reimplement it using iBatis instead of Hibernate as I would do if starting from scratch.

I have used iBatis 1.x before, and now I decided to use the latest 2.0, and the Spring support.
I was keen to see that it was like using Hibernate support, very easy. In fact is easier to understand how things work than using Hibernate.

While reading the Spring reference guide I saw that the iBatis section didn’t cover most changes in
version 2, so I decided to complete it. You can read the full section here until Spring people update
it.

iBATIS

Through the org.springframework.orm.ibatis
package, Spring supports iBATIS SqlMaps 1.3.x and 2.0.x. The iBATIS
support much resembles Hibernate support in that it supports the same
template style programming and just as with Hibernate, iBatis support
works with Spring’s exception hierarchy and let’s you enjoy the all IoC
features Spring has.

4.1. Overview and differences between 1.3.x and 2.0

Spring supports both iBATIS SqlMaps 1.3 and 2.0. First let’s have a look at the differences between the two.

The
xml config files have changed a bit, node and attribute names. Also the
Spring clases you need to extend are different, as some method names.

Table 1.1. iBATIS SqlMaps supporting classes for 1.3 and 2.0

Feature 1.3.x 2.0
Creation of SqlMap SqlMapFactoryBean SqlMapClientFactoryBean
Template-style helper class SqlMapTemplate SqlMapClientTemplate
Callback to use MappedStatement SqlMapCallback SqlMapClientCallback
Super class for DAOs SqlMapDaoSupport SqlMapClientDaoSupport

4.2. iBATIS 1.3.x

4.2.1. Setting up the SqlMap

Using
iBATIS SqlMaps involves creating SqlMap configuration files containing
statements and result maps. Spring takes care of loading those using
the SqlMapFactoryBean.


public class Account {
	private String name;
	private String email;

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return this.email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
}

Suppose
we would want to map this class. We’d have to create the following
SqlMap. Using the query, we can later on retrieve users through their
email addresses. Account.xml:

<sql-map name="Account">
	<result-map name="result" class="examples.Account">
		<property name="name" column="NAME" columnIndex="1"/>
		<property name="email" column="EMAIL" columnIndex="2"/>
	</result-map>


	<mapped-statement name="getAccountByEmail" result-map="result">
		select
			  ACCOUNT.NAME,
			  ACCOUNT.EMAIL
		from ACCOUNT
		where ACCOUNT.EMAIL = #value#
	</mapped-statement>

	<mapped-statement name="insertAccount">
		insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
	</mapped-statement>
</sql-map>

After having defined the Sql Map, we have to create a configuration file for iBATIS (sqlmap-config.xml):

<sql-map-config>

	<sql-map resource="example/Account.xml"/>

</sql-map-config>

iBATIS loads resources from the classpath so be sure to add the Account.xml file to the classpath somewhere.

Using Spring, we can now very easily set up the SqlMap, using the SqlMapFactoryBean:

<bean id="sqlMap" class="org.springframework.orm.ibatis.SqlMapFactoryBean">
	<property name="configLocation"><value>WEB-INF/sqlmap-config.xml</value></property>

</bean>

4.2.2. Using SqlMapDaoSupport

The SqlMapDaoSupport class offers a supporting class similar to the HibernateDaoSupport and the JdbcDaoSupport types. Let’s implement a DAO:

public class SqlMapAccountDao extends SqlMapDaoSupport implements AccountDao {

	public Account getAccount(String email) throws DataAccessException {
		return (Account) getSqlMapTemplate().executeQueryForObject("getAccountByEmail", email);
	}

	public void insertAccount(Account account) throws DataAccessException {
		getSqlMapTemplate().executeUpdate("insertAccount", account);
	}
}

As you can see, we’re using the SqlMapTemplate to execute the
query. Spring has initialized the SqlMap for us using the
SqlMapFactoryBean and when setting up the SqlMapAccountDao as follows,
you’re all set to go:

<!-- for more information about using datasource, have a look at the JDBC chapter -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
	<property name="url"><value>${jdbc.url}</value></property>
	<property name="username"><value>${jdbc.username}</value></property>

	<property name="password"><value>${jdbc.password}</value></property>
</bean>

<bean id="accountDao" class="example.SqlMapAccountDao">
	<property name="dataSource"><ref local="dataSource"/></property>

	<property name="sqlMap"><ref local="sqlMap"/></property>
</bean>

4.2.3. Transaction management

It’s
pretty easy to add declarative transaction management to applications
using iBATIS. Basically the only thing you need to do is adding a
transaction manager to you application context and declaratively set
your transaction boundaries using for example the TransactionProxyFactoryBean. More on this can be found in ???

TODO elaborate!

4.3. iBATIS 2

4.3.1. Setting up the SqlMap

If we want to map the previous Account class with iBATIS 2 we need to create the following SqlMap Account.xml:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap PUBLIC
  "-//iBATIS.com//DTD SQL Map 2.0//EN"
  "http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="Account">

	<resultMap id="result" class="examples.Account">
		<result property="name" column="NAME" columnIndex="1"/>
		<result property="email" column="EMAIL" columnIndex="2"/>
	</resultMap>

	<select id="getAccountByEmail" resultMap="result">
		select
			  ACCOUNT.NAME,
			  ACCOUNT.EMAIL
		from ACCOUNT
		where ACCOUNT.EMAIL = #value#
	</select>

	<insert id="insertAccount">
		insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
	</insert>

</sqlMap>

The configuration file for iBATIS 2 changes a bit (sqlmap-config.xml):

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC
  "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
  "http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

	<sqlMap resource="example/Account.xml"/>

</sqlMapConfig>

Remember that iBATIS loads resources from the classpath so be sure to add the Account.xml file to the classpath somewhere.

We can use the SqlMapClientFactoryBean in the Spring application context :

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
	<property name="configLocation"><value>WEB-INF/sqlmap-config.xml</value></property>
</bean>

4.3.2. Using SqlMapClientDaoSupport

The SqlMapClientDaoSupport class offers a supporting class similar to the SqlMapDaoSupport. We extend it to implement our DAO:

public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {

	public Account getAccount(String email) throws DataAccessException {
		Account acc = new Account();
		acc.setEmail();
		return (Account)getSqlMapClientTemplate().queryForObject("getAccountByEmail", email);
	}

	public void insertAccount(Account account) throws DataAccessException {
		getSqlMapClientTemplate().update("insertAccount", account);
	}
}

In the DAO we use the SqlMapClientTemplate to execute the
queries, after setting up the SqlMapAccountDao in the application
context:

<!-- for more information about using datasource, have a look at the JDBC chapter -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>

	<property name="url"><value>${jdbc.url}</value></property>
	<property name="username"><value>${jdbc.username}</value></property>
	<property name="password"><value>${jdbc.password}</value></property>

</bean>

<bean id="accountDao" class="example.SqlMapAccountDao">
	<property name="dataSource"><ref local="dataSource"/></property>
	<property name="sqlMapClient"><ref local="sqlMapClient"/></property>
</bean>