Use spring datasource of maven application within its dependency - java

I'm planning to build a library using spring and use it as an mvn dependency. The library would be used as an api in several projects. The api does only database operations. Can the included dependency get the datasource/jdbcTemplate of the project it is included in as an Autowired spring bean?
the datasource/jdbctemplate that we use in the spring application context is like following
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg index="0" type="javax.sql.DataSource" ref="dataSource" />
</bean>

Yes. As long as there is a been with the name datasource and class javax.sql.DataSource. It needs to be available either through configuration, XML wiring or component scanning.
If creating a new library API it would be good to document what the user needs to make available for wiring.

Related

Marklogic XCC ContentSource using JNDI

I'm trying to get a Marklogic ContentSource object loaded from Tomcat's context.xml using JNDI and Spring.
I'm using Tomcat 8.5, and Spring 2.5 (unfortunately)
I have added the following to context.xml in Tomcat
<Resource name="MLContentSource" auth="Container" type="com.marklogic.xcc.ContentSource"
factory="com.marklogic.xcc.jndi.ContentSourceBeanFactory"
url="xcc://username:password#mymarklogic-server/DatabaseName"/>
And the following in my applicationContext.xml
<bean id="contentSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/MLContentSource"/>
</bean>
I have another bean declared in my applicationContext.xml that relies on the ContentSource bean. Its expecting a property to be set that is of type com.marklogic.xcc.ContentSource
<bean id="marklogicRepository" class="org.example.repository.ingestion.MarkLogicRepositoryImpl">
<property name="contentSource" ref="contentSource" />
</bean>
The issue is that the contentSource bean is of type JndiObjectFactoryBean and not com.marklogic.xcc.ContentSource. Is there something I'm missing to get a proper ContentSource from the JndiObjectFactoryBean?
It turns out the above code actually worked, my IDE was complaining about types but Spring will automatically cast the object stored inside JndiObjectFactoryBean to the target type at runtime.
Maybe try XQJ?
https://github.com/cfoster/xqj-pool-example/blob/master/src/main/java/simple/WithJNDI.java
http://xqj.net/
The XQuery API for Java
A standard Java interface to XML DataSources which support XQuery 1.0.
The XQJ API is to XML Databases as the JDBC API is to Relational Databases.
Is a light-weight design and is very easy to pick up.

How spring load configuration file by environment?

I use spring framework in my application,and i use some configuration files,but in different environment,i need to use different properties like db config properties.Now i put different files in different path,then i use maven profile method to package different WAR.
Now,i want to package only one WAR in all environment,and want by transfer different parameters to use different configuration files.In addition i don't want to put the configuration file out of the project.
You can use spring bean profiles or conditional beans.You can use following configuration to define propertyplaceholder beans for each environment.
<beans profile="environment1">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database_env1.properties</value>
</property>
</bean>
</beans>
<beans profile="environment2">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database_env2.properties</value>
</property>
</bean>
</beans>
For database configuration, a possible approach is to define the JDBC DataSource as a JNDI resource directly in your application server that you then use (see how) - this way your WAR file doesn't contain the connection information, the runtime environment does hold this info instead.
One advantage of this approach is that the connection information then can be managed by a server administrator instead of the application developer.
Not sure it meets your "no configuration outside project" requirement though.

How to Create Service class Object in Spring

I am using ehcache in my project so when server start data of few table will be loaded into the cache ..in my application i am using Spring,Hibernate,JSF
I m using this configurationin applicationCOntext.xml file
<bean id="cacheManager" class="com.ccc.service.cache.CacheManager" init-method="init">
<property name="delay" value="${timer.delay}" />
</bean>
<bean id="companyCache" class="com.ccc.service.cache.clients.ValidCacheClient"/>
<context:component-scan base-package="com.ccc.spring" />
<context:annotation-config />
<context:spring-configured />
In Jsf Managed Bean i am creating Object of Service class like this
#ManagedProperty(value = "#{GlobalDataService}")
static GlobalDataService globalDataService;
But in ValidCacheClient.java how to create object of Service class? ValidCacheClient.java is not a manged class so how to create the Object of Service class?
You have two options:
Inject the necessary beans to be known from JSF as ServletContext attributes, so these beans will be treat by JSF as application scoped attributes. You can do this using Spring ServletContextAttributeExporter:
<bean class="org.springframework.web.context.support.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="globalDataService" value-ref="GlobalDataService" />
</map>
</property>
</bean>
Then you can inject it without problems in JSF:
#ManagedProperty(value = "#{globalDataService}")
GlobalDataService globalDataService; //no need to be static
Let Spring container manage the lyfecycle of JSF managed beans. With this approach, you may inject the springs beans using #Autowired. This is covered in Spring 3 + JSF 2 tutorials. Still, note that if you do this, you will lose access to JSF 2 view scope (crucial when working with ajax requests in the same view) because Spring still cannot support it. But this can be solved by creating a custom implementation for view scope, like Cagatay's
IMO I would use the latter approach rather than the former.
More info:
Set attributes of ServletContext in Spring 3.2 MVC configuration
Mkyong tutorial to integrate Spring 3 and JSF 2.0
Bean properties are shared across different sessions
Integration jsf, spring, hibernate. How to inject Spring beans into JSF managed beans?

EclipseLink and Spring 3 Web MVC: how should I integrate both technologies?

I'm currently learning EclipseLink and Spring 3.0 MVC:
I wrote a simple standalone application using EclipseLink : it uses a META-INF/persistence.xml file and it reads and writes data from a mysql database.
I also wrote a simple 'HelloWorld' application using Spring3 MVC under apache tomcat. It is based on the following tutorial: http://www.mkyong.com/spring-mvc/spring-3-rest-hello-world-example
now, how should I link both technologies ? As far as I understand from http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch14s06.html I need to create a LocalContainerEntityManagerFactoryBean:
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="someDataSource"/>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
but what is "someDataSource" ? should I use another library like http://commons.apache.org/dbcp/ ? then what should I do with eclipselink ?
And once the JPA will be configured, how should I access it from my spring Controller ?
Thank you
someDataSource would just be another bean, for example:
<bean id="someDataSource" 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}" />
</bean>
Here I'm also using a property replacement for the properties, this is designated by the following bean:
<context:property-placeholder location="classpath:properties/runtime.properties" />
Since context is under a different xml namespace add:
xmlns:context="http://www.springframework.org/schema/context"
to your XML namespaces, and
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
to your schemaLocation string within the bean xml document.
classpath:properties/runtime.properties
This property file would be found at the following location in a standard Maven setup:
src/main/resources/properties/runtime.properties
Within this runtime.properties file you'd need to define values for each of the properties that have placeholders (i.e. jdbc.driverClassName, jdbc.url, etc.). An example of this would be:
jdbc.driverClassName=com.mysql.jdbc.Driver
If you're using MySQL for your database.
Generally speaking, you might want a service layer between your controller and repository (DAO). The reason being is controller should concentrate only on handling requests, and responding. Any business logic should be done in a different layer, through business objects, etc. Service layer acts as an intermediary between web layer, and repository layer. This not only separates concerns, but also makes things infinitely more unit testable, a huge part of any Spring application (at least it should be!).
As to how to wire things up, try inserting this bean into your Context as well:
<context:component-scan base-package="xx.yy..." />
Where xx and yy are your package names, this will tell Spring to scan your packages for "components" or #Controller objects, #Service, and #Repository (there are a few other ones but those are the main things to know about). With this information provided to Spring, you can #Autowire beans (dependency inject) into other beans.
For example:
#Service
public class SomeServiceImpl implements SomeService
{
private SomeRepository someRepository;
#Autowired
public void setSomeRepository(SomeRepository someRepository)
{
this.someRepository = someRepository;
}
...
}
This will inject the repository into the service allowing you to access that repositories methods.
Another design tip, always program for interfaces in Spring. This is especially true when it comes to repositories due to the fact that early in development, you might want to implement a Hibernate repository, but down the line DBAs might scoff at that, and require a JDBC repository using straight SQL. This way, you just need to implement the Repository using a JDBC approach rather than Hibernate, inject the JDBC repository instead of Hibernate, and you're done.
Hope this gets you started!

Spring JTA TransactionManager config: Supporting both Tomcat and JBoss

I have a web application using JPA and JTA with Spring. I would like to support both JBoss and Tomcat. When running on JBoss, I'd like to use JBoss' own TransactionManager, and when running on Tomcat, I'd like to use JOTM.
I have both scenarios working, but I now find that I seem to need two separate Spring configurations for the two cases. With JOTM, I need to use Spring's JotmFactoryBean:
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction">
<bean class="org.springframework.transaction.jta.JotmFactoryBean"/>
</property>
</bean>
In JBoss, though, I just need to fetch "TransactionManager" from JNDI:
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="resourceRef" value="true" />
<property name="jndiName" value="TransactionManager" />
<property name="expectedType"
value="javax.transaction.TransactionManager" />
</bean>
</property>
</bean>
Is there a way to configure this so that the appropriate TransactionManager - JBoss or JOTM - is used, without the need for two different configuration files?
I think you have missed the point of JNDI. JNDI was pretty much written to solve the problem you have!
I think you can take it up a level, so instead of using the "userTransaction" or "transactionManager from JNDI" depending on your situation. Why not add the "JtaTransactionManager" to JNDI. That way you push the configuration to the JNDI where it is supposed to be instead of creating even more configuration files [ like there aren't enough already ;) ].
You can use PropertyConfigurerPlaceholder to inject bean references as well as simple values.
For example if you call your beans 'jotm' and 'jboss' then you could inject your TM like:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE">
<property name="location" value="classpath:/path/to/application.properties"/>
</bean>
<bean id="jotm">...</bean>
<bean id="jboss">...</bean>
<bean id="bean-requiring-transaction-manager">
<property name="transactionManager" ref="${transaction.strategy}"/>
</bean>
Then you can swap transaction managers using
transaction.strategy=jotm in a properties file
-Dtransaction.strategy=jotm as a system property
This is one possible approach. See my blog for a more complete example.
Hope this helps.
If you are using Spring 2.5 you can use <tx:jta-transaction-manager/>. I have not used it with JBoss but it should work for you according to section 9.8 Application server-specific integration from the Spring reference manual.
The <tx:jta-transaction-manager/> approach will look for a transaction manager in several default locations listed here. If your JBoss transaction manager is not in one of those locations, I suggest you move it, if possible, or move it in Tomcat so that both containers have their TM in the same JNDI location.
Just adding my experience here so I don't have to re-suffer the experience again.
As bmatthews68, Chochos and these posters have said, use <tx:jta-transaction-manager/> in your Spring bean file; it definitely provides the appropriate level of abstraction and there's no need to do anything extra on the Spring side.
As for Tomcat, I declared <Transaction factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60" /> in the default/shared conf/context.xml file, which binds to java:comp/UserTransaction. As this is one of the places searched for by Spring, you shouldn't need to do anything else.
One gotcha though: if like me you use Maven, make sure you exclude any dependencies on the javax.transaction:jta jar or set the scope to provided. Otherwise you will experience classloader issues.

Categories