You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
| Online: | 7 Members of 4087 |
| Forum: Seam Users |
03. Apr 2008, 18:33 CET | Link |
Hello,
I try to integrate Seam into my Spring 2.5 based project.
I am using the latest JBosss but due to some time issues I do not want to reprogram my DAOs to some session beans, so the database access should be covered still by my DAOs.
As persistence provider I chose Hibernate 3.2. After programming some pages with jsf and seam components I ran into the problem of getting LazyInitializationExceptions. I figured out that the problem is caused by spring. I tried to make an entity available during a long running conversation. After retrieving it from the database and rendering the first page the instance is detached, because the spring transaction finished, which is normal. Now I get the exception when I request the next page which refers to a lazy-loaded set of my object from the conversation scope. I thought ok, let's see what seam is offering me as a solution and found the magic seam managed persistence context! And now I am totally frustrated getting this into my application... ;)
Ok, maybe my current, not working configuration says more:
components.xml:
<core:manager conversation-timeout="120000"
concurrent-request-timeout="500"
conversation-id-parameter="cid"/>
<persistence:managed-persistence-context name="entityManager"
auto-create="true"
entity-manager-factory="#{entityManagerFactory}" />
<!-- Configuration of Hibernate Session -->
<persistence:hibernate-session-factory></persistence:hibernate-session-factory>
<persistence:managed-hibernate-session name="hibernateSession" auto-create="true" />
<core:init debug="true"/>
<spring:context-loader config-locations="/WEB-INF/applicationContext.xml"/>
<!-- Install the SpringDispatcher as default -->
<spring:task-executor-dispatcher schedule-dispatcher="#{threadPoolDispatcher}" task-executor="#{springThreadPoolTaskExecutor}"/>
<spring:spring-transaction platform-transaction-manager="#{transactionManager}"/>
</components>
application-context.xml
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>${dataSource.driverClassName}</value></property>
<property name="url"><value>${dataSource.url}</value></property>
<property name="username"><value>${dataSource.username}</value></property>
<property name="password"><value>${dataSource.password}</value></property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="myDb"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<tx:annotation-driven proxy-target-class="true" />
<!-- EMF that wraps a Seam Managed EM instance for use in Spring -->
<bean id="seamEntityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean">
<!-- The Seam managed-persistence-context component name. -->
<property name="persistenceContextName" value="entityManager" />
<!-- Optionally provide a unit name. If not specified the default would be the persistenceContextName -->
<property name="persistenceUnitName" value="myDb"/>
</bean>
<bean id="sessionFactory" class="org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean">
<property name="sessionName" value="hibernateSession"/>
</bean>
hibernate.cfg.xml
<hibernate-configuration> <session-factory name="java:/hibernateSessionFactory"> <property name="dataSource">java:/PofProjectDbDS</property> <property name="hibernate.dialect"> org.hibernate.dialect.SQLServerDialect </property> <property name="transaction.flush_before_completion"> true </property> <property name="connection.release_mode"> after_statement </property> <property name="transaction.manager_lookup_class"> org.hibernate.transaction.JBossTransactionManagerLookup </property> <property name="transaction.factory_class"> org.hibernate.transaction.JTATransactionFactory </property> <mapping package="com.project.model" /> <mapping class="com.project.model.Person" />
well, I tried everything to make it work, so some options are doubled now... persistence.xml
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="myDb" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MyProjectDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="transaction.flush_before_completion" value="true" />
<property name="connection.release_mode" value="after_statement" />
<property name="transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
<property name="transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
</properties>
</persistence-unit>
My application starts normally, everything seems to be mapped correctly, but when I send the first request to the application I get the following exception:
Caused by: java.lang.IllegalAccessException: Class org.jboss.seam.util.Reflections can not access a member of class org.springframework.beans.factory.config.AbstractFactoryBean with modifiers "protected" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65) at java.lang.reflect.Method.invoke(Method.java:588) at org.jboss.seam.util.Reflections.invoke(Reflections.java:21) at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31) at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56) at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31) at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42) at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:106) at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:155) at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:91) at org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean_$$_javassist_0.getEarlySingletonInterfaces(SeamManagedSessionFactoryBean_$$_javassist_0.java) at org.springframework.beans.factory.config.AbstractFactoryBean.getEarlySingletonInstance(AbstractFactoryBean.java:145) at org.springframework.beans.factory.config.AbstractFactoryBean.getObject(AbstractFactoryBean.java:133) at org.springframework.beans.factory.support.AbstractBeanFactory$3.run(AbstractBeanFactory.java:1304) ... 201 more
When I try to solve that problem by making my sessionFactory a seam component I get another exception:
java.lang.IllegalStateException: Seam application context not available and cannot be started. Seam Managed Persistence Context not available. Try placing the spring bean call inside of a spring transaction or try making the spring bean a Seam Component using <seam:component/>. at org.jboss.seam.ioc.spring.SeamLifecycleUtils.beginTransactionalSeamCall(SeamLifecycleUtils.java:44) at org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean$SeamManagedSessionFactoryHandler.getSession(SeamManagedSessionFactoryBean.java:129) at org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean$SeamManagedSessionFactoryHandler.getRawSessionFactory(SeamManagedSessionFactoryBean.java:122) at org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean$SeamManagedSessionFactoryHandler.invoke(SeamManagedSessionFactoryBean.java:145)
<bean id="sessionFactory" class="org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean"> <property name="sessionName" value="hibernateSession"/> <seam:component /> </bean>
Does anybody have some help? Thanks in advance...
A couple of comments.
1. You've got a confusing mixture of both Hibernate and JPA. Is there a reason why you have both? I'd recommend getting rid of one of the other. They are 2 separate things try to use only one or the other.
2. Delete the persistenceUnitName from your seamEntityManagerFactory. Having 2 EMFs with the same UnitName might be confusing to Spring.
3. Make sure you use a TX manager that matches the persistence you're using use the HibernateTransactionManager if using Hibernate or JPATransactionManager is using JPA and set the entityManagerFactory to seamEntityManagerFactory.
4. Reread the documentation on Spring persistence and transaction integration and make sure you understand what is going on there. There are a few levels of indirection going on so try to make a good effort to understand what this integration is doing.
5. Don't make any of these things seam:components. That error you got is probably more because your transaction managers were mixed up.
Mike
Ok, thanks for the advice.
1. I removed the mixture and migrated the HibernateDAOs to JpaDAOs, so I just use JPA.
2. Now it looks more like the example in the docs.
All my DAOs get the emf injected like this:
3. I removed the Spring TX manager.
...well after reading and trying out a bit more, I came to another blocking point: I make a request to a page, the Spring controller calls a method of a DAO and gets an object which is already detached from the session when the DAO method finishes. Now I supposed seam to have some feature for me to keep this object attached until the end of the rendering of the page.
I'm not sure whether this is a Seam or Spring issue. Should I try to use some of Springs TX features or did I miss something in my Seam configuration that would solve my problem?
I read the documentation now a third time and have some additional questions:
From chapter 23 of the seam docs
This implies to me I could get rid of the LIE if I just give a scope (seam.CONVERSATION ?) to all my DAOs and controllers or am I wrong?
I'm not quite sure what you mean by getting but my project is making use of a Spring DAO layer that uses a Seam-managed Session factory. In this set up, only the action/controller class should need to be Conversation-scoped if you want long running conversations. For example:
Seam Component: CustomerRegistrationAction : Scope.Conversation
Spring Bean: CustomerDAO : uses Autowired SessionFactory
In our design, we don't add any Seam specific configuration, other than the Seam-managed Session factory, to the Spring beans.
Ryan-
Ryan J. McDonough
http://damnhandy.com
Hi, I'm curious to know if you used Spring DAOs with Seam in long running conversations finally?
just try <spring:spring-transaction platform-transaction-manager-name="transactionManager" join-transaction="true"/> and remove <!-- EMF that wraps a Seam Managed EM instance for use in Spring --> <bean id="seamEntityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean"> <!-- The Seam managed-persistence-context component name. --> <property name="persistenceContextName" value="entityManager" /> <!-- Optionally provide a unit name. If not specified the default would be the persistenceContextName --> <property name="persistenceUnitName" value="myDb"/> </bean> <bean id="sessionFactory" class="org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean"> <property name="sessionName" value="hibernateSession"/> </bean> In you seam compenent inject spring Dao like this @In("#{springdao}") private SpringDao yws;and you'd better use JTA
transaction-type="JTA"
config your JTA transactionManager