Remove deleted resources from cached search results (#1732)
* Remove deleted resources from cached search results * Add changelog * Add tests
This commit is contained in:
parent
cb9906580e
commit
5bc554949b
|
@ -22,8 +22,11 @@ package ca.uhn.fhir.context;
|
|||
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -33,11 +36,11 @@ public abstract class BaseRuntimeElementDefinition<T extends IBase> {
|
|||
private final Class<? extends T> myImplementingClass;
|
||||
private final String myName;
|
||||
private final boolean myStandardType;
|
||||
private Map<Class<?>, Constructor<T>> myConstructors = Collections.synchronizedMap(new HashMap<Class<?>, Constructor<T>>());
|
||||
private List<RuntimeChildDeclaredExtensionDefinition> myExtensions = new ArrayList<RuntimeChildDeclaredExtensionDefinition>();
|
||||
private List<RuntimeChildDeclaredExtensionDefinition> myExtensionsModifier = new ArrayList<RuntimeChildDeclaredExtensionDefinition>();
|
||||
private List<RuntimeChildDeclaredExtensionDefinition> myExtensionsNonModifier = new ArrayList<RuntimeChildDeclaredExtensionDefinition>();
|
||||
private Map<String, RuntimeChildDeclaredExtensionDefinition> myUrlToExtension = new HashMap<String, RuntimeChildDeclaredExtensionDefinition>();
|
||||
private Map<Class<?>, Constructor<T>> myConstructors = Collections.synchronizedMap(new HashMap<>());
|
||||
private List<RuntimeChildDeclaredExtensionDefinition> myExtensions = new ArrayList<>();
|
||||
private List<RuntimeChildDeclaredExtensionDefinition> myExtensionsModifier = new ArrayList<>();
|
||||
private List<RuntimeChildDeclaredExtensionDefinition> myExtensionsNonModifier = new ArrayList<>();
|
||||
private Map<String, RuntimeChildDeclaredExtensionDefinition> myUrlToExtension = new HashMap<>();
|
||||
private BaseRuntimeElementDefinition<?> myRootParentDefinition;
|
||||
|
||||
public BaseRuntimeElementDefinition(String theName, Class<? extends T> theImplementingClass, boolean theStandardType) {
|
||||
|
@ -56,19 +59,17 @@ public abstract class BaseRuntimeElementDefinition<T extends IBase> {
|
|||
myImplementingClass = theImplementingClass;
|
||||
}
|
||||
|
||||
public void addExtension(RuntimeChildDeclaredExtensionDefinition theExtension) {
|
||||
if (theExtension == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
public void addExtension(@Nonnull RuntimeChildDeclaredExtensionDefinition theExtension) {
|
||||
Validate.notNull(theExtension, "theExtension must not be null");
|
||||
myExtensions.add(theExtension);
|
||||
}
|
||||
|
||||
public abstract ChildTypeEnum getChildType();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Constructor<T> getConstructor(Object theArgument) {
|
||||
private Constructor<T> getConstructor(@Nullable Object theArgument) {
|
||||
|
||||
Class<? extends Object> argumentType;
|
||||
Class<?> argumentType;
|
||||
if (theArgument == null) {
|
||||
argumentType = VOID_CLASS;
|
||||
} else {
|
||||
|
|
|
@ -377,9 +377,8 @@ public class FhirContext {
|
|||
*/
|
||||
public RuntimeResourceDefinition getResourceDefinition(final Class<? extends IBaseResource> theResourceType) {
|
||||
validateInitialized();
|
||||
if (theResourceType == null) {
|
||||
throw new NullPointerException("theResourceType can not be null");
|
||||
}
|
||||
Validate.notNull(theResourceType, "theResourceType can not be null");
|
||||
|
||||
if (Modifier.isAbstract(theResourceType.getModifiers())) {
|
||||
throw new IllegalArgumentException("Can not scan abstract or interface class (resource definitions must be concrete classes): " + theResourceType.getName());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 1732
|
||||
title: In the JPA server, quickly deleting a resource and then performing a query that had recently returned that
|
||||
search result could cause a cached stub resource (containing no data but with an ID and metadata populated) to
|
||||
be returned. This has been corrected.
|
|
@ -504,6 +504,9 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
|
||||
ResourcePersistentId resourceId;
|
||||
for (ResourceSearchView next : resourceSearchViewList) {
|
||||
if (next.getDeleted() != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<? extends IBaseResource> resourceType = myContext.getResourceDefinition(next.getResourceType()).getImplementingClass();
|
||||
|
||||
|
|
|
@ -9,20 +9,29 @@ import ca.uhn.fhir.rest.api.Constants;
|
|||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.blankOrNullString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class ResourceProviderR4CacheTest extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(ResourceProviderR4CacheTest.class);
|
||||
private CapturingInterceptor myCapturingInterceptor;
|
||||
@Autowired
|
||||
private ISearchDao mySearchEntityDao;
|
||||
|
@ -184,6 +193,39 @@ public class ResourceProviderR4CacheTest extends BaseResourceProviderR4Test {
|
|||
assertEquals(results1.getId(), results2.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletedSearchResultsNotReturnedFromCache() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("Foo");
|
||||
String p1Id = myPatientDao.create(p).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
p = new Patient();
|
||||
p.addName().setFamily("Foo");
|
||||
String p2Id = myPatientDao.create(p).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Bundle resp1 = ourClient
|
||||
.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.NAME.matches().value("foo"))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
assertEquals(2, resp1.getEntry().size());
|
||||
|
||||
ourClient.delete().resourceById(new IdType(p1Id)).execute();
|
||||
|
||||
Bundle resp2 = ourClient
|
||||
.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.NAME.matches().value("foo"))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
assertEquals(resp1.getId(), resp2.getId());
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp2));
|
||||
assertEquals(1, resp2.getEntry().size());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class BaseRuntimeElementDefinitionTest {
|
||||
|
||||
@Test
|
||||
public void testNewInstance_InvalidArgumentType() {
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
|
||||
BaseRuntimeElementDefinition<?> def = ctx.getElementDefinition("string");
|
||||
|
||||
try {
|
||||
def.newInstance(123);
|
||||
fail();
|
||||
} catch (ConfigurationException e) {
|
||||
assertEquals("Failed to instantiate type:org.hl7.fhir.r4.model.StringType", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue