[jboss-jira] [JBoss JIRA] (WFLY-10539) ServletContainerInitializer instances aren't invoked in the specified order (WarMetaData order)

Paulo Silva (JIRA) issues at jboss.org
Fri Jun 8 07:39:00 EDT 2018


Paulo Silva created WFLY-10539:
----------------------------------

             Summary: ServletContainerInitializer instances aren't invoked in the specified order (WarMetaData order)
                 Key: WFLY-10539
                 URL: https://issues.jboss.org/browse/WFLY-10539
             Project: WildFly
          Issue Type: Bug
          Components: Web (Undertow)
    Affects Versions: 13.0.0.Final, 12.0.0.Final
            Reporter: Paulo Silva
            Assignee: Stuart Douglas


After several tests I've found that ServletContainerInitializer instances aren't being called in a deterministic order, even when an absolute-ordering is configured in web.xml.

Stepping through the code, on wildfly startup, I've found that ServletContainerInitializer instances are being collected to ScisMetaData.The problem is that they are being stored in a HashSet, and that makes no guarantees of the iteration order!

The set is being initialized here:

{code:java}
Set<ServletContainerInitializer> scis = scisMetaData.getScis();
Set<Class<? extends ServletContainerInitializer>> sciClasses = new HashSet<>();
if (scis == null) {
   scis = new HashSet<ServletContainerInitializer>();
   scisMetaData.setScis(scis);
}
{code}


And the ServletContainerInitializer implementations that are found in jars are being added here:

{code:java}
        // Find local ServletContainerInitializer services
        List<String> order = warMetaData.getOrder();
        Map<String, VirtualFile> localScis = warMetaData.getScis();
        if (order != null && localScis != null) {
            for (String jar : order) {
                VirtualFile sci = localScis.get(jar);
                if (sci != null) {
                    scis.addAll(loadSci(classLoader, sci, jar, true, sciClasses));
                }
            }
        }
{code}

and later iterated and added to the DeployementInfo here (they are added to a List!):

{code:java}
           if (scisMetaData != null && scisMetaData.getHandlesTypes() != null) {
                for (final ServletContainerInitializer sci : scisMetaData.getScis()) {
                    final ImmediateInstanceFactory<ServletContainerInitializer> instanceFactory = new ImmediateInstanceFactory<>(sci);
                    d.addServletContainerInitalizer(new ServletContainerInitializerInfo(sci.getClass(), instanceFactory, scisMetaData.getHandlesTypes().get(sci)));
                }
            }
{code}


+But+, since scisMetaData.getScis() returns a HashSet, there is absolutely no guarantee that the iteration order is the same as the insertion order (the order that is imposed by warMetaData.getOrder()).

So a simple fix is to use a LinkedHashSet instead of a HashSet:

The ServletContainerInitializer instances are later iterated (List iteration) and called in DeployementManagerImpl:

{code:java}
//then run the SCI's
for (final ServletContainerInitializerInfo sci : deploymentInfo.getServletContainerInitializers()) {
    final InstanceHandle<? extends ServletContainerInitializer> instance = sci.getInstanceFactory().createInstance();
    try {
        instance.getInstance().onStartup(sci.getHandlesTypes(), servletContext);
    } finally {
        instance.release();
    }
}
{code}



--
This message was sent by Atlassian JIRA
(v7.5.0#75005)


More information about the jboss-jira mailing list