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

Friday 19 March, 2010

Ant Ear -Adding weblogic-application.xml

One of the extensions we can add to an application is for weblogic.

We can do so by adding an xml called weblogic-application.xml to an ear's meta-inf directory and also mention the preferences.


To add the same to the ear file simply update you ant target for creating the ear file to something like this:

<ear earfile="${ear file name}" appxml="${meta-inf-directory}/application.xml">
<metainf dir="${meta-inf-directory}" excludes="application.xml, .mf">
</metainf>


One reason you we might want to add this file to your ear file is when we want to provide class loader filtering for certain packages.

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.

MultiKeyMap , MultiValueMap - Apache commons

Very interesting implementation for a map. Something which I have been trying to implement or use for a while.

This has proved to be very useful, when we are iterating over collection of entities whose primary keys are composite then in such cases multi key maps can be used.

Simply use it like this
For example if an employee is uniquely identified by his id and department id then we can add it like this.
MultiKeyMap map = new MultiKeyMap();
map.put(employeeID, deptID, employee);

when getting the value back simply say :

map.get(employeeID, deptID);

On the other hand if we wish to store a collection of objects for a given key we can use MultiValueMap.

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.

Wednesday 17 March, 2010

Oracle Old Driver Vs New Driver

exception:code:java.lang.ArrayIndexOutOfBoundsException: 4at oracle.jdbc.driver.T4C8TTIdty.marshal(T4C8TTIdty.java:465)at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:329)at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:490)at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:202)at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:33)at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:474)at

Recently while trying to work with an oracle database I came across this wierd error. Thanks to some help which I recieved from forums. I was able to get rid of this problem

This problem occurs when you are working with a new version of JDK with an older version of Oracle.

Its often good practice to check the compatibility tables for JDK , Oracle database and driver versions before trying to code.

In my case I was using ojdbc6.jar which is the latest an compatible for oracle 11g as well and works well with JDK 6. However the database I was trying to connect to was Oracle 8.1.7.

Hence this wierd error.

To solve the problem I simply added an older version driver namely classes12.jar.

Other thing to note is there is a significant difference in the package name for the OracleDriver class.

In order to find the current version of oracle you are running we can use:

select * from product_component_version

SingleConnectionDataSource Oracle supressClose

org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Connection was closed in SingleConnectionDataSource. Check that user code checks shouldClose() before closing Connections, or set 'suppressClose' to 'true'
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:238)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:377)
at org.springframework.test.AbstractTransactionalSpringContextTests.startNewTransaction(AbstractTransactionalSpringContextTests.java:387)
at org.springframework.test.AbstractTransactionalSpringContextTests.onSetUp(AbstractTransactionalSpringContextTests.java:217)
at org.springframework.test.AbstractSingleSpringContextTests.setUp(AbstractSingleSpringContextTests.java:103)
at junit.framework.TestCase.runBare(TestCase.java:132)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.sql.SQLException: Connection was closed in SingleConnectionDataSource. Check that user code checks shouldClose() before closing Connections, or set 'suppressClose' to 'true'
at org.springframework.jdbc.datasource.SingleConnectionDataSource.getConnection(SingleConnectionDataSource.java:190)
at org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:133)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:200)


While trying to perform unit tests on the various dao methods I had written for an Oracle database (8.1.7) using a SingleConnectionDatasource i came across this exception.

As a result I had to set suppressClose to true for the data source and manually close the transaction after each test case, using the tearDown method like following:

@Override
protected void onTearDown() throws Exception {
super.onTearDown();
Connection con = DataSourceUtils.getConnection(getJdbcTemplate().getDataSource());
DataSourceUtils.releaseConnection(con, getJdbcTemplate().getDataSource());

}

This helps to avoid the above problem