How to define Spring datasource in controller? - java

Is it possible to define a datasource connector in a Spring controller ?
I'm working on a tool : synchronize a source table to a target table.
I would define source and target in my controller (to synchronize different databases - in my view I can select different source and target databases).
Actually, I define my datasource in file call : datasource.xml
My code :
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<bean id="sourceDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/source"/>
<!--<property name="url" value="jdbc:mysql://linkSource"/>-->
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="targetDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/target"/>
<!--<property name="url" value="jdbc:mysql://linkTarget"/>-->
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
</beans>
Thank you for your help !
Thank you for your help !
But I think I put my question badly.
Actually, I have in my sync-servelt.xml (just part) :
<!--sync query beans-->
<bean id="sourceDatasetQueryBean" class="ds.sync.db.SyncDatasetQuery" name="sourceDatasetsQuery">
<property name="dataSource" ref="sourceDataSource"/>
</bean>
<bean id="targetDatasetQueryBean" class="ds.sync.db.SyncDatasetQuery" name="targetDatasetsQuery">
<property name="dataSource" ref="targetDataSource"/>
</bean>
<bean id="sourceDatasetDescriptionQueryBean" class="ds.sync.db.SyncDatasetDescriptionQuery" name="sourceDatasetsDescriptionQuery">
<property name="dataSource" ref="sourceDataSource"/>
</bean>
<bean id="targetDatasetDescriptionQueryBean" class="ds.sync.db.SyncDatasetDescriptionQuery" name="targetDatasetsDescriptionQuery">
<property name="dataSource" ref="targetDataSource"/>
</bean>
...more...
And, in my controller I'm using :
#Autowired
#Qualifier("sourceDatasetQueryBean")
protected SyncDatasetQuery m_datasetQuerySource;
#Autowired
#Qualifier("targetDatasetQueryBean")
protected SyncDatasetQuery m_datasetQueryTarget;
#Autowired
#Qualifier("sourceDatasetDescriptionQueryBean")
protected SyncDatasetDescriptionQuery m_datasetDescriptionQuerySource;
#Autowired
#Qualifier("targetDatasetDescriptionQueryBean")
protected SyncDatasetDescriptionQuery m_datasetDescriptionQueryTarget;
...more...
I have 11 tables to sync between source and target...
Is there a way to group my query beans ?
My synchronizations must be performed on several databases.
For example, I have 3 sites in different places, 1 site is SOURCE (A), 2 sites are TARGET (B & C) ; with a form (made with YUI), I should be able to sync A->B and A->C.
To sum up :
1- with my form I select a SOURCE, and a TARGET (serveral databases),
2- my form send (in Ajax), the selected SOURCE and selected TARGET to my controller,
3- my controller points to the good database.
What is the best way to do this ?
Using a Factory ?
Using setDataSource ?
Thank you for help.

You should be able to use the following syntax to achieve what you want (see Spring 2.x docs):
#Autowired
#Qualifier("targetDataSource")
DataSource targetDataSource;
#Autowired
#Qualifier("sourceDataSource")
DataSource sourceDataSource;

So assuming your data sources are defined correctly it's only a matter of injecting them into your Controller:
<bean id="myController" class="...">
<property name="sourceDS" ref="sourceDataSource" />
<property name="targetDS" ref="targetDataSource" />
....
</bean>

If you don't want to be messing with spring xml files, and relay in properties or any other GUI to define those datasources at runtime, you might use:
applicationContext.getBean(bean,object[])
Be aware that is not a good practise with spring (even that it is quite handy sometimes).
This way you define your beans expecting constructor arguments and supply those arguments as part of the array. This way you create as many datasources you need at runtime getting those from wherever you want to store the information.

Finally, by using DriverManagerDataSource, and using setter, I can redefine my dataSource selected (target and source) dynamically in my controller.
I just need to use :
setDriverManagerDataSource(m_sourceDataSource);
and m_datasetQuerySource.setDataSource(dataSource); (SOURCE)
Same play with target and all tables.
I see also other way to do that :
http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/
http://grails.org/Spring+Bean+Builder

Related

how to read properties file using spring and exposed to class

I am using spring 3.0.5 and trying to read properties files to make some kind of validation as well as datasource. But i am getting null when i use #Value ,below are my cfg.
in applicationContext.xml
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"/>
<bean id="myDataSource" 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 It is perfectly establishing the data-source.
The Class where I want to exposed the values of properties file
#Component
public class PropertyReaderBean {
//#Value("#{propertyConfigurer1[dailyLimit]}")
//#Value("#{database['jdbc.driverClassName']}")
#Value("${jdbc.driverClassName}")// I tried all three but still getting null
private String limit;
public String getLimit()
{
System.out.println(" limit : "+limit);
return limit;
}
public void setLimit(String limit) {
System.out.println(" limit : "+this.limit);
this.limit = limit;
}
and finally the databse.properties file
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/imps
jdbc.username=root
jdbc.password=root
So whenever i am trying to access the values properties file using above configuration, i am getting null, please guide.
Update:
However the setter method of PropertyReaderBean is not working, i have checked the stacktrace, but when i add in xml like this then i can read the properties file values.
<bean id="propertyDao" class="com.alw.imps.validator.PropertyReaderBean">
<property name="limit" value="${jdbc.password}"></property>
</bean>
A likely cause is #Value doesn't work. Did you already declare < context:annotation-config /> in the application context?
You don't need property configurer, the definition of which in your code has syntax errors.
You can just do this and reference in code as you have :
<context:property-placeholder location="classpath:database.properties"/>
which relies on this
xmlns:context="http://www.springframework.org/schema/context"
and
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd

Common value configuration in Spring XML

I have several Spring beans in which one of the property value for all of them are same String value. Is there a way where I can define this String in XML at one place and refer it in all beans at property value settings?
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
<bean id="nextBean" class="test.NextBean">
<property name="property2" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
How to set commonValue in a seperate place and refer it in both places?
Try like this.
<bean id="commonConfig" abstract="true">
<property name="commonField" value="CommonValue"></property>
</bean>
<bean id="class1" class="com.dataclass.Class1" parent="commonConfig">
<property name="field1" value="value1"></property>
</bean>
<bean id="class2" class="com.dataclass.Class2" parent="commonConfig">
<property name="field2" value="value2"></property>
</bean>
Class1 & Class2 having one common field name "commonField", parent attribute is use for this common purpose only.
In Spring this is called bean definition inheritance(this is not java class inheritance, above example Class1 & n Class not inheriting in their respective java file.)
For more detail, look at Spring doc's link.
I've never tried it before, but this should work
<bean id="commonProp" class="java.lang.String">
<constructor-arg name="original" value="yourString"></constructor-arg>
</bean>
Then, in every bean you need to reference it:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" ref="commonProp"></property>
</bean>
You can define your string properties in some "init_constants.properties" file. Then you should load properties file in spring xml:
<bean id="properties"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
<value>classpath:mail.properties</value>
<value>classpath:init_constants.properties</value>
</list>
</property>
</bean>
And after that you can inject this properties using xml:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="{$prop1}"></property>
<property name="commonProperty" value="commonValue"></property>
</bean>
or in code using #Value annotation:
#Value(value="${prop1}")
private String property1;
Well If commonValue is string then you can put it in properties file and read it using #Value annotation.

How to access data in another spring bean using current spring bean

I am new to Spring and I have a small requirement.
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" ref="dataSource" />
</bean>
<bean id="dataSource" class="java.lang.String">
<property name="name" value="easy" />
</bean>
I have written beans as shown above. I need to access the value easy from the bean with id="triangle", but when I try doing this I get a exception. Can someone please suggest how to overcome this problem?
Try the following:
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" ref="dataSource" />
</bean>
<bean id="dataSource" class="com.thomson.learn.spring.shape">
<property name="name" value="easy" />
</bean>
where com.thomson.learn.spring.triangle and com.thomson.learn.spring.shape must exist as classes in your project. your String class bean couldn't have worked because String has no name property (getName() method getter) to access.
If it is going to be String(s) that you want to inject into all of your beans you can refer properties from a property file and use <context:property-placeholder location="location to .properties"/>
or you can define properties in the configuration xml with <util:properties />
Example for property-placeholder
<bean id="appDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/> // Refered from property file
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="classpath:jdbc.properties"/>
A String does not have a property 'name', so you can't instantiate one the way you are trying to. Moreover, you don't need to, as you can use it directly as the value, e.g.:
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" value="easy" />
</bean>
Edit in reply to your comment:
If "name" is of type shape, then you need to inject a shape here...
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" ref="shape" />
</bean>
<bean name="shape" class="com.thomson.learn.spring.shape">
<!-- configure properties here -->
</bean>
The objects wired by Spring are supposed to be JavaBeans. What this means in practice is that they have a no-argument constructor and a set of properties, each of which has both a getter and a setter. When you write a definition such as above, Spring uses the setters to set properties you defined in the configuration file.
For instance if Shape was a class as such:
package com.thomson.learn.spring.Shape;
class Shape {
private String name;
public Shape() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then you could wire it with the following:
<bean id="myShape" class="com.thomson.learn.spring.Shape">
<property name="name" value="blah" />
</bean>
Which really translates to Spring executing the following at runtime:
Shape myShape = new Shape();
shape.setName("blah");
That's all there is to it, except that properties can also be more complex instances of other classes of course, which is why you can use ref to refer to another bean for a property.
P.S.: Spring can use reflection to inject values in many cases, so it doesn't actually need a setter, but most people implement their beans this way for various reasons.

How to set dynamically a bean reference in Spring?

<bean id="Mybean" class="Bean">
<property name="config" ref="dev"/>
</bean>
<bean id="dev" class="Dev">
<property name="x" ref="Dev1">
<property name="y" ref="Dev2">
<property name="z" ref="Dev3">
</bean>
<bean id="stag" class="Dev">
<property name="x" ref="Stag1">
<property name="y" ref="Stag2">
<property name="z" ref="Stag3">
</bean>
In the above scenario, the config property in the bean MyBean change from environment to environment. At the time of dev, reference of config change to dev. And in staging, the reference change to stag. The problem comes at the time of checked in the spring file. We have to analyze everytime the reference of config before checked in. If the reference of config with the value of dev checked in, we might have to explain a lot of questions.
Is there any solution to solve to make it automate?
Note: Spring version is 2.0.1
Use the PropertyPlaceholderConfigurer from Spring, and remove an unused bean :
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>env.properties</value>
</property>
</bean>
<bean id="Mybean" class="Bean">
<property name="config" ref="config"/>
</bean>
<bean id="config" class="Config">
<property name="x" ref="${x}">
<property name="y" ref="${y}">
<property name="z" ref="${z}">
</bean>
and the env.properties file contains the following properties :
x=Dev1
y=Dev2
z=Dev3
or
x=Stag1
y=Stag2
z=Stag3
setup up the placeholder bean by specfiy, let spring know you want the placeholder
set up the config for the "my bean" by using the "${env}"
for example:
<beans>
<bean id="configBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"><value>env.properties</value></property>
</bean>
<bean id="Mybean" class="Bean">
<property name="config" ref="${env}"/>
</bean>
</beans>
and you need the add the env = dev key-value to the env.properties file
Assuming you meant Spring 3.1, rather than Spring 2.1 (which doesn't exist), then you can use the new "Environment Profiles" feature that was introduced in 3.1. This allows you to define a set of beans for each of your environments, and then select the "active" one at runtime.
See this SpringSource Blog Entry for examples.
You can do it using PropertyPlaceholderConfigurer or using #Profile
Also See
is-there-any-way-to-enable-or-disable-the-spring-bean-definition-in-applicationc
PropertyPlaceholderConfigurer example
PropertyPlaceholderConfigurer is the answer, yet I would imagine that you would like this to happen without the need to stay updating your properties file for each environment.
My suggestion would therefore be as follows
Use PropertyPlaceholderConfigurer, but do not create a properties file
By default, PropertyPlaceholderConfigurer first tries to find a value in a properties file, but if that fails, it will look for one in system properties
So all you need to do is to define both beans the same way that you are doing it, i.e. dev and stag.. which is a fine approach since you're clearly showing the different configurations... it would help if you also added some alias to show clearly the setting you want to use.
Next, pass in a system property defining what mode you are in... and ideally explicitly set PropertyPlaceholderConfigurer to use System properties.
So.. your config would look something like this
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
systemPropertiesMode="2"/>
<bean id="Mybean" class="Bean">
<property name="config" ref="${launch.mode}"/>
</bean>
<bean id="dev" name="dev_mode" class="Dev">
<property name="x" ref="Dev1">
<property name="y" ref="Dev2">
<property name="z" ref="Dev3">
</bean>
<bean id="stag" name="staging_mode" class="Dev">
<property name="x" ref="Stag1">
<property name="y" ref="Stag2">
<property name="z" ref="Stag3">
</bean>
You can then pass in the property upon startup in the following fashion
-D<property-name>=<value>
So in this case you'd use
-Dlaunch.mode=dev_mode
Or
-Dlaunch.mode=staging_mode
And you won't need to touch any of the configuration files.
Just a further note on systemPropertiesMode, accepted values are the following:
0 - never look in system properties
1 - use system properties as a fallback (i.e. if not found in properties files)
2 - system properties always override (the mode i'm suggesting)
Hope it helps :)
Note: This recommendation is only applicable to Spring < 3.1, since from 3.1 onward, the recommended approach is to use #Profile
Spring provides a mechanism called property placeholders. This way you can set certain properties in a database/properties file and spring will fill them in on startup.
The class to use for this is located here.

Having more than one data source

I haven't found a question on this topic so I'll ask. I've never actually tackled something which uses more than one data source. One example would be ETL which requires two data sources. How could such an application be designed?
Two data sources, two separate names. Inject each one by their respective bean IDs.
<bean id="fromDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${from.jdbc.driverClassName}"/>
<property name="url" value="${from.jdbc.url}"/>
<property name="username" value="${from.jdbc.username}"/>
<property name="password" value="${from.jdbc.password}"/>
</bean>
<context:property-placeholder location="from.jdbc.properties"/>
<bean id="toDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${to.jdbc.driverClassName}"/>
<property name="url" value="${to.jdbc.url}"/>
<property name="username" value="${to.jdbc.username}"/>
<property name="password" value="${to.jdbc.password}"/>
</bean>
<context:property-placeholder location="to.jdbc.properties"/>
You'd want to have a single DAO, but two instances of it - each with their own data source. One would SELECT from the source, the other would INSERT into the target.
A better way might be to forego Spring and just use bulk transfer mechanisms built into the databases.

Categories

Resources