Showing posts with label spring. Show all posts
Showing posts with label spring. Show all posts

Monday, 22 March 2010

Connecting to Oracle 8.1.7 from Weblogic10.3

This has been a nail biting issues for me where I had to connect to an older unsupported version of oracle from a newer version of Weblogic.

An upgrade document on weblogic 10.3 states that 8.1.7 is no longer supported by weblogic.
http://download.oracle.com/docs/cd/E15919_01/wlp.1032/e14253/upgrade_process.htm
This is true as we will not be able to simply create a datasource from weblogic 10.3 to oracle 8.1.7
coz the driver (ojdbc6.ja and ojdbc5.jar) as packaged with weblogic are not compatible with the same.

Hence the search began to find a suitable driver. The Drivers as mentioned by oracle for 8.1.7 can be viewed here:
http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc817.html.


Of course I started off with downloading classes12.jar

and I realised that though my standalone unit tests(JUNIT 4 using spring AbstractTransactionalDataSourceSpringContextTests) worked fine with some tweaks here and there.

However when the same spring config
<bean id="testDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"><value>oracle.driver.jdbc.OracleDriver</value></property> <property name="url"><value>jdbc:oracle:thin:@host:port:databasename</value></property> <property name="username"><value>USERNAME</value></property> <property name="password"><value>PASSWORD</value></property> </bean>

was used within an app deployed on weblogic to connect to the database I got a weird exception:
java.lang.ArrayIndexOutOfBoundsException: 4 at oracle.jdbc.driver.T4C8TTIdty.marshal(T4C8TTIdty.java:465) at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:329) at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java: 490) at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:202) at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtensio n.java:33) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:474) at java.sql.DriverManager.getConnection(DriverManager.java:582) at java.sql.DriverManager.getConnection(DriverManager.java:185)

The problem was obvious Weblogic class loader was trying to return the Oracle Driver as present in ojdbc6.jar or ojdbc5.jar and completely ignored my classes12.jar which I had in the classpath.

Hence I had to start from scratch again. I instead added classes12.jar to the weblogic classpath and tried creating a datasource using the weblogic console , even then I gotthe

same exception as above. I wondered if upgrading to another jar would help. I hence downloaded ojdbc14.jar and added it to the weblogic classpath and tried creating a datasource

and it was successful.

However I wondered if there was away of not changing the weblogic classpath and instead using ojdbc14.jar from within my application to be loaded in preference as ooposed to

odjbc6.jar/ojdbc5.jar as present in weblogic classpath.

I later added

<container-descriptor>
<prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>

to my weblogic.xml so as to change the classloader preference.

Some forums suggested using the weblogic-application.xml to achieve the same by adding

<prefer-application-packages>
<package-name>oracle.jdbc.driver.*</package-name>
</prefer-application-packages>

Both will change the order for class loader preferences.

However for me the first option worked.

So now I am able to connect to oracle 8.1.7 from an application which has ojdbc14.jar in web-inf/lib and the weblogic.xml says to prefer the same.

The datasource is not a jndi datasource as can be done in weblogic but it is a spring configured datasource.

I guess this is a neater and an easier option for me as it saves me the task of upgrading to a newer oracle or downgrading to a older weblogic

Thursday, 18 March 2010

Switching between datasources during runtime

Many a times we might want to unit test daos across multiple instances of the same database.


Many a times we might want to update multiple instance of a same database schema , so in such cases we would implement all dao methos in one dao however want to execute the method across multiple databases. In such cases we would want to switch the datasource the dao is connected to during runtime.

AbstractRoutingDataSource is the answer I have found for my problem.


One blog worth mentioning here is http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/ which helped me understand the whole concept and implement the same.

Unit Testing with multiple daos - AbstractTransactionalDataSourceSpringContextTests

I had a scenario where I wanted to unit test my dao methods , however some of the daos depended on data being provided from other daos to run successfully.

In order to achieve the same I required to be able to configure multiple data sources in my spring config and inject the data sources as and when required.

I used AbstractTransactionalDataSourceSpringContextTests for my Junit test cases.

And my spring config xml looked like :



<!-- Database 1-->
<bean id="testDataSource1" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">

</bean>

<!-- Database 2 -->
<bean id="testDataSource2" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">

</bean>

<bean id="dao1" class="Dao1Impl">
<property name="dataSource" ref="testDataSource1">
</property></bean>

<bean id="dao2" class="Dao2Impl">
<property name="dataSource" ref="testDataSource2">
</property></bean>

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="testDataSource1">
</property></bean>


When I re ran the unit test . I came across the following error:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'DaoTest': Unsatisfied dependency expressed through bean property 'dataSource': No unique bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: [testDataSource1, testDataSource2]

I had to change my unit test so that it looked like below:


import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;


public abstract class BaseTest extends AbstractTransactionalDataSourceSpringContextTests {

@Autowired
Dao1 dao1;

@Autowired
Dao2 dao2;

@Autowired
DataSource testDataSource1;

@Autowired
DataSource testDataSource2;

/* (non-Javadoc)
* @see org.springframework.test.AbstractSingleSpringContextTests#getConfigPath()
*/
@Override
protected String getConfigPath() {
return "spring-test-config.xml";
}

@Override
@Autowired
public void setDataSource(@Qualifier("testDataSource1") final DataSource dataSource){
super.setDataSource(dataSource);
}

/**
* @return the dao1
*/
public Dao1 getDao1() {
return dao1;
}

/**
* @param dao1 the dao1 to set
*/
public void setDao1(Dao1 dao1) {
this.dao1 = dao1;
}

/**
* @return the dao2
*/
public Dao2 getDao2() {
return dao2;
}

/**
* @param dao2 the dao2 to set
*/
public void setDao2(Dao2 dao2) {
this.dao2 = dao2;
}

/**
* @return the testDataSource1
*/
public DataSource getTestDataSource1() {
return testDataSource1;
}

/**
* @param testDataSource1 the testDataSource1 to set
*/
public void setTestDataSource1(@Qualifier("testDataSource1") DataSource testDataSource1) {
this.testDataSource1 = testDataSource1;
}

/**
* @return the testDataSource2
*/
public DataSource getTestDataSource2() {
return testDataSource2;
}

/**
* @param testDataSource2 the testDataSource2 to set
*/
public void setTestDataSource2(@Qualifier("testDataSource2") DataSource testDataSource2) {
this.testDataSource2 = testDataSource2;
}



}

the interesting thing above is the @Qualifier annotation which allows us to reference which data sources to inject while initializing the beans.

Now while writing my test cases I can simply switch between the datasources like :

setDataSource(getTestDataSource2());
// Perform transaction related to data source 2
setDataSource(getTestDataSource1());
// Set the data source back to the main data source


I know Unit test cases must be independent , and should be testing on real time data , however if in case a need arises to be able to test the same without having to worry about re deploying and re starting application servers , this method is useful.