Where to place and how to read configuration resource files in servlet based application? - servlets

In my web application I have to send email to set of predefined users like finance#xyz.example, so I wish to add that to a .properties file and access it when required. Is this a correct procedure, if so then where should I place this file? I am using Netbeans IDE which is having two separate folders for source and JSP files.

It's your choice. There are basically three ways in a Java web application archive (WAR):
1. Put it in classpath
So that you can load it by ClassLoader#getResourceAsStream() with a classpath-relative path:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("foo.properties");
// ...
Properties properties = new Properties();
properties.load(input);
Here foo.properties is supposed to be placed in one of the roots which are covered by the default classpath of a webapp, e.g. webapp's /WEB-INF/lib and /WEB-INF/classes, server's /lib, or JDK/JRE's /lib. If the propertiesfile is webapp-specific, best is to place it in /WEB-INF/classes. If you're developing a standard WAR project in an IDE, drop it in src folder (the project's source folder). If you're using a Maven project, drop it in /main/resources folder.
You can alternatively also put it somewhere outside the default classpath and add its path to the classpath of the appserver. In for example Tomcat you can configure it as shared.loader property of Tomcat/conf/catalina.properties.
If you have placed the foo.properties it in a Java package structure like com.example, then you need to load it as below
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("com/example/foo.properties");
// ...
Note that this path of a context class loader should not start with a /. Only when you're using a "relative" class loader such as SomeClass.class.getClassLoader(), then you indeed need to start it with a /.
ClassLoader classLoader = getClass().getClassLoader();
InputStream input = classLoader.getResourceAsStream("/com/example/foo.properties");
// ...
However, the visibility of the properties file depends then on the class loader in question. It's only visible to the same class loader as the one which loaded the class. So, if the class is loaded by e.g. server common classloader instead of webapp classloader, and the properties file is inside webapp itself, then it's invisible. The context class loader is your safest bet so you can place the properties file "everywhere" in the classpath and/or you intend to be able to override a server-provided one from the webapp on.
2. Put it in webcontent
So that you can load it by ServletContext#getResourceAsStream() with a webcontent-relative path:
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/foo.properties");
// ...
Note that I have demonstrated to place the file in /WEB-INF folder, otherwise it would have been public accessible by any webbrowser. Also note that the ServletContext is in any HttpServlet class just accessible by the inherited GenericServlet#getServletContext() and in Filter by FilterConfig#getServletContext(). In case you're not in a servlet class, it's usually just injectable via #Inject.
3. Put it in local disk file system
So that you can load it the usual java.io way with an absolute local disk file system path:
InputStream input = new FileInputStream("/absolute/path/to/foo.properties");
// ...
Note the importance of using an absolute path. Relative local disk file system paths are an absolute no-go in a Java EE web application. See also the first "See also" link below.
Which to choose?
Just weigh the advantages/disadvantages in your own opinion of maintainability.
If the properties files are "static" and never needs to change during runtime, then you could keep them in the WAR.
If you prefer being able to edit properties files from outside the web application without the need to rebuild and redeploy the WAR every time, then put it in the classpath outside the project (if necessary add the directory to the classpath).
If you prefer being able to edit properties files programmatically from inside the web application using Properties#store() method, put it outside the web application. As the Properties#store() requires a Writer, you can't go around using a disk file system path. That path can in turn be passed to the web application as a VM argument or system property. As a precaution, never use getRealPath(). All changes in deploy folder will get lost on a redeploy for the simple reason that the changes are not reflected back in original WAR file.
See also:
getResourceAsStream() vs FileInputStream
Adding a directory to tomcat classpath
Accessing properties file in a JSF application programmatically

Word of warning: if you put config files in your WEB-INF/classes folder, and your IDE, say Eclipse, does a clean/rebuild, it will nuke your conf files unless they were in the Java source directory. BalusC's great answer alludes to that in option 1 but I wanted to add emphasis.
I learned the hard way that if you "copy" a web project in Eclipse, it does a clean/rebuild from any source folders. In my case I had added a "linked source dir" from our POJO java library, it would compile to the WEB-INF/classes folder. Doing a clean/rebuild in that project (not the web app project) caused the same problem.
I thought about putting my confs in the POJO src folder, but these confs are all for 3rd party libs (like Quartz or URLRewrite) that are in the WEB-INF/lib folder, so that didn't make sense. I plan to test putting it in the web projects "src" folder when i get around to it, but that folder is currently empty and having conf files in it seems inelegant.
So I vote for putting conf files in WEB-INF/commonConfFolder/filename.properties, next to the classes folder, which is Balus option 2.

Ex: In web.xml file the tag
<context-param>
<param-name>chatpropertyfile</param-name>
<!-- Name of the chat properties file. It contains the name and description of rooms.-->
<param-value>chat.properties</param-value>
</context-param>
And chat.properties you can declare your properties like this
For Ex :
Jsp = Discussion about JSP can be made here.
Java = Talk about java and related technologies like J2EE.
ASP = Discuss about Active Server Pages related technologies like VBScript and JScript etc.
Web_Designing = Any discussion related to HTML, JavaScript, DHTML etc.
StartUp = Startup chat room. Chatter is added to this after he logs in.

It just needs to be in the classpath (aka make sure it ends up under /WEB-INF/classes in the .war as part of the build).

You can you with your source folder so whenever you build, those files are automatically copied to the classes directory.
Instead of using properties file, use XML file.
If the data is too small, you can even use web.xml for accessing the properties.
Please note that any of these approach will require app server restart for changes to be reflected.

Assume your code is looking for the file say app.properties. Copy this file to any dir and add this dir to classpath, by creating a setenv.sh in the bin dir of tomcat.
In your setenv.sh of tomcat( if this file is not existing, create one , tomcat will load this setenv.sh file.
#!/bin/sh
CLASSPATH="$CLASSPATH:/home/user/config_my_prod/"
You should not have your properties files in ./webapps//WEB-INF/classes/app.properties
Tomcat class loader will override the with the one from WEB-INF/classes/
A good read:
https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html

Related

How to get the project base path in Spring mvc web application?

I have spring mvc web application which is deployed on a tomcat server. On that project, I want to create folders and files in the runtime. currently I can create folders in the server root by using System.getProperty("catalina.base"). But when I deployed the project in a externel server I cant create folders on the root level of the tomcat server beacuse I don't have permissions. Intead of that I decided to create folders in following directory.
tomcat_dirctory/webapps/myproject_directory
so I need to create folders and files in side the myproject_directory in the runtime. Can anyone tell me what is the path for that. May be I can hardocde that as follows.
System.getProperty("catalina.base") + File.separator + "webapps"+File.separator+"myproject_directory"
But Instead of hard coding I prefer to know is there any alternative way to obtain my project path.
You can use getServletContext().getRealPath("/");
Gets the real path corresponding to the given virtual path.
For example, if path is equal to /index.html, this method will return the absolute file path on the server's filesystem to which a request of the form http://://index.html would be mapped, where corresponds to the context path of this ServletContext.
The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators.
Resources inside the /META-INF/resources directories of JAR files bundled in the application's /WEB-INF/lib directory must be considered only if the container has unpacked them from their containing JAR file, in which case the path to the unpacked location must be returned.
This method returns null if the servlet container is unable to translate the given virtual path to a real path.

How do I deploy application classes and Spring config files to Tomcat as a single jar?

Currently I create a new war file for each change but the changes are taking place in only a few classes and the Spring applicationContext.xml.
I would like to just update a jar file that contains these classes and not continually re-deploy hundreds of files that have not changed. I can create the jar easily enough but where do I put it and do I have to tell Spring to look in a specific jar for its' config files?
It is quite impossible to hot-redeploy code in Tomcat without using extra tools like JRebel or custom JVM agents.
But it is possible to modularize you application by:
1: Putting JARs to $TOMCAT_HOME/lib. Never do this, this solution is good only for simple cases.
2: Tune context.xml, putting Loader in it, like below:
<Context antiJARLocking="true" path="/">
<Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="${catalina.base}/my-app-plugins/*.jar"/>
</Context>
This will enable you putting JAR file in $TOMCAT_HOME/my-app-plugins and thet will be added to the classpath of you app. You should put context.xml to the src/main/webapp/META-INF folder (Maven layout). However, restart is still needed.
3: Use OSGi. May be an overkill.

IIS Web application and class-library configuration - config file is lost when deployed

I have an ASP.NET web application written in C# 4.0. The application references a class library that comes with its own configuration file. At runtime, the class library uses similar to the following code to load this specific configuration:
var exeConfigPath = this.GetType().Assembly.Location;
var config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
This is done because the library has to load its bundled configuration rather than the application configuration. The application configuration should not be concerned of the library's settings and should not be able to alter them.
Now, there are a few other things that need to be done for this concept to work. I have to set the library's configuration file build operation as Content in the properties window and the Copy to be Copy Always or Copy If Newer. So far so good - the file gets automatically both into the class library's bin directory, and the web applications's bin directory, and is correctly renamed from App.config to CustomLibrary.dll.config (as supposed, the library's dll is CustomLibrary.dll).
Now I am facing two issues.
1) When I publish the web application to a filesystem location (mapped in IIS), the CustomLibrary.dll.config appears back as App.config in the bin folder of the published app. OK - I will rename it in the class library project to match the expected convention - and problem solved.
2) Even when published, the IIS compiles the application again and stores it in the ASP.NET Temporary Files. There is a fancy directory structure with a folder dedicated for each assembly referenced. The folder corresponding to the CustomLibrary.dll does not contain the config file in it. Since this.GetType().Assembly.Location will return the path to the temp folder, the application fails to load the configuration and crashes as it should.
I need to preserve the pattern of having the configuration in the class library, and be able to make it work in the web application. When manually copying the .config to the temp folder, the app works, but see, I really hate manual copying to randomly-named folders.
Is there a way to either prevent IIS from using the temp folders, or to make it copy along the config files? I believe the problem I am facing is configuration-related rather than conceptual since the application works as expected when the config file is in place. I'd prefer not to mess with using hard-coded physical paths to the config file either.
Edit:
To make it clearer, I will point out what and why I want to achieve. The idea is that the library and the web project will be developed as separate products - there will be no user or application specific information in the configuration of the library, so it will not change for different use scenarios. It is also rather specific to the class library functionality rather than the end application. It makes sense for me to keep the library's configuration information bundled within it (similar to Java, where a spring context xml file, or a properties file, get bundled with the jar of the library). I'd like to avoid having to copy the configuration in each app/web config of the consumer application. There will be cases where the consumer application is developed by third parties, and I do not want to rely on them doing their configuration right for my stuff to work. Again, the only issue here is not having the config file copied to the right place.
If those are static, internal settings that nobody should see or change, wouldn't you be better off having a file with the configuration included within the class library as an embedded resource? Either that or just a static class with the settings.
That way you'd be certain that nobody alters it, which in your scenario seems to be a plus.
I have come along a way to work arround the described issue, still not a very pleasant one to my requirements.
The solution is to take advantage of the application configuration (web.config in web apps, or app.config) which is always available. I have added as settings the absolute paths to the config file for each library. So I ended up with:
<!--
THIS IS IN THE WEB.CONFIG FILE
-->
<appSettings>
<add key ="ClassLibrary_ConfigPath"
value ="{My Publish Output Folder}\ClassLibrary.dll.config"/>
</appSettings>
and the class library now uses the following code to load its configuration:
Configuration config = null;
try
{
var exeConfigPath = this.GetType().Assembly.Location;
config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
}
catch (Exception e)
{
if (!IsConfigurationNotFoundError(e))
{
// IsConfigurationNotFoundError logic skipped for brevity
var exeConfigPath =
ConfigurationManager.AppSettings["ClassLibrary_ConfigPath"];
if (exeConfigPath != null)
{
config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
}
}
else
{
throw;
}
}
While this works, I will wait for a better solution if possible. Still, I do not have to copy the entire ClassLibrary.dll.config into the web.config file, but now I must manage filesystem locations and be aware of app-setting names. What I really want is the consumer app of the ClassLibrary.dll not to deal with its configuration in any way. If it were a desktop app, I have this covered, as Visual Studio copies the ClassLibary.dll.config appropriately. I hope there is a way to make it work smoothly for web apps.
The short answer is: you can't. You have to merge both configuration sections and place all settings in the main configuration file of your application. In case of the web application it would be the web.config. Read this

