I'm having trouble deploying a Java web app. It centers on our application config file (myapp.properties). In certain situations, having this file external to the WAR seems to work fine, but whenever I try to deploy it properly (Docker, proper JBoss deployment, etc.) the deployments inevitably fail due to being unable to find/read from myapp.properties.
I've seen a few references here and elsewhere to packaging these files inside the WAR archive, but I can't find any information on how to actually do that. So, my questions is:
What is the proper way to include an application config file in a WAR archive and/or deployment?
It depends in how you want to access the file.
If you want to load it via classloader resources, you need it to be in the class-path, so the best location is inside WEB-INF/classes.
That's by the way, where resources in src/main/resources will end up if you are using Maven
You can also put it anywhere inside your WAR, for example, WEB-INF/config and access it via ServletContext.getResourceAsStream("/WEB-INF/config/..... Beware but, that it's not inside the WEB-INF directory, you will have to explicitly forbid the access to the file in the web.xml deployement descriptor, otherwise it would be accessible to client requests.
Related
I have a WAR file that requires additional data from an external config file residing in the same folder as the WAR file.
But once I deploy them to Tomcat, the WAR file and the config file will be residing in different places right?
Do I need to insert a special file path to my project before building the WAR file to make sure that the WAR file will still find the config file after deployment?
Thanks.
You can:
include the config file inside the war and read it from this predefined location. This isn't good if you're going to change it after you deploy since every time you deploy a new war, your changes will be overwritten
put the config file outside the war (and maybe even outside of tomcat) and read it from there. Doing this, your changes will survive redeploys of the war.
I am majorly confused about where the classpath is. I understand when we create a spring mvc, resources folder, or inside web-inf is considered classpath. And we can use "classpath:" inside xml files to declare the folder. However, where is this classpath exactly? How is it set ? I have been reading about it for a long time, i still couldnt manage to get a real clear image in my head how the classpath is initially determined etc.
For example when we create a war file, and deploy it on a tomcat server, all the resource files can still be read via given paths with "classpath:" in the xml files. How does this work?
Thanks.
Ok, if it's web application, the classpath begins in WEB-INF/classes. Also, jar files in WEB-INF/lib are also on the classpath.
The Classpath is where the JVM will look for class files and other resources. Since you are using Spring MVC, I assume you are deploying a Web application (ie WAR file). This means that the classpath is set by the container which is following the Servlet spec.
The classpath for a WAR file includes the WEB-INF/classes and WEB-INF/lib folders. The Java EE/Servlet container where the WAR file is deployed will also include other common folders in the classpath.
Here is how Tomcat works.
You might also want to try this StackOverflow article/answer
My organization is creating a "base" Java web app that is meant to be customized by adding jar files (with customized classes) by adding the jar files to the web app's WEB-INF/lib directory. The goal is that our developers can simply create custom code, packaged as a simple jar file, which can be loaded into this "base" web app, so the developer doesn't have to worry about all the web app plumbing, just the actual custom code.
We're investigating a few different deployment models, but one idea was to put these jar files somewhere on a network directory. When the Java web app starts up, a ServletContextListener copies these jar files into the web app's WEB-INF/lib directory (the web app is originally deployed as a war file).
Then, another ServletContextListener uses Stripes' ResolverUtil class (JavaDoc here) to load all of the classes of a particular type (in this case, that implement a particular interface) that are located in the jar files that were copied into WEB-INF/lib.
Unfortunately, ResolverUtil fails to find those classes, even though they are in those copied jars. If I restart Tomcat (with those jar files still in WEB-INF/lib) they are found, as expected.
The jar files need to be in WEB-INF/lib because we want to use the Servlet 3.0 feature in which JSPs can be served from jar files, and for that to work, apparently those jar files need to be in WEB-INF/lib. If that weren't the case we would just add those jar files in the shared.loader property in catalina.properties.
So, it appears that Tomcat has already scanned the classpath for all class definitions by the time a web app is started, and since those jar files weren't in WEB-INF/lib when the web app started up, the classes will not be found.
Is there a way for those classes to be found? I don't need Tomcat to completely reload itself; I just need those new jar files and the class files they contain to be visible to the class loader. Is there a way to tell the classloader, "Hey, check the classpath again for new jars!" as I would only need to do it once, when the web app starts up?
Any other ideas?
Thank you!!
I have this problem. I want to load a properties file located in a war file but the class loader is in another jar file. But they are compiled in one ear file. When I place the properties file in src folder of the jar file's project, it works but I wanted to put it in Web-INF/Classes for future update purposes.
Details.
Compiled in EAR
EJB
IBM Websphere
Thanks!
You war depends on your EJB but the EJB does not depends on your war.
Thus, it's not possible.
If configuration must be updated, you should externalize it.
You won't be able to modify files in your war.
A good practice is to generate EJB jars and WARs independtly of the environment.
It will enable your Exploitation team to deploy the same code in every environment. They will just need to adapt the externalized property files (DB login / password, etc...).
Recently I separated the core functionality of my core servlets application into a jar file. This jar file is now deployed in tomcat's lib folder and the application(i.e. servlets, jsps, properties files..etc) is deployed independently as a war file.
The jar files needs specific properties files. I place these properties files right under the "src" folder(i.e. in the top of the classes hierarchy) in the war file.
In the past when everything was in the same project and deployed in one war file. The properties files were accessible by the related classes. Now when these classes are deployed in a jar, they can't see the properties files located in the war file (i.e. deployed web application).
What could I be missing here ?
An example how I load my proeprties files:
properties.load(getClass().getResourceAsStream("/appconfig.properties"));
Thank you for your time.
You shouldn't get it by the class' own classloader. As the class is now managed by Tomcat, it only knows about Tomcat's internal resources, not about webapp-specific resources. You should get it by the context classloader of the current thread. That classloader knows about all resources dedicated to the current webapp.
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("appconfig.properties"));
Regardless of this, the proper location of such a properties file representing the global app configuration would not be inside the WAR file. You should rather place the properties file on a fixed path outside Tomcat and the WAR file and then add that fixed path to the shared.loader property of Tomcat's /conf/catalina.properties so that it becomes part of the classpath. This allows you for freely editing the configuration file without the need to rebuild/redeploy the whole WAR. Note that you still need to use the context classloader to load it.
Yes, that won't work because the jars in tomcat lib folder are loaded by a different classloader that knows nothing about your webapp's classes. In other words, tomcat lib is the parent class loader of the webapp classloader (which are created one per each webapp).
If you want to make it work, you can either place the properties file in an external location and make it known to the jar inside tomcat lib via absolute file path or place the jar back inside webapp's lib.
Here's some reference from the Tomcat site.
http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html
Typically, environment variables are used to identify $CATALINA_HOME which will then be prefixed to the relative file path in order to avoid hardcoding the absolute paths.
String catalinaHome = System.getProperty("CATALINA_HOME");
properties.load(new FileInputStream(new File(catalinaHome + "/path/to/appconfig.properties")));