-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
WeldExecutorServices.java
155 lines (134 loc) · 5.43 KB
/
WeldExecutorServices.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.jboss.as.weld.services.bootstrap;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.jboss.as.naming.context.NamespaceContextSelector;
import org.jboss.as.server.Services;
import org.jboss.msc.Service;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.threads.JBossThreadFactory;
import org.jboss.weld.Container;
import org.jboss.weld.ContainerState;
import org.jboss.weld.executor.AbstractExecutorServices;
import org.jboss.weld.manager.api.ExecutorServices;
import org.wildfly.security.manager.WildFlySecurityManager;
/**
* Weld's ExecutorServices implementation. The executor is shared across all Jakarta Contexts and Dependency Injection enabled deployments and used primarily for parallel Weld bootstrap.
*
* @author Jozef Hartinger
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
public class WeldExecutorServices extends AbstractExecutorServices implements Service {
public static final int DEFAULT_BOUND = Runtime.getRuntime().availableProcessors() + 1;
public static final ServiceName SERVICE_NAME = Services.JBOSS_AS.append("weld", "executor");
private static final String THREAD_NAME_PATTERN = "Weld Thread Pool -- %t";
private final int bound;
private final Consumer<ExecutorServices> executorServicesConsumer;
private ExecutorService executor;
public WeldExecutorServices() {
this(null, DEFAULT_BOUND);
}
public WeldExecutorServices(final Consumer<ExecutorServices> executorServicesConsumer, int bound) {
this.executorServicesConsumer = executorServicesConsumer;
this.bound = bound;
}
@Override
public void start(final StartContext context) throws StartException {
final ThreadFactory factory = new JBossThreadFactory(null, Boolean.FALSE, null, THREAD_NAME_PATTERN, null, null);
// set TCCL to null for new threads to make sure no deployment classloader leaks through this executor's TCCL
// Weld does not mind having null TCCL in this executor
this.executor = new WeldExecutor(bound, runnable -> {
Thread thread = factory.newThread(runnable);
if (WildFlySecurityManager.isChecking()) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
thread.setContextClassLoader(null);
return null;
}
});
} else {
thread.setContextClassLoader(null);
}
return thread;
}
);
if (executorServicesConsumer != null) executorServicesConsumer.accept(this);
}
@Override
public void stop(final StopContext context) {
if (executorServicesConsumer != null) executorServicesConsumer.accept(null);
if (executor != null) {
context.asynchronous();
new Thread(() -> {
super.shutdown();
executor = null;
context.complete();
}).start();
}
}
@Override
protected synchronized int getThreadPoolSize() {
return bound;
}
@Override
public synchronized ExecutorService getTaskExecutor() {
return executor;
}
@Override
public void cleanup() {
// noop on undeploy - the executor is a service shared across multiple deployments
}
static class WeldExecutor extends ThreadPoolExecutor {
WeldExecutor(int nThreads, ThreadFactory threadFactory) {
super(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
if (r instanceof WeldTaskWrapper) {
NamespaceContextSelector.pushCurrentSelector(((WeldTaskWrapper) r).currentSelector);
}
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
if (r instanceof WeldTaskWrapper) {
NamespaceContextSelector.popCurrentSelector();
}
}
@Override
public void execute(Runnable command) {
if (Container.instance().getState() == ContainerState.INITIALIZED) {
WeldTaskWrapper task = new WeldTaskWrapper(command, NamespaceContextSelector.getCurrentSelector());
super.execute(task);
} else {
super.execute(command);
}
}
}
static class WeldTaskWrapper implements Runnable {
private final Runnable runnable;
private final NamespaceContextSelector currentSelector;
public WeldTaskWrapper(Runnable runnable, NamespaceContextSelector currentSelector) {
this.runnable = runnable;
this.currentSelector = currentSelector;
}
@Override
public void run() {
runnable.run();
}
}
}