Merge pull request #610 from dangerousben/init-race-condition
Fix FhirContext initialisation race condition.
This commit is contained in:
commit
9201692c70
|
@ -82,7 +82,6 @@ public class FhirContext {
|
||||||
private Map<String, Class<? extends IBaseResource>> myDefaultTypeForProfile = new HashMap<String, Class<? extends IBaseResource>>();
|
private Map<String, Class<? extends IBaseResource>> myDefaultTypeForProfile = new HashMap<String, Class<? extends IBaseResource>>();
|
||||||
private volatile Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = Collections.emptyMap();
|
private volatile Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = Collections.emptyMap();
|
||||||
private boolean myInitialized;
|
private boolean myInitialized;
|
||||||
private boolean myInitializing;
|
|
||||||
private HapiLocalizer myLocalizer = new HapiLocalizer();
|
private HapiLocalizer myLocalizer = new HapiLocalizer();
|
||||||
private volatile Map<String, BaseRuntimeElementDefinition<?>> myNameToElementDefinition = Collections.emptyMap();
|
private volatile Map<String, BaseRuntimeElementDefinition<?>> myNameToElementDefinition = Collections.emptyMap();
|
||||||
private volatile Map<String, RuntimeResourceDefinition> myNameToResourceDefinition = Collections.emptyMap();
|
private volatile Map<String, RuntimeResourceDefinition> myNameToResourceDefinition = Collections.emptyMap();
|
||||||
|
@ -644,8 +643,6 @@ public class FhirContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> scanResourceTypes(Collection<Class<? extends IElement>> theResourceTypes) {
|
private synchronized Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> scanResourceTypes(Collection<Class<? extends IElement>> theResourceTypes) {
|
||||||
myInitializing = true;
|
|
||||||
|
|
||||||
List<Class<? extends IBase>> typesToScan = new ArrayList<Class<? extends IBase>>();
|
List<Class<? extends IBase>> typesToScan = new ArrayList<Class<? extends IBase>>();
|
||||||
if (theResourceTypes != null) {
|
if (theResourceTypes != null) {
|
||||||
typesToScan.addAll(theResourceTypes);
|
typesToScan.addAll(theResourceTypes);
|
||||||
|
@ -844,8 +841,8 @@ public class FhirContext {
|
||||||
return resTypes;
|
return resTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateInitialized() {
|
private synchronized void validateInitialized() {
|
||||||
if (!myInitialized && !myInitializing) {
|
if (!myInitialized) {
|
||||||
scanResourceTypes(toElementList(myResourceTypesToScan));
|
scanResourceTypes(toElementList(myResourceTypesToScan));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
package ca.uhn.fhir.context;
|
package ca.uhn.fhir.context;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
import org.hl7.fhir.dstu3.model.Reference;
|
import org.hl7.fhir.dstu3.model.Reference;
|
||||||
|
@ -81,4 +87,41 @@ public class FhirContextDstu3Test {
|
||||||
assertEquals(null, genderChild.getBoundEnumType());
|
assertEquals(null, genderChild.getBoundEnumType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitialisationThreadSafety() {
|
||||||
|
final FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
final int numThreads = 4;
|
||||||
|
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
|
||||||
|
final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads);
|
||||||
|
try {
|
||||||
|
final CountDownLatch threadsReady = new CountDownLatch(numThreads);
|
||||||
|
final CountDownLatch threadsFinished = new CountDownLatch(numThreads);
|
||||||
|
|
||||||
|
for (int i = 0; i < numThreads; i++) {
|
||||||
|
threadPool.submit(
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
threadsReady.countDown();
|
||||||
|
try {
|
||||||
|
threadsReady.await();
|
||||||
|
ctx.getResourceDefinition("patient");
|
||||||
|
} catch(final Exception e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
}
|
||||||
|
threadsFinished.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
threadsFinished.await();
|
||||||
|
} catch(final InterruptedException e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
} finally {
|
||||||
|
threadPool.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("failed with exception(s): " + exceptions, exceptions.isEmpty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue