SPRING, JPA(EclipseLink) with JTA Transaction Manager(JBoss 7) - NOT Committing to Database - spring

I have created an example - SPRING, JPA(EclipseLink persistence provider) with JTA Transaction Manager(JBoss 7). I have observed that all the data in database is being shown in UI properly for the read operations. But when it comes to save/update or delete operation the services layer is not committing the work to database. No exception is caught(I have checked the console/log too and also debugged the code where I can see entityManager.persist/remove is being invoked without any exception).
--Code Listing--
1. Datasource configuration in standalone.xml
<datasource jta="true" jndi-name="java:/mysql_customerdb3" pool-name="mysql_customerdb3_pool" enabled="true" use-java-context="true" use-ccm="true">
<connection-url>jdbc:mysql://localhost:3306/customerdb</connection-url>
<driver>mysql</driver>
<security>
<user-name>root</user-name>
<password>root</password>
</security>
<statement>
<prepared-statement-cache-size>10</prepared-statement-cache-size>
<share-prepared-statements>true</share-prepared-statements>
</statement>
</datasource>
<drivers>
<driver name="mysql" module="com.mysql">
<driver-class>com.mysql.jdbc.Driver</driver-class>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
</driver>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
Database driver configuration in module.xml
persistence.xml
org.eclipse.persistence.jpa.PersistenceProvider
java:/mysql_customerdb3
com.springforbeginners.model.Customer
customerdispatcher-servlet.xml
<context:annotation-config />
<context:component-scan base-package="com.springforbeginners" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="loadTimeWeaver" ref="loadTimeWeaver" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
</bean>
<bean id="loadTimeWeaver" class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" >
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:jboss/TransactionManager"/>
<property name="userTransactionName" value="java:jboss/UserTransaction"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
CustomerServiceImpl.java
package com.springforbeginners.service;
import com.springforbeginners.dao.CustomerDAO;
import com.springforbeginners.model.Customer;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDAO customerDAO;
#Transactional
#Override
public void addCustomer(Customer customer) {
customerDAO.addCustomer(customer);
}
#Transactional
#Override
public List<Customer> listCustomer() {
return customerDAO.listCustomer();
}
#Transactional
#Override
public void removeCustomer(Integer customerId) {
customerDAO.removeCustomer(customerId);
}
}
CustomerDAOImpl.java
package com.springforbeginners.dao;
import com.springforbeginners.model.Customer;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
#Repository
public class CustomerDAOImpl implements CustomerDAO {
#PersistenceContext(unitName="CustomerDetailsPU3")
private EntityManager entityManager;
#Override
public void addCustomer(Customer customer) {
entityManager.persist(customer);
}
#Override
public List<Customer> listCustomer() {
return entityManager.createQuery("select c from Customer c", Customer.class).getResultList();
}
#Override
public void removeCustomer(Integer customerId) {
Customer customer = (Customer) entityManager.getReference(Customer.class, customerId);
if (null != customer) {
entityManager.remove(customer);
}
}
}
I do not know what and where exactly is something missing. But with the above code the read operations are working as expected. Problem is with save operations. I have converted the above example to use non-JTA datasource(also modified standalone.xml for jta=false) and to use JpaTransactionManager as below
With non-JTA datasource and 'org.springframework.orm.jpa.JpaTransactionManager' all operations(read as well as save/update/delete) are working fine.
But the JTA version of my example is not working as expected(save operations not committing work to database). Any help/pointers appreciated.
Thanks
Prakash
James,
I will be running this application on JBoss. But one datasource on JBoss and other on Glassfish and transaction should span save operation on both datasources simultaneously. This is what I am trying to achieve. I have a web application including spring for service(data) layer currently running on JBoss.
As you said earlier - I will have two persistence.xmls one for JBoss and one for Glassfish. As I am doing this first time I was/am in doubt whether the transaction(that spans two datasources on different servers-in this case JBoss and Glassfish), can this be executed entirely by JBoss(in case if the entire business logic resides in serviceImpl class deployed on JBoss)? In this case I will be using JBoss transaction manager( property name="transactionManagerName" value="java:jboss/TransactionManager" ). Is this sufficient or do I need to similarly have Glassfish transaction manager too? Sorry if this has created the confusion.
Another question from me was that is there a provision for speifying jndi ports in persistence.xml/anywhere else?(Definitely I will have two different persistence.xmls and I will mention the target server as JBoss in one and as Glassfish in another).
Do we have a technique in spring by which business logic can be distributed across different servers like JBoss/Glassfish and still under one single transatcion? I did not know if this can be an option. Were u talking about this scenario in which it will require two different deployment scripts one for each server?
Thanks
Prakash

