The first of three excerpts from O'Reillys new Java Enterprise Best Practices book have been published on onjava.com. It delves into best practices for Servlet development.
Some issues discussed in this excerpt:
- Choose the Right Servlet Framework
- Use Pre-Encoded Characters (Writers versus Streams)
- Load Configuration Files from the Classpath
- Think of HTTPSessions as a Local Cache
- Don't Use SingleThreadModel... ever.
Check out the first excerpt
The TOC of the Book is impressive, hope the contents live up to the expectations,
In the section titled "Load Configuration Files from the Classpath", the author says the Servlet API lacks a standard mechanism to retrieve external configuration files.
As far as I know, this is not true. In the Servlet 2.3 spec, section "SRV.3.5 Resources" describes reading resources by using the ServletContext methods "getResource" and "getResourceAsStream". I used this last method successfully in the past, with Tomcat, to read ".properties" files from /WEB-INF.
Am I missing something, or there is in fact such a standard mechanism?
You are partially correct. Please note that using the API which you mentioned you can retrieve files from your own ear or war files. But suppose if there is a common config file, which you want to access from your application, there is no standard path in the application server to place those. In Websphere, tomcat etc. those files should be under "bin" directory. In Sun ONE app.server, it should be placed under "conf" of respective server under respective domain.
Am correct and made it clear? Any comments?
What about ClassLoader.getResourceAsStream()? Put your resources in a jar and add it to CLASSPATH, you can load them from every application.
The problem with loading from the jar (or war , or ear) is that it's all zipped up and not easy for an administrator to change. If you have network administrators who don't want developers to know message queue,database passwords then it's hard to put configuration files inside the zipped file.
Usually it's easier to put properties outside the application on the webserver/appserver classpath. This makes it much easier for administrators to just type in passwords etc and the developers don't need to be bothered.
Plus you don't need such complicated ant build scripts.
I thought that one of the great things about getResourceAsStream() is that it will find items in the CLASSPATH in general. So you could place the config in a jar file, or it could be in a directory which is in the classpath. One key is having a mechanism to get your application to reload the config, if you need that functionality.
I am quite shocked by this discussion. There is one configuration file type you are supposed to edit *when deploying*. These are called deployment descriptors. You may access flat files on paths defined therein *wherever they reside* as long as the java security settings allow you to. Also in Java 1.4 there is the preferences API that might be used to some extent. And if you have complicated configuration settings that need adjustment at deployment you can of course use getResourceAsStream. Also think about the fact that web container, conceptually, should support multiple users deploying war files into them, sometimes remotely.
I agree with Fan Zhou, Dion and others reg. the use of getResourceAsStream() to retrieve any files and as mentioned by Fan Zhou, jar which contains the config file should be made available in CLASSPATH. Is there a common way to make changes to app.server config file to add the jar in CLASSPATH, as some app.servers might use XML as config files while most other might use pure text file as config file. In short, is there an app.server independent way to add CLASSPATH settings.
Also is there any way to install our application ear file in an app.server and/or OS indepent way. This installation includes creating resources (JDBC, JMS etc.), changes in our config files for the deployed environment (asked by Peter Storch) etc.
Also, Karl, do you think a component assembler/deployer can mention the path to the file irrespective of the app.server as almost all the app.server vendors have their own directory structure for their app.servers.
I don't want to put all my application properties in the deployment descriptor. Imagine an administrator (or deployer) who has to edit this file and find the way through all the <context-param>, <init-param> tags.
.properties files works better for me.
Ok, I can deploy the .properties file(s) separately and use getResourceAsStream to read them. Then they aren't overwritten by accident with the next update and the admins don't have to unpack the .war file first. But I can think of two drawbacks here: 1) this is not a J2EE like deployment (not a single .war file). 2) if properties in the .properties file changes (add, remove) how do I tell this to the operations people? Do they have to merge the new and old .properties file?
We were thinking about splitting the .properties file. A general application.properties and a specialized application_prod.properties which overrides the properties of the gerneral one. But I'm still not happy with that.
I'm looking for a way like some installers for fat clients do. They recognize older versions of the same program and just add the new properties e.g. to the registry. Or guide the admin through the setup process.
One of the things that we do to ease deployment is create separate web.xml (or any config file for that matter) for dev, test and prod. So the files would be named as web.xml.dev, web.xml.test and web.xml.prod
when a support person builds an ear file, he builds it with an environment variable which indicates the environment and the ant script takes that web.xml.<environment> and builds the ear out of it. this would make sure that you dont hvae to overwrite ur config files for each environment.
That's the way we do it now. But that means that the development team is responsible for all config issues and has to track all the different environments in the build process.
If the production environment changes somehow, we have to to build a new version with changed properties. Or we have to synchronize the changes made in the production environment directly with the dev environment.
Now our company splittet the IT dep in development and operation and we (development) have to deploy our packages to the operation colleagues. Now it's a little bit tricky to keep track of their config changes in the production environment.
I don't want to put all my application properties in the >deployment descriptor. Imagine an administrator (or >deployer) who has to edit this file and find the way >through all the <context-param>, <init-param> tags.
>.properties files works better for me.
Absolutely. Therefore, in my opinion, there is just NO GOOD REASON AT ALL, to put such frequently changing data in the war file in the first place. On the other hand, if the configuration data just changes with each application
deployment rather than at runtime, go and provide some sensible build scripts (ant, make, whatever).
For frequently changing data, I would advocate that you put them in a well defined place that you define consistently within your organization and configure your web-app descriptor to find it. If worse comes to worse, drop some XML into the database.
From experience the spec of web.xml for config data is really flawed. There is no standard way other than bouncing the web server for this to be reread.
So, what instead? Config files (either xml or properties, don't care) which reside in a config dir, using the realpath to read them. BUT, this means they must be incuded in the war file at build time which is also flawed.
So, what instead? Using the database with a management suite to change config properties in a APP_CONFIG table which is simply key/value pairs. This is cool, decouples config from build. BUT, one of the most common config items is the db connection string...which can't go in the database.
So, what instead? Some arbitrary combination of the above. Or even an entirely seperate directory holding config items, or environment variables, or some other.
Basically, as this thread hints, there is no good solution. Just a set of adequate ones.
Is there a pattern for configuration files in .war and .ear packages?
I'm missing a solution for a flexible and maintainable configuration.
E.g. we in the development department are developing a Webapplication an give the packaged .war file including the config files to our operation department. They deploy it on the production server and adjust the config files to the production needs.
Now, what about updates? Do the operation people have to make their config changes each time over and over again?
String cfgFile = cfg.getServletContext().getRealPath("WEB-INF/myconfig.xml");
To load my configuration files, i use something like this.
Then I can use complex configuration files with xml.
You can now check out the second excerpt here
It discusses caching with servlets.
Is it appropriate to use a File handle to configure a refresh of the configuration file? I know its a pervasively used tool to get around the limitations of the InputStream class, but it is a no-no in the J2EE world.
The recurring theme in the posts to date has been the need to update the configuration of the system, independent of the code base. I think the app server market and the spec has responded well to issues of hot code deployment, but has not created a structure for updates of their dependent resources. I can have no EJB classes that requires configuration parameters. These parameters may need to be refreshed without modifying the class itself.
Do I want to deploy a new EAR or WAR to change configuration files? If the configurations are deployed as part of a jar then there exists no machinery for detecting those changes. The "getResourceAsStream" call does not give me a file handle, so I can't write code to sit and watch for updates. The alternatives involving JDBC, JMS or JMX solutions are fairly significant efforts to implement, and costly in terms of what I am trying to solve.
On a separate, but related note, as I recall, a recent posting about the Java Logging API (maybe even ONJava?) pointed out that the only implementation was a file-based system, which is inconsistent with Sun's own J2EE policy. In all seriousness, do we need a JMS or JDBC implementation of logging? Is that effort warranted to adhere to no java.io?