diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index f9d43602500..9965a51e88b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -25,9 +25,24 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; import java.io.UnsupportedEncodingException; import java.text.Normalizer; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; -import javax.persistence.*; +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceContextType; +import javax.persistence.Tuple; +import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; @@ -43,22 +58,64 @@ import org.apache.http.client.utils.URLEncodedUtils; import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb; import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.StringType; -import org.hl7.fhir.instance.model.api.*; +import org.hl7.fhir.instance.model.api.IAnyResource; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseCoding; +import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; +import org.hl7.fhir.instance.model.api.IBaseReference; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; import com.google.common.base.Charsets; import com.google.common.collect.ArrayListMultimap; -import ca.uhn.fhir.context.*; +import ca.uhn.fhir.context.BaseRuntimeChildDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition; +import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.context.RuntimeChildResourceDefinition; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.dao.data.IForcedIdDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao; import ca.uhn.fhir.jpa.dao.data.ISearchDao; import ca.uhn.fhir.jpa.dao.data.ISearchResultDao; -import ca.uhn.fhir.jpa.entity.*; +import ca.uhn.fhir.jpa.entity.BaseHasResource; +import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam; +import ca.uhn.fhir.jpa.entity.BaseTag; +import ca.uhn.fhir.jpa.entity.ForcedId; +import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum; +import ca.uhn.fhir.jpa.entity.ResourceHistoryTable; +import ca.uhn.fhir.jpa.entity.ResourceHistoryTag; +import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords; +import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate; +import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber; +import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity; +import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString; +import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken; +import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri; +import ca.uhn.fhir.jpa.entity.ResourceLink; +import ca.uhn.fhir.jpa.entity.ResourceTable; +import ca.uhn.fhir.jpa.entity.ResourceTag; +import ca.uhn.fhir.jpa.entity.Search; +import ca.uhn.fhir.jpa.entity.SearchTypeEnum; +import ca.uhn.fhir.jpa.entity.TagDefinition; +import ca.uhn.fhir.jpa.entity.TagTypeEnum; import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider; import ca.uhn.fhir.jpa.util.DeleteConflict; -import ca.uhn.fhir.model.api.*; +import ca.uhn.fhir.model.api.IQueryParameterAnd; +import ca.uhn.fhir.model.api.IQueryParameterType; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; import ca.uhn.fhir.model.dstu.resource.BaseResource; @@ -73,10 +130,21 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.method.MethodUtil; import ca.uhn.fhir.rest.method.QualifiedParamList; import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum; -import ca.uhn.fhir.rest.param.*; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.UriAndListParam; +import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.IBundleProvider; -import ca.uhn.fhir.rest.server.exceptions.*; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; @@ -86,16 +154,17 @@ import ca.uhn.fhir.util.OperationOutcomeUtil; public abstract class BaseHapiFhirDao implements IDao { - private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest"; public static final long INDEX_STATUS_INDEXED = Long.valueOf(1L); + public static final long INDEX_STATUS_INDEXING_FAILED = Long.valueOf(2L); public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile"; public static final String OO_SEVERITY_ERROR = "error"; public static final String OO_SEVERITY_INFO = "information"; public static final String OO_SEVERITY_WARN = "warning"; - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class); private static final Map ourRetrievalContexts = new HashMap(); + + private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest"; /** * These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)} */ @@ -104,8 +173,8 @@ public abstract class BaseHapiFhirDao implements IDao { * These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)} */ static final Map> RESOURCE_META_PARAMS; - public static final String UCUM_NS = "http://unitsofmeasure.org"; + static { Map> resourceMetaParams = new HashMap>(); Map>> resourceMetaAndParams = new HashMap>>(); @@ -122,7 +191,6 @@ public abstract class BaseHapiFhirDao implements IDao { RESOURCE_META_PARAMS = Collections.unmodifiableMap(resourceMetaParams); RESOURCE_META_AND_PARAMS = Collections.unmodifiableMap(resourceMetaAndParams); } - @Autowired(required = true) private DaoConfig myConfig; @@ -157,6 +225,12 @@ public abstract class BaseHapiFhirDao implements IDao { @Autowired private ISearchResultDao mySearchResultDao; + protected void clearRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) { + if (theRequestDetails != null) { + theRequestDetails.getUserData().remove(PROCESSING_SUB_REQUEST); + } + } + protected void createForcedIdIfNeeded(ResourceTable theEntity, IIdType theId) { if (theId.isEmpty() == false && theId.hasIdPart()) { if (isValidPid(theId)) { @@ -471,6 +545,17 @@ public abstract class BaseHapiFhirDao implements IDao { return (IFhirResourceDao) myResourceTypeToDao.get(theType); } + @Override + public RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName) { + Map params = mySearchParamRegistry.getActiveSearchParams(theResourceDef.getName()); + return params.get(theParamName); + } + + @Override + public Collection getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) { + return mySearchParamRegistry.getActiveSearchParams(theResourceDef.getName()).values(); + } + protected TagDefinition getTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) { CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); CriteriaQuery cq = builder.createQuery(TagDefinition.class); @@ -587,6 +672,12 @@ public abstract class BaseHapiFhirDao implements IDao { theProvider.setSearchResultDao(mySearchResultDao); } + protected void markRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) { + if (theRequestDetails != null) { + theRequestDetails.getUserData().put(PROCESSING_SUB_REQUEST, Boolean.TRUE); + } + } + protected void notifyInterceptors(RestOperationTypeEnum theOperationType, ActionRequestDetails theRequestDetails) { if (theRequestDetails.getId() != null && theRequestDetails.getId().hasResourceType() && isNotBlank(theRequestDetails.getResourceType())) { if (theRequestDetails.getId().getResourceType().equals(theRequestDetails.getResourceType()) == false) { @@ -607,18 +698,6 @@ public abstract class BaseHapiFhirDao implements IDao { } } - protected void markRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) { - if (theRequestDetails != null) { - theRequestDetails.getUserData().put(PROCESSING_SUB_REQUEST, Boolean.TRUE); - } - } - - protected void clearRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) { - if (theRequestDetails != null) { - theRequestDetails.getUserData().remove(PROCESSING_SUB_REQUEST); - } - } - public String parseContentTextIntoWords(IBaseResource theResource) { StringBuilder retVal = new StringBuilder(); @SuppressWarnings("rawtypes") @@ -897,12 +976,6 @@ public abstract class BaseHapiFhirDao implements IDao { return ids; } - @Override - public RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName) { - Map params = mySearchParamRegistry.getActiveSearchParams(theResourceDef.getName()); - return params.get(theParamName); - } - @SuppressWarnings("unused") @CoverageIgnore public BaseHasResource readEntity(IIdType theValueId) { @@ -1627,26 +1700,6 @@ public abstract class BaseHapiFhirDao implements IDao { } } - protected static List translateMatchUrl(String theMatchUrl) { - List parameters; - String matchUrl = theMatchUrl; - int questionMarkIndex = matchUrl.indexOf('?'); - if (questionMarkIndex != -1) { - matchUrl = matchUrl.substring(questionMarkIndex + 1); - } - matchUrl = matchUrl.replace("|", "%7C"); - matchUrl = matchUrl.replace("=>=", "=%3E%3D"); - matchUrl = matchUrl.replace("=<=", "=%3C%3D"); - matchUrl = matchUrl.replace("=>", "=%3E"); - matchUrl = matchUrl.replace("=<", "=%3C"); - if (matchUrl.contains(" ")) { - throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)"); - } - - parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&'); - return parameters; - } - public static SearchParameterMap translateMatchUrl(IDao theCallingDao, FhirContext theContext, String theMatchUrl, RuntimeResourceDefinition resourceDef) { SearchParameterMap paramMap = new SearchParameterMap(); List parameters = translateMatchUrl(theMatchUrl); @@ -1729,6 +1782,26 @@ public abstract class BaseHapiFhirDao implements IDao { return paramMap; } + protected static List translateMatchUrl(String theMatchUrl) { + List parameters; + String matchUrl = theMatchUrl; + int questionMarkIndex = matchUrl.indexOf('?'); + if (questionMarkIndex != -1) { + matchUrl = matchUrl.substring(questionMarkIndex + 1); + } + matchUrl = matchUrl.replace("|", "%7C"); + matchUrl = matchUrl.replace("=>=", "=%3E%3D"); + matchUrl = matchUrl.replace("=<=", "=%3C%3D"); + matchUrl = matchUrl.replace("=>", "=%3E"); + matchUrl = matchUrl.replace("=<", "=%3C"); + if (matchUrl.contains(" ")) { + throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)"); + } + + parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&'); + return parameters; + } + public static void validateResourceType(BaseHasResource theEntity, String theResourceName) { if (!theResourceName.equals(theEntity.getResourceType())) { throw new ResourceNotFoundException( diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java index ae92e971c4d..098b090a123 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java @@ -1,5 +1,6 @@ package ca.uhn.fhir.jpa.dao; +import java.util.Collection; import java.util.Set; import org.hl7.fhir.instance.model.api.IAnyResource; @@ -77,4 +78,7 @@ public interface IDao { void populateFullTextFields(IBaseResource theResource, ResourceTable theEntity); RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName); + + Collection getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef); + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamRegistryDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamRegistryDstu3.java index 75123b7fa8b..7d36cd25dee 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamRegistryDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamRegistryDstu3.java @@ -71,7 +71,7 @@ public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry { if (runtimeSp == null) { continue; } - + int dotIdx = runtimeSp.getPath().indexOf('.'); if (dotIdx == -1) { ourLog.warn("Can not determine resource type of {}", runtimeSp.getPath()); @@ -89,11 +89,22 @@ public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry { Map> activeSearchParams = new HashMap>(); for (Entry> nextEntry : searchParams.entrySet()) { for (RuntimeSearchParam nextSp : nextEntry.getValue().values()) { - if (nextSp.getStatus() == RuntimeSearchParamStatusEnum.ACTIVE) { - if (!activeSearchParams.containsKey(nextEntry.getKey())) { - activeSearchParams.put(nextEntry.getKey(), new HashMap()); - } - activeSearchParams.get(nextEntry.getKey()).put(nextSp.getName(), nextSp); + String nextName = nextSp.getName(); + if (nextSp.getStatus() != RuntimeSearchParamStatusEnum.ACTIVE) { + nextSp = null; + } + + if (!activeSearchParams.containsKey(nextEntry.getKey())) { + activeSearchParams.put(nextEntry.getKey(), new HashMap()); + } + if (activeSearchParams.containsKey(nextEntry.getKey())) { + ourLog.info("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName); + } + + if (nextSp != null) { + activeSearchParams.get(nextEntry.getKey()).put(nextName, nextSp); + } else { + activeSearchParams.get(nextEntry.getKey()).remove(nextName); } } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java index b58d32c493a..b55b70e4e08 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java @@ -31,7 +31,9 @@ import org.hl7.fhir.dstu3.model.CapabilityStatement.*; import org.hl7.fhir.dstu3.model.Enumerations.SearchParamType; import org.springframework.beans.factory.annotation.Autowired; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; @@ -67,9 +69,6 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se myDaoConfig = theDaoConfig; super.setCache(false); } - - @Autowired - private ISearchParamRegistry mySearchParamRegistry; @Override public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { @@ -98,7 +97,9 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se } nextResource.getSearchParam().clear(); - Collection searchParams = mySearchParamRegistry.getAllSearchParams(nextResource.getType()); + String resourceName = nextResource.getType(); + RuntimeResourceDefinition resourceDef = myRestfulServer.getFhirContext().getResourceDefinition(resourceName); + Collection searchParams = mySystemDao.getSearchParamsByResourceType(resourceDef); for (RuntimeSearchParam runtimeSp : searchParams) { CapabilityStatementRestResourceSearchParamComponent confSp = nextResource.addSearchParam(); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java index ca2c680b359..86d6e3df282 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java @@ -2,6 +2,8 @@ package ca.uhn.fhir.jpa.provider.dstu3; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @@ -10,16 +12,21 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.hl7.fhir.dstu3.model.*; +import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.CapabilityStatement; import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent; import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent; import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent; import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; +import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.SearchParameter; import org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType; import org.hl7.fhir.instance.model.api.IIdType; import org.junit.After; import org.junit.AfterClass; +import org.junit.Before; import org.junit.Test; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; @@ -29,7 +36,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.rest.gclient.ReferenceClientParam; import ca.uhn.fhir.rest.gclient.TokenClientParam; import ca.uhn.fhir.rest.server.IBundleProvider; -import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.util.TestUtil; public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProviderDstu3Test { @@ -58,14 +65,35 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv try { ourClient.create().resource(sp).execute(); fail(); - } catch (InvalidRequestException e) { - assertEquals("HTTP 400 Bad Request: Resource.status is missing or invalid: null", e.getMessage()); + } catch (UnprocessableEntityException e) { + assertEquals("HTTP 422 Unprocessable Entity: Resource.status is missing or invalid: null", e.getMessage()); } } - @SuppressWarnings("unused") + @Override + @Before + public void beforeResetConfig() { + super.beforeResetConfig(); + + myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden()); + mySearchParamRegsitry.forceRefresh(); + } + @Test - public void testConformance() { + public void testConformanceOverrideAllowed() { + myDaoConfig.setDefaultSearchParamsCanBeOverridden(true); + + CapabilityStatement conformance = ourClient + .fetchConformance() + .ofType(CapabilityStatement.class) + .execute(); + Map map = extractSearchParams(conformance, "Patient"); + + CapabilityStatementRestResourceSearchParamComponent param = map.get("foo"); + assertNull(param); + + param = map.get("gender"); + assertNotNull(param); // Add a custom search parameter SearchParameter fooSp = new SearchParameter(); @@ -76,7 +104,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL); fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE); mySearchParameterDao.create(fooSp, mySrd); - + // Disable an existing parameter fooSp = new SearchParameter(); fooSp.setCode("gender"); @@ -87,15 +115,72 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.RETIRED); mySearchParameterDao.create(fooSp, mySrd); - CapabilityStatement conformance = ourClient - .fetchConformance() - .ofType(CapabilityStatement.class) - .execute(); + mySearchParamRegsitry.forceRefresh(); - Map map = extractSearchParams(conformance, "Patient"); - - CapabilityStatementRestResourceSearchParamComponent param = map.get("foo"); + conformance = ourClient + .fetchConformance() + .ofType(CapabilityStatement.class) + .execute(); + map = extractSearchParams(conformance, "Patient"); + + param = map.get("foo"); assertEquals("foo", param.getName()); + + param = map.get("gender"); + assertNull(param); + + } + + @Test + public void testConformanceOverrideNotAllowed() { + myDaoConfig.setDefaultSearchParamsCanBeOverridden(false); + + CapabilityStatement conformance = ourClient + .fetchConformance() + .ofType(CapabilityStatement.class) + .execute(); + Map map = extractSearchParams(conformance, "Patient"); + + CapabilityStatementRestResourceSearchParamComponent param = map.get("foo"); + assertNull(param); + + param = map.get("gender"); + assertNotNull(param); + + // Add a custom search parameter + SearchParameter fooSp = new SearchParameter(); + fooSp.setCode("foo"); + fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN); + fooSp.setTitle("FOO SP"); + fooSp.setXpath("Patient.gender"); + fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL); + fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE); + mySearchParameterDao.create(fooSp, mySrd); + + // Disable an existing parameter + fooSp = new SearchParameter(); + fooSp.setCode("gender"); + fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN); + fooSp.setTitle("Gender"); + fooSp.setXpath("Patient.gender"); + fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL); + fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.RETIRED); + mySearchParameterDao.create(fooSp, mySrd); + + mySearchParamRegsitry.forceRefresh(); + + conformance = ourClient + .fetchConformance() + .ofType(CapabilityStatement.class) + .execute(); + map = extractSearchParams(conformance, "Patient"); + + param = map.get("foo"); + assertEquals("foo", param.getName()); + + param = map.get("gender"); + assertNotNull(param); + } private Map extractSearchParams(CapabilityStatement conformance, String resType) { @@ -112,7 +197,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv } return map; } - + @SuppressWarnings("unused") @Test public void testSearchWithCustomParam() { @@ -125,9 +210,9 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL); fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE); mySearchParameterDao.create(fooSp, mySrd); - + mySearchParamRegsitry.forceRefresh(); - + Patient pat = new Patient(); pat.setGender(AdministrativeGender.MALE); IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless(); @@ -142,17 +227,16 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv Bundle result; result = ourClient - .search() - .forResource(Patient.class) - .where(new TokenClientParam("foo").exactly().code("male")) - .returnBundle(Bundle.class) - .execute(); + .search() + .forResource(Patient.class) + .where(new TokenClientParam("foo").exactly().code("male")) + .returnBundle(Bundle.class) + .execute(); foundResources = toUnqualifiedVersionlessIdValues(result); assertThat(foundResources, contains(patId.getValue())); } - @Test public void testCreatingParamMarksCorrectResourcesForReindexing() { Patient pat = new Patient(); @@ -167,7 +251,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue()); res = myResourceTableDao.findOne(obsId.getIdPartAsLong()); assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue()); - + SearchParameter fooSp = new SearchParameter(); fooSp.setCode("foo"); fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN); @@ -184,7 +268,6 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv } - @SuppressWarnings("unused") @Test public void testSearchQualifiedWithCustomReferenceParam() { @@ -197,9 +280,9 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL); fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE); mySearchParameterDao.create(fooSp, mySrd); - + mySearchParamRegsitry.forceRefresh(); - + Patient pat = new Patient(); pat.setGender(AdministrativeGender.MALE); IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless(); @@ -218,16 +301,16 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv Bundle result; result = ourClient - .search() - .forResource(Observation.class) - .where(new ReferenceClientParam("foo").hasChainedProperty(Patient.GENDER.exactly().code("male"))) - .returnBundle(Bundle.class) - .execute(); + .search() + .forResource(Observation.class) + .where(new ReferenceClientParam("foo").hasChainedProperty(Patient.GENDER.exactly().code("male"))) + .returnBundle(Bundle.class) + .execute(); foundResources = toUnqualifiedVersionlessIdValues(result); assertThat(foundResources, contains(obsId1.getValue())); } - + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 58fb44044d8..4c12c5bc397 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -23,6 +23,12 @@ ]]> + + The JPA server now supports custom search parameters in DSTU3 + mode. This allows users to create search parameters which contain + custom paths, or even override and disable existing search + parameters. + Fix issue in AuthorizationIntetceptor where transactions are blocked even when they