What is your persistence.xml?
Since you are using JTA, you must define the "eclipselink.target-server"="JBoss"

My persistence.xml(modified) now looks like below. Added target server property in persistence.xml. This solved the problem.
<persistence-unit name="CustomerDetailsPU3" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:/mysql_customerdb3</jta-data-source>
<class>com.springforbeginners.model.Customer</class>
<properties>
<property name="eclipselink.target-server" value="JBoss" />
</properties>
</persistence-unit>
Thanks
Prakash

Related

LazyInitializationException and #Transactional not working

I'm using Spring 3.2.9 with multilayered architecture design broken down to 3 modules web, service, repository. In repository i defined a generic DAO class which i inherit by other entity specific DAO classes.
The problem is that when i try to lazy fetch collection of my entity from service layer, I always get LazyInitializationException. I have tried putting #Transactional on my service class, but It appears to not work. I can only avoid exception if I initialize all lazy collections right away in the DAO class method (and only if i annotate DAO class with #Transactional), but I want to fetch those collections only when they are needed in bussiness logic, and not all in advance.
Strange thing is that #Transactional works only in DAO layer, but not in Service layer, where it should be used. I found a couple of ways to work around this issue, but I am interested to really underestend and solve this issue, and not only make make code work.
repository MODULE:
#Repository
public abstract class GenericDao<T> {
protected Class<T> entityClass;
#PersistenceContext
protected EntityManager entityManager;
.........
public T findById(long id) {
T entity = entityManager.find(entityClass, id);
if (entity == null) {
throw new EntityNotFoundException(entityClass.getSimpleName(), id);
}
return entity;
}
}
My service class in service MODULE:
#Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
#SuppressWarnings("SpringJavaAutowiringInspection")
#Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
#Transactional(readOnly = true)
#Override
public UserDto getUserById(long id) {
User user = userDao.findById(id);
return new UserDto(user);
}
The DTO constructor tries to access user.getTeams() and then exception occurs. Instead of that, collection should be fetched with additional query to DB.
CONFIGURATION:
repository configuration:
......some other configurations like datasource...
<!--EntityManagerFactory-->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.dialect" value="${hibernate_dialect}"/>
<entry key="hibernate.hbm2ddl.auto" value="${hibernate_Hbm2ddlAuto}"/>
<entry key="hibernate.show_sql" value="${hibernate_showSql}"/>
<entry key="hibernate.format_sql" value="${hibernate_formatSql}"/>
</map>
</property>
</bean>
persistence.xml:
<persistence-unit name="persistenceUnit">
...other classes..
<class>com.example.entity.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
service configuration:
<import resource="classpath*:META-INF/repositoryApplicationContext.xml"/>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
It looks like #OneToMany association between the user and his or her teams which is lazy loaded. When you assign them to Dto it is still proxy not real collection. Put a break point there and see it in debug mode. Keep in mind any request (get a team or its size make it alive). One way is to fetch them in query, but
entityManager.find(entityClass, id)
doesn't have option for it. You may use
Hibernate.initialize(user.getTeams())
Found the answer after few days of headache.
I had to move:
<import resource="classpath*:META-INF/repositoryApplicationContext.xml"/>
<tx:annotation-driven/>
from repositoryConfiguration.xml to dispatcher-servlet.xml since that is the parent Spring context.
Thanks for the help.

Spring + TestNG integration tests, injecting DAO with annotations fails

