- Grails
- Groovy
- OSGi
- Spring Batch
- Spring Security 2.0
- Spring Web Services
- AspectJ
- JBoss Seam
- RichFaces
- Mule
- JavaFX
- Selenium
Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts
Friday, February 22, 2008
12 Technologies I Would Like to Grasp in 2008
Wednesday, January 16, 2008
Gavin King: first impression (contrasting Spring guys)
Today I attended Red Hat's "Gavin King" event. While I have attended many Spring events in Sydney, this is my first time attending a Hibernate/JBoss/Red Hat event. And the impressions are quite different...
- First impression - clothes:
- The Spring guys are always well-suited and businessmen-like. They are often the centre of the crowd.
- Gavin's clothes were the most casual in the room. Before his presentation, I thought that fitted T-shirt wearing guy in trendy jeans was some skateboarding Ruby programmer who happened to want to know something in the Java world...
- Presentation style:
- The presentations by the Spring guys are always very professional, with the right level in technology details according to the nature of the event, the structure well organised, and seemingly well rehearsed.
- Gavin's presentation is, again, more casual, just like a technology chat. I don't know how much the other people in the audience know about Web Beans and Seam, but Gavin lost me a few times because I haven't been following what's happening in the JBoss world...
- Technology inclination:
- The Spring guys can be very pedantic (in a good way), always emphasising best practices, such as programming to interfaces, abstraction levels, separation of concerns, etc.
- Gavin is more pragmatic. Interfaces did not even make it to his slides. His Web Beans JSR recommends to make business interface optional for EJB 3.1 in Java EE 6. He reckons AOP is too complex for ordinary Java developers, there are only a handful of cross-cutting concerns, and EJB interceptors are enough to get the job done.
- Spring framework focuses on enterprise applications that are typically developed by financial institutions and usually involves lots of web services and enterprise application integration, and some of these enterprise applications may not even have a web tier.
- Web Beans JSR, JBoss Seam and Rich Faces, promoted by Gavin, are all mostly relevant to web-focused projects. Web Beans and JBoss Seam are particularly designed to ease development burden on entity management website with lots of CRUD operations, which make them competitors of (J)Ruby on Rails and Grails. I'll try to compare these frameworks in a later post. Enterprise applications seem off the target.
- The apparent weakness in the Spring framework are: no type-safety check in the application context until runtime, verbose XML configuration, no bean id (or name) namespaces and the statelessness of Spring-managed beans. However, the first two have been addressed by JavaConfig and XML namespace. Noticeably, JavaConfig also uses annotations, but only in the config class without polluting the service bean or the service client. The stateless singleton issue has also been tackled with 'scopes' and domain object dependency injection, which is enabled by Spring AOP.
- Gavin loves type-safety check in Java, so he hates the lack of type-safety check in Spring XML configuration, and he embraces annotation wholeheartedly. So he prefers Google Guice to Spring for dependency injection. In contrast to Spring's JavaConfig, Google Guice's annotations are used everywhere, in the service bean, in the service client or both. JBoss Seam introduces lots of annotations, and Web Beans JSR is to make many of these annotations into Java EE standard. I don't remember how many times Gavin showed the definition of an annotation in his slides today. Probably a dozen! And he still relies on XML configuration to override annotations. He classifies services beans according to deployment, such as one for production, one for stubbing in testing. So what will you do if you have two classes with the same service API, both used in production environment? My guess is you need to write a new annotation to differentiate them... Seems overuse of annotations, doesn't it?
- Hostility:
- Spring guys rarely publicly show their hostility towards JBoss, though in after session chats, they describe JBoss Seam as a "big hack", "annotation hell", "technologically inferior" and "would have been just another web framework were it not for Gavin King's fame".
- Gavin is more straight forward, rubbished Spring guys as "AOP nerds" during the session, and I wouldn't be surprised if he called Spring "XML hell". He deliberately omitted Spring when he enumerated the open source frameworks that have influenced Java EE.
- The audience:
- Spring events usually draw a huge audience. Many times, some people who came late had to stand in the back of the room for the whole session. They are almost always held in the evening.
- Today's Hibernate event was held in the morning with only a few dozen people attending. One-third of the seats were empty.
Anyway, I was pretty impressed by Gavin's demo of fast web project development with JBoss AS, JBoss Seam, Rich Faces and JBoss Tools. I'll definitely give it a try when I have the time...
Friday, November 2, 2007
classpath*:BeanRefFactory.xml not found when instantiating a singleton Spring application context inside EJB2.x running on Sun application server 8.2
For the project I'm currently working on, we use Spring's EJB support. In order to share application context among all EJB instances, SingletonBeanFactoryLocator is used to locate or load the shared application context. And we used the default "classpath*:beanRefFactory.xml" selector key.
However, when the EJB is deployed and invoked, a FatalBeanException is thrown stating
Looking into the implementation of SingletonBeanFactoryLocator, we found that it delegates to PathMatchingResourcePatternResolver to load the XML file. If the resource starts with "classpath*:" prefix, it uses ClassLoader's getResources(String) method to load the resource; otherwise, a ClasspathResource is returned, which eventually uses ClassLoader's getResource(String) method to load the resource. Pay attention to the plural form of the method name.
In the base java.lang.ClassLoader, both getResource(String) and getResources(String) delegate to its parent first. If the resource is not found by the parent, it invokes findResource(String) and findResources(String) methods, both of which simply return null. The Javadoc of ClassLoader recommends that, for both finder methods:
However, when tracing the execution in debug mode, we found that the EJBClassLoader used by Sun Application Server 8.2 only overrides findResource(String) method and searches for the resource in the expanded directory of the EJB Jar file; it does not override findResources(String), which remains returning null, against their own advice.
Now it's obvious, this is due to a defect in Sun Application Server 8.2. The simplest solution is to specify the selector key as "classpath:beanRefFactory.xml" instead of the default value.
However, when the EJB is deployed and invoked, a FatalBeanException is thrown stating
Unable to find resource for specified definition. Group resource name
[classpath*:beanRefFactory.xml], factory key [...]
Looking into the implementation of SingletonBeanFactoryLocator, we found that it delegates to PathMatchingResourcePatternResolver to load the XML file. If the resource starts with "classpath*:" prefix, it uses ClassLoader's getResources(String) method to load the resource; otherwise, a ClasspathResource is returned, which eventually uses ClassLoader's getResource(String) method to load the resource. Pay attention to the plural form of the method name.
In the base java.lang.ClassLoader, both getResource(String) and getResources(String) delegate to its parent first. If the resource is not found by the parent, it invokes findResource(String) and findResources(String) methods, both of which simply return null. The Javadoc of ClassLoader recommends that, for both finder methods:
Class loader implementations should override this method to specify where to
load resources from.
However, when tracing the execution in debug mode, we found that the EJBClassLoader used by Sun Application Server 8.2 only overrides findResource(String) method and searches for the resource in the expanded directory of the EJB Jar file; it does not override findResources(String), which remains returning null, against their own advice.
Now it's obvious, this is due to a defect in Sun Application Server 8.2. The simplest solution is to specify the selector key as "classpath:beanRefFactory.xml" instead of the default value.
Saturday, October 27, 2007
Integrating Spring, Hibernate and EJB 2.x
How to configure Hibernate Session Factory in a Spring application context used in an EJB 2.x stateless session bean?
Most of the examples found on the internet about Hibernate and Spring integration are targeted at web applications. How to configure Hibernate and Spring inside an EJB 2.x stateless session bean is rarely mentioned, and it is not as simple and straightforward as many assume.
The most important issue of the integration is around the management of JDBC connections:
In EJB 2.x, JDBC connections are managed by the data source registered with JNDI on the application server:
When database is accessed outside EJB 2.x, such as in a web application running in Tomcat, the application itself is responsible for transaction demarcation. When using a local database transaction, the application code must ensure that the same JDBC connection be used in all database access within the same transaction. Because database access occurs in multiple classes that collaborate to complete a transaction, it is very unwieldy for applications to pass around the JDBC connection in order to re-use the same JDBC connection.
Enter Spring and Hibernate.
Spring guarantees the same JDBC connection is reused, provided the same Spring-managed data source is re-used. The magic happens when a JDBC connection is retrieved for the first time from a Spring-managed data source, Spring binds the JDBC connection to the current execution thread. When another JDBC connection is requested within the same transaction from the Spring-managed data source, Spring returns the thread-bound JDBC connection. When the transaction ends, Spring invokes the commit() or rollback() method of the thread-bound JDBC connection and then unbinds it from the thread.
Hibernate 3.x employs similar technique. By default, a Hibernate session is bound to the thread and returned whenever SessionFactory.getCurrentSession() is invoked within the same transaction. The same JDBC connection is used for all JDBC operations initiated by the same Hibernate session. It is possible to specify other current session context class other than the default thread local context since Hibernate 3.1.
As can be seen from the above discussion, Spring and Hibernate by default re-use the same thread-bound JDBC connection. This setting does not go well with the aggressive connection release mode expected by EJB 2.x. Therefore, non-default settings must be configured for both Spring and Hibernate for Spring and Hibernate combination to be integrated within EJB 2.x.
Below is the recommended configuration. The reasons behind this configuration are explained following the configuration.
The reasons behind this configuration are explained below. It is recommended to have your IDE opened and source code of Spring and Hibernate 3.1 or above ready.
Spring uses LocalSessionFactoryBean, which is a subclass of AbstractSessionFactoryBean, to configure a Hibernate session factory.
There are lots of javadoc to read for each bean property that can be set for a LocalSessionFactoryBean. It's better off to read the buildSessionFactory() method to understand what each property value does in the build time.
Note that the above configuration has two parts for LocalSessionFactoryBean, the 'normal' Spring bean properties, such as 'dataSource', and the 'hibernateProperties' that takes a java.util.Properties value. The 'normal' properties are used to configure the default settings, which can be overriden by the 'hibernateProperties'.
As a side note, we don't set the 'jtaTransactionManager' property. Note that the class for this property is javax.transaction.TransactionManager, not the JtaTransactionManager that implements Spring's PlatformTransactionManager. In order to set this property, we need to know the JNDI name that the target application server binds its JTA transaction manager. The benefit of setting this property would be that we don't need to configure Hibernate's 'hibernate.transaction.manager_lookup_class' and 'hibernate.transaction.factory_class' properties. We concluded that this benefit could not justify explicitly specifying the application server specific JNDI name for transaction manager. We would rather set those two properties in Hibernate configuration.
If 'jtaTransactionManager' property is not set, Spring automatically set the 'hibernate.connection.release_mode' property to 'on_close'. Because we are running Hibernate inside an EJB 2.x, we must set this property to other value in the overriding 'hibernateProperties'.
The 'exposeTransactionAwareSessionFactory' property has a default value of true. If set to true, Spring will set the 'hibernate.current_session_context_class' property to Spring's own thread-bound implementation, which must be overriden by a value of 'jta' in the 'hibernateProperties'.
The 'useTransactionAwareDataSource' property must be left to the default 'false' value. Otherwise, Spring will wrap the data source with a TransactionAwareDataSourceProxy, which will effectively re-use the same JDBC transaction within the same transaction, even if Hibernate aggressively releases connections.
It must be pointed out that when 'useTransactionAwareDataSource' is set to false, Spring will supply LocalDataSourceConnectionProvider as the implementation of Hibernate's ConnectionProvider. LocalDataSourceConnectionProvider informs Hibernate that it does not support aggressive release of connection. However, in Hibernate's SettingsFactory, if the ConnectionProvider does not support aggressive release of connections and connection release mode is set to 'after_statement', the connection release mode will be automatically rectified to 'after_transaction', which effectively re-uses the same JDBC transaction for the whole transaction. A warning message "Overriding release mode as connection provider does not support 'after_statement'" is logged. Therefore, the connection release mode in the 'hibernateProperties' must be set to 'auto' instead of 'after_statement'. When the transaction factory is set to 'CMTTransactionFactory', the default connection release mode is 'after_statement', which is precisely what we want.
The other property settings are self-explanatory:
I hope this post will help anyone who has encountered mysterious connection problems when integrating Spring, Hibernate and EJB 2.x
Most of the examples found on the internet about Hibernate and Spring integration are targeted at web applications. How to configure Hibernate and Spring inside an EJB 2.x stateless session bean is rarely mentioned, and it is not as simple and straightforward as many assume.
The most important issue of the integration is around the management of JDBC connections:
In EJB 2.x, JDBC connections are managed by the data source registered with JNDI on the application server:
- Applications are not expected to hold on JDBC connections after each use, that is, applications should aggressively release JDBC connections, preferrably after each statement.
- Applications can acquire JDBC connections multiple times during the execution of one EJB invocation. The application server may return the same JDBC connection, or it may return different JDBC connections, but it assures that all JDBC connections returned are registered within the same Container Managed Transaction.
When database is accessed outside EJB 2.x, such as in a web application running in Tomcat, the application itself is responsible for transaction demarcation. When using a local database transaction, the application code must ensure that the same JDBC connection be used in all database access within the same transaction. Because database access occurs in multiple classes that collaborate to complete a transaction, it is very unwieldy for applications to pass around the JDBC connection in order to re-use the same JDBC connection.
Enter Spring and Hibernate.
Spring guarantees the same JDBC connection is reused, provided the same Spring-managed data source is re-used. The magic happens when a JDBC connection is retrieved for the first time from a Spring-managed data source, Spring binds the JDBC connection to the current execution thread. When another JDBC connection is requested within the same transaction from the Spring-managed data source, Spring returns the thread-bound JDBC connection. When the transaction ends, Spring invokes the commit() or rollback() method of the thread-bound JDBC connection and then unbinds it from the thread.
Hibernate 3.x employs similar technique. By default, a Hibernate session is bound to the thread and returned whenever SessionFactory.getCurrentSession() is invoked within the same transaction. The same JDBC connection is used for all JDBC operations initiated by the same Hibernate session. It is possible to specify other current session context class other than the default thread local context since Hibernate 3.1.
As can be seen from the above discussion, Spring and Hibernate by default re-use the same thread-bound JDBC connection. This setting does not go well with the aggressive connection release mode expected by EJB 2.x. Therefore, non-default settings must be configured for both Spring and Hibernate for Spring and Hibernate combination to be integrated within EJB 2.x.
Below is the recommended configuration. The reasons behind this configuration are explained following the configuration.
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/datasource" resource-ref="true"/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- default value is "false"
<property name="useTransactionAwareDataSource" value="false"/>
-->
<property name="exposeTransactionAwareSessionFactory" value="false"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SomeDialect</prop>
<!--
WARNING! 'hibernate.connection.release_mode' must not be set to
'after_statement'. Otherwise, it will be overriden with 'after_transaction'
by Hibernate because Spring's LocalConnectionProvider does not support
aggressive connection release.
-->
<prop key="hibernate.connection.release_mode">auto</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</prop>
<prop key="hibernate.transaction.flush_before_completion">true</prop>
<prop key="hibernate.transaction.auto_close_session">true</prop>
</props>
</property>
<property name="mappingResources">
<list>...</list>
</property>
</bean>
The reasons behind this configuration are explained below. It is recommended to have your IDE opened and source code of Spring and Hibernate 3.1 or above ready.
Spring uses LocalSessionFactoryBean, which is a subclass of AbstractSessionFactoryBean, to configure a Hibernate session factory.
There are lots of javadoc to read for each bean property that can be set for a LocalSessionFactoryBean. It's better off to read the buildSessionFactory() method to understand what each property value does in the build time.
Note that the above configuration has two parts for LocalSessionFactoryBean, the 'normal' Spring bean properties, such as 'dataSource', and the 'hibernateProperties' that takes a java.util.Properties value. The 'normal' properties are used to configure the default settings, which can be overriden by the 'hibernateProperties'.
As a side note, we don't set the 'jtaTransactionManager' property. Note that the class for this property is javax.transaction.TransactionManager, not the JtaTransactionManager that implements Spring's PlatformTransactionManager. In order to set this property, we need to know the JNDI name that the target application server binds its JTA transaction manager. The benefit of setting this property would be that we don't need to configure Hibernate's 'hibernate.transaction.manager_lookup_class' and 'hibernate.transaction.factory_class' properties. We concluded that this benefit could not justify explicitly specifying the application server specific JNDI name for transaction manager. We would rather set those two properties in Hibernate configuration.
If 'jtaTransactionManager' property is not set, Spring automatically set the 'hibernate.connection.release_mode' property to 'on_close'. Because we are running Hibernate inside an EJB 2.x, we must set this property to other value in the overriding 'hibernateProperties'.
The 'exposeTransactionAwareSessionFactory' property has a default value of true. If set to true, Spring will set the 'hibernate.current_session_context_class' property to Spring's own thread-bound implementation, which must be overriden by a value of 'jta' in the 'hibernateProperties'.
The 'useTransactionAwareDataSource' property must be left to the default 'false' value. Otherwise, Spring will wrap the data source with a TransactionAwareDataSourceProxy, which will effectively re-use the same JDBC transaction within the same transaction, even if Hibernate aggressively releases connections.
It must be pointed out that when 'useTransactionAwareDataSource' is set to false, Spring will supply LocalDataSourceConnectionProvider as the implementation of Hibernate's ConnectionProvider. LocalDataSourceConnectionProvider informs Hibernate that it does not support aggressive release of connection. However, in Hibernate's SettingsFactory, if the ConnectionProvider does not support aggressive release of connections and connection release mode is set to 'after_statement', the connection release mode will be automatically rectified to 'after_transaction', which effectively re-uses the same JDBC transaction for the whole transaction. A warning message "Overriding release mode as connection provider does not support 'after_statement'" is logged. Therefore, the connection release mode in the 'hibernateProperties' must be set to 'auto' instead of 'after_statement'. When the transaction factory is set to 'CMTTransactionFactory', the default connection release mode is 'after_statement', which is precisely what we want.
The other property settings are self-explanatory:
- 'hibernate.current_session_context_class' should be set to 'jta'.
- 'hibernate.transaction.manager_lookup_class' should be set the a class mapped to the target application server.
- 'hibernate.transaction.factory_class' should be set to 'org.hibernate.transaction.CMTTransactionFactory'.
I hope this post will help anyone who has encountered mysterious connection problems when integrating Spring, Hibernate and EJB 2.x
Friday, September 28, 2007
Spring 2.0 schemas not found? And the solution is...
We've experienced a mysterious problem that the Spring 2.0 schemas could not be found when the application context is being created inside an EJB 2.1, using Spring's AbstractStatelessSessionBean.
The problem manifests itself with the following exception:
Normally this is caused by the incorrect XML namespace or schema location declaration at the head of the application context. However, in our case, the declaration was correct:
After some research, we found that other people have also experienced this problem.
The cause is that somehow the "META-INF/spring.schemas" and "META-INF/spring.handlers" files packaged in spring.jar could not be found.
What are these two files?
One raised the topic in Spring's support forum that it was because of no internet access for the application server to access the schemas over the internet. Another post even provided a solution to reference the schemas using classpath prefix directly in the application context configuration files.
However, that's not the root cause and a good solution, because even if the application server can access the schemas over the internet or via classpath prefix, the bootstrap code still cannot access the "spring.handlers" file and would not know how to handle various namespaces other than the default "beans".
In fact, the root cause is that the META-INF directory of a can be blocked when referenced inside an EJB jar.
I tried a few ways to get around this problem, and the final solution I adopted is to extract these two files and put them in the META-INF directory of a JAR file that contains only this directory, and place this JAR file in the lib/ext directory of the application server domain where the application is deployed.
I hope this would help others who may face this problem.
The problem manifests itself with the following exception:
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from class path resource [springContext.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.
Caused by:
org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
Normally this is caused by the incorrect XML namespace or schema location declaration at the head of the application context. However, in our case, the declaration was correct:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
...
</bean>
After some research, we found that other people have also experienced this problem.
The cause is that somehow the "META-INF/spring.schemas" and "META-INF/spring.handlers" files packaged in spring.jar could not be found.
What are these two files?
- "spring.schemas" specifies the classpaths of all Spring schemas within the spring.jar. The content of this file is listed below:
http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd
http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd
http\://www.springframework.org/schema/tx/spring-tx-2.0.xsd=org/springframework/transaction/config/spring-tx-2.0.xsd
http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-2.0.xsd
http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd
http\://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-2.0.xsd
http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd
- "spring.handlers" specifies the handler class that implements the NamespaceHandler interface for each namespace. The content of this file is listed below:
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
One raised the topic in Spring's support forum that it was because of no internet access for the application server to access the schemas over the internet. Another post even provided a solution to reference the schemas using classpath prefix directly in the application context configuration files.
However, that's not the root cause and a good solution, because even if the application server can access the schemas over the internet or via classpath prefix, the bootstrap code still cannot access the "spring.handlers" file and would not know how to handle various namespaces other than the default "beans".
In fact, the root cause is that the META-INF directory of a can be blocked when referenced inside an EJB jar.
I tried a few ways to get around this problem, and the final solution I adopted is to extract these two files and put them in the META-INF directory of a JAR file that contains only this directory, and place this JAR file in the lib/ext directory of the application server domain where the application is deployed.
I hope this would help others who may face this problem.
Sunday, July 29, 2007
Springify a "Singleton"-infested application
The singleton pattern has been avidly avoided by most developers since the introduction of Spring, which solved the problem in an elegant way.
However, there have been many applications that were developed before and were infested with the "evil" singleton pattern. Quite often, these singletons are not really singletons; the singleton pattern was just misapplied to a problem that may be more suitable to use Registry to solve.
Every now and then, developers are asked to add Spring to such applications with minimal code changes and refactoring because these applications typically do not have any automated unit tests or do not have a good enough test coverage.
Adding Spring to such applications is rather simple if there is no dependency between the existing codes and the Spring-managed beans.
If Spring-managed beans have a dependency on a "singleton" that is not managed by Spring. We can define the "singleton" as a Spring-managed bean using a "factory-method", such as "getInstance()", to retrieve the "singleton" instance and inject it into other beans.
Things get more complex when you want to use Spring to configure these "singletons".
For example, one of the application that I need to springify used a "singleton" to look up data source from JNDI. In order to add tests that can be run out of container, we need to inject a Spring-configured data source, whether it is registered with JNDI or not, to that "singleton" instance, instead of letting the "singleton" to look up JNDI.
What we did was that we added a new static factory method "createInstance(DataSource)" accepting a pre-configured data source and returning the singleton instance. Then we configure Spring to invoke this new factory method to create a bean, which is stored in the original static variable and returned to caller of the static "getInstance()" method.
I have read on the internet that some call this a "Singleton with a back door" pattern. To me, it is pretty clear that the singleton pattern is misused here. What the original developer really needed was a "Registry" pattern that allows other objects to "find common objects and services" using "a well-known object". Spring creates and configures the common object or service, which is registered so that other objects in the same application can locate it.
In fact, Spring itself uses "Registry" pattern in many places. Some of the significant places include transaction management and JDBC connection management. Spring uses a thread-local scoped registry to hold JDBC connection so that all JDBC operations within the same transaction use the same JDBC connection...
One thing to note when using Spring to configure such "singletons" is that there are typically many implicit dependencies between these "singletons". If Spring instantiates these "singletons" in a wrong order, the application cannot run properly, usually with failure in constructing application context. The solution to this is to use the "depends-on" attribute in bean definition to explicitly specify the dependencies between these "singletons".
However, there have been many applications that were developed before and were infested with the "evil" singleton pattern. Quite often, these singletons are not really singletons; the singleton pattern was just misapplied to a problem that may be more suitable to use Registry to solve.
Every now and then, developers are asked to add Spring to such applications with minimal code changes and refactoring because these applications typically do not have any automated unit tests or do not have a good enough test coverage.
Adding Spring to such applications is rather simple if there is no dependency between the existing codes and the Spring-managed beans.
If Spring-managed beans have a dependency on a "singleton" that is not managed by Spring. We can define the "singleton" as a Spring-managed bean using a "factory-method", such as "getInstance()", to retrieve the "singleton" instance and inject it into other beans.
Things get more complex when you want to use Spring to configure these "singletons".
For example, one of the application that I need to springify used a "singleton" to look up data source from JNDI. In order to add tests that can be run out of container, we need to inject a Spring-configured data source, whether it is registered with JNDI or not, to that "singleton" instance, instead of letting the "singleton" to look up JNDI.
What we did was that we added a new static factory method "createInstance(DataSource)" accepting a pre-configured data source and returning the singleton instance. Then we configure Spring to invoke this new factory method to create a bean, which is stored in the original static variable and returned to caller of the static "getInstance()" method.
I have read on the internet that some call this a "Singleton with a back door" pattern. To me, it is pretty clear that the singleton pattern is misused here. What the original developer really needed was a "Registry" pattern that allows other objects to "find common objects and services" using "a well-known object". Spring creates and configures the common object or service, which is registered so that other objects in the same application can locate it.
In fact, Spring itself uses "Registry" pattern in many places. Some of the significant places include transaction management and JDBC connection management. Spring uses a thread-local scoped registry to hold JDBC connection so that all JDBC operations within the same transaction use the same JDBC connection...
One thing to note when using Spring to configure such "singletons" is that there are typically many implicit dependencies between these "singletons". If Spring instantiates these "singletons" in a wrong order, the application cannot run properly, usually with failure in constructing application context. The solution to this is to use the "depends-on" attribute in bean definition to explicitly specify the dependencies between these "singletons".
Friday, June 29, 2007
Workflow engine integration, where does it go?
In one of the projects I have worked on, OSWorkflow is used to manage workflows. It is integrated to the service layer instead of to the domain objects.
The design feels unnatural somehow:
IMHO, this design smells.
The change of state in a domain object should be managed by the domain itself. Any application requirements, such as sending email notifications, can be implemented as state change event listeners.
If the workflow logic gets too complicated, workflow engines like OSWorkflow come to rescue. But even if the workflow logic is delegated or outsourced to a workflow engine, it is still domain logic; thus, the workflow engine should be integrated directly into the domain objects instead of to the service layer.
In order for domain objects to work with a workflow engine, domain objects need to have a reference to the workflow engine, which used to be an issue.
With domain object dependency injection feature introduced in Spring 2, this problem is solved. Even if you are using Spring 1.2 or other IoC Containers that do not support domain object dependency injection, or if you are not using an IoC container at all, you can still use Registry pattern where a domain object can look up a dependency.
In conclusion, state change is part of the domain logic, and even if it is outsourced to a workflow engine, the workflow engine integration should still happen in the domain object, without leaking the implementation details to other layers. And technically, there is no more barrier that prevents injecting the workflow engine into domain objects.
The design feels unnatural somehow:
- The workflow id is stored in the domain object, passed as a parameter in constructor. However, it is not used by the domain object itself. The domain class provides a getter method so that the service layer can retrieve the workflow id and load the workflow instance from OSWorkflow.
- After loading the domain object and then the workflow instance, the service layer needs to pass to the workflow engine some properties from the domain object and some properties from the DTO that carries the input of the user for the current request, so that the workflow engine can work out what is the next status for the domain object.
- The domain class also expose a method to allow arbitrary update of the 'status' field so that the service layer can update the domain object with the status that is come up with by the workflow engine. The domain model loses encapsulation.
- The service layer becomes thick while the domain model becomes anaemic...
IMHO, this design smells.
The change of state in a domain object should be managed by the domain itself. Any application requirements, such as sending email notifications, can be implemented as state change event listeners.
If the workflow logic gets too complicated, workflow engines like OSWorkflow come to rescue. But even if the workflow logic is delegated or outsourced to a workflow engine, it is still domain logic; thus, the workflow engine should be integrated directly into the domain objects instead of to the service layer.
In order for domain objects to work with a workflow engine, domain objects need to have a reference to the workflow engine, which used to be an issue.
With domain object dependency injection feature introduced in Spring 2, this problem is solved. Even if you are using Spring 1.2 or other IoC Containers that do not support domain object dependency injection, or if you are not using an IoC container at all, you can still use Registry pattern where a domain object can look up a dependency.
In conclusion, state change is part of the domain logic, and even if it is outsourced to a workflow engine, the workflow engine integration should still happen in the domain object, without leaking the implementation details to other layers. And technically, there is no more barrier that prevents injecting the workflow engine into domain objects.
Subscribe to:
Posts (Atom)