Change the default location of Runtime Shared Library files

To make my Ant Generated swf as small as possible, i used the Runtime Shared Library like described in this URL.
By default, the RSL files should be located with the compiled swf (without RSL).
Thus, do you know how can I change the location's property of the SRL files?
Because I have the compiled swf in many directories, that's why we should have only one resource of the RSL as well as in one separated directory
Have a look at an RSL linkage definition:
<runtime-shared-library-path>
<path-element>libs/framework.swc</path-element>
<rsl-url>http://fpdownload.adobe.com/pub/swz/flex/4.6.0.23201/framework_4.6.0.23201.swz</rsl-url>
<policy-file-url>http://fpdownload.adobe.com/pub/swz/crossdomain.xml</policy-file-url>
<rsl-url>framework_4.6.0.23201.swz</rsl-url>
<policy-file-url></policy-file-url>
</runtime-shared-library-path>
The rsl-url nodes define where the application will look for the library. It will first try to get it from the first URL; if that fails it will try the second; and so on until it finds a link that works or fails.
You can add as many URL's as you like, but for framework RSL's you'll typically have a link to Adobe's repository as the first URL, and one fallback URL on your own server.
These URL's can be absolute or relative. If for instance you'd want you SDK RSL's to be located in a directory called 'sdk' under the same directory your application is in, just change the secondary rsl-url node to:
<rsl-url>sdk/framework_4.6.0.23201.swz</rsl-url>
The same principle applies if you wish to do it through compiler arguments. You could do it like this:
-runtime-shared-library-path=${swc},${swz.primary},http://fpdownload.adobe.com/pub/swz/crossdomain.xml,${swz.secondary}

