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>

Spring Framework 1.1.5 released

The Spring Framework has released the 1.1.5 version, the last one before 1.2 release candidate comes out with major improvements as Hibernate 3 and JMX support. As with previous versions I have uploaded it to the maven repository at ibiblio, so maven users can download automatically.

Hi everybody,

I’m pleased to announce that Spring Framework 1.1.5 has just been released. This is the last bug fix and minor enhancement release in the 1.1.x series, featuring many minor improvements such as:

* added overloaded "reject" and "rejectValue" methods without default message to Errors interface and BindException
* added "lookup(name, requiredType)" convenience method to JndiTemplate, matching the JNDI object against the given type
* added "homeInterface" property to AbstractRemoteSlsbInvokerInterceptor, for specifying the home interface to narrow to
* introduced MailMessage interface as common interface for SimpleMailMessage and JavaMail MIME messages
* Log4jConfigurer accepts a "classpath:" URL or a "file:" URL as location too, not just a plain file path
* Log4jConfigurer accepts config files that do not reside in the file system, as long as there is no refresh interval

* added "int[] batchUpdate(String[] sql)" method to JdbcTemplate, for executing a group of SQL statements as a batch
* added C3P0NativeJdbcExtractor for C3P0 0.8.5 or later (for earlier C3P0 versions, use SimpleNativeJdbcExtractor)
* added "maxRows" bean property to JdbcTemplate, allowing to specify the maximum number of rows to be fetched
* added "fetchSize" and "maxRows" bean properties to RdbmsOperation, passing the values to the internal JdbcTemplate
* added ClobStringTypeHandler, BlobByteArrayTypeHandler and BlobSerializableTypeHandler for iBATIS SQL Maps 2.0.9
* ResourceHolderSupport throws TransactionTimedOutException if no time-to-live left (before attempting an operation)
* TransactionSynchronization objects can influence their execution order through implementing the Ordered interface
* JtaTransactionManager is able to work with a JTA TransactionManager only (i.e. without a UserTransaction handle)

* upgraded MockHttpServletRequest to Servlet API 2.4 (added getRemotePort, getLocalName, getLocalAddr, getLocalPort)
* upgraded MockPageContext to JSP API 2.0 (added getExpressionEvaluator, getVariableResolver, overloaded include)
* added "contextOverride" option to ServletContextPropertyPlaceholderConfigurer, letting web.xml override local settings
* added "searchContextAttributes" option to ServletContextPropertyPlaceholderConfigurer, resolving context attributes
* added "clear" and "isEmpty" methods to ModelAndView, allowing to clear the view of a given ModelAndView object
* added JasperReportsMultiFormatView, allowing to specify the output format dynamically via a discriminator in the model
* JSP EL expressions in Spring’s JSP tags will be parsed with JSP 2.0 ExpressionEvaluator on JSP 2.0 (Jakarta JSTL else)
* changed "spring:transform" tag’s "value" attribute from String to Object, to allow for expressions resolved by JSP 2.0

See the changelog for details.

Our next milestone is 1.2 RC1, which we intend to release as soon as possible: with Hibernate3 support, JMX support and further major new features. Nightly 1.2-dev snapshots with Hibernate3 support and JMX support will be available within a few days, so feel free to give 1.2 an early try 🙂

Cheers,
Juergen

Acegi Security: reducing configuration in web.xml

Until now, to use Acegi Security System for Spring in your web application you needed to add at least three filters and filtermappings to your web.xml, eg. to secure an application using form based authentication these lines had to be present in every web.xml:

<filter>
  <filter-name>Acegi Authentication Processing Filter</filter-name>
  <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
    <param-name>targetClass</param-name>
    <param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value>
  </init-param>
</filter>
<filter>
  <filter-name>Acegi Security System for Spring Http Session Integration Filter</filter-name>
  <filter-class>net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter</filter-class>
</filter>
<filter>
  <filter-name>Acegi HTTP Request Security Filter</filter-name>
  <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
    <param-name>targetClass</param-name>
    <param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>Acegi Authentication Processing Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>Acegi Security System for Spring Http Session Integration Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
filter-mapping>
  <filter-name>Acegi HTTP Request Security Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

With the latest changes in CVS (thanks Ben) you only need to add one filter and filter mapping to web.xml:

<filter>
  <filter-name>Acegi Filter Chain Proxy</filter-name>
  <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
    <param-name>targetClass</param-name>
    <param-value>net.sf.acegisecurity.util.FilterChainProxy</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>Acegi Filter Chain Proxy</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

And a bean definition to the Spring application context, specifying the actual filters and the urls to map.

<bean id="filterChainProxy"
  class="net.sf.acegisecurity.util.FilterChainProxy">
  <property name="filterInvocationDefinitionSource">
    <value>
      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
      PATTERN_TYPE_APACHE_ANT
      /**=authenticationProcessingFilter,httpSessionIntegrationFilter,securityEnforcementFilter
    </value>
  </property>
</bean> 

This approach allow you to reuse the bean across all your applications, as it won’t change if you’re using the same authentication schema (eg. form based). As a sideeffect also allows using ant patterns or regular expresions in the url mappings.

Hibernate vs JDBC == Maven vs Ant

While coding with JDBC directly provides powerful posibilities I
think no one could argue that it’s better coding at such low level in
the vast majority of the cases.

I think Maven does the same to
build systems. Maven doesn’t substitute Ant, abstracts and simplifies
it. For some cases you’ll still need to write Ant build files inside
Maven, as you can write SQL inside hibernate, but you will have the
power from both worlds.

Maven has made a risky bet, as Hibernate
has done, but fortunately both achieved a growing community. Currently
there are too much people asking for features compared to those
implementing them, so I encourage any of you to take the bull by the
horns and become actively involved.

And you should never forget
that behind high level tools and technologies there’re always low level
ones (Maven – Ant, Hibernate – JDBC, Struts – Servlets,…)