Tuesday, December 21, 2004

Datasources selection with Spring

The aim is to permit to an application (and the user) to select a specific datasource to use, so a user can choose a specific database and datas to access. We can use the same mechanism than Acegi: a filter to get the datasource name and place it in known holder ( based on a thread local ) and a specific datasource ( proxy on datasources ) to get this name in order to select the datasource to use.

- Datasource name context: it's in fact a class to store the name of the DataSource et a class (a simple ThreadLocal) to hold it (the known place).
Here is an example of these two classes and interfaces:


public class DataSourceContextHolder {
private static ThreadLocal contextHolder = new ThreadLocal();

public static void setContext(DataSourceContext context) {
contextHolder.set(context);
}

public static DataSourceContext getContext() {
return (DataSourceContext) contextHolder.get();
}
}


public interface DataSourceContext {
public void setId(String id);
public String getId();
}


public class DataSourceContextImpl implements DataSourceContext {
private String id;

public void setId(String id) {
this.id=id;
}

public String getId() {
return id;
}
}


- Filter to detect context: the filter look for an datasource id in the session and put it in the context holder. The filter might be enhanced to have the feature to select the id and block this change when a user is authenticated on a database.

- Datasource selector: thanks to Spring, there is a datasource abstraction so we can put a proxy between our datasource and application. Our datasource proxy could select another datasource configure in Spring at runtime using the datasource context.
Here is an example of this proxy:


public class DataSourceSelector extends AbstractDataSource
implements BeanFactoryAware {
private BeanFactory beanFactory;

public void setBeanFactory(BeanFactory beanFactory)
throws BeansException {
this.beanFactory=beanFactory;
}

public Connection getConnection() throws SQLException {
DataSourceContext context=DataSourceContextHolder.getContext();
DataSource datasource=(DataSource)beanFactory.getBean(
context.getId());
return datasource.getConnection();
}

public Connection getConnection(String login,String password)
throws SQLException {
DataSourceContext context=DataSourceContextHolder.getContext();
DataSource datasource=(DataSource)beanFactory.getBean(
context.getId());
return datasource.getConnection(arg0,arg1);
}
}


