Rename war file to change the context path of an webapplication - java

I am building a webapplication with maven. I want to change the name of the generated warfile to get a different context path.
To clarify misunderstandings: It is not about changing the name during development, it should be possible without touching any code (e.g. for customers). Also it should be possible to deploy those war on different servers (like WildFly, Tomcat etc.).
Example:
Hello.war = Hello.war -> URL: localhost:8080/Hello
stupid.war = stupid.war -> URL: localhost:8080/stupid
How can I achieve this? Is that even possible?

For popular servlet containers (JBoss, Tomcat, Jetty), WAR naming convention can drive context paths. Name of the war becomes the context path if no explicit context path is defined anywhere.
a.war > localhost:8080/a
b.war > localhost:8080/b
The problem then is just to rename the war into different names as per your clients.
https://docs.jboss.org/jbossas/guides/webguide/r2/en/html/ch06.html
https://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Naming
http://www.eclipse.org/jetty/documentation/current/configuring-contexts.html

Overriding the default finalName element within the build element to the desired filename (without extension) may archive what you wish. You will then of course need to take care with versions. eg.
<build>
<finalName>YourName</finalName>
</build>

the easy way to do this is
to rename the file extension.war to .zip and expand it (double-click it)
drag out the web.xml to desktop
make changes to web.xml accordingly
drag the modified web.xml to its original location and replace the original
rename the file extension back to .war

Related

How to load resources without using an absolute path [duplicate]

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

getServletContext.getResourceAsStream returns null [duplicate]

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

Multiple war files for a single webapp or context

I have an application that has the following structure
$TOMCAT_HOME/webapps/myapp
|-css
|-myapp.css
|-js
|-myapp.js
|-forum
|-index.jsp
|-list.jsp
|-users.jsp
|-Articles
|-index.jsp
|-ListArticles.jsp
|-Guestbook
|-viewGuestBook.jsp
|-AddnewEntry.jsp
|-WEB-INF
|-classes
com
|-myapp
|-forum
|-DisplayForum.class
|-ListUsers.class
|-article
|-ArticleList.class
|-AddArticle.class
|-guestbk
|-LoadGuestBook.class
|-ProcessGuestBook.class
The application is delivered as a war file (i.e. myapp.war) and is deployed into the $TOMCAT_HOME/webapps folder. If any of the files change (either the jsp, css, js or java files) i have to always rebuild the whole war file. This means i deploy every single file on every release.
I am wondering if there is a way to deploy specific areas of the application. I am particularly interested if it is possible to separate the application into multiple war files. i.e. myapp.war, articles.war and forum.war. I would like to still access the application via the same context i.e. http://0.0.0.0/myapp even though multiple war files are used.
Using this approach, i will be able to deliver just the module that was affected by the change. Is this at all possible?
I dont mind having to restart the container after each war file is deployed.
I don't remember how you do this is Tomcat exactly, you'll probably have to do some manual configuration (in context.xml or something like that) but I'm fairly certain you can deploy your three applications (.wars) with the following context paths:
myapp.war -> /myapp
articles.war -> /myapp/articles
forum.war -> /myapp/forum
I've found a bit of information specific to Tomcat here:
http://tomcat.apache.org/tomcat-6.0-doc/config/context.html
Specifically:
In individual files (with a ".xml" extension) in the
$CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The name of
the file (less the .xml extension) will be used as the context path.
Multi-level context paths may be defined using #, e.g. foo#bar.xml for
a context path of /foo/bar. The default web application may be defined
by using a file called ROOT.xml.
Alternatively, you may want to do something like:
myapp.war -> / (by calling it ROOT.war)
articles.war -> /articles
forum.war -> /forum
Having said that, keep in mind that if you do this, you'll not be able to have shared state (session information) between the three applications without some effort. For instance, if "forum.war" requires authentication, that authentication information will not be available to myapp.war or articles.war.

Parametrized value of Apache Tomcat Context Attributes or Context variables?

I have java webapp under Tomcat with such sample context:
<Context path="reports" docBase="E:\generatedReports"></Context>
On unix attribute docBase different:
<Context path="reports" docBase="/usr/generatedReports"></Context>
Can I have ONE context.xml (for crossplatform and keeping simple build scripts)?
Value of docBase attribute must be parameter managed in other place?
Technically Yes, you can keep one file and parametrize it when building.
The problem with doing this via build scripts is that context.xml sits outside the webapps and is part of the conf, i.e. the Tomcat installation directory.
You ideally want minimum interference with files in the conf folder and so rather than having it as part of the build and released artifacts, I would suggest you version control it as context.xml.windows and context.xml.unix or something similar.
And yourself or your admin should manually change/edit these files ensuring all changes are justified.

jboss 6 virtual directory

I cannot find a proper way to add a directory to my app context on jboss 6.
I'll use this mapping for static content. Can someone give me a hand on that?
There are no more 'virtual directories' in JBoss 6. Apparently this went out with JBoss 5. The only available options I've found are:
create a blank /WEB-INF/web.xml (so like just <web-app/>) in your static content directory and make a symlink with a .war extension in your jboss deploy directory. You can also copy the directory containing the static content to your deploy directory, but I find a symlink much more useful.
create a webapp with a servlet that serves static content from a configured directory (discussed here)
if you're using a web framework like spring mvc 3, you can use the 'resources' feature to serve content for you (discussed here)
The bad news is that you can serve static content only inside JBoss applications. The good news is that it is very easy to transform any folder into an application folder.
The easiest solution is to copy all your static content into your server\default\deploy\ROOT.war directory.
A more complex solution is the following.
Copy the ROOT.war folder in the position where you want to put your
static content.
Rename ROOT.war into any name you like but it must end with .war,
for instance my_static_content.war.
Put all your static content into that directory.
Enable external deploy to the folder that contains your static
content folder. External deploy with JBoss 6 and JBoss 5
Restart JBoss
Your content will be into the URI http:\\localhost:8080\my_static_content\. You have to specify the exact name of the files that you want to serve, because directory listing is not allowed.
this thread helped me get static content in an external directory served up on jboss eap 5.1 without the use of links and without moving or renaming the ROOT.war folder.
note that you still have to create a directory structure that tricks jboss into serving up your content. it's not as easy as adding a <Context> child element to the <Host name="localhost"> in the server.xml file. it seems like a hack but at least it works.

Categories