[
https://issues.jboss.org/browse/WFLY-10539?page=com.atlassian.jira.plugin...
]
Paulo Silva updated WFLY-10539:
-------------------------------
Description:
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. I've tested this in wildfly 10, 12 and 13.
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 as to 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 and called by insertion order
(List iteration) 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}
was:
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. I've tested this in wildfly 10, 12 and 13.
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 as to 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}
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: 10.0.0.Final, 12.0.0.Final, 13.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. I've tested this in wildfly 10, 12 and 13.
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 as to 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 and called by insertion
order (List iteration) 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)