problem with the injection of an EJB that resides in a jar

I have some problems regarding the EJB injection and I haven't been able to find a solution anywhere.
My situation is the following: I have an EAR file that includes a WAR and several JARs, all listed in the application.xml file. All is working fine for this part.
The problems come out when I try to add what we can call a “plugin system”.
I have a JAR with inside some .xhtml pages, backing beans and EJBs. This JAR, if needed, is inserted inside the EAR in a specific directory (let's call it “plugins”) and is detected from the application at startup.
When the JAR is detected it's path is added to the WAR class loader so all the pages and the backing bean are detected without problems. What is not working is the injection of the EJBs (I tried to use the notation #EJB, #Inject, the lookup...). I can't inject any of the EJBs that is inside the JAR plugin.
My guess is that the application server treats the JAR as a simple library module and doesn't look for any EJB inside it, so they are inside the JAR but not usable from the application.
My question is: there's a way of having this working? I tried to add the JAR in the EAR's MANIFEST.MF but nothing changed...
the application server i'm using is glassfish 3.0. About the application.xml: there's no reference in it about the JARs that are part of what i called "plugin system". This because i detect them when i deploy (or i restart) the application in the application server, so they may or may not be inside the system and i don't really know that before the system is started.
Each plugin JAR is a "collection" of pages and functionalities that can be added or removed from the system dynamically (more less like a real plugin system).
My EAR structure is the following:
MyApp.EAR
META-INF
lib
plugins
plugin1.JAR
app.WAR
logic1.JAR
logic2.JAR
for example: in the application.xml i have the references for app.WAR, logic1.JAR and logic2.JAR (they are always inside the system), at startup the application looks inside the folder "plugins" for any plugin (specific JARs) to be added to the system.
I hope i've been more clear about what i'm trying to do...
It seems that the EJB are not even registered in the JNDI tree of the server. Which application server are you using? You can have a look to this JNDI tree to see if the EJBs are there, but the way to do this depends on the specific server.
How are you declaring the JAR that contains the EJBs in the EAR application.xml?
It should be someting lide this:
<application>
....
<module>
<ejb>nameOfTheJarFile.jar</ejb>
</module>
</application>
The Jar should be in a the "/lib" directory of the EAR.
I hope this helps.

Resources