I would like to configure a DataSource using JNDI in a Java SE app. What is the best way to do this?
So far, I've come across 2 projects:
Apache Naming. The project page has a specific example for configuring a data source, but it looks like the project is super old and no longer active.
JBossNS. It looks like it's easy to configure a local-only JNDI using LocalOnlyContextFactory, but I haven't found any docs on how to actually configure a data source.
If possible, I would like to also configure the data source with a JTA transaction manager (using JOTM?).
Why are you using JNDI for this? It's not that it's a bad solution if you have a provider but there are alternatives such as dependency injection (IoC: via Spring or Guice).
The Spring JDBC data access is described here. The great thing is that you can use Spring to inject a DataSource into your code:
<bean class="com.my.Persister">
<property name="dataSource" ref="dataSource" />
</bean>
The data source can be defined using a JNDI-lookup:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource" />
In a test environment, you could inject the data source directly:
<bean id="dataSource" class="apache.db.PoolingDataSource">
<!-- config goes here -->
</bean>
These references are pretty old but may help to use jnpserver (JBoss Naming Service provider):
Working With JNDI In A J2SE Application
Standalone JNDI server using jnpserver.jar
A very easy to use solution for stand-alone JNDI is simple-jndi. It works like a charm as long as you only need it within a single JVM, since it's a library no network server.
The Simple-JNDI version, referenced by klenkes74, is not under active development any more. Because I encountered some issues with it I forked it, did some bug fixes and implemented some new features. I already used the old version not only for testing but in production too because I prefer a Service Locator pattern over Dependency Injection although the latter one is more trendy nowadays.
You can easily use Simple-JNDI to define a DataSource or a connection pool declaratively and get it bound to a JNDI Context.
Define a jndi.properties file in your classpath:
java.naming.factory.initial=org.osjava.sj.SimpleContextFactory
org.osjava.sj.root=[absolute_or_relative_path_to_a_property_file]
The property file looks like:
type=javax.sql.DataSource
driver=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost/testdb
user=testuser
password=testing
Now you can access your DataSource from inside your code this way:
InitialContext ctxt = new InitialContext();
DataSource ds = (DataSource) ctxt.lookup("name_of_your_datasource");
For more information see https://github.com/h-thurow/Simple-JNDI
Related
I have a web application which is initialised using spring and built using maven.
The various properties are loaded using properties files which are statically present. Since various environments require different values for the same properties, i use maven profiles to load different properties files depending upon the environment at build time.
Ex:- dev.properties for dev environment and prod.properties for production environment.
Now i want to make the build independent of the properties files,
The value of the properties will be fetched from some datasource(zookeeper) during context initialisation.
How to load the properties before the context is initialised?
Spring Cloud Config Zookeeper offers a way to do that. I posted a brief example of use here
Properties is just one of Java class and that Apache Configuration project exactly provides such an abstraction. I just showed you a sample for JDBC, but there is really many other stuff there. Here is a sample how I load properties from DB StoredProcedure:
<jee:jndi-lookup id="dataSource" jndi-name="DS"/>
<bean id="storedProcedureConfiguration" class="com.my.proj.config.StoredProcedureConfiguration"
p:dataSource-ref="dataSource"
p:sqlQuery="pki_props.getProperties"/>
<bean id="propertiesFromDB" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
p:staticMethod="org.apache.commons.configuration.ConfigurationConverter.getProperties"
p:arguments-ref="storedProcedureConfiguration"/>
<context:property-placeholder properties-ref="propertiesFromDB"/>
So, you can implement your own AbstractConfiguration to load Properties from Zookeeper and inject it to the <context:property-placeholder>.
In the java constructor, simply set a connection to the Zookeeper server and get the needed data using the zookeeper client methods. You can find examples here: http://zookeeper.apache.org/doc/trunk/javaExample.html
It would look like this (but you would have to elaborate this)
public YourConstructor() {
Zookeeper zk = new ZooKeeper(host,...);
zk.getData(...);
}
Found couple of blogs providing steps to define jndi datasources and then accessing from Spring Container.
Method 1 :
1. Creating a file context.xml in src\main\webapp\META-INF folder and defining all
relevant jndi datasources.
2. Accessing jndi datasource from spring application context.xml file by using
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/MyDB"/>
</bean>
I tried above configuration and this works.
I found some other approaches too.
Method 2 : http://makecodeeasy.blogspot.in/2013/05/jndi-datasource-in-spring.html and Tomcat 6/7 JNDI with multiple datasources where
1. Datasources are defined in server.xml file (tomcat) and refered in web.xml file.
2. Accessing jndi datasources from spring application context.xml file
using JndiObjectFactoryBean with an additional resource ref attribute.
Again. what about using below line to achieve Step 2 in above two methods.
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/MyDB" />
Basically I want to know which one is better server connection pooling mechanism. Is there any advantage of one approach over other. Which one is advanced and why?
==EDITED==
Once spring application context gets datasource related info through jndi defined in context.xml, how do Junit testcases which run Standalone not in Web Container would access JNDI resources ?
Can someone help me in figuring out these.
Looking at this documentation, it seems that both methods do exactly the same thing.
As far as connection pooling is concerned, JNDI lookups have nothing to do with that. Whatever connection pool you declare in context.xml (or whatever equivalent you use) will be looked up and used by Spring. If you declare BoneCP as your connection pool then that will be used, likewise if you use the Tomcat Connection pool or whatever else.
Recently I started a maven project to build an application for integrating
Spring, JPA, JSF
But in the automatically generated folder structure I can see one file named as
db.properties
and also I have one
persistence.xml
Now my question is that Database connection can be defined in either of these files, Can anybody tell me
1. Which way is better and why ?
2. Why there is db.properties file automatically generated while I already have persistence.xml ?
db.properties file is like messages.properties which is used to define key value pair. And after that we will use keys in expression language. So configurations will only be done in
persistence.xml or dataSource.xml
whichever is preferred choice but the values we will take from db.properties in the form of expression language eg.
driverClassName=com.mysql.jdbc.Driver
this is an entry in your db.properties. and you will use it in persistence.xml as follows.
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}" />
I assume, from the fact that you mention JSF, that you are building a web application for deployment to an application server. I also caveat this question in that I don't know about db.properties or where it comes from.
When deploying to an application server, it is always best to configure your database connections in the container and expose them to the application via JNDI. This allows the container to manage connection pooling and credentials and keeps this information out of your WAR/EAR files. It also ensures that your WAR/EAR files are agnostic to the particular database instance, so can be deployed to a container in any environment without modification.
Therefore, I recommend against configuring your datasource in persistence.xml.
See also Difference between configuring data source in persistence.xml and in spring configuration files which is a similar question- the accepted answer there expresses the solution in more detail.
Note: Although at first similar, this is not a duplicate of Using Spring, JPA with Hibernate to access multiple databases/datasources configured in Jboss
Dear Stackoverflow,
I had a spring-jpa with hibernate application running on jboss-4.2.1.GA and using a single database.
I now have a second spring-hibernate project bundled up in the same ear file with the project described above but it needs to use a second database. This second hibernate/spring project is set up with the database.properties and hibernate.cfg.xml files.
The two databases details are stored on jboss oracle-ds.xml file:
<datasources>
<local-tx-datasource>
<jndi-name>DefaultDS</jndi-name>
...
</local-tx-datasource>
<local-tx-datasource>
<jndi-name>SecondDS</jndi-name>
...
</local-tx-datasource>
</datasources>
My question is, in the second project, with objects for the second database and not the first one, how can I call sessionFactory for the second database whose details are stored on the oracle-ds.xml instead of using database.properties files?
I have seen an example calling
#Resource(mappedName = "java:SecondDS")
private DataSource secondDS;
...
java.sql.Connection conn = secondDS.getConnection();
If it is that easy to obtain a connection, that is only useful for prepared statements, how can I in get hold of the sessionFactory? Is there a similar approach?
All examples I have seen refer to database.properties and not the jboss ds.xml file.
Thanks in advance
There is several solution, depending on how you bind the data source to a presistance context, Spring way, JPA way or Hibernate way....
Spring
To link spring/hibernate application to JNDI data source, you will need to use JndiObjectFactoryBean
<bean id="serverDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/blah"/>
<property name="proxyInterface" value="javax.sql.DataSource"></property>
</bean>
This way you have a spring bean representing the JNDI data source. You will need to create 2 of them (one for each of you data source). They you need to inject the data source in your spring defined SessionFactory. The same can be use if you use Spring managed JPA entity manager.
JPA
If you are using JPA (session factory is hibernate not jpa...) you can also defined a jndi data source name in the corresponding persistance.xml file.
<persistence-unit name="sample">
<jta-data-source>java:/DefaultDS</jta-data-source>
...
</persistence-unit>
You need to use unitName parameter when injecting the entityManager:
#PersistenceContext(unitName="sample")
Hibernate
For hibernate.cfg.xml file you can specify the JNDI data source with this property
<property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
The database.property should be removed to be sure the jndi data source is used.
These are only example, the final result will depend on how you made your plumbing.
I'm using Spring and Hibernate and want to do some intergration testing with DBUnit. In my application-context.xml I currently specify a datasource via jndi-lookup which reads the jndi-name from a properties file:
<jee:jndi-lookup id="dataSource"
jndi-name="${datasource.myapp.jndi}"
cache="true"
resource-ref="true"
proxy-interface="javax.sql.DataSource" />
I'd like to swap this out to an in memory database (hsqldb, h2 etc) for integration testing by just supplying a new properties file, is this possible? Or should I just use a different application-context.xml for the integration testing?
You can either have separate application contexts for prod and test or specify a default data source for the JNDI data source that should be used if the lookup fails. Then don't have a JNDI data source configured on your integration test environment. Spring will automatically fail over to the in-memory source when the lookup fails.
This is why Spring 3.1 introduced profiles: http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/
Upgrade application to 3.1 or use different configs for integrations tests.
Move the datasource bean definition to a separate config file (infrastructure-config.xml), create another version of it called test-infrastructure-config.xml in which you can define a datasource either using the jdbc:embedded-database tag
<jdbc:embedded-database type="hsql">
<!-- in case you want to populate database, list the sql script files here -->
<jdbc:script location=".."/>
<jdbc:script location=".."/>
</jdbc:embedded-database>
Once you do this you specify the main application-context.xml and test-infrastructure-config.xml for out of conatiner testing and with the infrastructure-config.xml for deployment.
Use a #Bean to define your datasource. In that method you can use conditional logic to determine the environment and either do the JNDI lookup or connect to your in-memory DB.