I first did not mention what was the key component of this issue: I am using TestNG here.
I have a DAO layer performing persistence. It works fine as part of my little web app (I have a classic Controller, Service, DAO layers design). I can update this question with my XMLs if required.
My Service layer
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Override
public GoodVibeUserDetails getUser(String username) throws UsernameNotFoundException {
GoodVibeUserDetails user = userDao.getDetailsRolesAndImagesForUser(username);
return user;
}
// more methods...
}
My DAO layer
#Repository
public class UserDaoImplHibernate implements UserDao {
#Autowired
private SessionFactory sessionFactory;
// My methods using sessionFactory & "talking" to the Db via the sessionFactory
}
And here is my Test Class
#Component
public class UserDaoImplHibernateTests{
#Autowired
private UserDao userDao;
private GoodVibeUserDetails user;
#BeforeMethod
public void beforeEachMethod() throws ParseException{
user = new GoodVibeUserDetails();
user.setUsername("adrien");
user.setActive(true);
// & so on...
}
/*
* When everything is fine - test cases
*/
#Test
public void shouldAcceptRegistrationAndReturnUserWithId() throws Exception{
assertNotNull(userDao) ;
user = userDao.registerUser(user);
assertNotNull(user.getId()) ;
}
// more test cases...
}
But for my test class the Autowiring, userDao always returns Null, I'm only starting to do tests in Spring and I'm a bit lost. Any pointers are welcome.
Latest edit after Boris Treukhov's answer
import ...
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.junit.Assert.assertNotNull;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/applicationContext.xml")
public class UserDaoImplHibernateTests{
#Autowired
#Qualifier("userDao")
private UserDao userDao;
private GoodVibeUserDetails user;
#BeforeMethod
public void beforeEachMethod() throws ParseException{
user = new GoodVibeUserDetails();
user.setUsername("adrien");
user.setActive(true);
// & so on...
}
/*
* When everything is fine - test cases
*/
#Test
public void shouldAcceptRegistrationAndReturnUserWithId() throws Exception{
assertNotNull(userDao) ;
user = userDao.registerUser(user);
assertNotNull(user.getId()) ;
}
// more test methods...
}
And this is my applicationContext.xml
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" >
<!-- the application context definition scans within the base package of the application -->
<!-- for #Components, #Controller, #Service, #Configuration, etc. -->
<context:annotation-config />
<context:component-scan base-package="com.goodvibes" />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.databaseurl}"
p:username="${jdbc.username}" p:password="${jdbc.password}" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">${jdbc.show_sql}</prop>
<prop key="hibernate.connection.SetBigStringTryClob">true</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
[...]
</beans>
I did not add a repository-config.xml as this should be enough to access userDao. I still get userDao equal null though.
Thanks in advance
If you create unit tests, Spring IoC functionality is unavailable(as it was intended by the framework designers), because you are testing your objects in isolation(i.e. you are mocking only minimal set of interfaces which are required for the test to complete). In this case you should inject your mock repository manually, for example in #Before test initialization method. The whole idea is that your classes only depend on interfaces, so basically Spring container evaluates which class to use as the interface implementation, but when you create a unit test you need to have a strict control of which interface methods were called(and have a minimal set of dependencies), that is why you perform the injection manually.
If you are doing integration testing, you should have a Spring IoC container instance up and running, for this to work you should use jUnit(assuming that you are using jUnit) specific test runner, as it described in the Spring documentation on testing.
So, returning to the question, you have what looks like a simple unit test to jUnit, and the Spring container is not used. So, if you are going to use Spring TestContext framework, you should have something like
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/path-to-app-config.xml", "/your-test-specific-config.xml"})
public class UserDaoImplHibernateTests
instead of #Component.
update in TestNg case I think it should be (I used Spring Dependency Injection with TestNG as the reference)
#ContextConfiguration(locations={"/path-to-app-config.xml", "/your-test-specific-config.xml"})
public class UserDaoImplHibernateTests extends AbstractTestNGSpringContextTests
See also: What is the difference between integration and unit tests?

JSF ManagedBean - injected properties not working correctly on STATE_SAVING_METHOD=client

