My WAR application is deployed to Amazon Elastic Beanstalk. They don't support JNDI, but I need it for JPA and unit tests. What JNDI context factory I can use as a workaround? I need a simple open source solution, that would allow me to configure entire factory through jndi.properties. I tried GuiceyFruit, but looks like it doesn't allow data source configuration inside one file. Any suggestions?
ps. OpenEJB will work, but it's an overkill for such a simple task
Try Simple-JNDI. It gives you an in-memory implementation of a JNDI Service and allows you to populate the JNDI environment with objects defined in property files. There is also support for loading datasources or connection pools configured in a file.
To get a connection pool you have to create a file like this:
type=javax.sql.DataSource
driver=com.sybase.jdbc3.jdbc.SybDriver
pool=myDataSource
url=jdbc:sybase:Tds:servername:5000
user=user
password=password
In your application you can access the pool via
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("path/to/your/connectionPool");
You can find more about it at https://github.com/h-thurow/Simple-JNDI.
Related
How to bind a JDBC datasource to JNDI context java:comp/env/jdbc only using code-based approach.
We need to write resource-ref in the web.xml for binding a dataSource to JNDI local context java:comp/env/jdbc.
But I want to use only org.springframework.web.context.AbstractContextLoaderInitializer instead of web.xml(the old approach).
We know the method InitialContext#createSubcontext. But some application servers(e.g. Websphere) do not accept to edit the context java:comp/env/jdbc/.
Any solutions?
Versions:
Spring 4.0.7
Servlet 3.0
You could try a full programmatic approach using Spring's SimpleNamingContextBuilder:
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
DataSource ds = new DriverManagerDataSource(...);
builder.bind("java:comp/env/jdbc/myds", ds); // you control the datasource
builder.activate();
It's mainly there for test-purposes. If you choose to use it then you need to provide your own connection pool (e.g. Apache's Jakarta Commons DBCP).
I once used for testing when I deployed to cloudbees. see this blogpost
This works in "plain" Tomcat. I don't have a EE server to test with, but you could try it and see what happens (I guess the JNDI binding name has to be unique to the server though).
What is your application server?
See if this helps.
How to use JNDI DataSource provided by Tomcat in Spring?
How I can create web application project which is loading the jndi datasource set in the server configuration? I want to make the web application independent from the server and the database. Is it possible.
You create the DataSource in your web/application server and expose it through JNDI
You configure the following hibernate property:
<property name="hibernate.connection.datasource">java:comp/env/jdbc/MyDataSource</p>
This way the application is decoupled from the JNDI provider. Even the JNDI url can be configured using a Maven property, so switching to an application server (that uses a different JNDI resource pattern) is just a mater of adding a new Maven profile.
One better approach is to set up the DataSource in your application configuration.
#Autowired
private DataSource dataSource;
...
properties.put("hibernate.connection.datasource", dataSource);
This way you can use any connection pooling framework, like the fastest connection pooling framework, HikariCP.
You can even set up DataSource proxies, like:
datasource-proxy, to log SQL queries with PreparedStatement parameters
FlexyPool, to monitor connection pooling usage and adjust the pool size using adapting startegies
In a java application, If we want to use javax.sql.DataSource instead of java.sql.DriverManager to get connections, which approach would be better to create DataSource and WHY?
Create DataSource in the application itself at the application startup time
or
Configure DataSource in the application server and get it via JNDI
Well, it actually depends upon the requirement. You can take this as a general rule.If you have multiple applications and sharing the same DataSource, then it can be a good choice to configure the DataSource in the server. Otherwise, if this is the only application uses the DataSource, then you can have it in the application level itself.
What I am trying to do is to retrieve a DataSource from a locally running JBoss (EAP 5.1) per JNDI.
It works fine inside a deployed DAO, but I seem to misunderstand something as when I am trying to get the DataSource in a test case, I keep getting a javax.naming.NoInitialContextException when trying
Properties env = new Properties();
env.put(Context.PROVIDER_URL, "jnp://localhost:1099");
final InitialContext ic = new InitialContext(env);
ds = (DataSource) ic.lookup(DATASOURCE_NAME);
If i add
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
I get a ClassNotFoundException for the org.jnp.interfaces.NamingContextFactory
Being new to JNDI and JBoss, I'm stuck at that point. Searching the web just adds to my confusion as all I find are scattered pieces of info that I try to apply by trial-and-error with no real progress.
Thank you
What functionality is it that you are testing? Is it the retrieval of a DataSource or some actual database code? If the latter, then I would suggest not using JNDI at all and using a local DataSource implementation.
This thread shows how to use Commons DBCP to set up local DataSources.
http://forum.springsource.org/showthread.php?16670-Problem-running-JUNIT-test-with-JNDI-datasource
If you really need the JNDI aspect, this example shows how to populate an InitialContext with a minimum of values to get a DataSource back. You can probably use the same Commons DBCP config as above to configure the DataSource(s) that you need.
http://blogs.oracle.com/randystuph/entry/injecting_jndi_datasources_for_junit
I have a .properties file in my application which contains dataSource properties.
I set up a JNDI reference to this dataSource using the following code :
// first I create MyDataSource from the properties found in the .properties file
//then :
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind(jdbc/oracle/myDataSource, MyDataSource);
If I use a lookup in this application, the dataSource is found :
Context initContext = new InitialContext();
BasicDataSource dataSource =
(BasicDataSource) initContext.lookup("jdbc/oracle/myDataSource")
//everything works fine and I can use my dataSource to getConnection,
//requests, etc...
Now I would like to use this dataSource in another application. But if I do the same lookup than previously, I don't find myDataSource (whereas there is still the previous application in tomcat and the jndi binding is done on start-up with the help of a listener).
How can I get myDataSource in this second application, given that I can't use a Tomcat's resource in server.xml or a context.xml file (for different reasons I have to use this .properties file)?
Thanks
"local" JDNI directories are read-only in Tomcat. Nevertheless, you can bind "global" JNDI resources in a LifecycleListener, and then "link" them to your context(s)(*):
You need to implement org.apache.catalina.LifecycleListener http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/LifecycleListener.html
Then register it in your server.xml like this (along with the other listeners):
<Listener className="yourlistener.YourLifecycleListener"/>
Your listener should await for 2 events:
public void lifecycleEvent(final LifecycleEvent event) {
if (Lifecycle.START_EVENT.equals(event.getType())) {
// Create your datasource instance...
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind("jdbc/oracle/myDataSource", myDataSource);
} else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
// unbind...
}
}
Then you'll have to propagate resource accesses by "linking" them from "global" JNDI directory to "local" JNDI directory using ResourceLink element in your META-INF/context.xml:
<ResourceLink name="jdbc/oracle/myDataSource" global="jdbc/oracle/myDataSource"
type="javax.sql.DataSource" />
That worked for me so far.
(*) Some notes:
There's an advantage on using lifecycle listeners. Since the order of context creation is not guaranteed. The advantage is that all of your contexts will see this object created.
If you need to create and configure datasource creation more dynamically that on lifecycle listener creation, note that you can bind a custom class implementing the Factory pattern.
To avoid classloading incompatibility problems, consider putting your listener, datasource, etc. classes in a jar file in the Tomcat lib directory, so they're included y the common classloader.
Regards.
What you are trying to do is not going to work. J2EE applications are not allowed to modify the JNDI environment provided by the application server (J2EE spec, section 5.2.2) and the Tomcat JNDI documentation also states, that each web applications gets each own read-only JNDI environment. I'm not sure why binding/rebinding your datasource is not failing immediately and why it's working within the same web application, but even such application-internal usage of the JNDI environment is undocumented behaviour, which I would not rely on.
A couple people have already commented on this, but I think the answer to your question is: Tomcat has a file called server.xml that you need to use. A good reference I have used before is below:
http://tomcat.apache.org/tomcat-5.5-doc/jndi-resources-howto.html
Resources defined here will be visible to all apps deployed (if set up correctly). If you set up a JNDI resource in your apps context or web xml file, it should only be available to your app.
JNDI context are private to each webapp. Context created in one app can't be accessed by others.
Try to create an entry in GlobalNamingResources and links in both webapps using <ResourceLink> to see if it works.
I used this setup before to read from both apps but never tried to write from one. So not sure if it will work.
Actually, it is possible to access others JNDI resources, if the servlet implements org.apache.catalina.ContainerServlet. This interface has a org.apache.catalina.Wrapper attribute, that is "populated" by the container itself.
through that, I created a simple application to monitor resources.
BUT, I would like to do that in a listener, so my resource monitor could start when the container starts. Anyone knows a way?