In my application I am injecting some of services based on EJB with use of Spring IOC through JndiObjectFactoryBean like below mentioned so during run the junit I am getting this exception "java.lang.IllegalArgumentException: This JNDI operation is not implemented by the JNDI provider."
Could some please let me know how I'll configure for Junit.
<bean id="xxxMenuItemService" class="xxxMenuItemServiceyyy">
<property name="xxxMenuItemDelegator" ref="xxxMenuItemDelegator" />
</bean>
<bean id="approveMenuItemServiceRemote"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"
value="ejb/XXXXXXXX" />
have a look at the SimpleNamingContextBuilder from org.springframework.mock as it provides a full context builder where you can bind mock or other objects for use by Spring's JNDI lookup.
One thing to do though is to make sure you build the SimpleNamingContextBuilder in the static #BeforeClass of JUnit 4. this means that it is all initialized and waiting before the Spring Application Context is started and you won't have any JNDI lookup failures.
Related
I read in Spring in Action that a good way to set up JDBCTemplate is adding this in the Spring config file:
<jee:jndi-lookup id="dbDataSource" jndi-name="jdbc/AOICMainDB" expected-type="javax.sql.DataSource" />
<bean id="jdbcTemplateDB2" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dbDataSource" />
</bean>
it makes sense, now we can autowire jdbcTemplateDB2 in a DAO and do jdbcTemplate stuff with it.
but how would I set this up using a java config file? Specifically I'm not sure how the jee: namespace translates over to java confg.
The jee:jndi-lookup is just syntactical sugar for the JndiObjectFactoryBean.
The spring documentation provides a before and after example like so:
Before…
<bean id="simple" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/MyDataSource"/>
</bean>
After…
<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource">
</jee:jndi-lookup>
Now to convert this into a java config you will need to do something like this:
#Bean
public JndiObjectFactoryBean simple() {
JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
bean.setJndiName("jdbc/MyDataSource");
return bean;
}
Then you can just retrieve the jndi object from the bean.
References:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/xsd-configuration.html#xsd-config-body-schemas-jee-jndi-lookup-environment-single
Disclaimer: The public void afterPropertiesSet() must run to populate the jndi object.
Your question should be: Who is running the JNDI service that will give the data source to my app?
If your app doesn't run on a Java EE app server with a JNDI service available, the answer is "No one." You should use a DriverManager data source in that case.
If your app does run on a Java EE app server with a JNDI service available, you have to know how to set up your data source in the pool.
I can use annotation #Transactional at the top of my service PersonServiceBean and config transactionManager like below. After that, my service can execute db operations under transaction control through AOP.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
.........
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">
<property name="dataSource" ref="dataSource"/>
</bean>
But i didn't include aspectj.jar into my project. How does it work? I heard spring implements AOP through aspectj.
It doesn't use AspectJ by default, but uses proxies (either JDK interface proxies or CGLIB proxies). So, when you inject a transactional bean into another bean, what you get injected is in fact a proxy to your actual bean instance, which intercepts the method calls and starts/commits/rollbacks transactions.
More in the documentation, of course.
We have developed a data persistence framework using Mybatis. The framework uses plain MyBatis APIs. (We were prohibited from using any mybatis-spring, do not ask… why?)
Now we have to integrate this persistence framework with another framework developed by other teams. This other framework heavily uses spring transactions for everything. Our persistent framework DAOs will be used by this framework within its own API ….that means the spring managed transactions will be propagated to MyBatis DAO. It is expected that our MyBatis based persistence framework should participate in spring managed transactions without any issues.
There are two options for us to make this work
(1)Change our persistent framework to use mybatis-spring module. Change DAOs to use mappers directly injected using spring and spring’s SqlSessionFactoryBean. I did build a small example simulating both the frameworks and everything works without any issue. The problem is with this approach that it requires changing almost all the DAOs to use spring injected mapper, extensively test the framework again. We simply do not have time available due to delivery timeline.
(2)Use mybatis-spring, define SqlSeeionFactory using spring – set the datasource and transaction manager used by other framework. Something like
<bean id="smpDataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="connectionCachingEnabled" value="true" />
<property name="URL"> <value>${db.thin.url}</value></property>
<property name="user"> <value>${db.user}</value></property>
<property name="password"><value>${db.password}</value>
</property>
</bean>
<bean id="dbTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="smpDataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="smpDataSource" />
<property name="typeAliasesPackage" value="spike.smp51.domain" />
<property name="mapperLocations" value="classpath*:spike/smp51/mappers/*.xml" </bean>
Then in applicataion code MyBatis DAO gets the sqlseesionfactory from spring like
public static SqlSessionFactory getSqlSessionFactory() throws Exception
{
DefaultSqlSessionFactory sessionFactory = (DefaultSqlSessionFactory)ctx.getBean("sqlSessionFactory");
return sessionFactory;
}
All DAOs already use SqlSeesionFactory to open and close sessions. Just replace that mybatis created sqlseeionfactory with spring created sqlseeionfactory. That way we will have only few lines of changes.
This approach is outlined here
http://mybatis.github.io/spring/using-api.html
The mybatis documentation warns about this approach – specifically that it will not participate in spring transactions.
When I tried the 2nd approach, our framework was able to participate in spring transactions. This is strange. Is the MyBatis documentation incorrect then? I did verify it extensively by creating various transaction boundaries using spring transactions + AOP . MyBatis DAOs are able to participate in spring managed transactions every time. Since this second approach will save us 90% of the development time – we really like to use it – but worried since MyBatis warns following this approach. Has anyone tried this approach? Any feedback is greatly appreciated.
Did you have any return on that ?
I'm wondering if in the doc they're talking about org.apache.ibatis.session.SqlSessionFactory from Mybatis-api while the SqlSessionFactory you're using is from the mybatis-spring lib : org.mybatis.spring.SqlSessionFactoryBean
Right now i am using the following bean entry
<bean id="Service" >
<property name="target">
<bean class="someClass" lazy-init="false">
<property name="SessionFactory1"><ref bean="SessionFactory1"/></property>
<property name="SessionFactory2"><ref bean="SessionFactory2"/></property>
<property name="SessionFactory3"><ref bean="SessionFactory3"/></property>
</bean>
</property>
</bean>
Now the requirement is to first check which all session factories have an active datasource and include those only in the above bean definition. So that the application does not break if we try to initialize a session factory with inactive datasource.
sessionfactory initialization will be take care by using seperate config xml for session factories and loading only the ones with active datasources.
Please help on how can this be achieved.
You can use Spring InitializingBean interface, which makes you implement an afterPropertiesSet() method. This method will be executed after Spring instantiates your class, and you could check if your session factories are available or not.
InitializingBean: Interface to be implemented by beans that need to react once all their properties have been set by a BeanFactory: for example, to perform custom initialization, or merely to check that all mandatory properties have been set.
link: Spring InitializingBean
I am having multiple datasource and one one database configured with JPA. I am using websphere 7. I want all these datasouces to be configured as global transactions. I am using below spring configurations but the transactions are not working as expected global transaction. If one db is failing then the other db is getting commited which is not expected as single global transactions. Can you please help me where i m doing incorrect,
I am having 2 datasouce one as configured below with id="us_icfs_datasource" and another using JPA
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/persistenceUnit"/>
<bean id="pabpp" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- Needed for #Transactional annotation -->
<tx:annotation-driven/>
<jee:jndi-lookup id="US_ICFS_DATASORCE"
jndi-name="jdbc/financing_tools_docgen_txtmgr"
cache="true"
resource-ref="true"
proxy-interface="javax.sql.DataSource" />
also I have added below code in web.xml
<persistence-unit-ref>
<persistence-unit-ref-name>persistence/persistenceUnit</persistence-unit-ref-name>
<persistence-unit-name>persistenceUnit</persistence-unit-name>
</persistence-unit-ref>
<persistence-context-ref>
<persistence-context-ref-name>persistence/persistenceUnit</persistence-context-ref-name>
<persistence-unit-name>persistenceUnit</persistence-unit-name>
</persistence-context-ref>
below is my code where i m using transaction
> #Transactional public TemplateMapping addTemplateMapping(User user,
> TemplateMapping templateMapping) throws
> TemplateMappingServiceException { .... }
On Websphere you should use this bean to hook into the Websphere transaction manager:
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
See also this article
EDIT:
In order to use 2-phase commit (i.e. ensuring consistency across multiple resources), you will need to use XA data sources. See this article for details.
First of all your data sources that participate in global transaction must be of javax.sql.XADataSource type.
You also have to set transaction type in your persistence unit to JTA (not RESOURCE_LOCAL).
And you need to inform your JPA implementation that you want to do global transactions.