I have a servlet that I would like to run within ColdFusion MX 7. I would like to make use of an existing ColdFusion DSN as a javax.sql.DataSource, if possible.
I thought something like
coldfusion.server.ServiceFactory.getDataSourceService().getDatasource(dsname);
would work, but unfortunately the servlet returns
java.lang.NoClassDefFoundError: coldfusion/server/ServiceFactory
That code will work fine, you just don't have ServiceFactory in your classpath. Ie, Java can't load that class. Try including a dependency on cfusion.jar from C:\CFusionMX7\lib.
It seems the simplest way to do this is to add an additional JNDI datasource into jrun-resources.xml. This can then be accessed in the conventional way:
Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("mydatasource");
It does mean duplicating database connection configuration, but I would rather do this than work with the largely undocumented coldfusion.server.* classes.
Related
I'm looking to distribute my web app to many different departments of the company i work for and i'm wondering what would be the best way of allowing each deployment to provide their own database instance. I am using Hibernate and the first deployment actually creates the database and imports tons of data in it but i'm looking for the cleanest, most reliable way of allowing the users to specify their own database URL and credentials. Currently my code has a hard coded reference for the database info :
public DataSource dataSource()
{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try
{
dataSource.setDriverClass("net.sourceforge.jtds.jdbc.Driver");
String hostName = InetAddress.getLocalHost().getHostName();
dataSource.setJdbcUrl("jdbc:jtds:sqlserver://localhost:1433/MDHIS;InstanceName=ADT;sendUnicode=false");
dataSource.setUser("sa");
dataSource.setPassword("N0tY0urBu$1nes$");
}
catch (Exception ignored) {}
return dataSource;
}
I read online that you cannot easily read a config file using a relative path from a web app (by all means please crush this myth if it is one) so i was thinking of using environment variables. I want this to be completely portable and work on Ubuntu as well as Windows so not sure how well that would work. I am using a 100% annotation based method so there is no XML file whatsoever and i intend it to stay that way.
Any suggestions?
Thanks!
Thanks for the help, i ended up annotating my configuration class with :
#PropertySource("classpath:config.properties")
I then placed said file in the java folder which is the base of the classpath. I put this in the file :
dbUrl=jdbc:jtds:sqlserver://localhost:1433/MDHIS;InstanceName=ADT;sendUnicode=false
I can now access the info in the code by doing :
dataSource.setJdbcUrl(environment.getProperty("dbUrl"));
Environment is a dependency that is autowired in my Hibernate config class.
Thanks!
I am implementing JNDI concept to get a connection to Database. I googled to get the starting point, however didn't get it.
The things that i want to do is have a simple java standalone application which used JNDI concept for getting connected to a database.
Sample source that i have is:
DataSource dataSource = null;
Context context = null;
try {
context = new InitialContext();
dataSource = (DataSource) context.lookup("database_connection");
}
catch (NamingException e) {
System.out.println("Got naming exception, details are -> " + e.getMessage());
}
Now, where we define database_connection? Is that defined in an xml file, and if so where do we specify that and what format of that is?
If any pointers can be provided, that would be great.
Thanks
The real difference between your question and the examples is that you're using a standalone Java application. Pretty-much every example assumes that you're running within a Java EE application container. In that case you define the database connection to the container, use JNDI to get the DataSource, and get the connection from that.
When you do a JNDI lookup to get your DataSource, the JNDI framework looks for an initial context factory (a class that implements InitialContextFactory). In your Java EE application, the container provides that. In your standalone Java application, the initial context is null, and no further lookups resolve correctly.
One of the ways you can resolve this is to create your own initial context factory:
public class MyContextFactory implements InitialContextFactory
and inject that into JNDI at startup:
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "mypackag.MyContextFactory");
and then return a new ObjectFactory from the getInitialContext call, and then implement the ObjectFactory to return a DataSource (also probably custom) from the getConnection() call.
That would all work, but it's overkill. It would be easier to just use the normal JDBC connection string approach to get a connection directly in your application rather than trying to use a DataSource. Or use a framework like Spring to inject it for you or to separate the database connect information from the code (in which case you're using Spring configuration files rather than JNDI directly).
The one reason I'd advocate creating a custom context factory and data source approach is if you have common JPA code that you want to run both within a Java EE app and within a standalone app (it's otherwise non-trivial to configure the same code to do both). That doesn't sound like your case.
So, since you're standalone and not in a Java EE container, I think your real answer is that your use case is not appropriate for a DataSource (unless you move to a framework like Spring that would provide one).
There's a nice tutorial for that here and here
The database should be defined somewhere (LDAP)? There's a series of old articles using the directory service with JNDI (ultimately in your case to get the server information) here.
A nice introduction to naming services here
This may be a somewhat strange question, but I'm not sure how to do this another way. Basically, I am sharing connection code between two maven projects. One is a Maven Web application and the other is a regular Maven project.
To set up the database connection context, I'm using META_INF/context.xml in the Maven web application.
However, the regular Maven project doesn't use this file, so when the code to get the data source is run:
Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
dbPool = (DataSource) envCtx.lookup("jdbc/MyAppUCP");
of course a NamingException is thrown. How can I reuse this method of getting the database connection with the regular Maven java application? Copying the META_INF/ directory into the project doesn't work.
The InitialContext with default constructor works only in managed environment (j2EE container). If you need to lookup for JNDI from a Java SE process, you need to pass in a property object as parameter to the overloaded constructor.
Each app/webserver has it's own set of properties that needs to be set in the property object. Refer to app server's documentation (http://docs.oracle.com/javase/jndi/tutorial/beyond/env/source.html).
Again, there would be security constraint on looking up for JNDI entries from external process.
I'm developing a web application with Java and it needs a connection with a data base. Well administration of resources is very important. The application will be in a Tomcat 6 servlet container, and I've implemented BoneCP to manage connections (I can't use Spring).
I've read that JNDI lookup for DataSource is too much expensive and I'm thinking about creating a singleton of DataSource object, to get the JNDI resource only once, and return the same DataSource for future connections.
Question: Is it a good idea to create a DataSource only once, and get connections from the same DataSource? I don't want to get the same connection, only the same DataSource.
Thank you ;)
Use a pooling datasource, such as is described here:
http://www.javaranch.com/journal/200601/JDBCConnectionPooling.html
Yes, as Renjith suggested, you only need to create the DataSource one time. I actually ran into this same issue yesterday. Every time in my "getConnection" method I noticed I was creating a new InitialContext and DataSource unnecessarily. I revised my Connection Manager class to have a static block of code that creates the DataSource object only when the class gets loaded the first time (after reading BalusC's answer in Proper usage of JDBC Connection Pool (Glassfish))
I thought about using the old-school ServiceLocator pattern (see Pascal's answer in the above link), but I felt it was a bit too overkill for my needs.
Another possibility is that you could also use the #Resource annotation with injection on the DataSources, but that doesn't seem to work with Tomcat 7.
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?