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
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
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(); } }
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.
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.
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.
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.
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 |
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>
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>
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!
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>
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>