From 2c722e64c27dd240addf5d7037f0e92fe9ad08c1 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Sun, 23 May 2021 16:50:37 -0400 Subject: [PATCH] Add support for including qualified star syntax (#2672) * Add support for including qualified star syntax * Add changelog * Add docs * Build fix --- ...2672-fix-concurrency-error-under-load.yaml | 5 + .../2672-support-include-restpe-star.yaml | 5 + hapi-fhir-jacoco/pom.xml | 7 + .../fhir/jpa/dao/index/IdHelperService.java | 27 +- .../jpa/search/SearchCoordinatorSvcImpl.java | 7 +- .../jpa/search/builder/SearchBuilder.java | 27 ++ .../uhn/fhir/jpa/util/MemoryCacheService.java | 19 ++ .../FhirResourceDaoR4ConcurrentWriteTest.java | 65 +++- .../r4/FhirResourceDaoR4SearchNoFtTest.java | 305 +++++++++++------- .../jpa/searchparam/SearchParameterMap.java | 120 +++---- pom.xml | 2 +- 11 files changed, 392 insertions(+), 197 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-fix-concurrency-error-under-load.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-support-include-restpe-star.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-fix-concurrency-error-under-load.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-fix-concurrency-error-under-load.yaml new file mode 100644 index 00000000000..57ac0a12b29 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-fix-concurrency-error-under-load.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 2672 +title: "A concurrency error was fixed when using client assigned IDs on a highly concurrent server + with resource deletion disabled." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-support-include-restpe-star.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-support-include-restpe-star.yaml new file mode 100644 index 00000000000..60888789428 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_5_0/2672-support-include-restpe-star.yaml @@ -0,0 +1,5 @@ +--- +type: add +issue: 2672 +title: "Support has been added to the JPA server for `_include` and `_revinclude` where the + value is a qualified star, e.g. `_include=Observation:*`." diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index 7d875c36e9a..1379062ae1c 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -144,6 +144,13 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + + validatenone + + diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/IdHelperService.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/IdHelperService.java index b60eb46b89f..7b4996aff27 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/IdHelperService.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/IdHelperService.java @@ -42,6 +42,8 @@ import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -82,7 +84,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; @Service public class IdHelperService { private static final String RESOURCE_PID = "RESOURCE_PID"; - + private static final Logger ourLog = LoggerFactory.getLogger(IdHelperService.class); @Autowired protected IForcedIdDao myForcedIdDao; @Autowired @@ -142,7 +144,7 @@ public class IdHelperService { retVal = new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId()); } else { String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theId); - retVal = myMemoryCacheService.get(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, t -> new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId())); + retVal = myMemoryCacheService.getThenPutAfterCommit(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, t -> new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId())); } } else { @@ -252,7 +254,6 @@ public class IdHelperService { return retVal; } - public Optional translatePidIdToForcedIdWithCache(ResourcePersistentId theId) { return myMemoryCacheService.get(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theId.getIdAsLong(), pid -> myForcedIdDao.findByResourcePid(pid).map(t -> t.getForcedId())); } @@ -334,7 +335,7 @@ public class IdHelperService { if (!myDaoConfig.isDeleteEnabled()) { String key = resourceType + "/" + forcedId; - myMemoryCacheService.put(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, key, lookup); + myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, key, lookup); } } } @@ -378,7 +379,7 @@ public class IdHelperService { theTarget.add(t); if (!myDaoConfig.isDeleteEnabled()) { String nextKey = Long.toString(t.getResourceId()); - myMemoryCacheService.put(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, nextKey, t); + myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, nextKey, t); } }); @@ -386,12 +387,11 @@ public class IdHelperService { } /** - * * Given a set of PIDs, return a set of public FHIR Resource IDs. * This function will resolve a forced ID if it resolves, and if it fails to resolve to a forced it, will just return the pid * Example: * Let's say we have Patient/1(pid == 1), Patient/pat1 (pid == 2), Patient/3 (pid == 3), their pids would resolve as follows: - * + *

* [1,2,3] -> ["1","pat1","3"] * * @param thePids The Set of pids you would like to resolve to external FHIR Resource IDs. @@ -408,6 +408,7 @@ public class IdHelperService { return resolvedResourceIds; } + public Map> translatePidsToForcedIds(Set thePids) { Map> retVal = new HashMap<>(myMemoryCacheService.getAllPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, thePids)); @@ -423,7 +424,7 @@ public class IdHelperService { Long nextResourcePid = forcedId.getResourceId(); Optional nextForcedId = Optional.of(forcedId.getForcedId()); retVal.put(nextResourcePid, nextForcedId); - myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, nextForcedId); + myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, nextForcedId); } }); @@ -433,7 +434,7 @@ public class IdHelperService { .collect(Collectors.toList()); for (Long nextResourcePid : remainingPids) { retVal.put(nextResourcePid, Optional.empty()); - myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, Optional.empty()); + myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, Optional.empty()); } return retVal; @@ -491,11 +492,11 @@ public class IdHelperService { */ public void addResolvedPidToForcedId(ResourcePersistentId theResourcePersistentId, @Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, @Nullable String theForcedId) { if (theForcedId != null) { - myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.of(theForcedId)); + myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.of(theForcedId)); String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theForcedId); - myMemoryCacheService.put(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, theResourcePersistentId); - }else { - myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.empty()); + myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, theResourcePersistentId); + } else { + myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.empty()); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java index 1babac735ba..581a741169b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java @@ -1250,9 +1250,12 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc { theSearch.setStatus(SearchStatusEnum.LOADING); theSearch.setSearchQueryString(theQueryString, theRequestPartitionId); - for (Include next : theParams.getIncludes()) { - theSearch.addInclude(new SearchInclude(theSearch, next.getValue(), false, next.isRecurse())); + if (theParams.hasIncludes()) { + for (Include next : theParams.getIncludes()) { + theSearch.addInclude(new SearchInclude(theSearch, next.getValue(), false, next.isRecurse())); + } } + for (Include next : theParams.getRevIncludes()) { theSearch.addInclude(new SearchInclude(theSearch, next.getValue(), true, next.isRecurse())); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java index 8a221b15879..ed825f14920 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java @@ -787,7 +787,18 @@ public class SearchBuilder implements ISearchBuilder { iter.remove(); } + // Account for _include=* boolean matchAll = "*".equals(nextInclude.getValue()); + + // Account for _include=[resourceType]:* + String wantResourceType = null; + if (!matchAll) { + if (nextInclude.getParamName().equals("*")) { + wantResourceType = nextInclude.getParamType(); + matchAll = true; + } + } + if (matchAll) { StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("SELECT r.").append(findPidFieldName); @@ -797,11 +808,27 @@ public class SearchBuilder implements ISearchBuilder { sqlBuilder.append(" FROM ResourceLink r WHERE r."); sqlBuilder.append(searchPidFieldName); sqlBuilder.append(" IN (:target_pids)"); + + // Technically if the request is a qualified star (e.g. _include=Observation:*) we + // should always be checking the source resource type on the resource link. We don't + // actually index that column though by default, so in order to try and be efficient + // we don't actually include it for includes (but we do for revincludes). This is + // because for an include it doesn't really make sense to include a different + // resource type than the one you are searching on. + if (wantResourceType != null && theReverseMode) { + sqlBuilder.append(" AND r.mySourceResourceType = :want_resource_type"); + } else { + wantResourceType = null; + } + String sql = sqlBuilder.toString(); List> partitions = partition(nextRoundMatches, getMaximumPageSize()); for (Collection nextPartition : partitions) { TypedQuery q = theEntityManager.createQuery(sql, Object[].class); q.setParameter("target_pids", ResourcePersistentId.toLongList(nextPartition)); + if (wantResourceType != null) { + q.setParameter("want_resource_type", wantResourceType); + } List results = q.getResultList(); for (Object nextRow : results) { if (nextRow == null) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java index c1d1d8badbd..9c3d0b75f09 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java @@ -28,6 +28,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hl7.fhir.instance.model.api.IIdType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.support.TransactionSynchronization; @@ -94,6 +95,24 @@ public class MemoryCacheService { return cache.get(theKey, theSupplier); } + /** + * Fetch an item from the cache if it exists, and use the loading function to + * obtain it otherwise. + * + * This method will put the value into the cache using {@link #putAfterCommit(CacheEnum, Object, Object)}. + */ + public T getThenPutAfterCommit(CacheEnum theCache, K theKey, Function theSupplier) { + assert theCache.myKeyType.isAssignableFrom(theKey.getClass()); + + Cache cache = getCache(theCache); + T retVal = cache.getIfPresent(theKey); + if (retVal == null) { + retVal = theSupplier.apply(theKey); + putAfterCommit(theCache, theKey, retVal); + } + return retVal; + } + public V getIfPresent(CacheEnum theCache, K theKey) { assert theCache.myKeyType.isAssignableFrom(theKey.getClass()); return (V) getCache(theCache).getIfPresent(theKey); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java index 72954eadaef..1e1bda39256 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java @@ -25,6 +25,7 @@ import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Practitioner; +import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.SearchParameter; import org.hl7.fhir.r4.model.StringType; import org.junit.jupiter.api.AfterEach; @@ -147,12 +148,12 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { creator.run(); } - runInTransaction(()->{ + runInTransaction(() -> { Map counts = new TreeMap<>(); myResourceTableDao .findAll() .stream() - .forEach(t->{ + .forEach(t -> { counts.putIfAbsent(t.getResourceType(), 0); int value = counts.get(t.getResourceType()); value++; @@ -166,7 +167,6 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { } - @Test public void testCreateWithClientAssignedId() { myInterceptorRegistry.registerInterceptor(myRetryInterceptor); @@ -603,4 +603,63 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { } + + @Test + public void testTransactionWithCreateClientAssignedIdAndReferenceToThatId() { + myInterceptorRegistry.registerInterceptor(myRetryInterceptor); + myDaoConfig.setDeleteEnabled(false); + + ServletRequestDetails srd = mock(ServletRequestDetails.class); + String value = UserRequestRetryVersionConflictsInterceptor.RETRY + "; " + UserRequestRetryVersionConflictsInterceptor.MAX_RETRIES + "=10"; + when(srd.getHeaders(eq(UserRequestRetryVersionConflictsInterceptor.HEADER_NAME))).thenReturn(Collections.singletonList(value)); + when(srd.getUserData()).thenReturn(new HashMap<>()); + when(srd.getServer()).thenReturn(new RestfulServer(myFhirCtx)); + when(srd.getInterceptorBroadcaster()).thenReturn(new InterceptorService()); + + List> futures = new ArrayList<>(); + int repetitionCount = 3; + for (int i = 0; i < repetitionCount; i++) { + String patientId = "PATIENT" + i; + + Runnable task = () -> { + BundleBuilder bb = new BundleBuilder(myFhirCtx); + + Patient p = new Patient(); + p.setId(patientId); + p.setActive(true); + bb.addTransactionUpdateEntry(p); + + Observation obs = new Observation(); + obs.setSubject(new Reference("Patient/" + patientId)); + bb.addTransactionCreateEntry(obs); + + ourLog.info("Submitting transaction"); + mySystemDao.transaction(srd, (Bundle) bb.getBundle()); + }; + + for (int j = 0; j < 5; j++) { + Future future = myExecutor.submit(task); + futures.add(future); + } + } + + // Look for failures + for (Future next : futures) { + try { + next.get(); + ourLog.info("Future produced success"); + } catch (Exception e) { + ourLog.info("Future produced exception: {}", e.toString()); + throw new AssertionError("Failed with message: " + e.toString(), e); + } + } + + // Make sure we saved the object + for (int i = 0; i < repetitionCount; i++) { + Patient patient = myPatientDao.read(new IdType("Patient/PATIENT0")); + assertEquals(true, patient.getActive()); + } + + } + } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java index a3ec8f94745..72ca9a23214 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java @@ -1,40 +1,60 @@ package ca.uhn.fhir.jpa.dao.r4; -import static ca.uhn.fhir.rest.api.Constants.PARAM_TYPE; -import static org.apache.commons.lang3.StringUtils.countMatches; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.not; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.IOException; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletRequest; - +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.interceptor.api.HookParams; +import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor; +import ca.uhn.fhir.interceptor.api.Pointcut; +import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.entity.Search; +import ca.uhn.fhir.jpa.model.config.PartitionSettings; +import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri; +import ca.uhn.fhir.jpa.model.entity.ResourceLink; +import ca.uhn.fhir.jpa.model.entity.ResourceTable; +import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage; +import ca.uhn.fhir.jpa.model.util.UcumServiceUtil; +import ca.uhn.fhir.jpa.searchparam.MatchUrlService; +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum; +import ca.uhn.fhir.jpa.util.SqlQuery; +import ca.uhn.fhir.jpa.util.TestUtil; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import ca.uhn.fhir.parser.StrictErrorHandler; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.CompositeParam; +import ca.uhn.fhir.rest.param.DateParam; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.HasAndListParam; +import ca.uhn.fhir.rest.param.HasOrListParam; +import ca.uhn.fhir.rest.param.HasParam; +import ca.uhn.fhir.rest.param.NumberParam; +import ca.uhn.fhir.rest.param.ParamPrefixEnum; +import ca.uhn.fhir.rest.param.QuantityParam; +import ca.uhn.fhir.rest.param.ReferenceAndListParam; +import ca.uhn.fhir.rest.param.ReferenceOrListParam; +import ca.uhn.fhir.rest.param.ReferenceParam; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringOrListParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; +import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.TokenParamModifier; +import ca.uhn.fhir.rest.param.UriParam; +import ca.uhn.fhir.rest.param.UriParamQualifierEnum; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; +import ca.uhn.fhir.util.HapiExtensions; +import com.google.common.collect.Lists; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; @@ -116,61 +136,38 @@ import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; -import com.google.common.collect.Lists; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; -import ca.uhn.fhir.context.RuntimeResourceDefinition; -import ca.uhn.fhir.interceptor.api.HookParams; -import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor; -import ca.uhn.fhir.interceptor.api.Pointcut; -import ca.uhn.fhir.jpa.api.config.DaoConfig; -import ca.uhn.fhir.jpa.entity.Search; -import ca.uhn.fhir.jpa.model.config.PartitionSettings; -import ca.uhn.fhir.jpa.model.entity.ModelConfig; -import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; -import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber; -import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity; -import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized; -import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString; -import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; -import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri; -import ca.uhn.fhir.jpa.model.entity.ResourceLink; -import ca.uhn.fhir.jpa.model.entity.ResourceTable; -import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage; -import ca.uhn.fhir.jpa.searchparam.MatchUrlService; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum; -import ca.uhn.fhir.jpa.util.SqlQuery; -import ca.uhn.fhir.jpa.util.TestUtil; -import ca.uhn.fhir.model.api.Include; -import ca.uhn.fhir.model.api.TemporalPrecisionEnum; -import ca.uhn.fhir.parser.StrictErrorHandler; -import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.api.server.IBundleProvider; -import ca.uhn.fhir.rest.param.CompositeParam; -import ca.uhn.fhir.rest.param.DateParam; -import ca.uhn.fhir.rest.param.DateRangeParam; -import ca.uhn.fhir.rest.param.HasAndListParam; -import ca.uhn.fhir.rest.param.HasOrListParam; -import ca.uhn.fhir.rest.param.HasParam; -import ca.uhn.fhir.rest.param.NumberParam; -import ca.uhn.fhir.rest.param.ParamPrefixEnum; -import ca.uhn.fhir.rest.param.QuantityParam; -import ca.uhn.fhir.rest.param.ReferenceAndListParam; -import ca.uhn.fhir.rest.param.ReferenceOrListParam; -import ca.uhn.fhir.rest.param.ReferenceParam; -import ca.uhn.fhir.rest.param.StringAndListParam; -import ca.uhn.fhir.rest.param.StringOrListParam; -import ca.uhn.fhir.rest.param.StringParam; -import ca.uhn.fhir.rest.param.TokenAndListParam; -import ca.uhn.fhir.rest.param.TokenOrListParam; -import ca.uhn.fhir.rest.param.TokenParam; -import ca.uhn.fhir.rest.param.TokenParamModifier; -import ca.uhn.fhir.rest.param.UriParam; -import ca.uhn.fhir.rest.param.UriParamQualifierEnum; -import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; -import ca.uhn.fhir.util.HapiExtensions; -import ca.uhn.fhir.jpa.model.util.UcumServiceUtil; +import static ca.uhn.fhir.rest.api.Constants.PARAM_TYPE; +import static org.apache.commons.lang3.StringUtils.countMatches; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; @SuppressWarnings({"unchecked", "Duplicates"}) public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { @@ -186,8 +183,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches()); myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds()); myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields()); - myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED); - } + myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED); + } @BeforeEach public void beforeDisableCacheReuse() { @@ -573,7 +570,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * "))); }); - SearchParameterMap map = SearchParameterMap.newSynchronous(); + SearchParameterMap map = SearchParameterMap.newSynchronous(); map.add(MedicationAdministration.SP_MEDICATION, new ReferenceAndListParam().addAnd(new ReferenceOrListParam().add(new ReferenceParam("code", "04823543")))); myCaptureQueriesListener.clear(); @@ -607,8 +604,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { String yesterday = new DateType(DateUtils.addDays(new Date(), -1)).getValueAsString(); String tomorrow = new DateType(DateUtils.addDays(new Date(), 1)).getValueAsString(); - runInTransaction(()->{ - ourLog.info("Resources:\n * {}", myResourceTableDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * "))); + runInTransaction(() -> { + ourLog.info("Resources:\n * {}", myResourceTableDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * "))); }); RuntimeResourceDefinition resDef = myFhirCtx.getResourceDefinition("DiagnosticReport"); @@ -768,8 +765,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { pat2.getManagingOrganization().setReferenceElement(orgId); IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless(); - runInTransaction(()->{ - ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * "))); + runInTransaction(() -> { + ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * "))); }); // All patient IDs @@ -1229,7 +1226,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { ourLog.info(toStringMultiline(results)); assertEquals(0, results.size()); }); - + List actual = toUnqualifiedVersionlessIds( mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT")))); assertThat(actual, contains(id)); @@ -1244,45 +1241,45 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(123); res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232); res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232); - + IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless(); List actual = toUnqualifiedVersionlessIds( mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 12300, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")))); assertThat(actual, contains(id)); - + } - + @Test public void testQuantityWithNormalizedQuantitySearchSupported_InvalidUCUMCode() { myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED); Substance res = new Substance(); res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("FOO").setValue(123); - + IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless(); - + List actual = toUnqualifiedVersionlessIds( mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "FOO")))); assertThat(actual, contains(id)); - + } - + @Test public void testQuantityWithNormalizedQuantitySearchSupported_NotUCUM() { myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED); Substance res = new Substance(); res.addInstance().getQuantity().setSystem("http://bar").setCode("FOO").setValue(123); - + IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless(); List actual = toUnqualifiedVersionlessIds( mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://bar", "FOO")))); assertThat(actual, contains(id)); - + } - + @Test public void testIndexNoDuplicatesQuantityWithNormalizedQuantityStorageSupported() { @@ -1297,9 +1294,9 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { List actual = toUnqualifiedVersionlessIds( mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "m")))); - assertThat(actual, contains(id)); + assertThat(actual, contains(id)); } - + @Test public void testIndexNoDuplicatesReference() { ServiceRequest pr = new ServiceRequest(); @@ -1509,7 +1506,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { // Should not crash myServiceRequestDao.create(serviceRequest); - runInTransaction(()->{ + runInTransaction(() -> { assertEquals(1, myResourceIndexedSearchParamDateDao.findAll().size()); }); } @@ -1517,7 +1514,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { @Test public void testPeriodWithNoEnd() { ServiceRequest serviceRequest = new ServiceRequest(); - + Period period = new Period(); period.setStart(new Date()); Timing timing = new Timing(); @@ -1527,11 +1524,11 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { // Should not crash myServiceRequestDao.create(serviceRequest); - runInTransaction(()->{ + runInTransaction(() -> { assertEquals(1, myResourceIndexedSearchParamDateDao.findAll().size()); }); } - + @Test public void testSearchByIdParamInverse() { @@ -1840,6 +1837,72 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { } + + @Test + public void testSearchWithIncludeStarQualified() { + + Patient pt = new Patient(); + pt.setActive(true); + IIdType ptId = myPatientDao.create(pt, mySrd).getId().toUnqualifiedVersionless(); + + Encounter enc = new Encounter(); + enc.setStatus(Encounter.EncounterStatus.ARRIVED); + IIdType encId = myEncounterDao.create(enc, mySrd).getId().toUnqualifiedVersionless(); + + Observation obs = new Observation(); + obs.getSubject().setReference(ptId.getValue()); + obs.getEncounter().setReference(encId.getValue()); + IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + + // Async Search + SearchParameterMap map = new SearchParameterMap(); + map.addInclude(new Include("Observation:*")); + List ids = toUnqualifiedVersionlessIds(myObservationDao.search(map)); + assertThat(ids, containsInAnyOrder(obsId, ptId, encId)); + + // Sync Search + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.addInclude(new Include("Observation:*")); + ids = toUnqualifiedVersionlessIds(myObservationDao.search(map)); + assertThat(ids, containsInAnyOrder(obsId, ptId, encId)); + } + + @Test + public void testSearchWithRevIncludeStarQualified() { + + Patient pt = new Patient(); + pt.setActive(true); + IIdType ptId = myPatientDao.create(pt, mySrd).getId().toUnqualifiedVersionless(); + + Encounter enc = new Encounter(); + enc.setStatus(Encounter.EncounterStatus.ARRIVED); + IIdType encId = myEncounterDao.create(enc, mySrd).getId().toUnqualifiedVersionless(); + + Observation obs = new Observation(); + obs.getSubject().setReference(ptId.getValue()); + obs.getEncounter().setReference(encId.getValue()); + IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + + MedicationRequest mr = new MedicationRequest(); + mr.getEncounter().setReference(encId.getValue()); + myMedicationRequestDao.create(mr, mySrd); + + // Async Search + SearchParameterMap map = new SearchParameterMap(); + map.addRevInclude(new Include("Observation:*")); + List ids = toUnqualifiedVersionlessIds(myEncounterDao.search(map)); + assertThat(ids, containsInAnyOrder(obsId, encId)); + + // Sync Search + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.addRevInclude(new Include("Observation:*")); + ids = toUnqualifiedVersionlessIds(myEncounterDao.search(map)); + assertThat(ids, containsInAnyOrder(obsId, encId)); + } + + @Test public void testComponentQuantity() { Observation o1 = new Observation(); @@ -2758,7 +2821,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { assertEquals(1, myChargeItemDao.search(map).size().intValue()); } - + @Test public void testSearchNameParam() { IIdType id1; @@ -3122,7 +3185,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { assertEquals(1, found.size().intValue()); } } - + @Test public void testSearchResourceLinkOnCanonical() { @@ -3902,8 +3965,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { patient.addName().setFamily("Tester").addGiven("testSearchTokenParam2"); myPatientDao.create(patient, mySrd); - runInTransaction(()->{ - ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().filter(t->t.getParamName().equals("identifier")).map(t->t.toString()).collect(Collectors.joining("\n * "))); + runInTransaction(() -> { + ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().filter(t -> t.getParamName().equals("identifier")).map(t -> t.toString()).collect(Collectors.joining("\n * "))); }); { @@ -3945,8 +4008,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { female = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue(); } - runInTransaction(()->{ - ourLog.info("Tokens:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * "))); + runInTransaction(() -> { + ourLog.info("Tokens:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * "))); }); List patients; @@ -5446,9 +5509,9 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { c3.getEncounter().setReference(e3Id); myCommunicationDao.create(c3); - runInTransaction(()->{ - ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * "))); - ourLog.info("Dates:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * "))); + runInTransaction(() -> { + ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * "))); + ourLog.info("Dates:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * "))); }); SearchParameterMap map; diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java index 85a6ef8cf4a..c27b864a6d9 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java @@ -58,13 +58,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; */ public class SearchParameterMap implements Serializable { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParameterMap.class); public static final Integer INTEGER_0 = 0; - - private final HashMap>> mySearchParameterMap = new LinkedHashMap<>(); - + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParameterMap.class); private static final long serialVersionUID = 1L; - + private final HashMap>> mySearchParameterMap = new LinkedHashMap<>(); private Integer myCount; private Integer myOffset; private EverythingModeEnum myEverythingMode = null; @@ -81,7 +78,7 @@ public class SearchParameterMap implements Serializable { private Integer myLastNMax; private boolean myDeleteExpunge; private SearchContainedModeEnum mySearchContainedMode = SearchContainedModeEnum.FALSE; - + /** * Constructor */ @@ -467,7 +464,9 @@ public class SearchParameterMap implements Serializable { sort = sort.getChain(); } - addUrlIncludeParams(b, Constants.PARAM_INCLUDE, getIncludes()); + if (hasIncludes()) { + addUrlIncludeParams(b, Constants.PARAM_INCLUDE, getIncludes()); + } addUrlIncludeParams(b, Constants.PARAM_REVINCLUDE, getRevIncludes()); if (getLastUpdated() != null) { @@ -514,6 +513,13 @@ public class SearchParameterMap implements Serializable { return b.toString(); } + /** + * @since 5.5.0 + */ + public boolean hasIncludes() { + return myIncludes != null && !myIncludes.isEmpty(); + } + @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); @@ -555,14 +561,14 @@ public class SearchParameterMap implements Serializable { theAndOrParams.removeIf(List::isEmpty); } - public void setNearDistanceParam(QuantityParam theQuantityParam) { - myNearDistanceParam = theQuantityParam; - } - public QuantityParam getNearDistanceParam() { return myNearDistanceParam; } + public void setNearDistanceParam(QuantityParam theQuantityParam) { + myNearDistanceParam = theQuantityParam; + } + public boolean isWantOnlyCount() { return SummaryEnum.COUNT.equals(getSummaryMode()) || INTEGER_0.equals(getCount()); } @@ -576,6 +582,52 @@ public class SearchParameterMap implements Serializable { return this; } + public List> get(String theName) { + return mySearchParameterMap.get(theName); + } + + public void put(String theName, List> theParams) { + mySearchParameterMap.put(theName, theParams); + } + + public boolean containsKey(String theName) { + return mySearchParameterMap.containsKey(theName); + } + + public Set keySet() { + return mySearchParameterMap.keySet(); + } + + public boolean isEmpty() { + return mySearchParameterMap.isEmpty(); + } + + // Wrapper methods + + public Set>>> entrySet() { + return mySearchParameterMap.entrySet(); + } + + public List> remove(String theName) { + return mySearchParameterMap.remove(theName); + } + + public int size() { + return mySearchParameterMap.size(); + } + + public SearchContainedModeEnum getSearchContainedMode() { + return mySearchContainedMode; + } + + public void setSearchContainedMode(SearchContainedModeEnum theSearchContainedMode) { + if (theSearchContainedMode == null) { + mySearchContainedMode = SearchContainedModeEnum.FALSE; + } else { + this.mySearchContainedMode = theSearchContainedMode; + } + } + public enum EverythingModeEnum { /* * Don't reorder! We rely on the ordinals @@ -689,40 +741,6 @@ public class SearchParameterMap implements Serializable { return retVal; } - // Wrapper methods - - public List> get(String theName) { - return mySearchParameterMap.get(theName); - } - - public void put(String theName, List> theParams) { - mySearchParameterMap.put(theName, theParams); - } - - public boolean containsKey(String theName) { - return mySearchParameterMap.containsKey(theName); - } - - public Set keySet() { - return mySearchParameterMap.keySet(); - } - - public boolean isEmpty() { - return mySearchParameterMap.isEmpty(); - } - - public Set>>> entrySet() { - return mySearchParameterMap.entrySet(); - } - - public List> remove(String theName) { - return mySearchParameterMap.remove(theName); - } - - public int size() { - return mySearchParameterMap.size(); - } - public static SearchParameterMap newSynchronous() { SearchParameterMap retVal = new SearchParameterMap(); retVal.setLoadSynchronous(true); @@ -736,17 +754,5 @@ public class SearchParameterMap implements Serializable { return retVal; } - public SearchContainedModeEnum getSearchContainedMode() { - return mySearchContainedMode; - } - public void setSearchContainedMode(SearchContainedModeEnum theSearchContainedMode) { - if (theSearchContainedMode == null) { - mySearchContainedMode = SearchContainedModeEnum.FALSE; - } else { - this.mySearchContainedMode = theSearchContainedMode; - } - } - - } diff --git a/pom.xml b/pom.xml index 8f73f95571b..014df1f98cf 100644 --- a/pom.xml +++ b/pom.xml @@ -2204,7 +2204,7 @@ com.puppycrawl.tools checkstyle - 8.41.1 + 8.42