We are having a debate at my office around what can and cannot go in a JAR file. It has been suggested that it is poor form to have anything that is not a .class file go into a JAR. We currently have some XML configurations for Ibatis/etc, some property files.. the usual. However, there is a push to extract all such files from JARs and put them onto the local file system of each deployment machine. Does this sound reasonable?
it is poor form to have anything that
is not a .class file go into a JAR
That is nonsense. It is in fact very good form to put resources like icons and other data files that user used by the code into the JAR together with the code. This is what the getResource() and getResourceAsStream() methods of Class and ClassLoader are for, and it makes for much more robust applications than messing around with resource paths manually.
However, config files are possibly a different matter. If they're meant to be changed during or after deployment, then having them inside a JAR file is rather inconvenient, and having them in a separate directory is preferable.
If you make changes in a configuration file inside a JAR (even without altering any line of Java code), the whole JAR needs to be rebuilt and redeployed. Does this sound reasonable?
It's absolutely OK to put non-class files in a JAR file, especially resources that the application needs (images, localized strings, etc.) Knowing this, you must decide which scenario fits your situation:
If the configuration is fixed and will only change when a new JAR file is deployed, put it in the JAR.
If the configuration must be altered, either manually or by the application, store it on the filesystem.
If you choose the latter, note that it's good practice to include a default configuration in the JAR file to handle the case when the external configuration file is missing. The default can be loaded directly from the JAR or copied to the filesystem to become the new editable configuration.
It does not sound reasonable to me. I believe, that some application's configuration should be in jar file. Such things as ORM mappings, spring config, custom spring namespace XSD, other XSDs, etc.. should be in most cases in jar. It's important part of deployment artifact.
The fact, that it's not class file, does not mean, that it should be taken out of jar just because it's theoretically can be modified without building a new jar. Can you imagine a modification of *.hbm.xml in production? for me it sounds very scary.
I think some configuration, like spring xml, is meant in most cases to better organize your application and dependencies, but not to change them at runtime in production.
Do you want or expect them to be changed without a new release of the code? Then you need to extract them.
If the answer to the question in no than you shouldn't extract them, as it would allow support to tinker around with them without going through the release process. (Of course this is also possible if they are in the JAR but slightly less tempting.)
Update: But since you mentioned multiple deployment machines, there's a third option: extract them and place them in a commonly accessible area on a network drive. Manually editable config files which are replicated on several machines (but should be identical) are notorious for getting out of sync.
ORM tools (such as Hibernate or IBatis) are not really supposed to be modified once the application is deployed. So, no, I would say that it doesn't make sense for that kind of files.
Depending on your requirements, application-wide configuration files can be placed outside the Jar/War so that they can be modified without having to rebuild the jar.
Do keep in mind that modifying application parameters in production is, imho, a bad practice. Changes should be tested first in some pre-production environment.
Related
I have a situation wherein i have multiple war files with 90% code base same (controllers, html files etc).
They have some custom code for each along with different configurations.
Currently these projects are nothing but a copy of each others (with minor tweaks and config changes).
How should i approach this for creating a single module/jar from where these multiple wars can be created with minim code(their respective changes) in the war modules.
So, the common module will have all the code along with the html files and in each war module i'll just override/provide different implementation.
I am using Gradle for build.
Using Java, Spring.
Say, I have a Project FOO.
It's a web project with java classes, html, properties and configuration (beans, persistence) files and web.xml file.
I have another project BOO.
which is a copy of FOO but there are some property changes, some code changes to existing implementation and some new code of it's own.
I dont want to keep duplicate code in BOO, BOO should ideally have the new code and the changed implementation.
This is what i want to achieve.
I cant post the code as its a big project.
Hope this makes it clear.
This is perfectly a refactoring project. Your main concentration area are all config files and default servlet and default html pages. As your project codes are not available here we can not directly advice you any more. You have to carefully check configuration of each project and find a solution how you can club together all the config files. Especially concentrate in spring-bean.xml and web.xml. You must be very careful else it will take ages for you to merge all the application. Good luck.
Our system is split up into different environments, each one as a separate Tomcat instance.
Development (Windows)
QA: Accessed by our QA department (Linux)
Production: Live site, accessible to customers. (Linux)
Each of these environments rely on separate databases, and several other web services. This means we need to keep track of the various URLs, usernames, and passwords that are all different. Many of these settings are shared across several apps, so it would be ideal to have them all in one place to remove duplication.
Right now we have config files in the application itself. We use Maven profiles to fill in the different config settings when we build the app. But this is clumsy because we have to build a different WAR for each environment.
Where is a good place to store the config files so that we can deploy the same WAR file to each server?
I've done a fair amount of research on this already. But I haven't found an solution that completely makes sense to me yet.
Separate Config Directory
Define a directory to hold config files. Such as /opt/config on linux.
I like this idea, but how do I tell Tomcat where this directory is? I see references to context.xml, but every example I've seen puts the context.xml in the META-INF folder inside the WAR. Is there a way to configure this outside the WAR?
System Property to define environment
This involves setting a system property, and then using some sort of if/else or switching logic to load the appropriate config file. This seems workable, but a bit messy. But where/how do you set this property? I typically start tomcat with ./startup.sh. Do I add arguments to that command or is there another configuration somewhere?
JNDI
I don't think this is an option for us. Every tutorial I've looked at for this seems to be dependent on LDAP or something similar. To my knowledge we don't have that available to us, and it seems like too much overhead to get set up for only a half-dozen config files.
Use system property that refers to the location where your configuration file or directory is located. In this case you can manage different environment easily and no if/else logic is needed.
You application can have hard coded value of config file path, that will allow running application without any additional system property. The application however should fail to start if mandatory data is not found.
Concerning to partial sharing of data among environments.
You can split your data into several files by categories. Some files will be shared, some other different for different environments. You can even develop your own mechanism of references between data files.
However better approach is using some ready-to-use packages. For example Spring framework supports very flexible configuration mechanism. However if you already have Spring-less application introducing this framework for configuration only seems like an overkill. In this case take a look on Apache Commons Configuration package.
Worked with my team on this and we came up with what we feel is a cleaner approach. While every tutorial I found put the context.xml inside the WAR, it can also be placed in the conf folder of the Tomcat directory.
This works for us as all our servers are Tomcat based. So each server can have it's own context.xml which has a property pointing to the config folder on that particular server.
I'm distributing a simple Java webapp as open source. The webapp needs to be configured before it can be run – a configuration file needs to be created, and the location of that configuration file needs to be made known to the webapp as a parameter in web.xml.
Now my question is how to best package and distribute the webapp in order to make it easy to install, and how to describe that installation process in the documentation. The options I can think of are:
Distribute the webapp as a WAR archive. Recommend that users deploy the WAR into their Tomcat/Jetty/whatever, then drop their configuration file into /webapps/myapp/WEB-INF, and modify /webapps/myapp/WEB-INF/web.xml accordingly
Distribute the webapp as source. Recommend that users should drop their configuration file into the /src/main/webapp/WEB-INF folder, then modify their /src/main/webapp/WEB-INF/web.xml accordingly, then build a WAR using Ant or Maven, and deploy that into their servlet container.
There are probably other options that I can't think of.
What setup is likely to be most convenient to users that need to install, configure and deploy the webapp?
Edit: I should add that the configuration file isn't just a few lines – it's a large file that contains a database schema and other stuff and is potentially generated using an external editor; so just providing good defaults isn't an option.
Externalize this configuration and maybe provide some default values. If you make a new version of your app, everybody will have to remember to back-up that configuration file, then redeploy and then copy back that file--> this is a nightmare.
There are many ways to put that configuration somewhere else. You can use Java Preferences for example.
I would say the WAR, although not requiring the configuration would likely be more convenient :)
What is it, loosely, that must be configured such that there isn't a sensible default value for everyone? URL string?
Providing an answer of my own, after more reading on the issue: JNDI seems to be the “official”, although somewhat heavyweight, way of solving this. With JNDI, a configuration option (like the location of the full config file I need) can be declared in the web.xml, and its actual value can be set in a per-webapp context.xml that lives in the /webapps directory of Tomcat (or the /contexts directory of Jetty). This setup has a bunch of advantages:
The big configuration file can live outside of the servlet container and webapp
The webapp can be updated without danger of losing the configuration
The distributed war doesn't need to be modified or rebuilt
Downside: It's sort of complicated, requires messing around with XML, and configuring JNDI on Tomcat works differently from Jetty (requiring twice as much documentation).
Maybe use a system property for the config file location. Can easily be passed on the command line as -Dorg.example.config.file=/foo/bar, in startup scripts or in Java code. I think I've seen some tools, e.g. logging frameworks, use system properties for similar things in webapps.
My code require one PNG file. Where should I put it ?
I saw some people put them along with .java, then use getClassLoader().getResourceAsStream.
Personally, I feel it is not clean to mix resource files with source code.
Is this a OK approach ?
That is a very common and accepted practice. It has the advantage that the PNG file will be bundled inside of the JAR file along with the code. So you do not have to worry about file system issues and installation processes. If your code is there, so will the resource.
You can have multiple source folders for the same project, one for Java, one for resources. If you are using Maven, it is recommended to have that kind of structure. However, mixing the PNG (and properties, and XML) files into the source tree is not a problem, either (especially since the separation would complicate the build process if you do not use Maven).
The only things you should keep apart from the source (and the compiled result) is user-editable data, such as configuration files. This may apply here if you want the user to be able to replace the image. If it is fixed (or a default is provided), bundle it up with your program to reduce the number of movable (= breakable) parts.
A web application usually has at least one configuration file, that contains jdbc configuration and other settings. You can put such file(-s) inside a .war file or outside it. What are the cons and pros of these approaches? What is your approach and why?
Imho, outside seems the most convenient if you need to deploy the same war in different environments. Like, dev, itt, uat and production. Same build different configurations.
In my opinion an application setting value should never be merged with a binary. They should be placed in a separate file or database. This is a basic best practice. You never know when you or anyone else will need to adjust one of the settings -- and you may not be around -- or the source code may not be available.
IMHO the best way is to use flexible approach and allow config to be inside and/or outside WAR (with some extra logic for config lookup order and what file/dir names that config may be kept in).
I have experience with extremely different deploy models/schemas - sometimes it is one build/many configs, other time - even: many builds/one config on one server - strange, but can happen ;-).
This may be especially helpful if you are developing some kind of platform that your customers/users may deploy in custom environments unspecified at WAR build time.
Put them inside the war and use some sort of build-profiles (like maven build profiles). That way:
you have one-step deployment. No manual editing of properties on remote environments.
you can have different artifacts (war files) for different environments, so the build is still portable, but you don't need to open wars with a ZIP software to modify settings.
The way to implement/use the build profiles depends on your build environment.