So Liferay has a great system for creating global startup actions. You configure the portal-ext.properties to run a class derived from AppStartupAction and Liferay runs it during startup.
I found a problem however...
20:27:35,500 ERROR [pool-2-thread-1][MainServlet:325] java.lang.ArrayIndexOutOfBoundsException: 0
Strange, isn't it? The companyId is provided by the PortalInstances class which should have been initialized, right?
The problem is that Liferay's MainServlet runs the global startup events BEFORE it initializes the PortalInstances object. Since PortalInstances supplies the default companyId, it isn't available yet if you need it in your custom startup action.
The solution I used was to modify the MainServlet.java class to place the global startup actions right after company initialization.