Skip to content

Commit 590b9d8

Browse files
committed
[#1803,TCK] Use org.ops4j.pax.web.configuration.deferred flag to eagerly start contexts
1 parent 8863ef7 commit 590b9d8

File tree

6 files changed

+103
-16
lines changed

6 files changed

+103
-16
lines changed

pax-web-jetty/src/main/java/org/ops4j/pax/web/service/jetty/internal/JettyServerWrapper.java

+25-3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import org.eclipse.jetty.util.thread.QueuedThreadPool;
6565
import org.eclipse.jetty.xml.XmlConfiguration;
6666
import org.ops4j.pax.web.service.AuthenticatorService;
67+
import org.ops4j.pax.web.service.PaxWebConfig;
6768
import org.ops4j.pax.web.service.jetty.internal.web.JettyResourceServlet;
6869
import org.ops4j.pax.web.service.spi.config.Configuration;
6970
import org.ops4j.pax.web.service.spi.config.LogConfiguration;
@@ -245,6 +246,13 @@ class JettyServerWrapper implements BatchVisitor {
245246

246247
private final Map<String, TreeMap<OsgiContextModel, SecurityConfigurationModel>> contextSecurityConstraints = new HashMap<>();
247248

249+
/**
250+
* Whether contexts should be started immediately or only after some <em>active</em> element
251+
* (like Servlet) was registered. Pax Web runs with deferred configuration, but for TCK we switch
252+
* to immediate;
253+
*/
254+
private boolean deferredConfiguration = true;
255+
248256
JettyServerWrapper(Configuration config, JettyFactory jettyFactory,
249257
Bundle paxWebJettyBundle, ClassLoader classLoader) {
250258
this.configuration = config;
@@ -253,6 +261,10 @@ class JettyServerWrapper implements BatchVisitor {
253261
this.classLoader = classLoader;
254262

255263
this.mainHandler = new PrioritizedHandlerCollection();
264+
265+
String flag = paxWebJettyBundle == null ? null
266+
: paxWebJettyBundle.getBundleContext().getProperty(PaxWebConfig.BUNDLE_CONTEXT_PROPERTY_CONFIGURATION_DEFERRED);
267+
deferredConfiguration = flag == null || Boolean.parseBoolean(flag);
256268
}
257269

258270
// --- lifecycle and configuration methods
@@ -1127,6 +1139,10 @@ public void visitServletModelChange(ServletModelChange change) {
11271139
return;
11281140
}
11291141

1142+
if (!deferredConfiguration && model.getLoadOnStartup() == null) {
1143+
model.setLoadOnStartup(0);
1144+
}
1145+
11301146
LOG.debug("Adding servlet {} to {}", model.getName(), contextPath);
11311147

11321148
// there may be many instances of ServletHolder using the same instance of servlet (added to
@@ -1668,12 +1684,18 @@ public void visitEventListenerModelChange(EventListenerModelChange change) {
16681684
// if there are many OsgiServletContexts per ServletContext)
16691685
servletContextHandler.addEventListener(eventListenerModel, eventListener);
16701686

1671-
if (stopped) {
1687+
if (stopped || !deferredConfiguration) {
16721688
// we have to start it again
16731689
// register a "callback batch operation", which will be submitted within a new batch
16741690
// as new task in single paxweb-config thread pool's thread
1675-
LOG.info("Scheduling start of the {} context after listener registration for already started context", contextPath);
1676-
change.registerBatchCompletedAction(new ContextStartChange(OpCode.MODIFY, contextPath));
1691+
if (stopped) {
1692+
LOG.info("Scheduling start of the {} context after listener registration for already started context", contextPath);
1693+
} else {
1694+
LOG.info("Scheduling start of the {} context after listener registration for immediately started context", contextPath);
1695+
}
1696+
ContextStartChange action = new ContextStartChange(OpCode.MODIFY, contextPath);
1697+
action.setAsync(change.getEventListenerModel().isAsynchronusRegistration());
1698+
change.registerBatchCompletedAction(action);
16771699
}
16781700
});
16791701
}

pax-web-runtime/src/main/java/org/ops4j/pax/web/service/internal/HttpServiceEnabled.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -1085,17 +1085,29 @@ private void doRegisterEventListener(Collection<HttpContext> httpContexts, Event
10851085
// registration change may contain a "callback change" that has to be scheduled in another tick
10861086
// of the event (config) thread
10871087
Batch toSchedule = new Batch("After registration of " + model);
1088+
boolean sync = false;
10881089
for (Change c : batch.getOperations()) {
1089-
if (c.getBatchCompletedAction() != null) {
1090-
toSchedule.getOperations().add(c.getBatchCompletedAction());
1090+
Change action = c.getBatchCompletedAction();
1091+
if (action != null) {
1092+
toSchedule.getOperations().add(action);
1093+
if (action instanceof ContextStartChange) {
1094+
sync |= !((ContextStartChange) action).isAsync();
1095+
}
10911096
}
10921097
}
10931098
if (!toSchedule.getOperations().isEmpty()) {
10941099
LOG.info("Scheduling {}", toSchedule);
1095-
serverModel.runAsync(() -> {
1096-
serverController.sendBatch(toSchedule);
1097-
return null;
1098-
});
1100+
if (sync) {
1101+
serverModel.run(() -> {
1102+
serverController.sendBatch(toSchedule);
1103+
return null;
1104+
}, false);
1105+
} else {
1106+
serverModel.runAsync(() -> {
1107+
serverController.sendBatch(toSchedule);
1108+
return null;
1109+
});
1110+
}
10991111
}
11001112

11011113
event(WebElementEvent.State.DEPLOYED, model);

pax-web-spi/src/main/java/org/ops4j/pax/web/service/spi/model/ServerModel.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1492,7 +1492,7 @@ public void addServletModel(final ServletModel model, Batch batch) throws Namesp
14921492
ServletModel existing = sc.getServletUrlPatternMapping().get(pattern);
14931493
if (existing != null) {
14941494
// service.ranking/service.id checking
1495-
if (model.compareTo(existing) < 0) {
1495+
if (model.compareTo(existing) < 0 || existing.getDtoFailureCode() >= DTOConstants.FAILURE_REASON_UNKNOWN) {
14961496
// we won, but still can lose, because it's not the only pattern (or the only context)
14971497
newlyDisabled.add(existing);
14981498
} else {

pax-web-spi/src/main/java/org/ops4j/pax/web/service/spi/task/ContextStartChange.java

+9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class ContextStartChange extends Change {
2828

2929
private final String contextPath;
3030
private final OsgiContextModel osgiContextModel;
31+
private boolean async = true;
3132

3233
public ContextStartChange(OpCode op, String contextPath) {
3334
super(op);
@@ -54,4 +55,12 @@ public OsgiContextModel getOsgiContextModel() {
5455
return osgiContextModel;
5556
}
5657

58+
public boolean isAsync() {
59+
return async;
60+
}
61+
62+
public void setAsync(boolean async) {
63+
this.async = async;
64+
}
65+
5766
}

pax-web-tomcat/src/main/java/org/ops4j/pax/web/service/tomcat/internal/TomcatServerWrapper.java

+25-3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
import org.apache.tomcat.util.digester.Digester;
7979
import org.apache.tomcat.util.http.Rfc6265CookieProcessor;
8080
import org.apache.tomcat.util.http.SameSiteCookies;
81+
import org.ops4j.pax.web.service.PaxWebConfig;
8182
import org.ops4j.pax.web.service.spi.config.Configuration;
8283
import org.ops4j.pax.web.service.spi.config.LogConfiguration;
8384
import org.ops4j.pax.web.service.spi.config.SessionConfiguration;
@@ -160,6 +161,13 @@ class TomcatServerWrapper implements BatchVisitor {
160161
*/
161162
private final ClassLoader classLoader;
162163

164+
/**
165+
* Whether contexts should be started immediately or only after some <em>active</em> element
166+
* (like Servlet) was registered. Pax Web runs with deferred configuration, but for TCK we switch
167+
* to immediate;
168+
*/
169+
private boolean deferredConfiguration = true;
170+
163171
/**
164172
* Actual instance of {@link org.apache.catalina.core.StandardServer}. In Jetty we had extended class. Here
165173
* we hold direct instance, because it is final.
@@ -272,6 +280,10 @@ class TomcatServerWrapper implements BatchVisitor {
272280
this.tomcatFactory = tomcatFactory;
273281
this.paxWebTomcatBundle = paxWebTomcatBundle;
274282
this.classLoader = classLoader;
283+
284+
String flag = paxWebTomcatBundle == null ? null
285+
: paxWebTomcatBundle.getBundleContext().getProperty(PaxWebConfig.BUNDLE_CONTEXT_PROPERTY_CONFIGURATION_DEFERRED);
286+
deferredConfiguration = flag == null || Boolean.parseBoolean(flag);
275287
}
276288

277289
// --- lifecycle and configuration methods
@@ -1148,6 +1160,10 @@ public void visitServletModelChange(ServletModelChange change) {
11481160
return;
11491161
}
11501162

1163+
if (!deferredConfiguration && model.getLoadOnStartup() == null) {
1164+
model.setLoadOnStartup(0);
1165+
}
1166+
11511167
LOG.debug("Adding servlet {} to {}", model.getName(), contextPath);
11521168

11531169
// there should already be a context for this path
@@ -1537,12 +1553,18 @@ public void visitEventListenerModelChange(EventListenerModelChange change) {
15371553
standardContext.addApplicationEventListener(eventListenerModel, eventListener);
15381554
}
15391555

1540-
if (stopped) {
1556+
if (stopped || !deferredConfiguration) {
15411557
// we have to start it again
15421558
// register a "callback batch operation", which will be submitted within a new batch
15431559
// as new task in single paxweb-config thread pool's thread
1544-
LOG.info("Scheduling start of the {} context after listener registration for already started context", contextPath);
1545-
change.registerBatchCompletedAction(new ContextStartChange(OpCode.MODIFY, contextPath));
1560+
if (stopped) {
1561+
LOG.info("Scheduling start of the {} context after listener registration for already started context", contextPath);
1562+
} else {
1563+
LOG.info("Scheduling start of the {} context after listener registration for immediately started context", contextPath);
1564+
}
1565+
ContextStartChange action = new ContextStartChange(OpCode.MODIFY, contextPath);
1566+
action.setAsync(change.getEventListenerModel().isAsynchronusRegistration());
1567+
change.registerBatchCompletedAction(action);
15461568
}
15471569
});
15481570
}

pax-web-undertow/src/main/java/org/ops4j/pax/web/service/undertow/internal/UndertowServerWrapper.java

+25-3
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
import io.undertow.servlet.util.ImmediateInstanceFactory;
111111
import io.undertow.servlet.util.InMemorySessionPersistence;
112112
import org.ops4j.pax.web.service.AuthenticatorService;
113+
import org.ops4j.pax.web.service.PaxWebConfig;
113114
import org.ops4j.pax.web.service.spi.config.Configuration;
114115
import org.ops4j.pax.web.service.spi.config.LogConfiguration;
115116
import org.ops4j.pax.web.service.spi.config.SessionConfiguration;
@@ -386,12 +387,23 @@ class UndertowServerWrapper implements BatchVisitor, UndertowSupport {
386387

387388
private final Map<String, TreeMap<OsgiContextModel, SecurityConfigurationModel>> contextSecurityConstraints = new HashMap<>();
388389

390+
/**
391+
* Whether contexts should be started immediately or only after some <em>active</em> element
392+
* (like Servlet) was registered. Pax Web runs with deferred configuration, but for TCK we switch
393+
* to immediate;
394+
*/
395+
private boolean deferredConfiguration = true;
396+
389397
UndertowServerWrapper(Configuration config, UndertowFactory undertowFactory,
390398
Bundle paxWebUndertowBundle, ClassLoader classLoader) {
391399
this.configuration = config;
392400
this.undertowFactory = undertowFactory;
393401
this.paxWebUndertowBundle = paxWebUndertowBundle;
394402
this.classLoader = classLoader;
403+
404+
String flag = paxWebUndertowBundle == null ? null
405+
: paxWebUndertowBundle.getBundleContext().getProperty(PaxWebConfig.BUNDLE_CONTEXT_PROPERTY_CONFIGURATION_DEFERRED);
406+
deferredConfiguration = flag == null || Boolean.parseBoolean(flag);
395407
}
396408

397409
// --- lifecycle and configuration methods
@@ -1501,6 +1513,10 @@ public void visitServletModelChange(ServletModelChange change) {
15011513
return;
15021514
}
15031515

1516+
if (!deferredConfiguration && model.getLoadOnStartup() == null) {
1517+
model.setLoadOnStartup(0);
1518+
}
1519+
15041520
LOG.debug("Adding servlet {} to {}", model.getName(), contextPath);
15051521

15061522
// manager (lifecycle manager of the deployment) - null until
@@ -2108,12 +2124,18 @@ public void visitEventListenerModelChange(EventListenerModelChange change) {
21082124
}
21092125
}
21102126

2111-
if (stopped) {
2127+
if (stopped || !deferredConfiguration) {
21122128
// we have to start it again
21132129
// register a "callback batch operation", which will be submitted within a new batch
21142130
// as new task in single paxweb-config thread pool's thread
2115-
LOG.info("Scheduling start of the {} context after listener registration for already started context", contextPath);
2116-
change.registerBatchCompletedAction(new ContextStartChange(OpCode.MODIFY, contextPath));
2131+
if (stopped) {
2132+
LOG.info("Scheduling start of the {} context after listener registration for already started context", contextPath);
2133+
} else {
2134+
LOG.info("Scheduling start of the {} context after listener registration for immediately started context", contextPath);
2135+
}
2136+
ContextStartChange action = new ContextStartChange(OpCode.MODIFY, contextPath);
2137+
action.setAsync(change.getEventListenerModel().isAsynchronusRegistration());
2138+
change.registerBatchCompletedAction(action);
21172139
}
21182140
});
21192141
}

0 commit comments

Comments
 (0)