-
Notifications
You must be signed in to change notification settings - Fork 23
/
ConcurrencyProvider.java
178 lines (166 loc) · 8.36 KB
/
ConcurrencyProvider.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* Copyright (c) 2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.microprofile.concurrent.spi;
import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.microprofile.concurrent.ManagedExecutorBuilder;
import org.eclipse.microprofile.concurrent.ThreadContextBuilder;
/**
* <p>MicroProfile Concurrency provider implementation supplied by the
* container, which creates new instances of
* <code>ManagedExecutorBuilder</code> and
* <code>ThreadContextBuilder</code>.</p>
*
* <p>The container must register its <code>ConcurrencyProvider</code>
* implementation via the <code>register</code> method, or by providing
* an implementation via the standard {@link ServiceLoader} mechanism.</p>
*
* <p><code>ConcurrencyProvider</code> implementations that wish to use
* the {@link ServiceLoader} registration mechanism must include a file
* of the following name and location in their jar:</p>
*
* <code>META-INF/services/org.eclipse.microprofile.concurrent.spi.ConcurrencyProvider</code>
*
* <p>The content of the aforementioned file must be exactly one line, specifying
* the fully qualified name of a <code>ConcurrencyProvider</code> implementation
* that is provided within the JAR file.</p>
*
* <p>If there is no manually registered <code>ConcurrencyProvider</code> (via
* {@link #register(ConcurrencyProvider)}), any call to {@link #instance()} will
* look up any <code>ConcurrencyProvider</code> implementation via the aforementioned
* {@link ServiceLoader} mechanism. If there are more than one such implementation
* registered, the {@link #instance()} method will throw an exception as documented</p>
*/
public interface ConcurrencyProvider {
static AtomicReference<ConcurrencyProvider> INSTANCE = new AtomicReference<ConcurrencyProvider>();
/**
* Obtains the <code>ConcurrencyProvider</code> instance that has been previously registered, or
* uses {@link ServiceLoader} to load and register a <code>ConcurrencyProvider</code> from the
* current context class loader.
*
* @return the registered <code>ConcurrencyProvider</code> instance.
* @throws IllegalStateException if there are no registered <code>ConcurrencyProvider</code> and
* we could not discover any via {@link ServiceLoader}, or if there are more than one
* {@link ServiceLoader} results.
*/
public static ConcurrencyProvider instance() {
ConcurrencyProvider provider = INSTANCE.get();
if (provider == null) {
for (ConcurrencyProvider serviceProvider : ServiceLoader.load(ConcurrencyProvider.class)) {
if (INSTANCE.compareAndSet(null, serviceProvider)) {
provider = serviceProvider;
}
else {
throw new IllegalStateException("ConcurrencyProvider already set");
}
}
if (provider == null) {
throw new IllegalStateException("Container has not registered a ConcurrencyProvider");
}
}
return provider;
}
/**
* Allows the container to register the <code>ConcurrencyProvider</code>
* implementation. At most one implementation can be registered at any
* given point in time. In order to register a different implementation,
* the container must first unregister its previous implementation.
*
* @param provider the provider implementation to register.
* @throws IllegalStateException if an implementation is already registered.
*/
public static ConcurrencyProviderRegistration register(ConcurrencyProvider provider) throws IllegalStateException {
if (INSTANCE.compareAndSet(null, provider)) {
return new ConcurrencyProviderRegistration(provider);
}
else {
throw new IllegalStateException("A ConcurrencyProvider implementation has already been registered.");
}
}
/**
* Gets a {@link ConcurrencyManager} for the current thread-context {@link ClassLoader}. This
* is equivalent to calling <code>getConcurrencyManager(Thread.currentThread().getContextClassLoader())</code>
*
* @return a {@link ConcurrencyManager} for the current thread-context {@link ClassLoader}.
* @see #getConcurrencyManager(ClassLoader)
*/
public ConcurrencyManager getConcurrencyManager();
/**
* Gets a {@link ConcurrencyManager} for the given {@link ClassLoader}. If there is already
* a {@link ConcurrencyManager} registered for the given {@link ClassLoader}, the existing
* instance will be returned. If not, one will be created using a {@link ConcurrencyManagerBuilder}
* using the specified {@link ClassLoader} (with {@link ConcurrencyManagerBuilder#forClassLoader(ClassLoader)})
* and with {@link ConcurrencyManagerBuilder#addDiscoveredThreadContextProviders()} called in
* order to load all {@link ThreadContextProvider} discoverable from the given {@link ClassLoader}.
* If created, the new {@link ConcurrencyManager} will then be registered for the given {@link ClassLoader}
* with {@link #registerConcurrencyManager(ConcurrencyManager, ClassLoader)}.
*
* @return a {@link ConcurrencyManager} for the given {@link ClassLoader}.
* @see ConcurrencyManagerBuilder#addDiscoveredThreadContextProviders()
* @see ConcurrencyManagerBuilder#build()
* @see #registerConcurrencyManager(ConcurrencyManager, ClassLoader)
*/
public ConcurrencyManager getConcurrencyManager(ClassLoader classLoader);
/**
* Returns a new {@link ConcurrencyManagerBuilder} to create new {@link ConcurrencyManager}
* instances. Watch out that instances created this way will not be automatically registered
* here, so you need to call {@link #registerConcurrencyManager(ConcurrencyManager, ClassLoader)}
* yourself if you need to.
*
* @return a new {@link ConcurrencyManagerBuilder}
*/
public ConcurrencyManagerBuilder getConcurrencyManagerBuilder();
/**
* Registers the given {@link ConcurrencyManager} for the given {@link ClassLoader}, so that
* further calls to {@link #getConcurrencyManager(ClassLoader)} for the same {@link ClassLoader}
* will return this instance instead of creating a new one.
*
* @param manager The {@link ConcurrencyManager} to register
* @param classLoader The {@link ClassLoader} to register it for
* @see #getConcurrencyManager(ClassLoader)
* @see #releaseConcurrencyManager(ConcurrencyManager)
*/
public void registerConcurrencyManager(ConcurrencyManager manager, ClassLoader classLoader);
/**
* Releases a {@link ConcurrencyManager} that was previously registered with
* {@link #registerConcurrencyManager(ConcurrencyManager, ClassLoader)}.
*
* @param manager The {@link ConcurrencyManager} to release
* @see #registerConcurrencyManager(ConcurrencyManager, ClassLoader)
*/
public void releaseConcurrencyManager(ConcurrencyManager manager);
/**
* Creates a new <code>ManagedExecutorBuilder</code> instance using the
* {@link ConcurrencyManager} returned by {@link #getConcurrencyManager()}.
*
* @return a new <code>ManagedExecutorBuilder</code> instance.
*/
default ManagedExecutorBuilder newManagedExecutorBuilder() {
return getConcurrencyManager().newManagedExecutorBuilder();
}
/**
* Creates a new <code>ThreadContextBuilder</code> instance using the
* {@link ConcurrencyManager} returned by {@link #getConcurrencyManager()}.
*
* @return a new <code>ThreadContextBuilder</code> instance.
*/
default ThreadContextBuilder newThreadContextBuilder() {
return getConcurrencyManager().newThreadContextBuilder();
}
}