I know that Tomcat and the Servlet spec do not support starting webapps in a particular order.
However, this seems to me like a common use case, and I\'m wondering i
In theory you could spawn a Runnable
by ExecutorService
in contextInitialized()
which in turn checks the availability of the other webapp at timed intervals (perhaps by firing a HTTP HEAD
request?). Once the other webapp is available, then set some attribute in the servlet context which indicates that. Add a Filter
which checks for the presence of that attribute and blocks/continues requests accordingly.
Since none of the options worked for Tomcat 9.0.19 (the one mentioned by @Luiz also) we used the code approach and replaced the Tomcat StandardHost and HostConfig with minimal custom implementations:
public class CustomTomcatHost extends StandardHost {
public CustomTomcatHost() {
super();
}
@Override
public void addLifecycleListener(LifecycleListener listener) {
if (listener instanceof HostConfig) {
listener = new OrderedHostConfig();
}
super.addLifecycleListener(listener);
}
}
The deployApps function in HostConfig had to be overriden for sorting to work for everything (incl. WAR files in /webapps folder and also for descriptor XML files in configbase folder (e.g. conf/Catalina/localhost)):
public class OrderedHostConfig extends HostConfig {
public OrderedHostConfig() {
super();
}
public String[] prioritySort(String[] paths) {
if (paths == null) return null;
Arrays.sort(paths, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b); //TODO: sort paths based on your criteria
}
});
return paths;
}
@Override
protected void deployApps() {
File appBase = host.getAppBaseFile();
File configBase = host.getConfigBaseFile();
String[] apps = prioritySort(filterAppPaths(appBase.list()));
// Deploy XML descriptors from configBase
deployDescriptors(configBase, prioritySort(configBase.list()));
// Deploy WARs
deployWARs(appBase, apps);
// Deploy expanded folders
deployDirectories(appBase, apps);
}
}
Then we placed the new classes in a new jar file in Tomcat /lib directory and modified conf/server.xml file to replace the host class with our own implementation:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" className="com.example.CustomTomcatHost" >
During start Tomcat loaded all components in the required order.
Here is a nice trick i use to create 2 levels of webapp loading. in each level the order is not guaranteed. This relies on the fact that tomcat will load first context descriptors from tomcat/conf/[Engine Name]/[Host Name] and only then contexts from the appBase attribute of the Host element in server.xml
Just add the following code somewhere in the webapp you would like to load in the 2nd level ( i.e. later )
File contextDescriptor = new File(getParameter("catalina.home"),"/conf/Catalina/localhost/mywebapp.xml");
contextDescriptor.deleteOnExit();