19 February 2010

Using DataSource in non-managed (standalone) java applications

I've wrote bunch of utility classes that facilitate working with java datasource interface in standalone java applications

1- the XML file : "datasource.xml"
 <?xml version="1.0" encoding="UTF-8"?>  
<datasource jndi="jdbc/testds" >
<initail-context-factory>com.sun.jndi.rmi.registry.RegistryContextFactory</initail-context-factory>
<provider-url>rmi://localhost:4099</provider-url>
<datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource</datasource-class>
<username>root</username>
<password>system</password>
<connection-url>jdbc:mysql://localhost:3306/test</connection-url>
</datasource>


2- a wrapper class that wraps this XML file "DataSourceWrapper"
 package org.daz.ds;  
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class DataSourceWrapper {
private static Document datasourceDoc;
private static DatasourceXmlMapping dsXmlMapping = null;
public static String getJndi() {
return dsXmlMapping.getJndi();
}
public static String getInitialContextFactory() {
return dsXmlMapping.getInitialContextFactory();
}
public static String getProviderUrl() {
return dsXmlMapping.getProviderUrl();
}
public static String getDataSourceClass() {
return dsXmlMapping.getDatasourceClass();
}
public static String getUsername() {
return dsXmlMapping.getUsername();
}
public static String getPassword() {
return dsXmlMapping.getPassword();
}
public static String getConnectionUrl() {
return dsXmlMapping.getConnectionUrl();
}
static {
try {
init();
initDatasourceXmlMapping();
}catch (Exception ex) {
throw new RuntimeException(ex.getMessage(), ex);
}
}
private static void init() throws Exception{
InputStream is = DataSourceWrapper.class.getClassLoader().getResourceAsStream("org/daz/ds/datasource.xml");
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
datasourceDoc = docBuilder.parse(is);
is.close();
}
private static void initDatasourceXmlMapping() {
final String datasource = "datasource";
final String jndi="jndi";
final String initailContextFactory = "initail-context-factory";
final String providerUrl = "provider-url";
final String datasourceClass = "datasource-class";
final String username = "username";
final String password = "password";
final String connectionUrl = "connection-url";
dsXmlMapping = new DatasourceXmlMapping();
Node datasourceNode = datasourceDoc.getDocumentElement();
Node jndiAttr = datasourceNode.getAttributes().getNamedItem(jndi);
if (jndiAttr == null)
throw new RuntimeException(jndi + " Attribute of " + datasource + " Element is null!");
dsXmlMapping.setJndi(jndiAttr.getNodeValue());
NodeList list = datasourceNode.getChildNodes();
for (int i=0; i <list.getLength(); i++) {
Node currentNode = list.item(i);
if (initailContextFactory.equals(currentNode.getNodeName()))
dsXmlMapping.setInitialContextFactory(currentNode.getTextContent());
if (providerUrl.equals(currentNode.getNodeName()))
dsXmlMapping.setProviderUrl(currentNode.getTextContent());
if (datasourceClass.equals(currentNode.getNodeName()))
dsXmlMapping.setDatasourceClass(currentNode.getTextContent());
if (username.equals(currentNode.getNodeName()))
dsXmlMapping.setUsername(currentNode.getTextContent());
if (password.equals(currentNode.getNodeName()))
dsXmlMapping.setPassword(currentNode.getTextContent());
if (connectionUrl.equals(currentNode.getNodeName()))
dsXmlMapping.setConnectionUrl(currentNode.getTextContent());
}
}
public static class DatasourceXmlMapping{
private String jndi;
private String initialContextFactory;
private String providerUrl;
private String datasourceClass;
private String username;
private String password;
private String connectionUrl;
public String getInitialContextFactory() {
return initialContextFactory;
}
public void setInitialContextFactory(String initialContextFactory) {
this.initialContextFactory = initialContextFactory;
}
public String getProviderUrl() {
return providerUrl;
}
public void setProviderUrl(String providerUrl) {
this.providerUrl = providerUrl;
}
public String getDatasourceClass() {
return datasourceClass;
}
public void setDatasourceClass(String datasourceClass) {
this.datasourceClass = datasourceClass;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConnectionUrl() {
return connectionUrl;
}
public void setConnectionUrl(String connectionUrl) {
this.connectionUrl = connectionUrl;
}
public String getJndi() {
return jndi;
}
public void setJndi(String jndi) {
this.jndi = jndi;
}
}
}


3- a class that you have to extend to support more Database vendors "DataSourceVendor"
 package org.daz.ds;  
public class DataSourceVendor {
public static MethodNames getMethodNames(String vendor) {
MethodNames mn = null;
if (vendor.toLowerCase().contains("mysql")) {
mn = new MethodNames();
mn.setUser = "setUser";
mn.setPassword = "setPassword";
mn.setURL = "setUrl";
return mn;
}
throw new RuntimeException("Non-supported DBMS");
}
public static class MethodNames{
public String setUser;
public String setPassword;
public String setURL;
}
}


4- a class that manage the whole last staff : "DataSourceManager"

 package org.daz.ds;  

import java.lang.reflect.Method;
import java.rmi.registry.LocateRegistry;
import java.util.Hashtable;
import java.util.logging.Logger;

import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.daz.ds.DataSourceVendor.MethodNames;

public class DataSourceManager {

private Logger logger = Logger.getLogger(DataSourceManager.class.getSimpleName());

public void startRegistry() throws Exception{
final String providerUrl = DataSourceWrapper.getProviderUrl();
final char separator = ':';
int rmiPort = Integer.parseInt(providerUrl.substring(providerUrl.lastIndexOf(separator) + 1));
System.out.println(rmiPort);
LocateRegistry.createRegistry(rmiPort);
}

public void storeDatasource() throws Exception{
Hashtable<string,> env = new Hashtable<string,>();
env.put(InitialContext.INITIAL_CONTEXT_FACTORY, DataSourceWrapper.getInitialContextFactory());
env.put(InitialContext.PROVIDER_URL, DataSourceWrapper.getProviderUrl());
InitialContext ctx = new InitialContext(env);

DataSource ds = (DataSource) Class.forName(DataSourceWrapper.getDataSourceClass()).newInstance();
logger.info("Using Datasource class : " + DataSourceWrapper.getDataSourceClass());

MethodNames mNames = DataSourceVendor.getMethodNames(DataSourceWrapper.getDataSourceClass());

Method m1 = ds.getClass().getMethod(mNames.setUser, String.class);
m1.invoke(ds, DataSourceWrapper.getUsername());
Method m2 = ds.getClass().getMethod(mNames.setPassword, String.class);
m2.invoke(ds, DataSourceWrapper.getPassword());
Method m3 = ds.getClass().getMethod(mNames.setURL, String.class);
m3.invoke(ds, DataSourceWrapper.getConnectionUrl());
logger.info("Using Connection Url : " + DataSourceWrapper.getConnectionUrl());
ctx.rebind(DataSourceWrapper.getJndi(), ds);
}

public DataSource getDatasource()throws Exception{
Hashtable<string,> env = new Hashtable<string,>();
env.put(InitialContext.INITIAL_CONTEXT_FACTORY, DataSourceWrapper.getInitialContextFactory());
env.put(InitialContext.PROVIDER_URL, DataSourceWrapper.getProviderUrl());
InitialContext ctx = new InitialContext(env);
return (DataSource) ctx.lookup(DataSourceWrapper.getJndi());
}
}


5- a Test class :

 package org.daz.ds;  
import java.sql.Statement;
import javax.sql.DataSource;
public class DatasourceTest {
public static void main(String[] args) throws Exception{
DataSourceManager dsm = new DataSourceManager();
dsm.startRegistry();
dsm.storeDatasource();
DataSource ds = dsm.getDatasource();
Statement stmt = ds.getConnection().createStatement();
stmt.executeQuery("select * from test");
}
}


Hope you find this helpful.

Thanks.

1 comment:

A.Orabi said...

OOh, so good, go on man, we all with you.