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.

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 😉

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.

Spring Framework 1.1.4 released

Juergen Hoeller has announced the release of Spring Framework 1.1.4

I’m pleased to announce that Spring Framework 1.1.4 has finally been released. This is a bugfix and minor enhancement release in the 1.1 series.
Among the new features are:

* added LazyInitTargetSource, lazily accessing a singleton from a BeanFactory (lazily initializing on first call)
* added ServiceLocatorFactoryBean, allowing to map custom service locator interface methods to BeanFactory.getBean calls
* reworked ResourcePatternResolver to extend ResourceLoader, for ResourcePatternResolver checks in ResourceLoaderAware
* made BindException serializable, provided that the contained target object is serializable

* added LazyConnectionDataSourceProxy, for lazily fetching JDBC Connections with native JDBC or Hibernate transactions
* added "Sybase-jConnect" to default sql-error-codes.xml file, for database product name "Adaptive Server Enterprise"
* added overloaded "queryForList"/"queryForObject"/"queryForLong"/"queryForInt" methods with arg types to JdbcTemplate
* added "alwaysUseNewSession" flag to HibernateTemplate, enforcing a new Session even in case of a pre-bound Session
* HibernateTemplate proxies exposed Sessions by default, applying query cache settings and transaction timeouts

* added "isConnectFailure(RemoteException)" hook to AbstractRemoteSlsbInvokerInterceptor, for customized failure checks
* added "isConnectFailure(RemoteException)" hook to (Jndi)RmiClientInterceptor, for customized connect failure checks
* added JaxRpcServicePostProcessor interface, intended for reusable custom type mappings etc for a JAX-RPC service
* added "servicePostProcessors" property to LocalJaxRpcServiceFactory and subclasses (incl. JaxRpcPortProxyFactoryBean)

* added "messageIdEnabled" and "messageTimestampEnabled" properties to JmsTemplate, to disable id/timestamp on producer
* added "pubSubNoLocal" property to JmsTemplate, leading to the NoLocal flag being specified on MessageConsumer creation
* added "receiveSelected" and "receivedSelectedAndConvert" methods to JmsTemplate, accepting JMS message selectors
* added "schedulerListeners", "(global)JobListeners", "(global)TriggerListeners" bean properties to SchedulerFactoryBean
* added "jobListenerNames"/"triggerListenerNames" property to JobDetailBean, CronTriggerBean, SimpleTriggerBean (resp.)

* added ServletContextAttributeFactoryBean, exposing an existing ServletContext attribute for bean references
* added ServletContextAttributeExporter, taking Spring-defined objects and exposing them as ServletContext attributes
* added ServletContextPropertyPlaceholderConfigurer, a subclass that falls back to web.xml context-param entries
* added "publishEvents" init-param to FrameworkServlet, allowing to turn off the publishing of RequestHandledEvents
* Spring JSP tags work outside DispatcherServlet too, falling back to root WebApplicationContext and JSTL/request locale

Acegi Security System for Spring benchmark

I’ve recently used Acegi for a simple application and as I wanted to know how
much it loads the webapp I used JMeter to benchmark it. I’ve just spent less
than 30 min. to setup everything, so yake it as is, just a small idea of what
involves adding the Acegi filters to process the requests.

What I have used:

  • Tomcat 4.0.6
  • Acegi 0.7.0
  • JMeter 2.0.2

Acegi filters defined in web.xml:

  • A ProcessingFilter made by myself
  • HttpSessionIntegrationFilter
  • SecurityEnforcementFilter

Here there are the results of three tries, each one with the number of threads,
the ramp-up (delay between threads in seconds), and the loops (number of times
the test was executed). The url tested was not secured.

threads ramp-up loop  
50 1 10  
 
  average (ms.) deviation (ms.)  
Using Acegi 107 47 15%
Not using Acegi 93 82

threads ramp-up loop  
50 1 100  
 
average (ms.) deviation (ms.)  
Using Acegi 233 137 13%
Not using Acegi 206 125

threads ramp-up loop  
5 1 1000  
 
  average (ms.) deviation (ms.)  
Using Acegi 15 12 67%
Not using Acegi 9 12

You can see that the overhead of using Acegi is about 14% increase of access
time in every page when the load is high. When it’s low, the overhead is
higher, but not relevant.