This mechanism is independant of the application (Spring offers this
facility!) but we must be carefull to not permit to access a database
without be authenticated. The order of filter (with use of security filter such Acegi's) could be dangerous... The solution is not to permit to switch from
a datasource to another when a user is authenticated.

Monday, December 13, 2004

Spring and ORM

Spring integrates several ORM at this time:

  • Hibernate
    See the following link for more informations:
    Spring reference documentation
    Hibernate site

  • JDO
    See the following link for informations about Spring and JPox ( a free JDO implementation ):
    JPox 1.1 documentation
    See the following link for informations about Spring and KODO ( another JDO implementation ):
    Confluence

  • OJB
    Javadocs:
    Spring javadocs
    Examples: see the PetClinic sample application in the Spring distribution!
    Threads on the subject:
    Spring adds support for ojb
    Thread
    Announce of support added

  • TopLink
    See the following link for informations about Spring and TopLink:
    Spring / TopLink on Oracle site

    Spring offers now a perfect integration of tools for J2EE architecture to access datas of relationnal databases.
  • Sunday, December 12, 2004

    JCA and Spring

    At the moment, Spring doesn't offer support for JCA ( Java Connector Architecture ). A support of JCA can be helpful in order to hide the use of CCI ( Common Client Interface ) API, to integrate with the IoC container of Spring and to use the AOP framework. The aim is offer facilities to use it:

  • Configuration of ConnectionFactory in a managed ( get from JNDI ) and in a non-managed mode ( configure as a bean )

  • Conversion from Record to Object / Object to Record

  • Declarative of transaction configuration ( local and global transactions ) with interceptors

  • Use of CCI with template and objects


  • The idea is then to extend the framework to different EIS to integrate them easier in J2EE applications. For example, with CICS, communications are based on a COMMAREA ( table of bytes ), so it could provide classes to work on table of bytes instead of Record and a data mapper to transform object to COMMAREA / COMMAREA to object.

    Thursday, November 25, 2004

    Integrate JAMon with Spring

    JAMon is a tool to monitor performance of application components. It's
    very useful to determine bottlenecks on application and find the impacted component. It provides too statistics on calls ( between the start and the end of monitors ).

    This tool can be download at the following url:
    http://sourceforge.net/project/showfiles.php?group_id=96550
    and you can find its documentations on these sites:
    http://jamonapi.sourceforge.net/
    http://www.javaperformancetuning.com/tools/jamon/index.shtml

    To install it in your application, only JAMon.jar must be in your classpath.


    Spring already has an aop interceptor to measure performance of application components based on commons-logging. The idea is to provide a simple JAMon interceptor to start monitor before the call and end it after the call.

    It provides too facilities to name the JAMon monitor with class and method names.


    The method getMonitorName determines the monitor name:




    protected String getMonitorName(MethodInvocation invocation) {
    StringBuffer monitorName=new StringBuffer();
    monitorName.append(
    invocation.getMethod().getDeclaringClass().getName());
    monitorName.append(" ( ");
    monitorName.append(invocation.getMethod().getName());
    monitorName.append(" )");
    return monitorName.toString();
    }


    The Spring AOP interceptor is simple:



    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;

    import com.jamonapi.Monitor;
    import com.jamonapi.MonitorFactory;

    public class PerfIntercepteur implements MethodInterceptor {

    protected String getMonitorName(MethodInvocation invocation) {
    StringBuffer monitorName=new StringBuffer();
    monitorName.append(
    invocation.getMethod().getDeclaringClass().getName());
    monitorName.append(" ( ");
    monitorName.append(invocation.getMethod().getName());
    monitorName.append(" )");
    return monitorName.toString();
    }

    public Object invoke(MethodInvocation invocation) throws Throwable {
    Monitor mon=MonitorFactory.start(getMonitorName(invocation));
    Object rval=invocation.proceed();
    mon.stop();
    return rval;
    }
    }


    and you can configure it in this way:


    <!DOCTYPE beans PUBLIC
    "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>
    ...
    <bean id="perfInterceptor" class="aop.PerfIntercepteur"/>

    <bean id="autoProxyCreator" class="org.springframework.aop.framework.
    autoproxy.BeanNameAutoProxyCreator">
    <property name="interceptorNames">
    <list>
    <idref local="perfInterceptor" />
    </list>
    </property>
    <property name="beanNames">
    <list>
    <idref local="service" />
    </list>
    </property>
    </bean>
    </beans>


    The aim is to plug the JAMon interceptor on the component of the application layer to identifity the component that has performance problem ( from presentation layer to dao layer ).

    Wednesday, November 24, 2004

    Integrate P6Spy with Spring

    P6Spy is a tool to debug JDBC interaction with a database. It's a wrapper
    of all JDBC elements ( Connection, PreparedStatement, ResultSet... ) and
    it has a powerful feature in order to log all informations about those
    interactions.

    JDBC wrapper is described in the "Java Performance Tuning" book of Jack Shirazi ( O'Reilly) in the chapter 16.


    All elements wrappers have a constructor with the element to wrap. We can use it but
    there is another mode for datasource. This last mode must be used to wrap a datasource
    defined in an application server for example.

    However since we can manage our objects ( beans ) in Spring ( and datasources
    too ), it's possible to add a P6Spy datasource and link it with the real datasource
    with constructor injection.



    <?xml version="1.0" encoding="ISO-8859-1"?>

    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>
    <bean id="myDataSourceTarget"
    class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName">
    <value>org.hsqldb.jdbcDriver</value>
    </property>
    <property name="url">
    <value>jdbc:hsqldb:hsql://localhost:9001</value>
    </property>
    <property name="username"><value>sa</value></property>
    <property name="password"><value></value></property>
    </bean>

    <bean id="myDataSource" class="com.p6spy.engine.spy.P6DataSource"
    destroy-method="close">
    <constructor-arg>
    <ref local="myDataSourceTarget"/>
    </constructor-arg>
    </bean>

    </beans>



    Moreover a p6spy.log file must be add to the classpath of the application
    to specify the location of the log file.



    module.log=com.p6spy.engine.logging.P6LogFactory

    executionthreshold=
    outagedetection=false
    outagedetectioninterval=
    filter=false
    include =
    exclude =
    sqlexpression =
    autoflush = true
    dateformat=
    includecategories=
    excludecategories=info,debug,result,batch

    stringmatcher=
    stacktraceclass=

    reloadproperties=false
    reloadpropertiesinterval=60

    useprefix=false

    appender=com.p6spy.engine.logging.appender.FileLogger
    logfile = c:/spy.log

    append=true

    log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
    log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
    log4j.appender.STDOUT.layout.ConversionPattern=p6spy - %m%n

    log4j.logger.p6spy=INFO,STDOUT



    The output can be graphically view with a tool like Iron Track SQL.



    Advantages of this solution are the following:

  • It isn't necessary to modify the configuration of the application
    server datasource in order to integrate P6Spy.

  • The use of P6Spy is much easier. No deep knowledge of the format
    of the P6Spy configuration file is required ( only specify the location
    of log file ).
  •