Until now, I solved this problem by creating a fragment bundle to the Apache Commons DBCP bundle. This fragment bundle contains the driver jars and adds them to the bundle class path. As a result, the class path of the DBCP bundle is extended with the jars and the driver can be found when creating a data source. Problem solved.
With the OSGi 4.2 enterprise specification, a different solution is provided: the JDBC service interface. This interface contains methods for creating Driver, DataSource, ConnectionPoolDataSource and XADataSource objects. In short, anything you may want from an enterprise point of view. Since I want to make use of standard OSGi solutions where possible for the re-factoring I am doing, a JDBC service is the way I want to go. Unfortunately, I could not find any implementation (yet?) for this service for MySQL, which is the database type I am using for the application.
As a result I wanted to create an implementation myself. However, I found that the specification about the JDBC service is at some points unclear or incorrect where it applies the properties that can be passed to the various methods of the DataSourceFactory. As a result, I made my own assumptions/changes:
- It is possible to pass the database URL as property. However, it is also possible to pass separately the server host name, port number, protocol, etc. I assume that when an URL is passed, that one takes precedence over the individual fields. If you want the URL to be automatically constructed, use the individual properties.
- According to the specification, it is possible to pass connection pool settings to the ConnectionPoolDataSource and XADataSource methods. But, according to the APIs of those interfaces, actual pool management is done outside the data source: the data sources just return a database connection without pooling behaviour. Pool settings are therefore meaningless for those data sources. I however took the settings for creating a connection pool for normal data sources (as returned by the createDataSource method).
- There is no indication about the time unit for JDBC_MAX_IDLE_TIME. I assume it is in ms.
- I really haven't a clue about the meaning of the JDBC_ROLE_NAME and JDBC_PROPERTY_CYLE properties. I silently ignore them.
If you are curious, here is what you need to get it working:
- Download Apache Commons DBCP (my version is 1.4) and Apache Commons Pool (my version is 1.5.5). The jars from the distribution archive are already bundles so just need to be loaded into your OSGi framework.
- Download the MySQL driver (my version is 5.1.13). The driver jar from the distribution is a bundle as well, so again just load the jar into your OSGi environment.
- Download the enterprise specification code from the OSGi site and load the jar as bundle in your OSGi environment.
- Download the service implementation and install/start the bundle.
DataSourceFactory factory = ... lookup service ...
Properties props = new Properties();
props.put(DataSourceFactory.JDBC_DATABASE_NAME, "database");
pops.put(DataSourceFactory.JDBC_USER, "root");
props.put(DataSourceFactory.JDBC_PASSWORD, "root");
props.put(DataSourceFactory.JDBC_SERVER_NAME, "localhost");
props.put(DataSourceFactory.JDBC_MAX_POOL_SIZE, 8);
props.put("validationQuery", "SELECT 1 FROM DUAL");
props.put("testOnBorrow", true);
DataSource source = factory.createDataSource(props);
or with Spring-DM beans (assuming you are using CM for property management):
<bean id="dataSource" class="org.avineas.jdbc.service.DelegatingDataSource">
<constructor-arg>
<osgi:reference interface="org.osgi.service.jdbc.DataSourceFactory"
filter="(osgi.jdbc.driver.class=com.mysql.*)"/>
</constructor-arg>
<constructor-arg>
<osgix:cm-properties persistent-id="hc.datasource">
<prop key="url">jdbc:mysql://localhost/database</prop>
<prop key="user">me</prop>
<prop key="password">mypassword</prop>
<prop key="maxWait">30000</prop>
<prop key="validationQuery">SELECT 1 FROM DUAL</prop>
</osgix:cm-properties>
</constructor-arg>
</bean>
I'm a newbie to using OSGi's JDBC service. Could you give an example of looking up that DataSourceFactory?
ReplyDelete