I am into a problem from two days and I can not get out from this.
The problem I am having is using a MangedBean property after the deserialization (I guess).
The property (purchaseManager) is set up with Spring, and use a DAO which extends MyBatis as data mapper to interact with the DB.
In fact, on the first access to the page, purchaseManager.getAll() inside init() method works fine.
When i try to call refreshList() as an action from a button, I have a NullPointerException on the getSqlSession() inside the DAO.
Letting only the relevant code the situation is as follow:
#ManagedBean(name = "purchaseController")
#ViewScoped
public class PurchaseController implements Serializable{
#ManagedProperty(value = "#{purchaseManager}")
private PurchaseManager purchaseManager;
#PostConstruct
public void init(){
purchaseManager.getAll();
}
public void refreshList(){
purchaseManager.getAll();
}
}
public class PurchaseManagerImpl implements PurchaseManager, Serializable {
PurchaseDAO purchaseDAO;
public void getAll() {
purchaseDAO.getAll()
}
}
public class PurchaseDAOImpl extends SqlSessionDaoSupport implements PurchaseDAO, Serializable {
public void getAll() {
SqlSession session = getSqlSession(); // when the call comes from refreshList(), session is null
session.selectList("PAYMENT.getAll", null);
}
}
in web.xml
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
If I change the STATE_SAVING_METHOD to server the application works fine but is not what I want. Same thing if I make the ManageBean as RequestScope but this too will penalize my requirements.
Thank you in advance to anyone for any kind of help!
Ermal
Solved the error adding <aop:scoped-proxy proxy-target-class="false" /> to the definition of the service/manager declared through Spring. This makes possible the injection of a fully serializable proxy instance.
<bean id="purchaseManager" class="al.ozone.bl.manager.impl.PurchaseManagerImpl">
<property name="purchaseDAO" ref="purchaseDAO" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
proxy-target-class="false" is for telling that PurchaseManagerImpl implements already an interface. If setted to true or omitted, CGLIB2 library must be used.
In this way JSF is correctly taking data from DB using Spring+MyBatis.
The mistery (for me) on this point (more theorical) is :
Is MyBatis object (PurchaseDAOImpl) and the dataSource, correctly handled behind the scenes?
Are they recreated or restored on each HTTP request?
Remember that I have STATE_SAVING_METHOD=client and BackingBean as ViewScope. My Goal is to have the server lighter possible because I expect an hight number of user interactions.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="poolPreparedStatements" value="true" />
<property name="defaultAutoCommit" value="false" />
</bean>
Thank you very much to anyone for some light on this matter!
Consulted links:
Spring session-scoped beans (controllers) and references to services, in terms of serialization
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection
http://www.infoq.com/presentations/Whats-New-in-Spring-3.0

Spring 3.1 JPA not inserting data while running in tomcat

I have spent three days trying to find the solution to this problem to no avail. I am desperate to figure this out. I have a simple spring app, running in servlet 2.5 with jstl tags 1.2, running in tomcat with spring 3.1, using hibernate and the hibernate jpa implementation.
I can list data from a page, but I cannot complete an insert. The record goes back, it appears to fire through with no problems. Yet no insert takes place. I know there are other posts similar but I have looked through them all and have not been able to find a solution anywhere.
If I run the exact same code via a MAIN class, the insert works fine. It just does not work when running as a web-app in tomcat.
I have tried running this via the main which works, inside the controller I have skipped calling the service layer, trying to go directly to the interface, when that didnt work, I tried going directly to the implementing DAO class, and that didnt work. It appears via the spring logs, that the entity manager is getting created, and shut down before a transaction takes place.
Please help me.
Here is my App-context
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="byName">
<context:component-scan base-package="com.naturalbornliar.site"/>
<tx:annotation-driven />
<!-- Bean declarations go here-->
<bean id="duke" class="com.naturalbornliar.site.entity.Admin">
<constructor-arg name="admin_id" type="Long" value="15" />
<constructor-arg name="admin_login" type="String" value="testUser" />
<constructor-arg name="admin_pwd" type="String" value="testPwd" />
<constructor-arg name="email_id" type="int" value="15" />
<constructor-arg name="quote" type="String" value="Something to say here" />
</bean>
<!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> -->
<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"/> -->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/nbl_db"/> -->
<!-- <property name="username" value="web_user"/> -->
<!-- <property name="password" value="web_pwd"/> -->
<!-- <property name="initialSize" value="5"/> -->
<!-- <property name="maxActive" value="10"/> -->
<!-- </bean> -->
<bean id="simpledataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/nbl_db"/>
<property name="username" value="web_user"/>
<property name="password" value="web_pwd"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="simpledataSource"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="nblPersistenceUnit"/>
<property name="dataSource" ref="simpledataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
</bean>
<!-- <bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> -->
<!-- <property name="persistenceUnitName" value="nblPersistenceUnit"/> -->
<!-- <property name="dataSource" ref="simpledataSource"/>-->
<!-- <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> -->
<!-- </bean> -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL"/>
<property name="showSql" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* *..CategoryDaoImpl.*(..))" advice-ref="txAdvice"/>
</aop:config>
</beans>
Here is my controller:
package com.naturalbornliar.site.mvc;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.naturalbornliar.site.entity.Category;
import com.naturalbornliar.site.entity.Link;
import com.naturalbornliar.site.service.CategoryService;
#Controller
#RequestMapping("/categories")
public class CategoryController {
protected final Logger logger = Logger.getLogger(CategoryController.class);
private final CategoryService categoryService;
#Inject
public CategoryController(CategoryService categoryService){
this.categoryService = categoryService;
}
#RequestMapping(value="/listCategories")
public String listLinks(Model model){
model.addAttribute("categories", categoryService.getAllCategories());
return "categories";
}
#RequestMapping(method=RequestMethod.GET, params="new")
public String showCreateCategoryForm(Model model){
model.addAttribute(new Category());
return "addcategory";
}
#RequestMapping(method=RequestMethod.POST)
public String addCategoryFromForm(Category category, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return"addcategory";
}
categoryService.addCategory(category);
return "redirect:/categories/listCategories";
}
}
Here is my service called from the controller:
package com.naturalbornliar.site.service;
import java.util.Collection;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import com.naturalbornliar.site.entity.Category;
import com.naturalbornliar.site.i.ICategoryDao;
#Service
public class CategoryService {
private ICategoryDao iCategoryDao;
#Inject
public CategoryService(ICategoryDao iCategoryDao){
this.iCategoryDao = iCategoryDao;
}
public Collection<Category> getAllCategories(){
return iCategoryDao.getAllCategories();
}
public Collection<Category> getCategoriesByType(String type) {
return iCategoryDao.getCategoriesByType(type);
}
public Category getCategoryById(Long id) {
throw new UnsupportedOperationException();
}
public void deleteCategory(Category category) {
throw new UnsupportedOperationException();
}
public void updateCategory(Category category) {
throw new UnsupportedOperationException();
}
public void inactivateCategory(Category category){
throw new UnsupportedOperationException();
}
public void addCategory(Category category){
iCategoryDao.addCategory(category);
}
}
Here is my implementing DAO:
package com.naturalbornliar.site.dao;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.naturalbornliar.site.entity.Content;
import com.naturalbornliar.site.i.IContentDao;
#Transactional
#Repository
public class ContentDaoImpl implements IContentDao {
protected final Logger logger = Logger.getLogger(ContentDaoImpl.class);
#PersistenceContext
private EntityManager em;
public EntityManager getEm() {
return em;
}
public void setEm(EntityManager em) {
this.em = em;
}
#Override
public void addContent(Content content) {
// TODO Auto-generated method stub
em.persist(content);
}
#Override
public void deleteContent(Content content) {
// TODO Auto-generated method stub
em.remove(content);
}
#Override
public void inactivateContent(Content content) {
// TODO Auto-generated method stub
}
#Override
public Content getContentById(Long id) {
// TODO Auto-generated method stub
return null;
}
#Override
public Content getContentByName(String name) {
// TODO Auto-generated method stub
return null;
}
#Override
public Collection<Content> getAllObjects() {
List<Content> resultList = em.createQuery("FROM Content", Content.class).getResultList();
return resultList;
}
}
Here is the interface (just in case)
package com.naturalbornliar.site.i;
import java.util.Collection;
import com.naturalbornliar.site.entity.Content;
public interface IContentDao {
public void addContent(Content content);
public void deleteContent(Content content);
public void inactivateContent(Content content);
public Content getContentById(Long id);
public Content getContentByName(String name);
public Collection<Content> getAllObjects();
}
Jeremy, thay may be many problems with that and I had similar problem.
In my case I used tomcat and I needed to add spring weaver to tomcat (this problem is described here: http://asrijaffar.blogspot.com/2007/02/spring-jpa-tomcat.html).
In my case I needed to have:
<tx:annotation-driven proxy-target-class="true" />
In DispatcherServlet config.
Additionally in db-context config:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="jpatest" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Well I actually solved the problem. Here is the solution, there was another stackoverflow issue that solved it:
Spring #Transaction not starting transactions
Basically all that was needed for transactions to fire correctly was for me to add:
<tx:annotation-driven proxy-target-class="true"/>
to my servlet xml. I guess if you just have it in the application config.xml it only works when running under the main class (like in a standalone) if you need to run it in a container you have to declare transaction annotations in the servlet as well.
I also spent several hours trying to figure out where the problem is although my previous application with the same stack is working fine and I wasn't able to understand the difference.
And.... the error was in tag in spring-servlet.xml - it was defined to scan the root package with all the web controller, repository classes, etc.
After changing it to make scanning of the package with web controllers only, the problem was gone..
Just for you (and for me) in case you might meet the same problem, just an additional hint
I also had this same problem, spent couple nights searching - alex solutions saved me - in servlet xml I changed context:component-scan to scan only package with web controller.
Example from this page should look like
<context:component-scan base-package="com.naturalbornliar.site.mvc"/>

Sharing Spring Security Configuration Between Applications

I'm brand spanking new at Spring and have gotten a majority of the knowledge I do have from the Spring Recipes book from Apress.
I've got LDAP authentication working with Spring Security within one webapp. I would like to rip out my application context beans and properties files from this one webapp, however, and somehow externalize them so that all of our webapps can reference the same beans. So when we need to change something (like the ldapuser or the ldap urls), we change it in one place and the rest of the apps just know.
UPDATE
I've implemented Reloadable Spring Properties which is reloading properties when the files they come from are touched. I am using encrypted properties, however, so below is class I created on top of the Reloadable Spring Properties ones.
ReloadingEncryptablePropertyPlaceholderConfigurer.java
package;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.util.text.TextEncryptor;
import org.jasypt.properties.PropertyValueEncryptionUtils;
import org.springframework.beans.factory.BeanDefinitionStoreException;
public class ReloadingEncryptablePropertyPlaceholderConfigurer extends ReloadingPropertyPlaceholderConfigurer {
protected final Log logger = LogFactory.getLog(getClass());
private final StringEncryptor stringEncryptor;
private final TextEncryptor textEncryptor;
public ReloadingEncryptablePropertyPlaceholderConfigurer(TextEncryptor textEncryptor) {
super();
logger.info("Creating configurer with TextEncryptor");
Validate.notNull(textEncryptor, "Encryptor cannot be null");
this.stringEncryptor = null;
this.textEncryptor = textEncryptor;
}
public ReloadingEncryptablePropertyPlaceholderConfigurer(StringEncryptor stringEncryptor) {
super();
logger.info("Creating configurer with StringEncryptor");
Validate.notNull(stringEncryptor, "Encryptor cannot be null");
this.stringEncryptor = stringEncryptor;
this.textEncryptor = null;
}
#Override
protected String convertPropertyValue(String originalValue) {
if (!PropertyValueEncryptionUtils.isEncryptedValue(originalValue)) {
return originalValue;
}
if (this.stringEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(originalValue, this.stringEncryptor);
}
return PropertyValueEncryptionUtils.decrypt(originalValue, this.textEncryptor);
}
#Override
protected String parseStringValue(String strVal, Properties props, Set visitedPlaceholders) throws BeanDefinitionStoreException {
return convertPropertyValue(super.parseStringValue(strVal, props, visitedPlaceholders));
}
}
And here's how I use it in my securityContext.xml:
<bean id="securityContextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldaps://ldapserver" />
<property name="urls" value="#{ldap.urls}" />
</bean>
<bean id="timer" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<bean id="reloadProperties" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="period" value="1000"/>
<property name="runnable">
<bean class="ReloadConfiguration">
<property name="reconfigurableBeans">
<list>
<ref bean="configproperties"/>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
<bean id="configproperties" class="ReloadablePropertiesFactoryBean">
<property name="location" value="classpath:ldap.properties"/>
</bean>
<bean id="ldapPropertyConfigurer" class="ReloadingEncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="properties" ref="configproperties"/>
</bean>
<bean id="jasyptConfig" class="org.jasypt.encryption.pbe.config.SimpleStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndTripleDES" />
<property name="password" value="########" />
</bean>
<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="jasyptConfig" />
</bean>
How about:
Writing a method that returns a list
of LDAP servers - reading from a
database table or property files
expose this wethod via jndi and use it to inject a list of the servers into your spring config
If you need the ldap servers to be refreshed dynamically you could have a job poll for changes periodically or else have an admin webpage or jmx bean to trigger the update. Be careful of concurrency isses for both these methods (something reading the list while you are updating)
Wouldn't that be Spring Security? It can deal with LDAPs. And if you make it one security service that everyone uses, wouldn't that be the way to manage it?

Resources