My question is rather complicated. I'll do my best to elucidate the issue.
I have written my own web framework based on servlets. Obviously, my framework has it's own XML config file (i.e.: /WEB-INF/myconfig.xml). Now, as I was developing the framework (and a few applications which run on it), I was using NetBeans as my IDE, and used the bundled Tomcat server. Essentially, I let NetBeans take care of all the details of deploying the application. It output the exploded application into a directory, and Tomcat ran it from there. It also output a .war file, but Tomcat wasn't loading it.
Now I've finished the apps and I went through the process of setting up Tomcat, mod_jk, and Apache on the production server. I got it all set up and stuck the .war file which NetBeans made into the proper folder. However, the application didn't work. I checked the log files and determined that Tomcat/mod_jk/Apache are all configured correctly because log messages from my framework are showing up in the Tomcat logs, followed by some revealing exceptions/stack traces: my framework can't find it's configuration file.
I was using the following code to get the absolute path of the root of the web application:
then I could append "/WEB-INF/myconfig.xml", and build it with JDOM. However, the servlet API docs say that ServletContext.getRealPath() returns null if the application is deployed from a .war file. That's why my framework couldn't find its config file. It was looking for "null/WEB-INF/myconfig.xml", which obviously is not valid.
I also explored Class.getResource(). However, as I understand it, this technique will fail when the servlet container doesn't expand .war files (Tomcat does by default, but can be configured to not do so).
So, I guess there are two options, neither of which I know how to do.
1) Build the .war file with the configuration file inside of it, and then somehow load the configuration file using a path relative to the root of the .war file.
2) Or, even better, have the configuration file outside of the .war file, and load it. Somehow. The challenge is in getting the location of the file to my framework. I'm fresh out of ideas.
I would really like to do number two, but I could live with number one.
I really don't know how to explain this dilemma without being so verbose, so I've had limited success googling for solutions. Hence this post.
You may place the file inside some directory of your war. Say for example, conf directory inside myApp.war. Later on maybe from some startup servlet(or any other java code) of your application, you can do:
If you are building a web-framework you might be interested how other frameworks handle this!
Struts for instance does something similar. You could download the sources and have a look. It is open-source so it is allowed to do this! The config loading is in the "ActionServlet" class if I remember correctly.
In my opinion, you shouldnt have used an IDE to **deploy** your application on to the server. Admittedly it may be a bit easy and quicker initially, but my experience has been that it often shields you from a lot of internal configuration quirks of your particular server, stuff which would be handy to know in the long term scheme of things. I would recommend that you use a build tool like 'ANT'. Enough said
Option 2 may not be too scalable.Unless you are prepared to be tied to the container vendor and even then there is no guarantee that things will always work correctly. For example, assume that you ship your application to some other machine for deployment. Where is the configuration file going to go?
There has been a post about using the ClassLoader's getResourceAsStream() method. An even better option is to use the ServletContext's version of this method. So if the configuration file is inside a folder called conf which is just below your web application root,
benjamin van der veen
Joined: Sep 11, 2006
Thanks for the suggestions. Using the getResourceAsStream() method, I got my configuration file to load, but now I'm faced with writing a custom Velocity ResourceLoader to load templates from a .war file. If possible, I'd like to be able to use the same code to load from both the .war and a physical directory (so templates can be edited without modifying the .war file).
I have tried doing some reseach on ServletContext.getResourceAsStream(), but I've come up dry. You guys indicated that it works when your application is deployed as a .war file, but does it behave the same way if your application is not in a .war file, but rather a physical directory structure? Also, suppose I had a "conf" directory in a .war file, but I also had a physical directory called "conf" alongside the .war file. That would render the following code ambiguous:
This is assuming, of course, that you can have both a .war and a physical directory structure in one webapp folder and Tomcat will recognize both. I'm not sure but it seems reasonable that Tomcat might do this. Correct me if I'm wrong.
The ServletContext's getResourceAsStream() (and the getRealPath()) method both work for resources that are part of the web application (either a war or an exploded directory in webApps). Any other physical directory inside the webapps folder that's not a web application will not be recognized by tomcat. Neither will it return you file or stream handles to resources in these directories.
Also, suppose I had a "conf" directory in a .war file, but I also had a physical directory called "conf" alongside the .war file. That would render the following code ambiguous: servletContext.getResourceAsStream("conf/myconfig.xml")
It would always refer to the conf folder in your war file. And note your path ought to start with a "/" which represents the context root (that in itself removes the ambiguity, doesnt it?)
Ideally your templates ought to be part of the web application. Placing them in a directory outside your context directory makes it non-scalable, especially when deploying to other systems.
However if you have to do it, here's a slightly roundabout approach. Have a property file inside your web application. This file has a property (name/value pair) that specifies the location of the external folder that contains your templates.
Name this file as template.properties and place it in the conf folder in your web application.
Your web application code reads in this property file, retrieves the property that is the path to the templates directory and creates a File object on that directory.
To make life easier, this may be done in a ServletContextListener which fires on application startup and the directory path can be set as an application wide attribute.
Note: The listener has to be registered in web.xml
Does that help? ram. [ September 13, 2006: Message edited by: ramprasad madathil ]