From c5b286921ebf45d6125f0a6643834208ec1edc3c Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Fri, 30 Mar 2018 15:18:57 -0400 Subject: [PATCH 1/5] Tests all passing --- .../jpa/cds/example/CdsServerExample.java | 4 +- .../jpa/config/dstu3/BaseDstu3Config.java | 17 +- .../uhn/fhir/jpa/config/r4/BaseR4Config.java | 6 +- .../ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java | 78 ++- .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 75 +-- .../ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java | 33 +- .../uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java | 484 +++++++++--------- .../ca/uhn/fhir/jpa/dao/SearchBuilder.java | 5 +- .../dao/data/ITermCodeSystemVersionDao.java | 23 +- .../fhir/jpa/dao/data/ITermConceptDao.java | 4 +- .../jpa/dao/dstu3/FhirSystemDaoDstu3.java | 242 +++++---- .../dao/dstu3/JpaValidationSupportDstu3.java | 5 + .../uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java | 21 +- .../uhn/fhir/jpa/entity/TermCodeSystem.java | 14 + .../jpa/entity/TermCodeSystemVersion.java | 2 +- ...a => BaseTerminologyUploaderProvider.java} | 76 ++- .../TerminologyUploaderProviderDstu3.java | 53 ++ .../r4/TerminologyUploaderProviderR4.java | 30 ++ .../jpa/term/BaseHapiTerminologySvcImpl.java | 282 ++++++---- .../jpa/term/HapiTerminologySvcDstu2.java | 5 + .../jpa/term/HapiTerminologySvcDstu3.java | 28 + .../fhir/jpa/term/HapiTerminologySvcR4.java | 15 + .../jpa/term/TerminologyLoaderSvcImpl.java | 14 +- .../jpa/term/VersionIndependentConcept.java | 16 +- .../java/ca/uhn/fhir/jpa/util/TestUtil.java | 2 +- .../java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java | 2 + .../jpa/dao/dstu2/FhirSystemDaoDstu2Test.java | 322 ++++++++++-- .../jpa/dao/dstu3/FhirSystemDaoDstu3Test.java | 208 ++++++++ .../fhir/jpa/dao/r4/FhirSystemDaoR4Test.java | 163 +++++- .../dstu3/BaseResourceProviderDstu3Test.java | 7 +- .../ResourceProviderDstu3CodeSystemTest.java | 35 +- .../TerminologyUploaderProviderDstu3Test.java | 191 +++---- .../r4/BaseResourceProviderR4Test.java | 5 +- .../r4/TerminologyUploaderProviderR4Test.java | 275 +++++----- ...minologyLoaderSvcIntegrationDstu3Test.java | 2 +- .../TerminologyLoaderSvcSnomedCtTest.java | 5 +- .../jpa/term/TerminologySvcImplDstu3Test.java | 344 ++++++------- .../uhn/fhir/rest/server/RestfulServer.java | 7 +- .../ctx/DefaultProfileValidationSupport.java | 31 +- .../DefaultProfileValidationSupport.java | 29 +- .../validation/ValidationSupportChain.java | 226 ++++---- 41 files changed, 2152 insertions(+), 1234 deletions(-) rename hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/{TerminologyUploaderProvider.java => BaseTerminologyUploaderProvider.java} (66%) create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3.java create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4.java diff --git a/example-projects/hapi-fhir-jpaserver-cds-example/src/main/java/ca/uhn/fhir/jpa/cds/example/CdsServerExample.java b/example-projects/hapi-fhir-jpaserver-cds-example/src/main/java/ca/uhn/fhir/jpa/cds/example/CdsServerExample.java index 5670c8213f3..ed5e7185cd4 100644 --- a/example-projects/hapi-fhir-jpaserver-cds-example/src/main/java/ca/uhn/fhir/jpa/cds/example/CdsServerExample.java +++ b/example-projects/hapi-fhir-jpaserver-cds-example/src/main/java/ca/uhn/fhir/jpa/cds/example/CdsServerExample.java @@ -5,9 +5,9 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; -import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3; import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3; +import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3; import ca.uhn.fhir.jpa.rp.dstu3.ActivityDefinitionResourceProvider; import ca.uhn.fhir.jpa.rp.dstu3.MeasureResourceProvider; import ca.uhn.fhir.jpa.rp.dstu3.PlanDefinitionResourceProvider; @@ -149,7 +149,7 @@ public class CdsServerExample extends RestfulServer { * so it is a potential security vulnerability. Consider using an AuthorizationInterceptor * with this feature. */ - registerProvider(myAppCtx.getBean(TerminologyUploaderProvider.class)); + registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class)); } public IResourceProvider getProvider(String name) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java index a01dd043e01..945e8227379 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java @@ -9,8 +9,11 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; import ca.uhn.fhir.jpa.dao.ISearchParamRegistry; import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3; import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3; -import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; -import ca.uhn.fhir.jpa.term.*; +import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3; +import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu3; +import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc; +import ca.uhn.fhir.jpa.term.IHapiTerminologySvcDstu3; +import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl; import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3; import ca.uhn.fhir.validation.IValidatorModule; import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport; @@ -32,9 +35,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; * 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. @@ -115,8 +118,8 @@ public class BaseDstu3Config extends BaseConfig { } @Bean(autowire = Autowire.BY_TYPE) - public TerminologyUploaderProvider terminologyUploaderProvider() { - TerminologyUploaderProvider retVal = new TerminologyUploaderProvider(); + public TerminologyUploaderProviderDstu3 terminologyUploaderProvider() { + TerminologyUploaderProviderDstu3 retVal = new TerminologyUploaderProviderDstu3(); retVal.setContext(fhirContextDstu3()); return retVal; } @@ -126,5 +129,5 @@ public class BaseDstu3Config extends BaseConfig { public IValidationSupport validationSupportChainDstu3() { return new JpaValidationSupportChainDstu3(); } - + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java index 6a0d5cc286b..c9ff4f94920 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java @@ -10,7 +10,7 @@ import ca.uhn.fhir.jpa.dao.ISearchParamRegistry; import ca.uhn.fhir.jpa.dao.r4.SearchParamExtractorR4; import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4; import ca.uhn.fhir.jpa.graphql.JpaStorageServices; -import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; +import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4; import ca.uhn.fhir.jpa.term.HapiTerminologySvcR4; import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc; import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4; @@ -133,8 +133,8 @@ public class BaseR4Config extends BaseConfig { } @Bean(autowire = Autowire.BY_TYPE) - public TerminologyUploaderProvider terminologyUploaderProvider() { - TerminologyUploaderProvider retVal = new TerminologyUploaderProvider(); + public TerminologyUploaderProviderR4 terminologyUploaderProvider() { + TerminologyUploaderProviderR4 retVal = new TerminologyUploaderProviderR4(); retVal.setContext(fhirContextR4()); return retVal; } 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 8c06a482c5f..5ae96597123 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 @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * 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. @@ -44,10 +44,12 @@ import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; +import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.util.*; import com.google.common.annotations.VisibleForTesting; @@ -67,7 +69,6 @@ import org.hl7.fhir.instance.model.api.*; import org.hl7.fhir.r4.model.BaseResource; import org.hl7.fhir.r4.model.Bundle.HTTPVerb; import org.hl7.fhir.r4.model.CanonicalType; -import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; @@ -110,6 +111,7 @@ public abstract class BaseHapiFhirDao implements IDao { private static final Map ourRetrievalContexts = new HashMap(); private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest"; private static boolean ourValidationDisabledForUnitTest; + private static boolean ourDisableIncrementOnUpdateForUnitTest = false; static { Map> resourceMetaParams = new HashMap>(); @@ -834,6 +836,22 @@ public abstract class BaseHapiFhirDao implements IDao { return new PersistedJpaBundleProvider(search.getUuid(), this); } + void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) { + String newVersion; + long newVersionLong; + if (theResourceId == null || theResourceId.getVersionIdPart() == null) { + newVersion = "1"; + newVersionLong = 1; + } else { + newVersionLong = theResourceId.getVersionIdPartAsLong() + 1; + newVersion = Long.toString(newVersionLong); + } + + IIdType newId = theResourceId.withVersion(newVersion); + theResource.getIdElement().setValue(newId.getValue()); + theSavedEntity.setVersion(newVersionLong); + } + @Override public void injectDependenciesIntoBundleProvider(PersistedJpaBundleProvider theProvider) { theProvider.setContext(getContext()); @@ -1816,6 +1834,55 @@ public abstract class BaseHapiFhirDao implements IDao { return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime, false, true); } + public ResourceTable updateInternal(T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion, RequestDetails theRequestDetails, ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) { + // Notify interceptors + ActionRequestDetails requestDetails = null; + if (theRequestDetails != null) { + requestDetails = new ActionRequestDetails(theRequestDetails, theResource, theResourceId.getResourceType(), theResourceId); + notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails); + } + + // Notify IServerOperationInterceptors about pre-action call + if (theRequestDetails != null) { + theRequestDetails.getRequestOperationCallback().resourcePreUpdate(theOldResource, theResource); + } + for (IServerInterceptor next : getConfig().getInterceptors()) { + if (next instanceof IServerOperationInterceptor) { + ((IServerOperationInterceptor) next).resourcePreUpdate(theRequestDetails, theOldResource, theResource); + } + } + + // Perform update + ResourceTable savedEntity = updateEntity(theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing); + + /* + * If we aren't indexing (meaning we're probably executing a sub-operation within a transaction), + * we'll manually increase the version. This is important because we want the updated version number + * to be reflected in the resource shared with interceptors + */ + if (!thePerformIndexing && !savedEntity.isUnchangedInCurrentOperation() && !ourDisableIncrementOnUpdateForUnitTest) { + if (theResourceId.hasVersionIdPart() == false) { + theResourceId = theResourceId.withVersion(Long.toString(savedEntity.getVersion())); + } + incrementId(theResource, savedEntity, theResourceId); + } + + // Notify interceptors + if (!savedEntity.isUnchangedInCurrentOperation()) { + if (theRequestDetails != null) { + theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource); + theRequestDetails.getRequestOperationCallback().resourceUpdated(theOldResource, theResource); + } + for (IServerInterceptor next : getConfig().getInterceptors()) { + if (next instanceof IServerOperationInterceptor) { + ((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theResource); + ((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theOldResource, theResource); + } + } + } + return savedEntity; + } + private void validateChildReferences(IBase theElement, String thePath) { if (theElement == null) { return; @@ -2133,6 +2200,11 @@ public abstract class BaseHapiFhirDao implements IDao { return b.toString(); } + @VisibleForTesting + public static void setDisableIncrementOnUpdateForUnitTest(boolean theDisableIncrementOnUpdateForUnitTest) { + ourDisableIncrementOnUpdateForUnitTest = theDisableIncrementOnUpdateForUnitTest; + } + /** * Do not call this method outside of unit tests */ diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 30dd60c30c2..c08cf315219 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -77,7 +77,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; public abstract class BaseHapiFhirResourceDao extends BaseHapiFhirDao implements IFhirResourceDao { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class); - private static boolean ourDisableIncrementOnUpdateForUnitTest = false; @Autowired protected PlatformTransactionManager myPlatformTransactionManager; @Autowired @@ -592,22 +591,6 @@ public abstract class BaseHapiFhirResourceDao extends B return retVal; } - private void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) { - String newVersion; - long newVersionLong; - if (theResourceId == null || theResourceId.getVersionIdPart() == null) { - newVersion = "1"; - newVersionLong = 1; - } else { - newVersionLong = theResourceId.getVersionIdPartAsLong() + 1; - newVersion = Long.toString(newVersionLong); - } - - IIdType newId = theResourceId.withVersion(newVersion); - theResource.getIdElement().setValue(newId.getValue()); - theSavedEntity.setVersion(newVersionLong); - } - protected boolean isPagingProviderDatabaseBacked(RequestDetails theRequestDetails) { if (theRequestDetails == null || theRequestDetails.getServer() == null) { return false; @@ -1229,54 +1212,24 @@ public abstract class BaseHapiFhirResourceDao extends B "Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]"); } - // Notify interceptors - ActionRequestDetails requestDetails = null; - if (theRequestDetails != null) { - requestDetails = new ActionRequestDetails(theRequestDetails, theResource, getResourceName(), resourceId); - notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails); - } - IBaseResource oldResource = toResource(entity, false); - // Notify IServerOperationInterceptors about pre-action call - if (theRequestDetails != null) { - theRequestDetails.getRequestOperationCallback().resourcePreUpdate(oldResource, theResource); + /* + * If we aren't indexing, that means we're doing this inside a transaction. + * The transaction will do the actual storate to the database a bit later on, + * after placeholder IDs have been replaced, by calling {@link #updateInternal} + * directly. So we just bail now. + */ + if (!thePerformIndexing) { + DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(false); + outcome.setPreviousResource(oldResource); + return outcome; } - for (IServerInterceptor next : getConfig().getInterceptors()) { - if (next instanceof IServerOperationInterceptor) { - ((IServerOperationInterceptor) next).resourcePreUpdate(theRequestDetails, oldResource, theResource); - } - } - - // Perform update - ResourceTable savedEntity = updateEntity(theResource, entity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing); /* - * If we aren't indexing (meaning we're probably executing a sub-operation within a transaction), - * we'll manually increase the version. This is important because we want the updated version number - * to be reflected in the resource shared with interceptors + * Otherwise, we're not in a transaction */ - if (!thePerformIndexing && !savedEntity.isUnchangedInCurrentOperation() && !ourDisableIncrementOnUpdateForUnitTest) { - if (resourceId.hasVersionIdPart() == false) { - resourceId = resourceId.withVersion(Long.toString(savedEntity.getVersion())); - } - incrementId(theResource, savedEntity, resourceId); - } - - // Notify interceptors - if (!savedEntity.isUnchangedInCurrentOperation()) { - if (theRequestDetails != null) { - theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource); - theRequestDetails.getRequestOperationCallback().resourceUpdated(oldResource, theResource); - } - for (IServerInterceptor next : getConfig().getInterceptors()) { - if (next instanceof IServerOperationInterceptor) { - ((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theResource); - ((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, oldResource, theResource); - } - } - } - + ResourceTable savedEntity = updateInternal(theResource, thePerformIndexing, theForceUpdateVersion, theRequestDetails, entity, resourceId, oldResource); DaoMethodOutcome outcome = toMethodOutcome(savedEntity, theResource).setCreated(false); if (!thePerformIndexing) { @@ -1366,9 +1319,5 @@ public abstract class BaseHapiFhirResourceDao extends B } } - @VisibleForTesting - public static void setDisableIncrementOnUpdateForUnitTest(boolean theDisableIncrementOnUpdateForUnitTest) { - ourDisableIncrementOnUpdateForUnitTest = theDisableIncrementOnUpdateForUnitTest; - } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java index 46ffdca1403..a1a06ad597d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * 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. @@ -22,24 +22,41 @@ package ca.uhn.fhir.jpa.dao; import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.rest.api.MethodOutcome; +import org.hl7.fhir.instance.model.api.IBaseResource; public class DaoMethodOutcome extends MethodOutcome { private ResourceTable myEntity; + private IBaseResource myPreviousResource; public ResourceTable getEntity() { return myEntity; } - @Override - public DaoMethodOutcome setCreated(Boolean theCreated) { - super.setCreated(theCreated); - return this; - } - public DaoMethodOutcome setEntity(ResourceTable theEntity) { myEntity = theEntity; return this; } + /** + * For update operations, this is the body of the resource as it was before the + * update + */ + public IBaseResource getPreviousResource() { + return myPreviousResource; + } + + /** + * For update operations, this is the body of the resource as it was before the + * update + */ + public void setPreviousResource(IBaseResource thePreviousResource) { + myPreviousResource = thePreviousResource; + } + + @Override + public DaoMethodOutcome setCreated(Boolean theCreated) { + super.setCreated(theCreated); + return this; + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java index ae465b9c483..a037de2706e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * 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. @@ -19,24 +19,6 @@ package ca.uhn.fhir.jpa.dao; * limitations under the License. * #L% */ -import static org.apache.commons.lang3.StringUtils.*; - -import java.util.*; - -import javax.persistence.TypedQuery; - -import ca.uhn.fhir.model.primitive.UriDt; -import org.apache.http.NameValuePair; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.instance.model.api.IIdType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.*; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionCallback; -import org.springframework.transaction.support.TransactionTemplate; - -import com.google.common.collect.ArrayListMultimap; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.jpa.entity.ResourceTable; @@ -51,15 +33,23 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryResponse; import ca.uhn.fhir.model.dstu2.resource.OperationOutcome; -import ca.uhn.fhir.model.dstu2.valueset.*; +import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum; +import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum; +import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.rest.api.*; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.RequestTypeEnum; +import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.RestfulServerUtils; -import ca.uhn.fhir.rest.server.exceptions.*; +import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.NotModifiedException; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.rest.server.method.BaseMethodBinding; import ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding; @@ -67,6 +57,23 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil.UrlParts; +import com.google.common.collect.ArrayListMultimap; +import org.apache.http.NameValuePair; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.persistence.TypedQuery; +import java.util.*; + +import static org.apache.commons.lang3.StringUtils.*; public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2.class); @@ -137,121 +144,11 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { } long delay = System.currentTimeMillis() - start; - ourLog.info("Batch completed in {}ms", new Object[] { delay }); + ourLog.info("Batch completed in {}ms", new Object[] {delay}); return resp; } - private String extractTransactionUrlOrThrowException(Entry nextEntry, HTTPVerbEnum verb) { - String url = nextEntry.getRequest().getUrl(); - if (isBlank(url)) { - throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionMissingUrl", verb.name())); - } - return url; - } - - /** - * This method is called for nested bundles (e.g. if we received a transaction with an entry that - * was a GET search, this method is called on the bundle for the search result, that will be placed in the - * outer bundle). This method applies the _summary and _content parameters to the output of - * that bundle. - * - * TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future. - */ - private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) { - IParser p = getContext().newJsonParser(); - RestfulServerUtils.configureResponseParser(theRequestDetails, p); - return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource)); - } - - private IFhirResourceDao getDaoOrThrowException(Class theClass) { - IFhirResourceDao retVal = getDao(theClass); - if (retVal == null) { - throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + getContext().getResourceDefinition(theClass).getName()); - } - return retVal; - } - - @Override - public MetaDt metaGetOperation(RequestDetails theRequestDetails) { - // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails); - notifyInterceptors(RestOperationTypeEnum.META, requestDetails); - - String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)"; - TypedQuery q = myEntityManager.createQuery(sql, TagDefinition.class); - List tagDefinitions = q.getResultList(); - - MetaDt retVal = toMetaDt(tagDefinitions); - - return retVal; - } - - protected MetaDt toMetaDt(Collection tagDefinitions) { - MetaDt retVal = new MetaDt(); - for (TagDefinition next : tagDefinitions) { - switch (next.getTagType()) { - case PROFILE: - retVal.addProfile(next.getCode()); - break; - case SECURITY_LABEL: - retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); - break; - case TAG: - retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); - break; - } - } - return retVal; - } - - - private ca.uhn.fhir.jpa.dao.IFhirResourceDao toDao(UrlParts theParts, String theVerb, String theUrl) { - RuntimeResourceDefinition resType; - try { - resType = getContext().getResourceDefinition(theParts.getResourceType()); - } catch (DataFormatException e) { - String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); - throw new InvalidRequestException(msg); - } - IFhirResourceDao dao = null; - if (resType != null) { - dao = getDao(resType.getImplementingClass()); - } - if (dao == null) { - String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); - throw new InvalidRequestException(msg); - } - - // if (theParts.getResourceId() == null && theParts.getParams() == null) { - // String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); - // throw new InvalidRequestException(msg); - // } - - return dao; - } - - @Transactional(propagation = Propagation.REQUIRED) - @Override - public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) { - if (theRequestDetails != null) { - ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null); - notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails); - } - - String actionName = "Transaction"; - return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName); - } - - private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) { - super.markRequestAsProcessingSubRequest(theRequestDetails); - try { - return doTransaction(theRequestDetails, theRequest, theActionName); - } finally { - super.clearRequestAsProcessingSubRequest(theRequestDetails); - } - } - @SuppressWarnings("unchecked") private Bundle doTransaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) { BundleTypeEnum transactionType = theRequest.getTypeElement().getValueAsEnum(); @@ -279,10 +176,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { /* * We want to execute the transaction request bundle elements in the order - * specified by the FHIR specification (see TransactionSorter) so we save the + * specified by the FHIR specification (see TransactionSorter) so we save the * original order in the request, then sort it. - * - * Entries with a type of GET are removed from the bundle so that they + * + * Entries with a type of GET are removed from the bundle so that they * can be processed at the very end. We do this because the incoming resources * are saved in a two-phase way in order to deal with interdependencies, and * we want the GET processing to use the final indexing state @@ -298,11 +195,12 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { } } Collections.sort(theRequest.getEntry(), new TransactionSorter()); - - List deletedResources = new ArrayList(); - List deleteConflicts = new ArrayList(); - Map entriesToProcess = new IdentityHashMap(); + + List deletedResources = new ArrayList<>(); + List deleteConflicts = new ArrayList<>(); + Map entriesToProcess = new IdentityHashMap<>(); Set nonUpdatedEntities = new HashSet(); + Set updatedEntities = new HashSet<>(); /* * Loop through the request and process any entries of type @@ -321,7 +219,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { nextResourceId = res.getId(); - if (nextResourceId.hasIdPart() == false) { + if (!nextResourceId.hasIdPart()) { if (isNotBlank(nextReqEntry.getFullUrl())) { nextResourceId = new IdDt(nextReqEntry.getFullUrl()); } @@ -361,86 +259,85 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { Entry nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry)); switch (verb) { - case POST: { - // CREATE - @SuppressWarnings("rawtypes") - IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); - res.setId((String) null); - DaoMethodOutcome outcome; - outcome = resourceDao.create(res, nextReqEntry.getRequest().getIfNoneExist(), false, theRequestDetails); - handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res); - entriesToProcess.put(nextRespEntry, outcome.getEntity()); - if (outcome.getCreated() == false) { - nonUpdatedEntities.add(outcome.getEntity()); - } - break; - } - case DELETE: { - // DELETE - String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); - UrlParts parts = UrlUtil.parseUrl(url); - ca.uhn.fhir.jpa.dao.IFhirResourceDao dao = toDao(parts, verb.getCode(), url); - int status = Constants.STATUS_HTTP_204_NO_CONTENT; - if (parts.getResourceId() != null) { - DaoMethodOutcome outcome = dao.delete(new IdDt(parts.getResourceType(), parts.getResourceId()), deleteConflicts, theRequestDetails); - if (outcome.getEntity() != null) { - deletedResources.add(outcome.getId().toUnqualifiedVersionless()); - entriesToProcess.put(nextRespEntry, outcome.getEntity()); - } - } else { - DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(parts.getResourceType() + '?' + parts.getParams(), deleteConflicts, theRequestDetails); - List allDeleted = deleteOutcome.getDeletedEntities(); - for (ResourceTable deleted : allDeleted) { - deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless()); - } - if (allDeleted.isEmpty()) { - status = Constants.STATUS_HTTP_404_NOT_FOUND; - } - } - - nextRespEntry.getResponse().setStatus(toStatusString(status)); - break; - } - case PUT: { - // UPDATE - @SuppressWarnings("rawtypes") - IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); - - DaoMethodOutcome outcome; - - String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); - - UrlParts parts = UrlUtil.parseUrl(url); - if (isNotBlank(parts.getResourceId())) { - res.setId(new IdDt(parts.getResourceType(), parts.getResourceId())); - outcome = resourceDao.update(res, null, false, theRequestDetails); - } else { + case POST: { + // CREATE + @SuppressWarnings("rawtypes") + IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); res.setId((String) null); - outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false, theRequestDetails); + DaoMethodOutcome outcome; + outcome = resourceDao.create(res, nextReqEntry.getRequest().getIfNoneExist(), false, theRequestDetails); + handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res); + entriesToProcess.put(nextRespEntry, outcome.getEntity()); + if (outcome.getCreated() == false) { + nonUpdatedEntities.add(outcome.getEntity()); + } + break; } + case DELETE: { + // DELETE + String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); + UrlParts parts = UrlUtil.parseUrl(url); + ca.uhn.fhir.jpa.dao.IFhirResourceDao dao = toDao(parts, verb.getCode(), url); + int status = Constants.STATUS_HTTP_204_NO_CONTENT; + if (parts.getResourceId() != null) { + DaoMethodOutcome outcome = dao.delete(new IdDt(parts.getResourceType(), parts.getResourceId()), deleteConflicts, theRequestDetails); + if (outcome.getEntity() != null) { + deletedResources.add(outcome.getId().toUnqualifiedVersionless()); + entriesToProcess.put(nextRespEntry, outcome.getEntity()); + } + } else { + DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(parts.getResourceType() + '?' + parts.getParams(), deleteConflicts, theRequestDetails); + List allDeleted = deleteOutcome.getDeletedEntities(); + for (ResourceTable deleted : allDeleted) { + deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless()); + } + if (allDeleted.isEmpty()) { + status = Constants.STATUS_HTTP_404_NOT_FOUND; + } + } - handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res); - entriesToProcess.put(nextRespEntry, outcome.getEntity()); - break; - } - case GET: - break; + nextRespEntry.getResponse().setStatus(toStatusString(status)); + break; + } + case PUT: { + // UPDATE + @SuppressWarnings("rawtypes") + IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); + + DaoMethodOutcome outcome; + + String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); + + UrlParts parts = UrlUtil.parseUrl(url); + if (isNotBlank(parts.getResourceId())) { + res.setId(new IdDt(parts.getResourceType(), parts.getResourceId())); + outcome = resourceDao.update(res, null, false, theRequestDetails); + } else { + res.setId((String) null); + outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false, theRequestDetails); + } + + if (outcome.getCreated() == Boolean.FALSE) { + updatedEntities.add(outcome.getEntity()); + } + + handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res); + entriesToProcess.put(nextRespEntry, outcome.getEntity()); + break; + } + case GET: + break; } } /* * Make sure that there are no conflicts from deletions. E.g. we can't delete something * if something else has a reference to it.. Unless the thing that has a reference to it - * was also deleted as a part of this transaction, which is why we check this now at the + * was also deleted as a part of this transaction, which is why we check this now at the * end. */ - - for (Iterator iter = deleteConflicts.iterator(); iter.hasNext(); ) { - DeleteConflict next = iter.next(); - if (deletedResources.contains(next.getTargetId().toVersionless())) { - iter.remove(); - } - } + + deleteConflicts.removeIf(next -> deletedResources.contains(next.getTargetId().toVersionless())); validateDeleteConflictsEmptyOrThrowException(deleteConflicts); /* @@ -489,8 +386,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource); Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null; - boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity()); - if (shouldUpdate) { + if (updatedEntities.contains(nextOutcome.getEntity())) { + updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource()); + } else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) { updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, updateTime, false, true); } } @@ -508,7 +406,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { Set val = resourceDao.processMatchUrl(matchUrl); if (val.size() > 1) { throw new InvalidRequestException( - "Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?"); + "Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?"); } } } @@ -537,9 +435,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { requestDetails.setServletRequest(theRequestDetails.getServletRequest()); requestDetails.setRequestType(RequestTypeEnum.GET); requestDetails.setServer(theRequestDetails.getServer()); - + String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerbEnum.GET); - + int qIndex = url.indexOf('?'); ArrayListMultimap paramValues = ArrayListMultimap.create(); requestDetails.setParameters(new HashMap()); @@ -564,7 +462,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { if (method == null) { throw new IllegalArgumentException("Unable to handle GET " + url); } - + if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) { requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch()); } @@ -574,7 +472,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) { requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch()); } - + if (method instanceof BaseResourceReturningMethodBinding) { try { IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails); @@ -594,23 +492,132 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { ourLog.info("Flushing context after {}", theActionName); myEntityManager.flush(); - + for (java.util.Map.Entry nextEntry : entriesToProcess.entrySet()) { nextEntry.getKey().getResponse().setLocation(nextEntry.getValue().getIdDt().toUnqualified().getValue()); nextEntry.getKey().getResponse().setEtag(nextEntry.getValue().getIdDt().getVersionIdPart()); } - + long delay = System.currentTimeMillis() - start; int numEntries = theRequest.getEntry().size(); long delayPer = delay / numEntries; - ourLog.info("{} completed in {}ms ({} entries at {}ms per entry)", new Object[] { theActionName , delay, numEntries, delayPer }); + ourLog.info("{} completed in {}ms ({} entries at {}ms per entry)", new Object[] {theActionName, delay, numEntries, delayPer}); response.setType(BundleTypeEnum.TRANSACTION_RESPONSE); return response; } + private String extractTransactionUrlOrThrowException(Entry nextEntry, HTTPVerbEnum verb) { + String url = nextEntry.getRequest().getUrl(); + if (isBlank(url)) { + throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionMissingUrl", verb.name())); + } + return url; + } + + /** + * This method is called for nested bundles (e.g. if we received a transaction with an entry that + * was a GET search, this method is called on the bundle for the search result, that will be placed in the + * outer bundle). This method applies the _summary and _content parameters to the output of + * that bundle. + *

+ * TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future. + */ + private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) { + IParser p = getContext().newJsonParser(); + RestfulServerUtils.configureResponseParser(theRequestDetails, p); + return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource)); + } + + private IFhirResourceDao getDaoOrThrowException(Class theClass) { + IFhirResourceDao retVal = getDao(theClass); + if (retVal == null) { + throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + getContext().getResourceDefinition(theClass).getName()); + } + return retVal; + } + + @Override + public MetaDt metaGetOperation(RequestDetails theRequestDetails) { + // Notify interceptors + ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails); + notifyInterceptors(RestOperationTypeEnum.META, requestDetails); + + String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)"; + TypedQuery q = myEntityManager.createQuery(sql, TagDefinition.class); + List tagDefinitions = q.getResultList(); + + MetaDt retVal = toMetaDt(tagDefinitions); + + return retVal; + } + + private ca.uhn.fhir.jpa.dao.IFhirResourceDao toDao(UrlParts theParts, String theVerb, String theUrl) { + RuntimeResourceDefinition resType; + try { + resType = getContext().getResourceDefinition(theParts.getResourceType()); + } catch (DataFormatException e) { + String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); + throw new InvalidRequestException(msg); + } + IFhirResourceDao dao = null; + if (resType != null) { + dao = getDao(resType.getImplementingClass()); + } + if (dao == null) { + String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); + throw new InvalidRequestException(msg); + } + + // if (theParts.getResourceId() == null && theParts.getParams() == null) { + // String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); + // throw new InvalidRequestException(msg); + // } + + return dao; + } + + protected MetaDt toMetaDt(Collection tagDefinitions) { + MetaDt retVal = new MetaDt(); + for (TagDefinition next : tagDefinitions) { + switch (next.getTagType()) { + case PROFILE: + retVal.addProfile(next.getCode()); + break; + case SECURITY_LABEL: + retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); + break; + case TAG: + retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); + break; + } + } + return retVal; + } + + @Transactional(propagation = Propagation.REQUIRED) + @Override + public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) { + if (theRequestDetails != null) { + ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null); + notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails); + } + + String actionName = "Transaction"; + return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName); + } + + private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) { + super.markRequestAsProcessingSubRequest(theRequestDetails); + try { + return doTransaction(theRequestDetails, theRequest, theActionName); + } finally { + super.clearRequestAsProcessingSubRequest(theRequestDetails); + } + } + private static void handleTransactionCreateOrUpdateOutcome(Map idSubstitutions, Map idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome, - Entry newEntry, String theResourceType, IResource theRes) { + Entry newEntry, String theResourceType, IResource theRes) { IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless(); IdDt resourceId = isPlaceholder(nextResourceId) ? nextResourceId : nextResourceId.toUnqualifiedVersionless(); if (newId.equals(resourceId) == false) { @@ -645,9 +652,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { } //@formatter:off + /** * Transaction Order, per the spec: - * + *

* Process any DELETE interactions * Process any POST interactions * Process any PUT interactions @@ -657,7 +665,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { public class TransactionSorter implements Comparator { @Override - public int compare(Entry theO1, Entry theO2) { + public int compare(Entry theO1, Entry theO2) { int o1 = toOrder(theO1); int o2 = toOrder(theO2); @@ -667,20 +675,20 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { private int toOrder(Entry theO1) { int o1 = 0; if (theO1.getRequest().getMethodElement().getValueAsEnum() != null) { - switch (theO1.getRequest().getMethodElement().getValueAsEnum()) { - case DELETE: - o1 = 1; - break; - case POST: - o1 = 2; - break; - case PUT: - o1 = 3; - break; - case GET: - o1 = 4; - break; - } + switch (theO1.getRequest().getMethodElement().getValueAsEnum()) { + case DELETE: + o1 = 1; + break; + case POST: + o1 = 2; + break; + case PUT: + o1 = 3; + break; + case GET: + o1 = 4; + break; + } } return o1; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java index 2469110cda2..de3746e753a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java @@ -1193,7 +1193,7 @@ public class SearchBuilder implements ISearchBuilder { codes = myTerminologySvc.findCodesBelow(system, code); } - ArrayList singleCodePredicates = new ArrayList(); + ArrayList singleCodePredicates = new ArrayList<>(); if (codes != null) { if (codes.isEmpty()) { @@ -1581,7 +1581,8 @@ public class SearchBuilder implements ISearchBuilder { } } if (valueSetUris.size() == 1) { - List candidateCodes = myTerminologySvc.expandValueSet(valueSetUris.iterator().next()); + String valueSet = valueSetUris.iterator().next(); + List candidateCodes = myTerminologySvc.expandValueSet(valueSet); for (VersionIndependentConcept nextCandidate : candidateCodes) { if (nextCandidate.getCode().equals(code)) { retVal = nextCandidate.getSystem(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java index c53f3bc2db7..9814a199364 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java @@ -1,5 +1,12 @@ package ca.uhn.fhir.jpa.dao.data; +import ca.uhn.fhir.jpa.entity.TermCodeSystem; +import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + import java.util.List; /* @@ -11,9 +18,9 @@ import java.util.List; * 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. @@ -22,17 +29,15 @@ import java.util.List; * #L% */ -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; +public interface ITermCodeSystemVersionDao extends JpaRepository { -import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; - -public interface ITermCodeSystemVersionDao extends JpaRepository { + @Modifying + @Query("DELETE FROM TermCodeSystemVersion csv WHERE csv.myCodeSystem = :cs") + void deleteForCodeSystem(@Param("cs") TermCodeSystem theCodeSystem); @Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResource.myId = :resource_id") List findByCodeSystemResource(@Param("resource_id") Long theCodeSystemResourcePid); - + @Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemHavingThisVersionAsCurrentVersionIfAny.myResource.myId = :resource_id") TermCodeSystemVersion findCurrentVersionForCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDao.java index 646b1407166..5f9dc078b6f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDao.java @@ -41,9 +41,9 @@ public interface ITermConceptDao extends JpaRepository { @Query("SELECT c FROM TermConcept c WHERE c.myCodeSystem = :code_system") List findByCodeSystemVersion(@Param("code_system") TermCodeSystemVersion theCodeSystem); - @Query("DELETE FROM TermConcept t WHERE t.myCodeSystem.myId = :cs_pid") + @Query("SELECT t FROM TermConcept t WHERE t.myCodeSystem.myId = :cs_pid") @Modifying - void deleteByCodeSystemVersion(@Param("cs_pid") Long thePid); + List findByCodeSystemVersion(@Param("cs_pid") Long thePid); @Query("UPDATE TermConcept t SET t.myIndexStatus = null") @Modifying diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java index 43dc130ee64..19ac3bf479a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java @@ -158,13 +158,11 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { ourLog.debug("Beginning {} with {} resources", theActionName, theRequest.getEntry().size()); -// long start = System.currentTimeMillis(); - final StopWatch transactionSw = new StopWatch(); final Date updateTime = new Date(); - final Set allIds = new LinkedHashSet(); - final Map idSubstitutions = new HashMap(); - final Map idToPersistedOutcome = new HashMap(); + final Set allIds = new LinkedHashSet<>(); + final Map idSubstitutions = new HashMap<>(); + final Map idToPersistedOutcome = new HashMap<>(); // Do all entries have a verb? for (int i = 0; i < theRequest.getEntry().size(); i++) { @@ -223,7 +221,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { Map entriesToProcess = txManager.execute(new TransactionCallback>() { @Override public Map doInTransaction(TransactionStatus status) { - return doTransactionWriteOperations(theRequestDetails, theRequest, theActionName, updateTime, allIds, idSubstitutions, idToPersistedOutcome, response, originalRequestOrder, entries, transactionSw); + return doTransactionWriteOperations(theRequestDetails, theRequest, theActionName, updateTime, allIds, idSubstitutions, idToPersistedOutcome, response, originalRequestOrder, entries); } }); for (Entry nextEntry : entriesToProcess.entrySet()) { @@ -300,20 +298,17 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { } - ourLog.info(theActionName + " completed in {}", transactionSw.toString()); - ourLog.info(theActionName + " details:\n{}", transactionSw.formatTaskDurations()); - response.setType(BundleType.TRANSACTIONRESPONSE); return response; } - - @SuppressWarnings("unchecked") - private Map doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set allIds, - Map theIdSubstitutions, Map idToPersistedOutcome, Bundle response, IdentityHashMap originalRequestOrder, List theEntries, StopWatch theStopWatch) { + + private Map doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date theUpdateTime, Set theAllIds, + Map theIdSubstitutions, Map theIdToPersistedOutcome, Bundle theResponse, IdentityHashMap theOriginalRequestOrder, List theEntries) { Set deletedResources = new HashSet<>(); List deleteConflicts = new ArrayList<>(); Map entriesToProcess = new IdentityHashMap<>(); Set nonUpdatedEntities = new HashSet<>(); + Set updatedEntities = new HashSet<>(); Map> conditionalRequestUrls = new HashMap<>(); /* @@ -333,7 +328,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { nextResourceId = res.getIdElement(); - if (nextResourceId.hasIdPart() == false) { + if (!nextResourceId.hasIdPart()) { if (isNotBlank(nextReqEntry.getFullUrl())) { nextResourceId = new IdType(nextReqEntry.getFullUrl()); } @@ -352,12 +347,12 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { * Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness */ if (isPlaceholder(nextResourceId)) { - if (!allIds.add(nextResourceId)) { + if (!theAllIds.add(nextResourceId)) { throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId)); } } else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) { IdType nextId = nextResourceId.toUnqualifiedVersionless(); - if (!allIds.add(nextId)) { + if (!theAllIds.add(nextId)) { throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId)); } } @@ -367,111 +362,112 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { HTTPVerb verb = nextReqEntry.getRequest().getMethodElement().getValue(); String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null; - BundleEntryComponent nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry)); - - theStopWatch.startTask("Process entry " + i + ": " + verb + " " + defaultString(resourceType)); + BundleEntryComponent nextRespEntry = theResponse.getEntry().get(theOriginalRequestOrder.get(nextReqEntry)); switch (verb) { - case POST: { - // CREATE - @SuppressWarnings("rawtypes") - IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); - res.setId((String) null); - DaoMethodOutcome outcome; - String matchUrl = nextReqEntry.getRequest().getIfNoneExist(); - matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl); - outcome = resourceDao.create(res, matchUrl, false, theRequestDetails); - if (nextResourceId != null) { - handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails); - } - entriesToProcess.put(nextRespEntry, outcome.getEntity()); - if (outcome.getCreated() == false) { - nonUpdatedEntities.add(outcome.getEntity()); - } else { - if (isNotBlank(matchUrl)) { - conditionalRequestUrls.put(matchUrl, res.getClass()); + case POST: { + // CREATE + @SuppressWarnings("rawtypes") + IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); + res.setId((String) null); + DaoMethodOutcome outcome; + String matchUrl = nextReqEntry.getRequest().getIfNoneExist(); + matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl); + outcome = resourceDao.create(res, matchUrl, false, theRequestDetails); + if (nextResourceId != null) { + handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails); } - } - - break; - } - case DELETE: { - // DELETE - String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); - UrlParts parts = UrlUtil.parseUrl(url); - ca.uhn.fhir.jpa.dao.IFhirResourceDao dao = toDao(parts, verb.toCode(), url); - int status = Constants.STATUS_HTTP_204_NO_CONTENT; - if (parts.getResourceId() != null) { - IdType deleteId = new IdType(parts.getResourceType(), parts.getResourceId()); - if (!deletedResources.contains(deleteId.getValueAsString())) { - DaoMethodOutcome outcome = dao.delete(deleteId, deleteConflicts, theRequestDetails); - if (outcome.getEntity() != null) { - deletedResources.add(deleteId.getValueAsString()); - entriesToProcess.put(nextRespEntry, outcome.getEntity()); + entriesToProcess.put(nextRespEntry, outcome.getEntity()); + if (outcome.getCreated() == false) { + nonUpdatedEntities.add(outcome.getEntity()); + } else { + if (isNotBlank(matchUrl)) { + conditionalRequestUrls.put(matchUrl, res.getClass()); } } - } else { - String matchUrl = parts.getResourceType() + '?' + parts.getParams(); - matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl); - DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails); - List allDeleted = deleteOutcome.getDeletedEntities(); - for (ResourceTable deleted : allDeleted) { - deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless().getValueAsString()); - } - if (allDeleted.isEmpty()) { - status = Constants.STATUS_HTTP_204_NO_CONTENT; - } - nextRespEntry.getResponse().setOutcome((Resource) deleteOutcome.getOperationOutcome()); + break; } - - nextRespEntry.getResponse().setStatus(toStatusString(status)); - - break; - } - case PUT: { - // UPDATE - @SuppressWarnings("rawtypes") - IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); - - String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); - - DaoMethodOutcome outcome; - UrlParts parts = UrlUtil.parseUrl(url); - if (isNotBlank(parts.getResourceId())) { - String version = null; - if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) { - version = ParameterUtil.parseETagValue(nextReqEntry.getRequest().getIfMatch()); - } - res.setId(new IdType(parts.getResourceType(), parts.getResourceId(), version)); - outcome = resourceDao.update(res, null, false, theRequestDetails); - } else { - res.setId((String) null); - String matchUrl; - if (isNotBlank(parts.getParams())) { - matchUrl = parts.getResourceType() + '?' + parts.getParams(); + case DELETE: { + // DELETE + String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); + UrlParts parts = UrlUtil.parseUrl(url); + ca.uhn.fhir.jpa.dao.IFhirResourceDao dao = toDao(parts, verb.toCode(), url); + int status = Constants.STATUS_HTTP_204_NO_CONTENT; + if (parts.getResourceId() != null) { + IdType deleteId = new IdType(parts.getResourceType(), parts.getResourceId()); + if (!deletedResources.contains(deleteId.getValueAsString())) { + DaoMethodOutcome outcome = dao.delete(deleteId, deleteConflicts, theRequestDetails); + if (outcome.getEntity() != null) { + deletedResources.add(deleteId.getValueAsString()); + entriesToProcess.put(nextRespEntry, outcome.getEntity()); + } + } } else { - matchUrl = parts.getResourceType(); - } - matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl); - outcome = resourceDao.update(res, matchUrl, false, theRequestDetails); - if (Boolean.TRUE.equals(outcome.getCreated())) { - conditionalRequestUrls.put(matchUrl, res.getClass()); - } - } + String matchUrl = parts.getResourceType() + '?' + parts.getParams(); + matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl); + DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails); + List allDeleted = deleteOutcome.getDeletedEntities(); + for (ResourceTable deleted : allDeleted) { + deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless().getValueAsString()); + } + if (allDeleted.isEmpty()) { + status = Constants.STATUS_HTTP_204_NO_CONTENT; + } + + nextRespEntry.getResponse().setOutcome((Resource) deleteOutcome.getOperationOutcome()); + } + + nextRespEntry.getResponse().setStatus(toStatusString(status)); + + break; + } + case PUT: { + // UPDATE + @SuppressWarnings("rawtypes") + IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); + + String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); + + DaoMethodOutcome outcome; + UrlParts parts = UrlUtil.parseUrl(url); + if (isNotBlank(parts.getResourceId())) { + String version = null; + if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) { + version = ParameterUtil.parseETagValue(nextReqEntry.getRequest().getIfMatch()); + } + res.setId(new IdType(parts.getResourceType(), parts.getResourceId(), version)); + outcome = resourceDao.update(res, null, false, theRequestDetails); + } else { + res.setId((String) null); + String matchUrl; + if (isNotBlank(parts.getParams())) { + matchUrl = parts.getResourceType() + '?' + parts.getParams(); + } else { + matchUrl = parts.getResourceType(); + } + matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl); + outcome = resourceDao.update(res, matchUrl, false, theRequestDetails); + if (Boolean.TRUE.equals(outcome.getCreated())) { + conditionalRequestUrls.put(matchUrl, res.getClass()); + } + } + + if (outcome.getCreated() == Boolean.FALSE) { + updatedEntities.add(outcome.getEntity()); + } + + handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails); + entriesToProcess.put(nextRespEntry, outcome.getEntity()); + break; + } + case GET: + case NULL: + break; - handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails); - entriesToProcess.put(nextRespEntry, outcome.getEntity()); - break; - } - case GET: - case NULL: - break; } } - theStopWatch.endCurrentTask(); - /* * Make sure that there are no conflicts from deletions. E.g. we can't delete something * if something else has a reference to it.. Unless the thing that has a reference to it @@ -479,12 +475,8 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { * end. */ - for (Iterator iter = deleteConflicts.iterator(); iter.hasNext();) { - DeleteConflict next = iter.next(); - if (deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue())) { - iter.remove(); - } - } + deleteConflicts.removeIf(next -> + deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue())); validateDeleteConflictsEmptyOrThrowException(deleteConflicts); /* @@ -492,13 +484,13 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { */ FhirTerser terser = getContext().newTerser(); - for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) { + for (DaoMethodOutcome nextOutcome : theIdToPersistedOutcome.values()) { IBaseResource nextResource = nextOutcome.getResource(); if (nextResource == null) { continue; } - // Refererences + // References List allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class); for (IBaseReference nextRef : allRefs) { IIdType nextId = nextRef.getReferenceElement(); @@ -534,18 +526,16 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { IPrimitiveType deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource); Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null; - boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity()); - if (shouldUpdate) { - updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, shouldUpdate, false, updateTime, false, true); + + if (updatedEntities.contains(nextOutcome.getEntity())) { + updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource()); + } else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) { + updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true); } } - theStopWatch.startTask("Flush Session"); - flushJpaSession(); - theStopWatch.endCurrentTask(); - /* * Double check we didn't allow any duplicates we shouldn't have */ @@ -557,12 +547,12 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao { Set val = resourceDao.processMatchUrl(matchUrl); if (val.size() > 1) { throw new InvalidRequestException( - "Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?"); + "Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?"); } } } - for (IdType next : allIds) { + for (IdType next : theAllIds) { IdType replacement = theIdSubstitutions.get(next); if (replacement == null) { continue; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/JpaValidationSupportDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/JpaValidationSupportDstu3.java index 93b4e36f51f..b84b5b3e2ca 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/JpaValidationSupportDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/JpaValidationSupportDstu3.java @@ -19,6 +19,8 @@ import javax.transaction.Transactional.TxType; import java.util.Collections; import java.util.List; +import static org.apache.commons.lang3.StringUtils.isBlank; + /* * #%L * HAPI FHIR JPA Server @@ -87,6 +89,9 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 { @Override public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) { + if (isBlank(theSystem)) { + return null; + } return fetchResource(theCtx, CodeSystem.class, theSystem); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java index 1b3f3230579..bba63698fd1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao.r4; * 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. @@ -29,7 +29,6 @@ import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.jpa.entity.TagDefinition; import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails; import ca.uhn.fhir.jpa.util.DeleteConflict; -import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.IParser; @@ -52,6 +51,7 @@ import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil.UrlParts; import com.google.common.collect.ArrayListMultimap; +import javolution.io.Struct; import org.apache.commons.lang3.Validate; import org.apache.http.NameValuePair; import org.hl7.fhir.instance.model.api.*; @@ -266,7 +266,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao { paramValues.put(next.getName(), next.getValue()); } for (java.util.Map.Entry> nextParamEntry : paramValues.asMap().entrySet()) { - String[] nextValue = nextParamEntry.getValue().toArray(new String[ nextParamEntry.getValue().size() ]); + String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]); requestDetails.addParameter(nextParamEntry.getKey(), nextValue); } url = url.substring(0, qIndex); @@ -323,6 +323,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao { List deleteConflicts = new ArrayList<>(); Map entriesToProcess = new IdentityHashMap<>(); Set nonUpdatedEntities = new HashSet<>(); + Set updatedEntities = new HashSet<>(); Map> conditionalRequestUrls = new HashMap<>(); /* @@ -467,6 +468,10 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao { } } + if (outcome.getCreated() == Boolean.FALSE) { + updatedEntities.add(outcome.getEntity()); + } + handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails); entriesToProcess.put(nextRespEntry, outcome.getEntity()); break; @@ -538,9 +543,11 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao { IPrimitiveType deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource); Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null; - boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity()); - if (shouldUpdate) { - updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, shouldUpdate, false, theUpdateTime, false, true); + + if (updatedEntities.contains(nextOutcome.getEntity())) { + updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource()); + } else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) { + updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java index b51192d8770..d7e0e5e4c8e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java @@ -20,6 +20,9 @@ package ca.uhn.fhir.jpa.entity; * #L% */ +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import javax.persistence.*; import java.io.Serializable; @@ -89,4 +92,15 @@ public class TermCodeSystem implements Serializable { public void setResource(ResourceTable theResource) { myResource = theResource; } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("codeSystemUri", myCodeSystemUri) + .append("currentVersion", myCurrentVersion) + .append("pid", myPid) + .append("resourcePid", myResourcePid) + .append("name", myName) + .toString(); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java index 4197c51121a..ea021ed1820 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java @@ -56,7 +56,7 @@ public class TermCodeSystemVersion implements Serializable { * issued. It should be made non-nullable at some point. */ @ManyToOne - @JoinColumn(name = "CODESYSTEM_PID", referencedColumnName = "PID", nullable = true) + @JoinColumn(name = "CODESYSTEM_PID", referencedColumnName = "PID", nullable = true, foreignKey = @ForeignKey(name = "FK_CODESYSVER_CS_ID")) private TermCodeSystem myCodeSystem; @SuppressWarnings("unused") @OneToOne(mappedBy = "myCurrentVersion", optional = true) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/TerminologyUploaderProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseTerminologyUploaderProvider.java similarity index 66% rename from hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/TerminologyUploaderProvider.java rename to hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseTerminologyUploaderProvider.java index ecf58bdd21b..e4318e8ed7e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/TerminologyUploaderProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseTerminologyUploaderProvider.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.provider; * 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. @@ -22,47 +22,47 @@ package ca.uhn.fhir.jpa.provider; import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc; import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc.UploadStatistics; -import ca.uhn.fhir.rest.annotation.Operation; -import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import org.hl7.fhir.r4.model.Attachment; import org.hl7.fhir.r4.model.IntegerType; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.StringType; import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.http.HttpServletRequest; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; +import java.io.*; import java.util.ArrayList; import java.util.List; -import static org.apache.commons.lang3.StringUtils.defaultString; -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; -public class TerminologyUploaderProvider extends BaseJpaProvider { +public abstract class BaseTerminologyUploaderProvider extends BaseJpaProvider { public static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "$upload-external-code-system"; - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProvider.class); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseTerminologyUploaderProvider.class); @Autowired private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc; - - @Operation(name = UPLOAD_EXTERNAL_CODE_SYSTEM, idempotent = false, returnParameters= { - @OperationParam(name="conceptCount", type=IntegerType.class, min=1) - }) - public Parameters uploadExternalCodeSystem( - HttpServletRequest theServletRequest, - @OperationParam(name="url", min=1) StringParam theCodeSystemUrl, - @OperationParam(name="localfile", min=1, max=OperationParam.MAX_UNLIMITED) List theLocalFile, - RequestDetails theRequestDetails - ) { + + protected Parameters handleUploadExternalCodeSystem( + HttpServletRequest theServletRequest, + StringParam theCodeSystemUrl, + List theLocalFile, + List thePackage, RequestDetails theRequestDetails + ) { startRequest(theServletRequest); + + if (theLocalFile == null || theLocalFile.size() == 0) { + if (thePackage == null || thePackage.size() == 0) { + throw new InvalidRequestException("No 'localfile' or 'package' parameter, or package had no data"); + } + } + try { List localFiles = new ArrayList<>(); if (theLocalFile != null && theLocalFile.size() > 0) { @@ -70,8 +70,8 @@ public class TerminologyUploaderProvider extends BaseJpaProvider { if (isNotBlank(nextLocalFile.getValue())) { ourLog.info("Reading in local file: {}", nextLocalFile.getValue()); File nextFile = new File(nextLocalFile.getValue()); - if (!nextFile.exists() || nextFile.isFile()) { - throw new InvalidRequestException("Unknown file: " +nextFile.getName()); + if (!nextFile.exists() || !nextFile.isFile()) { + throw new InvalidRequestException("Unknown file: " + nextFile.getName()); } localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() { @Override @@ -91,7 +91,27 @@ public class TerminologyUploaderProvider extends BaseJpaProvider { } } } - + + if (thePackage != null) { + for (Attachment nextPackage : thePackage) { + if (isBlank(nextPackage.getUrl())) { + throw new UnprocessableEntityException("Package is missing mandatory url element"); + } + + localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() { + @Override + public String getFilename() { + return nextPackage.getUrl(); + } + + @Override + public InputStream getInputStream() { + return new ByteArrayInputStream(nextPackage.getData()); + } + }); + } + } + String url = theCodeSystemUrl != null ? theCodeSystemUrl.getValue() : null; url = defaultString(url); @@ -99,11 +119,11 @@ public class TerminologyUploaderProvider extends BaseJpaProvider { if (IHapiTerminologyLoaderSvc.SCT_URI.equals(url)) { stats = myTerminologyLoaderSvc.loadSnomedCt(localFiles, theRequestDetails); } else if (IHapiTerminologyLoaderSvc.LOINC_URI.equals(url)) { - stats = myTerminologyLoaderSvc.loadLoinc(localFiles, theRequestDetails); + stats = myTerminologyLoaderSvc.loadLoinc(localFiles, theRequestDetails); } else { throw new InvalidRequestException("Unknown URL: " + url); } - + Parameters retVal = new Parameters(); retVal.addParameter().setName("conceptCount").setValue(new IntegerType(stats.getConceptCount())); return retVal; @@ -112,5 +132,5 @@ public class TerminologyUploaderProvider extends BaseJpaProvider { } } - + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3.java new file mode 100644 index 00000000000..d66d635482b --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3.java @@ -0,0 +1,53 @@ +package ca.uhn.fhir.jpa.provider.dstu3; + +import ca.uhn.fhir.jpa.provider.BaseTerminologyUploaderProvider; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import org.hl7.fhir.convertors.VersionConvertor_30_40; +import org.hl7.fhir.dstu3.model.Attachment; +import org.hl7.fhir.dstu3.model.IntegerType; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.exceptions.FHIRException; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.List; + +public class TerminologyUploaderProviderDstu3 extends BaseTerminologyUploaderProvider { + + @Operation(name = UPLOAD_EXTERNAL_CODE_SYSTEM, idempotent = false, returnParameters = { + @OperationParam(name = "conceptCount", type = IntegerType.class, min = 1) + }) + public Parameters uploadExternalCodeSystem( + HttpServletRequest theServletRequest, + @OperationParam(name = "url", min = 1) StringParam theCodeSystemUrl, + @OperationParam(name = "localfile", min = 1, max = OperationParam.MAX_UNLIMITED) List theLocalFile, + @OperationParam(name = "package", min = 0, max = OperationParam.MAX_UNLIMITED) List thePackage, + RequestDetails theRequestDetails + ) { + try { + List localFile = null; + if (theLocalFile != null) { + localFile = new ArrayList<>(); + for (StringType next : theLocalFile) { + localFile.add(VersionConvertor_30_40.convertString(next)); + } + } + List pkg = null; + if (thePackage!=null){ + pkg = new ArrayList<>(); + for (Attachment next : thePackage) { + pkg.add(VersionConvertor_30_40.convertAttachment(next)); + } + } + org.hl7.fhir.r4.model.Parameters retValR4 = handleUploadExternalCodeSystem(theServletRequest, theCodeSystemUrl, localFile, pkg, theRequestDetails); + return VersionConvertor_30_40.convertParameters(retValR4); + } catch (FHIRException e) { + throw new InternalErrorException(e); + } + } +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4.java new file mode 100644 index 00000000000..054123924cf --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.jpa.provider.r4; + +import ca.uhn.fhir.jpa.provider.BaseTerminologyUploaderProvider; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.StringParam; +import org.hl7.fhir.r4.model.Attachment; +import org.hl7.fhir.r4.model.IntegerType; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.StringType; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +public class TerminologyUploaderProviderR4 extends BaseTerminologyUploaderProvider { + + @Operation(name = UPLOAD_EXTERNAL_CODE_SYSTEM, idempotent = false, returnParameters = { + @OperationParam(name = "conceptCount", type = IntegerType.class, min = 1) + }) + public Parameters uploadExternalCodeSystem( + HttpServletRequest theServletRequest, + @OperationParam(name = "url", min = 1) StringParam theCodeSystemUrl, + @OperationParam(name = "localfile", min = 1, max = OperationParam.MAX_UNLIMITED) List theLocalFile, + @OperationParam(name = "package", min = 0, max = OperationParam.MAX_UNLIMITED) List thePackage, + RequestDetails theRequestDetails + ) { + return handleUploadExternalCodeSystem(theServletRequest, theCodeSystemUrl, theLocalFile, thePackage, theRequestDetails); + } +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index 9ad462731e2..d8da82784de 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java @@ -94,7 +94,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc private boolean myProcessDeferred = true; @Autowired private PlatformTransactionManager myTransactionMgr; - @Autowired + @Autowired(required = false) private IFhirResourceDaoCodeSystem myCodeSystemResourceDao; private void addCodeIfNotAlreadyAdded(String theCodeSystem, ValueSet.ValueSetExpansionComponent theExpansionComponent, Set theAddedCodes, TermConcept theConcept) { @@ -106,6 +106,19 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc } } + private void addConceptsToList(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set theAddedCodes, String theSystem, List theConcept) { + for (CodeSystem.ConceptDefinitionComponent next : theConcept) { + if (!theAddedCodes.contains(next.getCode())) { + theAddedCodes.add(next.getCode()); + ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains(); + contains.setCode(next.getCode()); + contains.setSystem(theSystem); + contains.setDisplay(next.getDisplay()); + } + addConceptsToList(theExpansionComponent, theAddedCodes, theSystem, next.getConcept()); + } + } + private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction bool, ValueSet.ConceptSetFilterComponent nextFilter) { bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery()); } @@ -142,11 +155,28 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc @Override public void deleteCodeSystem(TermCodeSystem theCodeSystem) { ourLog.info(" * Deleting code system {}", theCodeSystem.getPid()); + + myEntityManager.flush(); + TermCodeSystem cs = myCodeSystemDao.findOne(theCodeSystem.getPid()); + cs.setCurrentVersion(null); + myCodeSystemDao.save(cs); + myCodeSystemDao.flush(); + for (TermCodeSystemVersion next : myCodeSystemVersionDao.findByCodeSystemResource(theCodeSystem.getPid())) { myConceptParentChildLinkDao.deleteByCodeSystemVersion(next.getPid()); - myConceptDao.deleteByCodeSystemVersion(next.getPid()); + for (TermConcept nextConcept : myConceptDao.findByCodeSystemVersion(next.getPid())) { + myConceptPropertyDao.delete(nextConcept.getProperties()); + myConceptDao.delete(nextConcept); + } + if (next.getCodeSystem().getCurrentVersion() == next) { + next.getCodeSystem().setCurrentVersion(null); + myCodeSystemDao.save(next.getCodeSystem()); + } + myCodeSystemVersionDao.delete(next); } - myCodeSystemDao.delete(theCodeSystem.getPid()); + myCodeSystemVersionDao.deleteForCodeSystem(theCodeSystem); + myCodeSystemDao.delete(theCodeSystem); + } private int ensureParentsSaved(Collection theParents) { @@ -171,112 +201,140 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc @Override @Transactional(propagation = Propagation.REQUIRED) public ValueSet expandValueSet(ValueSet theValueSetToExpand) { - - ValueSet.ConceptSetComponent include = theValueSetToExpand.getCompose().getIncludeFirstRep(); - String system = include.getSystem(); - ourLog.info("Starting expansion around code system: {}", system); - - TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system); - if (cs == null) { - throw new InvalidRequestException("Unknown code system: " + system); - } - - TermCodeSystemVersion csv = cs.getCurrentVersion(); - ValueSet.ValueSetExpansionComponent expansionComponent = new ValueSet.ValueSetExpansionComponent(); Set addedCodes = new HashSet<>(); boolean haveIncludeCriteria = false; - /* - * Include Concepts - */ - for (ValueSet.ConceptReferenceComponent next : include.getConcept()) { - String nextCode = next.getCode(); - if (isNotBlank(nextCode) && !addedCodes.contains(nextCode)) { - haveIncludeCriteria = true; - TermConcept code = findCode(system, nextCode); - if (code != null) { - addedCodes.add(nextCode); - ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains(); - contains.setCode(nextCode); - contains.setSystem(system); - contains.setDisplay(code.getDisplay()); - } - } - } + for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getInclude()) { + String system = include.getSystem(); + if (isNotBlank(system)) { + ourLog.info("Starting expansion around code system: {}", system); - /* - * Filters - */ + TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system); + if (cs != null) { + TermCodeSystemVersion csv = cs.getCurrentVersion(); - if (include.getFilter().size() > 0) { - haveIncludeCriteria = true; - - FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager); - QueryBuilder qb = em.getSearchFactory().buildQueryBuilder().forEntity(TermConcept.class).get(); - BooleanJunction bool = qb.bool(); - - bool.must(qb.keyword().onField("myCodeSystemVersionPid").matching(csv.getPid()).createQuery()); - - for (ValueSet.ConceptSetFilterComponent nextFilter : include.getFilter()) { - if (isBlank(nextFilter.getValue()) && nextFilter.getOp() == null && isBlank(nextFilter.getProperty())) { - continue; - } - - if (isBlank(nextFilter.getValue()) || nextFilter.getOp() == null || isBlank(nextFilter.getProperty())) { - throw new InvalidRequestException("Invalid filter, must have fields populated: property op value"); - } - - - if (nextFilter.getProperty().equals("display:exact") && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) { - addDisplayFilterExact(qb, bool, nextFilter); - } else if ("display".equals(nextFilter.getProperty()) && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) { - if (nextFilter.getValue().trim().contains(" ")) { - addDisplayFilterExact(qb, bool, nextFilter); - } else { - addDisplayFilterInexact(qb, bool, nextFilter); - } - } else if ((nextFilter.getProperty().equals("concept") || nextFilter.getProperty().equals("code")) && nextFilter.getOp() == ValueSet.FilterOperator.ISA) { - - TermConcept code = findCode(system, nextFilter.getValue()); - if (code == null) { - throw new InvalidRequestException("Invalid filter criteria - code does not exist: {" + system + "}" + nextFilter.getValue()); + /* + * Include Concepts + */ + for (ValueSet.ConceptReferenceComponent next : include.getConcept()) { + String nextCode = next.getCode(); + if (isNotBlank(nextCode) && !addedCodes.contains(nextCode)) { + haveIncludeCriteria = true; + TermConcept code = findCode(system, nextCode); + if (code != null) { + addedCodes.add(nextCode); + ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains(); + contains.setCode(nextCode); + contains.setSystem(system); + contains.setDisplay(code.getDisplay()); + } + } } - ourLog.info(" * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay()); - bool.must(qb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery()); + /* + * Filters + */ - } else { + if (include.getFilter().size() > 0) { + haveIncludeCriteria = true; + + FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager); + QueryBuilder qb = em.getSearchFactory().buildQueryBuilder().forEntity(TermConcept.class).get(); + BooleanJunction bool = qb.bool(); + + bool.must(qb.keyword().onField("myCodeSystemVersionPid").matching(csv.getPid()).createQuery()); + + for (ValueSet.ConceptSetFilterComponent nextFilter : include.getFilter()) { + if (isBlank(nextFilter.getValue()) && nextFilter.getOp() == null && isBlank(nextFilter.getProperty())) { + continue; + } + + if (isBlank(nextFilter.getValue()) || nextFilter.getOp() == null || isBlank(nextFilter.getProperty())) { + throw new InvalidRequestException("Invalid filter, must have fields populated: property op value"); + } + + + if (nextFilter.getProperty().equals("display:exact") && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) { + addDisplayFilterExact(qb, bool, nextFilter); + } else if ("display".equals(nextFilter.getProperty()) && nextFilter.getOp() == ValueSet.FilterOperator.EQUAL) { + if (nextFilter.getValue().trim().contains(" ")) { + addDisplayFilterExact(qb, bool, nextFilter); + } else { + addDisplayFilterInexact(qb, bool, nextFilter); + } + } else if ((nextFilter.getProperty().equals("concept") || nextFilter.getProperty().equals("code")) && nextFilter.getOp() == ValueSet.FilterOperator.ISA) { + + TermConcept code = findCode(system, nextFilter.getValue()); + if (code == null) { + throw new InvalidRequestException("Invalid filter criteria - code does not exist: {" + system + "}" + nextFilter.getValue()); + } + + ourLog.info(" * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay()); + bool.must(qb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery()); + + } else { // bool.must(qb.keyword().onField("myProperties").matching(nextFilter.getStringProperty()+"="+nextFilter.getValue()).createQuery()); - bool.must(qb.phrase().onField("myProperties").sentence(nextFilter.getProperty() + "=" + nextFilter.getValue()).createQuery()); + bool.must(qb.phrase().onField("myProperties").sentence(nextFilter.getProperty() + "=" + nextFilter.getValue()).createQuery()); + + } + } + + Query luceneQuery = bool.createQuery(); + FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class); + jpaQuery.setMaxResults(1000); + + StopWatch sw = new StopWatch(); + + @SuppressWarnings("unchecked") + List result = jpaQuery.getResultList(); + + ourLog.info("Expansion completed in {}ms", sw.getMillis()); + + for (TermConcept nextConcept : result) { + addCodeIfNotAlreadyAdded(system, expansionComponent, addedCodes, nextConcept); + } + + expansionComponent.setTotal(jpaQuery.getResultSize()); + } + + if (!haveIncludeCriteria) { + List allCodes = findCodes(system); + for (TermConcept nextConcept : allCodes) { + addCodeIfNotAlreadyAdded(system, expansionComponent, addedCodes, nextConcept); + } + } + + } else { + // No codesystem matching the URL found in the database + + CodeSystem codeSystemFromContext = getCodeSystemFromContext(system); + if (codeSystemFromContext == null) { + throw new InvalidRequestException("Unknown code system: " + system); + } + + if (include.getConcept().isEmpty() == false) { + for (ValueSet.ConceptReferenceComponent next : include.getConcept()) { + String nextCode = next.getCode(); + if (isNotBlank(nextCode) && !addedCodes.contains(nextCode)) { + CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode); + if (code != null) { + addedCodes.add(nextCode); + ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains(); + contains.setCode(nextCode); + contains.setSystem(system); + contains.setDisplay(code.getDisplay()); + } + } + } + } else { + List concept = codeSystemFromContext.getConcept(); + addConceptsToList(expansionComponent, addedCodes, system, concept); + } } } - - Query luceneQuery = bool.createQuery(); - FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class); - jpaQuery.setMaxResults(1000); - - StopWatch sw = new StopWatch(); - - @SuppressWarnings("unchecked") - List result = jpaQuery.getResultList(); - - ourLog.info("Expansion completed in {}ms", sw.getMillis()); - - for (TermConcept nextConcept : result) { - addCodeIfNotAlreadyAdded(system, expansionComponent, addedCodes, nextConcept); - } - - expansionComponent.setTotal(jpaQuery.getResultSize()); - } - - if (!haveIncludeCriteria) { - List allCodes = findCodes(system); - for (TermConcept nextConcept : allCodes) { - addCodeIfNotAlreadyAdded(system, expansionComponent, addedCodes, nextConcept); - } } ValueSet valueSet = new ValueSet(); @@ -284,9 +342,17 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc return valueSet; } - @Override - public List expandValueSet(String theValueSet) { - throw new UnsupportedOperationException(); // FIXME implement + protected List expandValueSetAndReturnVersionIndependentConcepts(org.hl7.fhir.r4.model.ValueSet theValueSetToExpandR4) { + org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent expandedR4 = expandValueSet(theValueSetToExpandR4).getExpansion(); + + ArrayList retVal = new ArrayList<>(); + for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent nextContains : expandedR4.getContains()) { + retVal.add( + new VersionIndependentConcept() + .setSystem(nextContains.getSystem()) + .setCode(nextContains.getCode())); + } + return retVal; } private void fetchChildren(TermConcept theConcept, Set theSetToPopulate) { @@ -312,6 +378,16 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc } } + private CodeSystem.ConceptDefinitionComponent findCode(List theConcepts, String theCode) { + for (CodeSystem.ConceptDefinitionComponent next : theConcepts) { + if (theCode.equals(next.getCode())) { + return next; + } + findCode(next.getConcept(), theCode); + } + return null; + } + @Override public TermConcept findCode(String theCodeSystem, String theCode) { TermCodeSystemVersion csv = findCurrentCodeSystemVersionForSystem(theCodeSystem); @@ -398,6 +474,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc return myCodeSystemDao.findByCodeSystemUri(theSystem); } + protected abstract CodeSystem getCodeSystemFromContext(String theSystem); + private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap theConceptsStack, int theTotalConcepts) { if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) { return; @@ -429,7 +507,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc } } - for (TermConceptProperty next : theConcept.getProperties()){ + for (TermConceptProperty next : theConcept.getProperties()) { myConceptPropertyDao.save(next); } @@ -636,12 +714,16 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc for (TermCodeSystemVersion next : existing) { ourLog.info(" * Deleting code system version {}", next.getPid()); myConceptParentChildLinkDao.deleteByCodeSystemVersion(next.getPid()); - myConceptDao.deleteByCodeSystemVersion(next.getPid()); + for (TermConcept nextConcept : myConceptDao.findByCodeSystemVersion(next.getPid())) { + myConceptPropertyDao.delete(nextConcept.getProperties()); + myConceptDao.delete(nextConcept); + } } ourLog.info("Flushing..."); myConceptParentChildLinkDao.flush(); + myConceptPropertyDao.flush(); myConceptDao.flush(); ourLog.info("Done flushing"); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java index d7259cba057..b26aa5e9a28 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java @@ -76,6 +76,11 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl { throw new UnsupportedOperationException(); } + @Override + protected CodeSystem getCodeSystemFromContext(String theSystem) { + return null; + } + @Override public List expandValueSet(String theValueSet) { throw new UnsupportedOperationException(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java index d8f8aee0c5b..5087fc312b5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java @@ -153,6 +153,24 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen } } + @Override + public List expandValueSet(String theValueSet) { + ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet); + if (vs == null) { + return Collections.emptyList(); + } + + org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4; + try { + valueSetToExpandR4 = VersionConvertor_30_40.convertValueSet(vs); + } catch (FHIRException e) { + throw new InternalErrorException(e); + } + + + return expandValueSetAndReturnVersionIndependentConcepts(valueSetToExpandR4); + } + @Override public List fetchAllConformanceResources(FhirContext theContext) { return null; @@ -222,6 +240,16 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen return retVal; } + @Override + protected org.hl7.fhir.r4.model.CodeSystem getCodeSystemFromContext(String theSystem) { + CodeSystem codeSystem = myValidationSupport.fetchCodeSystem(myContext, theSystem); + try { + return VersionConvertor_30_40.convertCodeSystem(codeSystem); + } catch (FHIRException e) { + throw new InternalErrorException(e); + } + } + @Override public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) { return myTerminologySvc.supportsSystem(theSystem); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java index 3af96290f2f..41182ebcfa5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java @@ -112,6 +112,16 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements myValueSetResourceDao.update(theValueSet, matchUrl, theRequestDetails); } + @Override + public List expandValueSet(String theValueSet) { + ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet); + if (vs == null) { + return Collections.emptyList(); + } + + return expandValueSetAndReturnVersionIndependentConcepts(vs); + } + @Override public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) { ValueSet valueSetToExpand = new ValueSet(); @@ -188,6 +198,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements return retVal; } + @Override + protected CodeSystem getCodeSystemFromContext(String theSystem) { + return myValidationSupport.fetchCodeSystem(myContext, theSystem); + } + @Override public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) { return myTerminologySvc.supportsSystem(theSystem); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java index 4b3b8cfe841..c0112139d1b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java @@ -128,6 +128,13 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc { CSVParser parsed; try { reader = new InputStreamReader(nextZipBytes.getInputStream(), Charsets.UTF_8); + + if (ourLog.isTraceEnabled()) { + String contents = IOUtils.toString(reader); + ourLog.info("File contents for: {}\n{}", nextFilename, contents); + reader = new StringReader(contents); + } + CSVFormat format = CSVFormat.newFormat(theDelimiter).withFirstRecordAsHeader(); if (theQuoteMode != null) { format = format.withQuote('"').withQuoteMode(theQuoteMode); @@ -402,16 +409,15 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc { LoadedFileDescriptors(List theFileDescriptors) { try { for (FileDescriptor next : theFileDescriptors) { - File nextTemporaryFile = File.createTempFile("hapifhir", ".tmp"); - nextTemporaryFile.deleteOnExit(); - if (next.getFilename().toLowerCase().endsWith(".zip")) { ourLog.info("Uncompressing {} into temporary files", next.getFilename()); try (InputStream inputStream = next.getInputStream()) { ZipInputStream zis = new ZipInputStream(new BufferedInputStream(inputStream)); for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null; ) { BOMInputStream fis = new BOMInputStream(zis); - FileOutputStream fos = new FileOutputStream(nextTemporaryFile); + File nextTemporaryFile = File.createTempFile("hapifhir", ".tmp"); + nextTemporaryFile.deleteOnExit(); + FileOutputStream fos = new FileOutputStream(nextTemporaryFile, false); IOUtils.copy(fis, fos); String nextEntryFileName = nextEntry.getName(); myUncompressedFileDescriptors.add(new FileDescriptor() { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/VersionIndependentConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/VersionIndependentConcept.java index 59c5403d253..467bae71011 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/VersionIndependentConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/VersionIndependentConcept.java @@ -25,6 +25,16 @@ public class VersionIndependentConcept { private String mySystem; private String myCode; + /** + * Constructor + */ + public VersionIndependentConcept() { + super(); + } + + /** + * Constructor + */ public VersionIndependentConcept(String theSystem, String theCode) { setSystem(theSystem); setCode(theCode); @@ -34,16 +44,18 @@ public class VersionIndependentConcept { return mySystem; } - public void setSystem(String theSystem) { + public VersionIndependentConcept setSystem(String theSystem) { mySystem = theSystem; + return this; } public String getCode() { return myCode; } - public void setCode(String theCode) { + public VersionIndependentConcept setCode(String theCode) { myCode = theCode; + return this; } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/TestUtil.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/TestUtil.java index 4d5dafb825f..5beb2f3a67f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/TestUtil.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/TestUtil.java @@ -96,7 +96,7 @@ public class TestUtil { assertThat(joinColumn.name(), null); ForeignKey fk = joinColumn.foreignKey(); Validate.notNull(fk); - Validate.isTrue(isNotBlank(fk.name())); + Validate.isTrue(isNotBlank(fk.name()), "Foreign key on " + ae.toString() + " has no name()"); Validate.isTrue(fk.name().startsWith("FK_")); assertThat(fk.name(), theNames); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java index dd0730869a6..1b6e270875e 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java @@ -252,6 +252,7 @@ public abstract class BaseJpaTest { public Void doInTransaction(TransactionStatus theStatus) { entityManager.createQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate(); entityManager.createQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate(); + entityManager.createQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null").executeUpdate(); return null; } }); @@ -279,6 +280,7 @@ public abstract class BaseJpaTest { txTemplate.execute(new TransactionCallback() { @Override public Void doInTransaction(TransactionStatus theStatus) { + entityManager.createQuery("DELETE from " + TermConceptProperty.class.getSimpleName() + " d").executeUpdate(); entityManager.createQuery("DELETE from " + TermConcept.class.getSimpleName() + " d").executeUpdate(); for (TermCodeSystem next : entityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) { next.setCurrentVersion(null); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirSystemDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirSystemDaoDstu2Test.java index b894e83a823..70a5dac6d8d 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirSystemDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirSystemDaoDstu2Test.java @@ -1,6 +1,7 @@ package ca.uhn.fhir.jpa.dao.dstu2; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; +import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.entity.TagTypeEnum; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; import ca.uhn.fhir.model.api.IResource; @@ -18,11 +19,13 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryResponse; import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum; import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum; import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum; +import ca.uhn.fhir.model.dstu2.valueset.ObservationStatusEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.util.TestUtil; @@ -831,6 +834,213 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest { } } + @Test + public void testTransactionDoesntUpdateUnchangesResourceWithPlaceholderIds() { + Bundle output, input; + Bundle.EntryResponse respEntry; + IdType createdPatientId; + SearchParameterMap map; + IBundleProvider search; + + input = new Bundle(); + + /* + * Create a transaction with a patient and an observation using + * placeholder IDs in them + */ + Patient pat = new Patient(); + pat.setId(IdType.newRandomUuid()); + pat.addIdentifier().setSystem("foo").setValue("bar"); + input + .addEntry() + .setResource(pat) + .setFullUrl(pat.getId()) + .getRequest() + .setMethod(HTTPVerbEnum.POST) + .setUrl("/Patient") + .setIfNoneExist("Patient?identifier=foo|bar"); + Observation obs = new Observation(); + obs.addIdentifier().setSystem("foo").setValue("dog"); + obs.getSubject().setReference(pat.getId()); + input + .addEntry() + .setResource(obs) + .getRequest() + .setMethod(HTTPVerbEnum.PUT) + .setUrl("/Observation?identifier=foo|dog"); + output = mySystemDao.transaction(mySrd, input); + + /* + * Both resrouces should be created and have version 1 + */ + respEntry = output.getEntry().get(0).getResponse(); + assertEquals("201 Created", respEntry.getStatus()); + createdPatientId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdPatientId.getResourceType()); + assertEquals("1", createdPatientId.getVersionIdPart()); + + respEntry = output.getEntry().get(1).getResponse(); + assertEquals("201 Created", respEntry.getStatus()); + IdType createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0, 1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0, 1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference().getValue()); + + /* + * Now run the same transaction, which should not make any changes this time + * around + */ + + input = new Bundle(); + pat = new Patient(); + pat.setId(IdType.newRandomUuid()); + pat.addIdentifier().setSystem("foo").setValue("bar"); + input + .addEntry() + .setResource(pat) + .setFullUrl(pat.getId()) + .getRequest() + .setMethod(HTTPVerbEnum.POST) + .setUrl("/Patient") + .setIfNoneExist("Patient?identifier=foo|bar"); + obs = new Observation(); + obs.addIdentifier().setSystem("foo").setValue("dog"); + obs.getSubject().setReference(pat.getId()); + input + .addEntry() + .setResource(obs) + .getRequest() + .setMethod(HTTPVerbEnum.PUT) + .setUrl("/Observation?identifier=foo|dog"); + output = mySystemDao.transaction(mySrd, input); + + /* + * Should still have version 1 of both resources + */ + respEntry = output.getEntry().get(0).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + respEntry = output.getEntry().get(1).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should still work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0, 1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0, 1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference().getValue()); + + /* + * Now run the transaction, but this time with an actual + * change to the Observation + */ + + input = new Bundle(); + pat = new Patient(); + pat.setId(IdType.newRandomUuid()); + pat.addIdentifier().setSystem("foo").setValue("bar"); + input + .addEntry() + .setResource(pat) + .setFullUrl(pat.getId()) + .getRequest() + .setMethod(HTTPVerbEnum.POST) + .setUrl("/Patient") + .setIfNoneExist("Patient?identifier=foo|bar"); + obs = new Observation(); + obs.addIdentifier().setSystem("foo").setValue("dog"); + obs.setStatus(ObservationStatusEnum.FINAL); + obs.getSubject().setReference(pat.getId()); + input + .addEntry() + .setResource(obs) + .getRequest() + .setMethod(HTTPVerbEnum.PUT) + .setUrl("/Observation?identifier=foo|dog"); + output = mySystemDao.transaction(mySrd, input); + + /* + * Observation should now be version 2 + */ + respEntry = output.getEntry().get(0).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + respEntry = output.getEntry().get(1).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("2", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should still work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0, 1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0, 1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference().getValue()); + assertEquals(ObservationStatusEnum.FINAL.getCode(), obs.getStatus()); + + } + @Test(expected = InvalidRequestException.class) public void testTransactionFailsWithDuplicateIds() { Bundle request = new Bundle(); @@ -1193,62 +1403,6 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest { } - @Test - public void testTransactionUpdateResourceNewVersionCreatedWhenDataChanges() { - - Bundle request = new Bundle(); - String patientId = "Patient/IShouldUpdate"; - Patient p = new Patient(); - p.addName().addFamily("Hello"); - p.setId(patientId); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId); - - Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request); - assertEquals(1, initialBundleResponse.getEntry().size()); - ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse)); - - Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0); - assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus()); - assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1"))); - - p.addName().addFamily("AnotherName"); - - Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request); - assertEquals(1, secondBundleResponse.getEntry().size()); - ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse)); - - Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0); - assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus()); - assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("2"))); - } - - @Test - public void testTransactionUpdateResourceNewVersionNotCreatedWhenDataNotChanged() { - - Bundle request = new Bundle(); - String patientId = "Patient/IShouldNotUpdate"; - Patient p = new Patient(); - p.addName().addFamily("Hello"); - p.setId(patientId); - request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId); - - Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request); - assertEquals(1, initialBundleResponse.getEntry().size()); - ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse)); - - Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0); - assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus()); - assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1"))); - - Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request); - assertEquals(1, secondBundleResponse.getEntry().size()); - ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse)); - - Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0); - assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus()); - assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("1"))); - } - @Test public void testTransactionUpdateMatchUrlWithTwoMatch() { String methodName = "testTransactionUpdateMatchUrlWithTwoMatch"; @@ -1362,6 +1516,62 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest { } + @Test + public void testTransactionUpdateResourceNewVersionCreatedWhenDataChanges() { + + Bundle request = new Bundle(); + String patientId = "Patient/IShouldUpdate"; + Patient p = new Patient(); + p.addName().addFamily("Hello"); + p.setId(patientId); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId); + + Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request); + assertEquals(1, initialBundleResponse.getEntry().size()); + ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse)); + + Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0); + assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus()); + assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1"))); + + p.addName().addFamily("AnotherName"); + + Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request); + assertEquals(1, secondBundleResponse.getEntry().size()); + ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse)); + + Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0); + assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus()); + assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("2"))); + } + + @Test + public void testTransactionUpdateResourceNewVersionNotCreatedWhenDataNotChanged() { + + Bundle request = new Bundle(); + String patientId = "Patient/IShouldNotUpdate"; + Patient p = new Patient(); + p.addName().addFamily("Hello"); + p.setId(patientId); + request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId); + + Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request); + assertEquals(1, initialBundleResponse.getEntry().size()); + ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse)); + + Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0); + assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus()); + assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1"))); + + Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request); + assertEquals(1, secondBundleResponse.getEntry().size()); + ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse)); + + Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0); + assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus()); + assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("1"))); + } + @Test public void testTransactionWhichFailsPersistsNothing() { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java index 61b25430e87..7189e2548c6 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java @@ -12,6 +12,7 @@ import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.param.ReferenceParam; +import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.util.TestUtil; @@ -1439,6 +1440,213 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest { assertTrue(p.getGeneralPractitionerFirstRep().getReferenceElement().isIdPartValidLong()); } + @Test + public void testTransactionDoesntUpdateUnchangesResourceWithPlaceholderIds() { + Bundle output, input; + BundleEntryResponseComponent respEntry; + IdType createdPatientId; + SearchParameterMap map; + IBundleProvider search; + + input = new Bundle(); + + /* + * Create a transaction with a patient and an observation using + * placeholder IDs in them + */ + Patient pat = new Patient(); + pat.setId(IdType.newRandomUuid()); + pat.addIdentifier().setSystem("foo").setValue("bar"); + input + .addEntry() + .setResource(pat) + .setFullUrl(pat.getId()) + .getRequest() + .setMethod(HTTPVerb.POST) + .setUrl("/Patient") + .setIfNoneExist("Patient?identifier=foo|bar"); + Observation obs = new Observation(); + obs.addIdentifier().setSystem("foo").setValue("dog"); + obs.getSubject().setReference(pat.getId()); + input + .addEntry() + .setResource(obs) + .getRequest() + .setMethod(HTTPVerb.PUT) + .setUrl("/Observation?identifier=foo|dog"); + output = mySystemDao.transaction(mySrd, input); + + /* + * Both resrouces should be created and have version 1 + */ + respEntry = output.getEntry().get(0).getResponse(); + assertEquals("201 Created", respEntry.getStatus()); + createdPatientId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdPatientId.getResourceType()); + assertEquals("1", createdPatientId.getVersionIdPart()); + + respEntry = output.getEntry().get(1).getResponse(); + assertEquals("201 Created", respEntry.getStatus()); + IdType createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0, 1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0, 1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference()); + + /* + * Now run the same transaction, which should not make any changes this time + * around + */ + + input = new Bundle(); + pat = new Patient(); + pat.setId(IdType.newRandomUuid()); + pat.addIdentifier().setSystem("foo").setValue("bar"); + input + .addEntry() + .setResource(pat) + .setFullUrl(pat.getId()) + .getRequest() + .setMethod(HTTPVerb.POST) + .setUrl("/Patient") + .setIfNoneExist("Patient?identifier=foo|bar"); + obs = new Observation(); + obs.addIdentifier().setSystem("foo").setValue("dog"); + obs.getSubject().setReference(pat.getId()); + input + .addEntry() + .setResource(obs) + .getRequest() + .setMethod(HTTPVerb.PUT) + .setUrl("/Observation?identifier=foo|dog"); + output = mySystemDao.transaction(mySrd, input); + + /* + * Should still have version 1 of both resources + */ + respEntry = output.getEntry().get(0).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + respEntry = output.getEntry().get(1).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should still work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0, 1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0, 1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference()); + + /* + * Now run the transaction, but this time with an actual + * change to the Observation + */ + + input = new Bundle(); + pat = new Patient(); + pat.setId(IdType.newRandomUuid()); + pat.addIdentifier().setSystem("foo").setValue("bar"); + input + .addEntry() + .setResource(pat) + .setFullUrl(pat.getId()) + .getRequest() + .setMethod(HTTPVerb.POST) + .setUrl("/Patient") + .setIfNoneExist("Patient?identifier=foo|bar"); + obs = new Observation(); + obs.addIdentifier().setSystem("foo").setValue("dog"); + obs.setStatus(ObservationStatus.FINAL); + obs.getSubject().setReference(pat.getId()); + input + .addEntry() + .setResource(obs) + .getRequest() + .setMethod(HTTPVerb.PUT) + .setUrl("/Observation?identifier=foo|dog"); + output = mySystemDao.transaction(mySrd, input); + + /* + * Observation should now be version 2 + */ + respEntry = output.getEntry().get(0).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + respEntry = output.getEntry().get(1).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("2", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should still work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0, 1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0, 1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference()); + assertEquals(ObservationStatus.FINAL, obs.getStatus()); + + } + @Test public void testTransactionDoubleConditionalCreateOnlyCreatesOne() { Bundle inputBundle = new Bundle(); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java index ef9da79462d..494c4a39985 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java @@ -11,6 +11,7 @@ import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.param.ReferenceParam; +import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.util.TestUtil; @@ -1515,13 +1516,19 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest { } @Test - public void testTransactionDoesntDoubleCreate() { + public void testTransactionDoesntUpdateUnchangesResourceWithPlaceholderIds() { Bundle output, input; BundleEntryResponseComponent respEntry; - IdType createdId; + IdType createdPatientId; + SearchParameterMap map; + IBundleProvider search; input = new Bundle(); + /* + * Create a transaction with a patient and an observation using + * placeholder IDs in them + */ Patient pat = new Patient(); pat.setId(IdType.newRandomUuid()); pat.addIdentifier().setSystem("foo").setValue("bar"); @@ -1542,24 +1549,51 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest { .getRequest() .setMethod(HTTPVerb.PUT) .setUrl("/Observation?identifier=foo|dog"); - output = mySystemDao.transaction(mySrd, input); + + /* + * Both resrouces should be created and have version 1 + */ respEntry = output.getEntry().get(0).getResponse(); assertEquals("201 Created", respEntry.getStatus()); - createdId = new IdType(respEntry.getLocation()); - assertEquals("Patient", createdId.getResourceType()); - assertEquals("1", createdId.getVersionIdPart()); + createdPatientId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdPatientId.getResourceType()); + assertEquals("1", createdPatientId.getVersionIdPart()); respEntry = output.getEntry().get(1).getResponse(); assertEquals("201 Created", respEntry.getStatus()); - createdId = new IdType(respEntry.getLocation()); - assertEquals("Observation", createdId.getResourceType()); - assertEquals("1", createdId.getVersionIdPart()); + IdType createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); - // Same bundle again + /* + * Searches for both resources should work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0,1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0,1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference()); + + /* + * Now run the same transaction, which should not make any changes this time + * around + */ input = new Bundle(); - pat = new Patient(); pat.setId(IdType.newRandomUuid()); pat.addIdentifier().setSystem("foo").setValue("bar"); @@ -1580,20 +1614,111 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest { .getRequest() .setMethod(HTTPVerb.PUT) .setUrl("/Observation?identifier=foo|dog"); - - output = mySystemDao.transaction(mySrd, input); + + /* + * Should still have version 1 of both resources + */ respEntry = output.getEntry().get(0).getResponse(); assertEquals("200 OK", respEntry.getStatus()); - createdId = new IdType(respEntry.getLocation()); - assertEquals("Patient", createdId.getResourceType()); - assertEquals("1", createdId.getVersionIdPart()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); respEntry = output.getEntry().get(1).getResponse(); assertEquals("200 OK", respEntry.getStatus()); - createdId = new IdType(respEntry.getLocation()); - assertEquals("Observation", createdId.getResourceType()); - assertEquals("1", createdId.getVersionIdPart()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should still work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0,1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0,1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference()); + + /* + * Now run the transaction, but this time with an actual + * change to the Observation + */ + + input = new Bundle(); + pat = new Patient(); + pat.setId(IdType.newRandomUuid()); + pat.addIdentifier().setSystem("foo").setValue("bar"); + input + .addEntry() + .setResource(pat) + .setFullUrl(pat.getId()) + .getRequest() + .setMethod(HTTPVerb.POST) + .setUrl("/Patient") + .setIfNoneExist("Patient?identifier=foo|bar"); + obs = new Observation(); + obs.addIdentifier().setSystem("foo").setValue("dog"); + obs.setStatus(ObservationStatus.FINAL); + obs.getSubject().setReference(pat.getId()); + input + .addEntry() + .setResource(obs) + .getRequest() + .setMethod(HTTPVerb.PUT) + .setUrl("/Observation?identifier=foo|dog"); + output = mySystemDao.transaction(mySrd, input); + + /* + * Observation should now be version 2 + */ + respEntry = output.getEntry().get(0).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Patient", createdObservationId.getResourceType()); + assertEquals("1", createdObservationId.getVersionIdPart()); + + respEntry = output.getEntry().get(1).getResponse(); + assertEquals("200 OK", respEntry.getStatus()); + createdObservationId = new IdType(respEntry.getLocation()); + assertEquals("Observation", createdObservationId.getResourceType()); + assertEquals("2", createdObservationId.getVersionIdPart()); + + /* + * Searches for both resources should still work and the reference + * should be substituted correctly + */ + // Patient + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar")); + search = myPatientDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue())); + pat = (Patient) search.getResources(0,1).get(0); + assertEquals("foo", pat.getIdentifierFirstRep().getSystem()); + // Observation + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog")); + search = myObservationDao.search(map); + assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue())); + obs = (Observation) search.getResources(0,1).get(0); + assertEquals("foo", obs.getIdentifierFirstRep().getSystem()); + assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference()); + assertEquals(ObservationStatus.FINAL, obs.getStatus()); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/BaseResourceProviderDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/BaseResourceProviderDstu3Test.java index 962286ef449..599b88dff55 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/BaseResourceProviderDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/BaseResourceProviderDstu3Test.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig; import ca.uhn.fhir.jpa.dao.data.ISearchDao; import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test; import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3; -import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc; import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor; @@ -54,16 +53,16 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test { protected static CloseableHttpClient ourHttpClient; protected static int ourPort; protected static RestfulServer ourRestServer; - private static Server ourServer; protected static String ourServerBase; protected static GenericWebApplicationContext ourWebApplicationContext; - private TerminologyUploaderProvider myTerminologyUploaderProvider; protected static SearchParamRegistryDstu3 ourSearchParamRegistry; protected static DatabaseBackedPagingProvider ourPagingProvider; protected static SubscriptionRestHookInterceptor ourRestHookSubscriptionInterceptor; protected static SubscriptionEmailInterceptor ourEmailSubscriptionInterceptor; protected static ISearchDao mySearchEntityDao; protected static ISearchCoordinatorSvc mySearchCoordinatorSvc; + private static Server ourServer; + private TerminologyUploaderProviderDstu3 myTerminologyUploaderProvider; public BaseResourceProviderDstu3Test() { super(); @@ -93,7 +92,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test { ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); - myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class); + myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderDstu3.class); ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java index dc224445819..e0b580fd79a 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java @@ -32,12 +32,6 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu3CodeSystemTest.class); private IIdType myExtensionalVsId; - @AfterClass - public static void afterClassClearContext() { - TestUtil.clearAllStaticFieldsForUnitTest(); - } - - @Before @Transactional public void before02() throws IOException { @@ -47,11 +41,11 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless(); } - + @Test public void testLookupOnExternalCode() { ResourceProviderDstu3ValueSetTest.createExternalCs(myCodeSystemDao, myResourceTableDao, myTermSvc, mySrd); - + Parameters respParam = ourClient .operation() .onType(CodeSystem.class) @@ -62,9 +56,9 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); - + assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals(("SYSTEM NAME"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); @@ -82,9 +76,9 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); - + assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals(("SYSTEM NAME"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); @@ -104,7 +98,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); - + assertEquals("name", respParam.getParameter().get(0).getName()); assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); @@ -112,7 +106,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst assertEquals("abstract", respParam.getParameter().get(2).getName()); assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue()); } - + @Test public void testLookupOperationByCodeAndSystemBuiltInNonexistantCode() { //@formatter:off @@ -145,7 +139,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); - + assertEquals("name", respParam.getParameter().get(0).getName()); assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); @@ -185,7 +179,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); - + assertEquals("name", respParam.getParameter().get(0).getName()); assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); @@ -247,7 +241,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst } //@formatter:on } - + @Test // @Ignore public void testLookupOperationForBuiltInCode() { @@ -263,7 +257,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); - + assertEquals("name", respParam.getParameter().get(0).getName()); assertEquals("Unknown", ((StringType)respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); @@ -271,6 +265,11 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst assertEquals("abstract", respParam.getParameter().get(2).getName()); assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).booleanValue()); } + + @AfterClass + public static void afterClassClearContext() { + TestUtil.clearAllStaticFieldsForUnitTest(); + } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3Test.java index ba63454dc78..abd83f128cf 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/TerminologyUploaderProviderDstu3Test.java @@ -1,5 +1,6 @@ package ca.uhn.fhir.jpa.provider.dstu3; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -14,6 +15,7 @@ import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import org.apache.commons.io.IOUtils; import org.hl7.fhir.dstu3.model.Attachment; import org.hl7.fhir.dstu3.model.IntegerType; @@ -31,65 +33,81 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderDstu3Test.class); - @AfterClass - public static void afterClassClearContext() { - TestUtil.clearAllStaticFieldsForUnitTest(); + private byte[] createLoincZip() throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(bos); + + zos.putNextEntry(new ZipEntry("loinc.csv")); + zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv"))); + zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")); + zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"))); + zos.close(); + + byte[] packageBytes = bos.toByteArray(); + return packageBytes; } + private byte[] createSctZip() throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(bos); + List inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt"); + for (String nextName : inputNames) { + zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName)); + byte[] b = IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName)); + zos.write(b); + } + zos.close(); + byte[] packageBytes = bos.toByteArray(); + return packageBytes; + } @Test - public void testUploadSct() throws Exception { + public void testUploadInvalidUrl() throws Exception { byte[] packageBytes = createSctZip(); - - //@formatter:off - Parameters respParam = ourClient - .operation() - .onServer() - .named("upload-external-code-system") - .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) - .andParameter("package", new Attachment().setData(packageBytes)) - .execute(); - //@formatter:on - String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); - ourLog.info(resp); - - assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); + try { + ourClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO")) + .andParameter("package", new Attachment().setUrl("foo").setData(packageBytes)) + .execute(); + fail(); + } catch (InvalidRequestException e) { + assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage()); + } } @Test public void testUploadLoinc() throws Exception { byte[] packageBytes = createLoincZip(); - - //@formatter:off + Parameters respParam = ourClient .operation() .onServer() .named("upload-external-code-system") .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI)) - .andParameter("package", new Attachment().setData(packageBytes)) + .andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes)) .execute(); - //@formatter:on String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); - + assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); - + /* * Try uploading a second time */ - - //@formatter:off + respParam = ourClient .operation() .onServer() .named("upload-external-code-system") .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI)) - .andParameter("package", new Attachment().setData(packageBytes)) + .andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes)) .execute(); - //@formatter:on resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); @@ -97,73 +115,42 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs } @Test - public void testUploadSctLocalFile() throws Exception { - byte[] packageBytes = createSctZip(); - File tempFile = File.createTempFile("tmp", ".zip"); - tempFile.deleteOnExit(); - - FileOutputStream fos = new FileOutputStream(tempFile); - fos.write(packageBytes); - fos.close(); - - //@formatter:off - Parameters respParam = ourClient - .operation() - .onServer() - .named("upload-external-code-system") - .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) - .andParameter("localfile", new StringType(tempFile.getAbsolutePath())) - .execute(); - //@formatter:on - - String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); - ourLog.info(resp); - - assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); - } - - @Test - public void testUploadInvalidUrl() throws Exception { - byte[] packageBytes = createSctZip(); - - //@formatter:off + public void testUploadMissingPackage() throws Exception { + byte[] packageBytes = createLoincZip(); try { ourClient .operation() .onServer() .named("upload-external-code-system") - .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO")) + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) .andParameter("package", new Attachment().setData(packageBytes)) .execute(); fail(); - } catch (InvalidRequestException e) { - assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage()); + } catch (UnprocessableEntityException e) { + assertThat(e.getMessage(), containsString("Package is missing mandatory url element")); } - //@formatter:on } @Test public void testUploadMissingUrl() throws Exception { byte[] packageBytes = createSctZip(); - //@formatter:off try { ourClient .operation() .onServer() .named("upload-external-code-system") - .withParameter(Parameters.class, "package", new Attachment().setData(packageBytes)) + .withParameter(Parameters.class, "package", new Attachment().setUrl("foo").setData(packageBytes)) .execute(); fail(); } catch (InvalidRequestException e) { assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage()); } - //@formatter:on + } @Test - public void testUploadMissingPackage() throws Exception { - //@formatter:off + public void testUploadPackageMissingUrl() throws Exception { try { ourClient .operation() @@ -175,35 +162,55 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs } catch (InvalidRequestException e) { assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage()); } - //@formatter:on } - private byte[] createSctZip() throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(bos); - - List inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt"); - for (String nextName : inputNames) { - zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName)); - zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName))); - } - zos.close(); - byte[] packageBytes = bos.toByteArray(); - return packageBytes; + @Test + public void testUploadSct() throws Exception { + byte[] packageBytes = createSctZip(); + + Parameters respParam = ourClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) + .andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes)) + .execute(); + + String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); + ourLog.info(resp); + + assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); + } + + @Test + public void testUploadSctLocalFile() throws Exception { + byte[] packageBytes = createSctZip(); + File tempFile = File.createTempFile("tmp", ".zip"); + tempFile.deleteOnExit(); + + FileOutputStream fos = new FileOutputStream(tempFile); + fos.write(packageBytes); + fos.close(); + + ourLog.info("File is: {}", tempFile.getAbsolutePath()); + + Parameters respParam = ourClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) + .andParameter("localfile", new StringType(tempFile.getAbsolutePath())) + .execute(); + + String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); + ourLog.info(resp); + + assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); } - private byte[] createLoincZip() throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(bos); - - zos.putNextEntry(new ZipEntry("loinc.csv")); - zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv"))); - zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")); - zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"))); - zos.close(); - - byte[] packageBytes = bos.toByteArray(); - return packageBytes; + @AfterClass + public static void afterClassClearContext() { + TestUtil.clearAllStaticFieldsForUnitTest(); } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java index 28f3fd52b29..12e8f7f0967 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig; import ca.uhn.fhir.jpa.dao.data.ISearchDao; import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test; import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4; -import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc; import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor; @@ -59,7 +58,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test { protected static ISearchCoordinatorSvc mySearchCoordinatorSvc; private static Server ourServer; protected static GenericWebApplicationContext ourWebApplicationContext; - private TerminologyUploaderProvider myTerminologyUploaderProvider; + private TerminologyUploaderProviderR4 myTerminologyUploaderProvider; private Object ourGraphQLProvider; private boolean ourRestHookSubscriptionInterceptorRequested; @@ -90,7 +89,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test { ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); - myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class); + myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderR4.class); ourGraphQLProvider = myAppCtx.getBean("myGraphQLProvider"); ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider, ourGraphQLProvider); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4Test.java index 62aeba4f74d..8b9ffbe4eb1 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/TerminologyUploaderProviderR4Test.java @@ -1,9 +1,12 @@ package ca.uhn.fhir.jpa.provider.r4; -import static org.hamcrest.Matchers.greaterThan; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.util.TestUtil; +import org.apache.commons.io.IOUtils; +import org.hl7.fhir.r4.model.*; +import org.junit.AfterClass; +import org.junit.Test; import java.io.ByteArrayOutputStream; import java.io.File; @@ -14,118 +17,45 @@ import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.apache.commons.io.IOUtils; -import org.hl7.fhir.r4.model.Attachment; -import org.hl7.fhir.r4.model.IntegerType; -import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.r4.model.StringType; -import org.hl7.fhir.r4.model.UriType; -import org.junit.AfterClass; -import org.junit.Test; - -import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc; -import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -import ca.uhn.fhir.util.TestUtil; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.*; public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderR4Test.class); - @AfterClass - public static void afterClassClearContext() { - TestUtil.clearAllStaticFieldsForUnitTest(); + private byte[] createLoincZip() throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(bos); + + zos.putNextEntry(new ZipEntry("loinc.csv")); + zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv"))); + zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")); + zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"))); + zos.close(); + + byte[] packageBytes = bos.toByteArray(); + return packageBytes; } + private byte[] createSctZip() throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(bos); - - @Test - public void testUploadSct() throws Exception { - byte[] packageBytes = createSctZip(); - - //@formatter:off - Parameters respParam = myClient - .operation() - .onServer() - .named("upload-external-code-system") - .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) - .andParameter("package", new Attachment().setData(packageBytes)) - .execute(); - //@formatter:on - - String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); - ourLog.info(resp); - - assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); - } - - @Test - public void testUploadLoinc() throws Exception { - byte[] packageBytes = createLoincZip(); - - //@formatter:off - Parameters respParam = myClient - .operation() - .onServer() - .named("upload-external-code-system") - .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI)) - .andParameter("package", new Attachment().setData(packageBytes)) - .execute(); - //@formatter:on - - String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); - ourLog.info(resp); - - assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); - - /* - * Try uploading a second time - */ - - //@formatter:off - respParam = myClient - .operation() - .onServer() - .named("upload-external-code-system") - .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI)) - .andParameter("package", new Attachment().setData(packageBytes)) - .execute(); - //@formatter:on - - resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); - ourLog.info(resp); - - } - - @Test - public void testUploadSctLocalFile() throws Exception { - byte[] packageBytes = createSctZip(); - File tempFile = File.createTempFile("tmp", ".zip"); - tempFile.deleteOnExit(); - - FileOutputStream fos = new FileOutputStream(tempFile); - fos.write(packageBytes); - fos.close(); - - //@formatter:off - Parameters respParam = myClient - .operation() - .onServer() - .named("upload-external-code-system") - .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) - .andParameter("localfile", new StringType(tempFile.getAbsolutePath())) - .execute(); - //@formatter:on - - String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); - ourLog.info(resp); - - assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); + List inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt", "sct2_Concept_Full-en_INT_20160131.txt", "sct2_Description_Full-en_INT_20160131.txt", "sct2_Identifier_Full_INT_20160131.txt", "sct2_Relationship_Full_INT_20160131.txt", "sct2_StatedRelationship_Full_INT_20160131.txt", "sct2_TextDefinition_Full-en_INT_20160131.txt"); + for (String nextName : inputNames) { + zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName)); + zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName))); + } + zos.close(); + byte[] packageBytes = bos.toByteArray(); + return packageBytes; } @Test public void testUploadInvalidUrl() throws Exception { byte[] packageBytes = createSctZip(); - + //@formatter:off try { myClient @@ -133,7 +63,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes .onServer() .named("upload-external-code-system") .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO")) - .andParameter("package", new Attachment().setData(packageBytes)) + .andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes)) .execute(); fail(); } catch (InvalidRequestException e) { @@ -143,22 +73,41 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes } @Test - public void testUploadMissingUrl() throws Exception { - byte[] packageBytes = createSctZip(); - + public void testUploadLoinc() throws Exception { + byte[] packageBytes = createLoincZip(); + //@formatter:off - try { - myClient - .operation() - .onServer() - .named("upload-external-code-system") - .withParameter(Parameters.class, "package", new Attachment().setData(packageBytes)) - .execute(); - fail(); - } catch (InvalidRequestException e) { - assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage()); - } + Parameters respParam = myClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI)) + .andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes)) + .execute(); //@formatter:on + + String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); + ourLog.info(resp); + + assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); + + /* + * Try uploading a second time + */ + + //@formatter:off + respParam = myClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI)) + .andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes)) + .execute(); + //@formatter:on + + resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); + ourLog.info(resp); + } @Test @@ -178,32 +127,74 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes //@formatter:on } - private byte[] createSctZip() throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(bos); - - List inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt"); - for (String nextName : inputNames) { - zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName)); - zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName))); + @Test + public void testUploadMissingUrl() throws Exception { + byte[] packageBytes = createSctZip(); + + //@formatter:off + try { + myClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "package", new Attachment().setUrl("file.zip").setData(packageBytes)) + .execute(); + fail(); + } catch (InvalidRequestException e) { + assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage()); } - zos.close(); - byte[] packageBytes = bos.toByteArray(); - return packageBytes; + //@formatter:on } - - private byte[] createLoincZip() throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(bos); - - zos.putNextEntry(new ZipEntry("loinc.csv")); - zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv"))); - zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")); - zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"))); - zos.close(); - - byte[] packageBytes = bos.toByteArray(); - return packageBytes; + + @Test + public void testUploadSct() throws Exception { + byte[] packageBytes = createSctZip(); + + //@formatter:off + Parameters respParam = myClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) + .andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes)) + .execute(); + //@formatter:on + + String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); + ourLog.info(resp); + + assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); + } + + @Test + public void testUploadSctLocalFile() throws Exception { + byte[] packageBytes = createSctZip(); + File tempFile = File.createTempFile("tmp", ".zip"); + tempFile.deleteOnExit(); + + FileOutputStream fos = new FileOutputStream(tempFile); + fos.write(packageBytes); + fos.close(); + + //@formatter:off + Parameters respParam = myClient + .operation() + .onServer() + .named("upload-external-code-system") + .withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI)) + .andParameter("localfile", new StringType(tempFile.getAbsolutePath())) + .execute(); + //@formatter:on + + String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); + ourLog.info(resp); + + assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1)); + } + + @AfterClass + public static void afterClassClearContext() { + TestUtil.clearAllStaticFieldsForUnitTest(); } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcIntegrationDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcIntegrationDstu3Test.java index 15bcb11848b..710a59ce74f 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcIntegrationDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcIntegrationDstu3Test.java @@ -75,7 +75,7 @@ public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test { ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parameters)); assertEquals("SYSTEM", this.getPropertyPart(parameters, "property", "code").get().getValueAsString()); - assertEquals("Heart", this.getPropertyPart(parameters, "property", "value").get().getValueAsString()); + assertEquals("Heart", this.getPropertyPart(parameters, "property", "value").get().getValueAsString()); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcSnomedCtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcSnomedCtTest.java index 61c9db478f4..4fb9950230e 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcSnomedCtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcSnomedCtTest.java @@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.util.TestUtil; import org.apache.commons.io.IOUtils; import org.hl7.fhir.r4.model.CodeSystem; @@ -126,8 +127,8 @@ public class TerminologyLoaderSvcSnomedCtTest { try { mySvc.loadSnomedCt(list(bos.toByteArray()), details); fail(); - } catch (InvalidRequestException e) { - assertEquals("Invalid input zip file, expected zip to contain the following name fragments: [Terminology/sct2_Description_Full-en, Terminology/sct2_Relationship_Full, Terminology/sct2_Concept_Full_] but found: []", e.getMessage()); + } catch (UnprocessableEntityException e) { + assertThat(e.getMessage(), containsString("Could not find the following mandatory files in input: ")); } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java index ca5dc8639b0..9e795d95be6 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java @@ -11,8 +11,8 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.util.TestUtil; import org.hl7.fhir.dstu3.model.CodeSystem; import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode; -import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.ValueSet; import org.junit.AfterClass; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -28,136 +28,6 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { private static final String CS_URL = "http://example.com/my_code_system"; private static final String CS_URL_2 = "http://example.com/my_code_system2"; - - - @AfterClass - public static void afterClassClearContext() { - TestUtil.clearAllStaticFieldsForUnitTest(); - } - - - @Test - public void testStoreCodeSystemInvalidCyclicLoop() { - CodeSystem codeSystem = new CodeSystem(); - codeSystem.setUrl(CS_URL); - codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); - IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified(); - - ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong()); - - TermCodeSystemVersion cs = new TermCodeSystemVersion(); - cs.setResource(table); - - TermConcept parent = new TermConcept(); - parent.setCodeSystemVersion(cs); - parent.setCode("parent"); - cs.getConcepts().add(parent); - - TermConcept child = new TermConcept(); - child.setCodeSystemVersion(cs); - child.setCode("child"); - parent.addChild(child, RelationshipTypeEnum.ISA); - - child.addChild(parent, RelationshipTypeEnum.ISA); - - try { -// myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", , cs); - fail(); - } catch (InvalidRequestException e) { - assertEquals("CodeSystem contains circular reference around code parent", e.getMessage()); - } - } - - @Test - public void testFindCodesAboveAndBelowUnknown() { - createCodeSystem(); - - assertThat(myTermSvc.findCodesBelow("http://foo", "code"), empty()); - assertThat(myTermSvc.findCodesBelow(CS_URL, "code"), empty()); - assertThat(myTermSvc.findCodesAbove("http://foo", "code"), empty()); - assertThat(myTermSvc.findCodesAbove(CS_URL, "code"), empty()); - } - - @Test - public void testFindCodesBelowA() { - IIdType id = createCodeSystem(); - - Set concepts; - Set codes; - - concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "ParentA"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA", "childAAB", "childAB")); - - concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB")); - - // Try an unknown code - concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE"); - codes = toCodes(concepts); - assertThat(codes, empty()); - - } - - @Test - public void testFindCodesBelowBuiltInCodeSystem() { - List concepts; - Set codes; - - concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "inactive"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("inactive", "resolved")); - - concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "resolved"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("resolved")); - - // Unknown code - concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "FOO"); - codes = toCodes(concepts); - assertThat(codes, empty()); - - // Unknown system - concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status2222", "active"); - codes = toCodes(concepts); - assertThat(codes, empty()); - } - - @Test - public void testFindCodesAboveBuiltInCodeSystem() { - List concepts; - Set codes; - - concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "active"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("active")); - - concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "resolved"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("inactive", "resolved")); - - // Unknown code - concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "FOO"); - codes = toCodes(concepts); - assertThat(codes, empty()); - - // Unknown system - concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status2222", "active"); - codes = toCodes(concepts); - assertThat(codes, empty()); - } - - @Test - public void testReindexTerminology() { - IIdType id = createCodeSystem(); - - assertThat(mySystemDao.markAllResourcesForReindexing(), greaterThan(0)); - - assertThat(mySystemDao.performReindexingPass(100), greaterThan(0)); - } - - @Autowired private ITermCodeSystemDao myTermCodeSystemDao; @@ -194,7 +64,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { TermConcept parentB = new TermConcept(cs, "ParentB"); cs.getConcepts().add(parentB); - myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs); + myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs); return id; } @@ -213,30 +83,48 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { TermConcept parentA = new TermConcept(cs, "CS2"); cs.getConcepts().add(parentA); - myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL_2,"SYSTEM NAME" , cs); + myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL_2, "SYSTEM NAME", cs); return id; } @Test - public void testFindCodesAbove() { - IIdType id = createCodeSystem(); + public void testCreateDuplicateCodeSystemUri() { + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setUrl(CS_URL); + codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); + IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified(); - Set concepts; - Set codes; + ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong()); - concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("ParentA", "childAA")); + TermCodeSystemVersion cs = new TermCodeSystemVersion(); + cs.setResource(table); + + myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs); + + // Update + cs = new TermCodeSystemVersion(); + TermConcept parentA = new TermConcept(cs, "ParentA"); + cs.getConcepts().add(parentA); + id = myCodeSystemDao.update(codeSystem, null, true, true, mySrd).getId().toUnqualified(); + table = myResourceTableDao.findOne(id.getIdPartAsLong()); + cs.setResource(table); + myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs); + + // Try to update to a different resource + codeSystem = new CodeSystem(); + codeSystem.setUrl(CS_URL); + codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); + id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified(); + table = myResourceTableDao.findOne(id.getIdPartAsLong()); + cs.setResource(table); + try { + myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs); + fail(); + } catch (UnprocessableEntityException e) { + assertThat(e.getMessage(), containsString("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/")); + } - concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAAB"); - codes = toCodes(concepts); - assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAB")); - - // Try an unknown code - concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE"); - codes = toCodes(concepts); - assertThat(codes, empty()); } @Test @@ -305,18 +193,118 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { assertThat(codes, containsInAnyOrder("ParentA", "childAAA", "childAAB", "childAA", "childAB", "ParentB")); } - private List toCodesContains(List theContains) { - List retVal = new ArrayList<>(); + @Test + public void testFindCodesAbove() { + IIdType id = createCodeSystem(); - for (ValueSet.ValueSetExpansionContainsComponent next : theContains) { - retVal.add(next.getCode()); - } + Set concepts; + Set codes; - return retVal; + concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("ParentA", "childAA")); + + concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAAB"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAB")); + + // Try an unknown code + concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE"); + codes = toCodes(concepts); + assertThat(codes, empty()); } @Test - public void testCreateDuplicateCodeSystemUri() { + public void testFindCodesAboveAndBelowUnknown() { + createCodeSystem(); + + assertThat(myTermSvc.findCodesBelow("http://foo", "code"), empty()); + assertThat(myTermSvc.findCodesBelow(CS_URL, "code"), empty()); + assertThat(myTermSvc.findCodesAbove("http://foo", "code"), empty()); + assertThat(myTermSvc.findCodesAbove(CS_URL, "code"), empty()); + } + + @Test + public void testFindCodesAboveBuiltInCodeSystem() { + List concepts; + Set codes; + + concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "active"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("active")); + + concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "resolved"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("inactive", "resolved")); + + // Unknown code + concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "FOO"); + codes = toCodes(concepts); + assertThat(codes, empty()); + + // Unknown system + concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status2222", "active"); + codes = toCodes(concepts); + assertThat(codes, empty()); + } + + @Test + public void testFindCodesBelowA() { + IIdType id = createCodeSystem(); + + Set concepts; + Set codes; + + concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "ParentA"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA", "childAAB", "childAB")); + + concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB")); + + // Try an unknown code + concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE"); + codes = toCodes(concepts); + assertThat(codes, empty()); + + } + + @Test + public void testFindCodesBelowBuiltInCodeSystem() { + List concepts; + Set codes; + + concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "inactive"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("inactive", "resolved")); + + concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "resolved"); + codes = toCodes(concepts); + assertThat(codes, containsInAnyOrder("resolved")); + + // Unknown code + concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "FOO"); + codes = toCodes(concepts); + assertThat(codes, empty()); + + // Unknown system + concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status2222", "active"); + codes = toCodes(concepts); + assertThat(codes, empty()); + } + + @Test + public void testReindexTerminology() { + IIdType id = createCodeSystem(); + + assertThat(mySystemDao.markAllResourcesForReindexing(), greaterThan(0)); + + assertThat(mySystemDao.performReindexingPass(100), greaterThan(0)); + } + + @Test + public void testStoreCodeSystemInvalidCyclicLoop() { CodeSystem codeSystem = new CodeSystem(); codeSystem.setUrl(CS_URL); codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); @@ -327,31 +315,39 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { TermCodeSystemVersion cs = new TermCodeSystemVersion(); cs.setResource(table); - myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs); + TermConcept parent = new TermConcept(); + parent.setCodeSystemVersion(cs); + parent.setCode("parent"); + cs.getConcepts().add(parent); - // Update - cs = new TermCodeSystemVersion(); - TermConcept parentA = new TermConcept(cs, "ParentA"); - cs.getConcepts().add(parentA); - id = myCodeSystemDao.update(codeSystem, null, true, true, mySrd).getId().toUnqualified(); - table = myResourceTableDao.findOne(id.getIdPartAsLong()); - cs.setResource(table); - myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs); + TermConcept child = new TermConcept(); + child.setCodeSystemVersion(cs); + child.setCode("child"); + parent.addChild(child, RelationshipTypeEnum.ISA); + + child.addChild(parent, RelationshipTypeEnum.ISA); - // Try to update to a different resource - codeSystem = new CodeSystem(); - codeSystem.setUrl(CS_URL); - codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); - id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified(); - table = myResourceTableDao.findOne(id.getIdPartAsLong()); - cs.setResource(table); try { - myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs); + myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", "SYSTEM NAME", cs); fail(); - } catch (UnprocessableEntityException e) { - assertThat(e.getMessage(), containsString("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/")); + } catch (InvalidRequestException e) { + assertEquals("CodeSystem contains circular reference around code parent", e.getMessage()); + } + } + + private List toCodesContains(List theContains) { + List retVal = new ArrayList<>(); + + for (ValueSet.ValueSetExpansionContainsComponent next : theContains) { + retVal.add(next.getCode()); } + return retVal; + } + + @AfterClass + public static void afterClassClearContext() { + TestUtil.clearAllStaticFieldsForUnitTest(); } } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java index 52d998878dd..ee4b0af5013 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java @@ -279,8 +279,11 @@ public class RestfulServer extends HttpServlet implements IRestfulServer myStructureDefinitions; private Map myValueSets; + private void addConcepts(ConceptSetComponent theInclude, ValueSetExpansionComponent theRetVal, Set theWantCodes, List theConcepts) { + for (ConceptDefinitionComponent next : theConcepts) { + if (theWantCodes.isEmpty() || theWantCodes.contains(next.getCode())) { + theRetVal + .addContains() + .setSystem(theInclude.getSystem()) + .setCode(next.getCode()) + .setDisplay(next.getDisplay()); + } + addConcepts(theInclude, theRetVal, theWantCodes, next.getConcept()); + } + } + @Override public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) { ValueSetExpansionComponent retVal = new ValueSetExpansionComponent(); - Set wantCodes = new HashSet(); + Set wantCodes = new HashSet<>(); for (ConceptReferenceComponent next : theInclude.getConcept()) { wantCodes.add(next.getCode()); } CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem()); - for (ConceptDefinitionComponent next : system.getConcept()) { - if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) { - retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); + if (system != null) { + List concepts = system.getConcept(); + addConcepts(theInclude, retVal, wantCodes, concepts); + } + + for (UriType next : theInclude.getValueSet()) { + ValueSet vs = myValueSets.get(defaultString(next.getValueAsString())); + if (vs != null) { + for (ConceptSetComponent nextInclude : vs.getCompose().getInclude()) { + ValueSetExpansionComponent contents = expandValueSet(theContext, nextInclude); + retVal.getContains().addAll(contents.getContains()); + } } } diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java index 8bcc81dde0e..332e2dab9e1 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java @@ -20,6 +20,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.*; +import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.isNotBlank; public class DefaultProfileValidationSupport implements IValidationSupport { @@ -44,15 +45,37 @@ public class DefaultProfileValidationSupport implements IValidationSupport { } CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem()); - for (ConceptDefinitionComponent next : system.getConcept()) { - if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) { - retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); + if (system != null) { + List concepts = system.getConcept(); + addConcepts(theInclude, retVal, wantCodes, concepts); + } + + for (UriType next: theInclude.getValueSet()) { + ValueSet vs = myValueSets.get(defaultString(next.getValueAsString())); + if (vs != null) { + for (ConceptSetComponent nextInclude : vs.getCompose().getInclude()) { + ValueSetExpansionComponent contents = expandValueSet(theContext, nextInclude); + retVal.getContains().addAll(contents.getContains()); + } } } return retVal; } + private void addConcepts(ConceptSetComponent theInclude, ValueSetExpansionComponent theRetVal, Set theWantCodes, List theConcepts) { + for (ConceptDefinitionComponent next : theConcepts) { + if (theWantCodes.isEmpty() || theWantCodes.contains(next.getCode())) { + theRetVal + .addContains() + .setSystem(theInclude.getSystem()) + .setCode(next.getCode()) + .setDisplay(next.getDisplay()); + } + addConcepts(theInclude, theRetVal, theWantCodes, next.getConcept()); + } + } + @Override public List fetchAllConformanceResources(FhirContext theContext) { ArrayList retVal = new ArrayList<>(); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/ValidationSupportChain.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/ValidationSupportChain.java index e30d2267e74..c4a87b4f8d5 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/ValidationSupportChain.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/ValidationSupportChain.java @@ -4,6 +4,7 @@ import ca.uhn.fhir.context.FhirContext; import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport; import org.hl7.fhir.dstu3.model.CodeSystem; import org.hl7.fhir.dstu3.model.StructureDefinition; +import org.hl7.fhir.dstu3.model.UriType; import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -14,131 +15,140 @@ import java.util.List; import java.util.Set; import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; public class ValidationSupportChain implements IValidationSupport { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationSupportChain.class); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationSupportChain.class); - private List myChain; + private List myChain; - /** - * Constructor - */ - public ValidationSupportChain() { - myChain = new ArrayList<>(); - } + /** + * Constructor + */ + public ValidationSupportChain() { + myChain = new ArrayList<>(); + } - /** - * Constructor - */ - public ValidationSupportChain(IValidationSupport... theValidationSupportModules) { - this(); - for (IValidationSupport next : theValidationSupportModules) { - if (next != null) { - myChain.add(next); - } - } - } + /** + * Constructor + */ + public ValidationSupportChain(IValidationSupport... theValidationSupportModules) { + this(); + for (IValidationSupport next : theValidationSupportModules) { + if (next != null) { + myChain.add(next); + } + } + } - public void addValidationSupport(IValidationSupport theValidationSupport) { - myChain.add(theValidationSupport); - } + public void addValidationSupport(IValidationSupport theValidationSupport) { + myChain.add(theValidationSupport); + } - @Override - public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) { - for (IValidationSupport next : myChain) { - if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) { - return next.expandValueSet(theCtx, theInclude); - } - } - return myChain.get(0).expandValueSet(theCtx, theInclude); - } + @Override + public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) { + for (IValidationSupport next : myChain) { + if (isNotBlank(theInclude.getSystem())) { + if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) { + return next.expandValueSet(theCtx, theInclude); + } + } + for (UriType nextValueSet : theInclude.getValueSet()) { + ValueSetExpansionComponent retVal = next.expandValueSet(theCtx, theInclude); + if (retVal != null && retVal.getContains().size() > 0) { + return retVal; + } + } + } + return myChain.get(0).expandValueSet(theCtx, theInclude); + } - @Override - public List fetchAllConformanceResources(FhirContext theContext) { - List retVal = new ArrayList<>(); - for (IValidationSupport next : myChain) { - List candidates = next.fetchAllConformanceResources(theContext); - if (candidates != null) { - retVal.addAll(candidates); - } - } - return retVal; - } + @Override + public List fetchAllConformanceResources(FhirContext theContext) { + List retVal = new ArrayList<>(); + for (IValidationSupport next : myChain) { + List candidates = next.fetchAllConformanceResources(theContext); + if (candidates != null) { + retVal.addAll(candidates); + } + } + return retVal; + } - @Override - public List fetchAllStructureDefinitions(FhirContext theContext) { - ArrayList retVal = new ArrayList(); - Set urls = new HashSet(); - for (IValidationSupport nextSupport : myChain) { - for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) { - if (isBlank(next.getUrl()) || urls.add(next.getUrl())) { - retVal.add(next); - } - } - } - return retVal; - } + @Override + public List fetchAllStructureDefinitions(FhirContext theContext) { + ArrayList retVal = new ArrayList(); + Set urls = new HashSet(); + for (IValidationSupport nextSupport : myChain) { + for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) { + if (isBlank(next.getUrl()) || urls.add(next.getUrl())) { + retVal.add(next); + } + } + } + return retVal; + } - @Override - public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) { - for (IValidationSupport next : myChain) { - CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem); - if (retVal != null) { - return retVal; - } - } - return null; - } + @Override + public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) { + for (IValidationSupport next : myChain) { + CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem); + if (retVal != null) { + return retVal; + } + } + return null; + } - @Override - public T fetchResource(FhirContext theContext, Class theClass, String theUri) { - for (IValidationSupport next : myChain) { - T retVal = next.fetchResource(theContext, theClass, theUri); - if (retVal != null) { - return retVal; - } - } - return null; - } + @Override + public T fetchResource(FhirContext theContext, Class theClass, String theUri) { + for (IValidationSupport next : myChain) { + T retVal = next.fetchResource(theContext, theClass, theUri); + if (retVal != null) { + return retVal; + } + } + return null; + } - @Override - public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) { - for (IValidationSupport next : myChain) { - StructureDefinition retVal = next.fetchStructureDefinition(theCtx, theUrl); - if (retVal != null) { - return retVal; - } - } - return null; - } + @Override + public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) { + for (IValidationSupport next : myChain) { + StructureDefinition retVal = next.fetchStructureDefinition(theCtx, theUrl); + if (retVal != null) { + return retVal; + } + } + return null; + } - @Override - public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) { - for (IValidationSupport next : myChain) { - if (next.isCodeSystemSupported(theCtx, theSystem)) { - return true; - } - } - return false; - } + @Override + public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) { + for (IValidationSupport next : myChain) { + if (next.isCodeSystemSupported(theCtx, theSystem)) { + return true; + } + } + return false; + } - @Override - public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) { + @Override + public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) { - ourLog.debug("Validating code {} in chain with {} items", theCode, myChain.size()); + ourLog.debug("Validating code {} in chain with {} items", theCode, myChain.size()); - for (IValidationSupport next : myChain) { - if (next.isCodeSystemSupported(theCtx, theCodeSystem)) { - CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay); - ourLog.debug("Chain item {} returned outcome {}", next, result.isOk()); - return result; - } else { - ourLog.debug("Chain item {} does not support code system {}", next, theCodeSystem); - } - } - return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay); - } + for (IValidationSupport next : myChain) { + if (next.isCodeSystemSupported(theCtx, theCodeSystem)) { + CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay); + ourLog.debug("Chain item {} returned outcome {}", next, result.isOk()); + return result; + } else { + ourLog.debug("Chain item {} does not support code system {}", next, theCodeSystem); + } + } + return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay); + } } From 33ea06b98302f9e73437c009910d3d23ac1f88b8 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Tue, 3 Apr 2018 06:29:14 -0400 Subject: [PATCH 2/5] Fix compile issues --- .../jpa/term/BaseHapiTerminologySvcImpl.java | 12 --- .../ResourceProviderDstu3CodeSystemTest.java | 89 ++++++++----------- 2 files changed, 36 insertions(+), 65 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index 79e90e4ba36..1e9b3eaa10c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java @@ -130,18 +130,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc } } - private void addConceptsToList(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set theAddedCodes, String theSystem, List theConcept) { - for (CodeSystem.ConceptDefinitionComponent next : theConcept) { - if (!theAddedCodes.contains(next.getCode())) { - theAddedCodes.add(next.getCode()); - ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains(); - contains.setCode(next.getCode()); - contains.setSystem(theSystem); - contains.setDisplay(next.getDisplay()); - } - addConceptsToList(theExpansionComponent, theAddedCodes, theSystem, next.getConcept()); - } - } private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction bool, ValueSet.ConceptSetFilterComponent nextFilter) { bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery()); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java index ded3314ee5a..c535f1fdfb4 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemTest.java @@ -1,31 +1,19 @@ package ca.uhn.fhir.jpa.provider.dstu3; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.stringContainsInOrder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.io.IOException; - -import org.hl7.fhir.dstu3.model.BooleanType; -import org.hl7.fhir.dstu3.model.CodeSystem; -import org.hl7.fhir.dstu3.model.CodeType; -import org.hl7.fhir.dstu3.model.Coding; -import org.hl7.fhir.dstu3.model.Parameters; -import org.hl7.fhir.dstu3.model.StringType; -import org.hl7.fhir.dstu3.model.UriType; -import org.hl7.fhir.dstu3.model.ValueSet; +import ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.util.TestUtil; +import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.instance.model.api.IIdType; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; import org.springframework.transaction.annotation.Transactional; -import ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest; -import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; -import ca.uhn.fhir.util.TestUtil; +import java.io.IOException; + +import static org.junit.Assert.*; public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDstu3Test { @@ -58,34 +46,34 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst ourLog.info(resp); assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals(("SYSTEM NAME"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals(("SYSTEM NAME"), ((StringType) respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); - assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue()); + assertEquals("Parent A", ((StringType) respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); - assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue()); + assertEquals(false, ((BooleanType) respParam.getParameter().get(2).getValue()).getValue().booleanValue()); // With HTTP GET respParam = ourClient - .operation() - .onType(CodeSystem.class) - .named("lookup") - .withParameter(Parameters.class, "code", new CodeType("ParentA")) - .andParameter("system", new UriType(FhirResourceDaoDstu3TerminologyTest.URL_MY_CODE_SYSTEM)) - .useHttpGet() - .execute(); + .operation() + .onType(CodeSystem.class) + .named("lookup") + .withParameter(Parameters.class, "code", new CodeType("ParentA")) + .andParameter("system", new UriType(FhirResourceDaoDstu3TerminologyTest.URL_MY_CODE_SYSTEM)) + .useHttpGet() + .execute(); resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); ourLog.info(resp); assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals(("SYSTEM NAME"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals(("SYSTEM NAME"), ((StringType) respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); - assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue()); + assertEquals("Parent A", ((StringType) respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); - assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue()); + assertEquals(false, ((BooleanType) respParam.getParameter().get(2).getValue()).getValue().booleanValue()); } - + @Test public void testLookupOperationByCodeAndSystemBuiltInCode() { Parameters respParam = ourClient @@ -100,13 +88,13 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst ourLog.info(resp); assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals(("Unknown"), ((StringType) respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); - assertEquals("Accession ID", ((StringType)respParam.getParameter().get(1).getValue()).getValue()); + assertEquals("Accession ID", ((StringType) respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); - assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue()); + assertEquals(false, ((BooleanType) respParam.getParameter().get(2).getValue()).getValue().booleanValue()); } - + @Test public void testLookupOperationByCodeAndSystemBuiltInNonexistantCode() { //@formatter:off @@ -141,11 +129,11 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst ourLog.info(resp); assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals(("Unknown"), ((StringType) respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); - assertEquals(("Systolic blood pressure--expiration"), ((StringType)respParam.getParameter().get(1).getValue()).getValue()); + assertEquals(("Systolic blood pressure--expiration"), ((StringType) respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); - assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue()); + assertEquals(false, ((BooleanType) respParam.getParameter().get(2).getValue()).getValue().booleanValue()); } @Test @@ -181,11 +169,11 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst ourLog.info(resp); assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals(("Unknown"), ((StringType) respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); - assertEquals(("Systolic blood pressure--expiration"), ((StringType)respParam.getParameter().get(1).getValue()).getValue()); + assertEquals(("Systolic blood pressure--expiration"), ((StringType) respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); - assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue()); + assertEquals(false, ((BooleanType) respParam.getParameter().get(2).getValue()).getValue().booleanValue()); } @Test @@ -259,16 +247,11 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst ourLog.info(resp); assertEquals("name", respParam.getParameter().get(0).getName()); - assertEquals("Unknown", ((StringType)respParam.getParameter().get(0).getValue()).getValue()); + assertEquals("Unknown", ((StringType) respParam.getParameter().get(0).getValue()).getValue()); assertEquals("display", respParam.getParameter().get(1).getName()); - assertEquals("Married", ((StringType)respParam.getParameter().get(1).getValue()).getValue()); + assertEquals("Married", ((StringType) respParam.getParameter().get(1).getValue()).getValue()); assertEquals("abstract", respParam.getParameter().get(2).getName()); - assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).booleanValue()); - } - - @AfterClass - public static void afterClassClearContext() { - TestUtil.clearAllStaticFieldsForUnitTest(); + assertEquals(false, ((BooleanType) respParam.getParameter().get(2).getValue()).booleanValue()); } @AfterClass @@ -276,5 +259,5 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst TestUtil.clearAllStaticFieldsForUnitTest(); } - + } From b8b3ff8a8f18a6a3e1d77ba179171eb87c953342 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Wed, 4 Apr 2018 09:34:16 -0400 Subject: [PATCH 3/5] Loinc property updates --- .../uhn/fhir/context/support/IContextValidationSupport.java | 4 ++-- .../java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java | 4 ++-- .../java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoCodeSystem.java | 4 ++-- .../ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java | 4 ++-- .../ca/uhn/fhir/jpa/dao/data/ITermConceptDesignationDao.java | 4 ++-- .../ca/uhn/fhir/jpa/dao/data/ITermConceptPropertyDao.java | 4 ++-- .../fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java | 4 ++-- .../java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java | 4 ++-- .../java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java | 4 ++-- .../main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java | 4 ++-- .../uhn/fhir/jpa/entity/TermConceptPropertyFieldBridge.java | 4 ++-- .../ca/uhn/fhir/jpa/entity/TermConceptPropertyTypeEnum.java | 4 ++-- .../fhir/jpa/provider/BaseTerminologyUploaderProvider.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java | 4 ++-- .../main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/IHapiTerminologyLoaderSvc.java | 4 ++-- .../main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java | 4 ++-- .../main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvcR4.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/term/IRecordHandler.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java | 4 ++-- .../src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseHandler.java | 4 ++-- .../jpa/term/loinc/BaseLoincTop2000LabResultsHandler.java | 4 ++-- .../ca/uhn/fhir/jpa/term/loinc/LoincAnswerListHandler.java | 4 ++-- .../uhn/fhir/jpa/term/loinc/LoincAnswerListLinkHandler.java | 4 ++-- .../uhn/fhir/jpa/term/loinc/LoincDocumentOntologyHandler.java | 4 ++-- .../main/java/ca/uhn/fhir/jpa/term/loinc/LoincHandler.java | 4 ++-- .../ca/uhn/fhir/jpa/term/loinc/LoincHierarchyHandler.java | 4 ++-- .../jpa/term/loinc/LoincIeeeMedicalDeviceCodeHandler.java | 4 ++-- .../fhir/jpa/term/loinc/LoincImagingDocumentCodeHandler.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/loinc/LoincPartHandler.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/loinc/LoincPartLinkHandler.java | 4 ++-- .../jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java | 4 ++-- .../ca/uhn/fhir/jpa/term/loinc/LoincRsnaPlaybookHandler.java | 4 ++-- .../fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java | 4 ++-- .../fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java | 4 ++-- .../fhir/jpa/term/loinc/LoincUniversalOrderSetHandler.java | 4 ++-- .../java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerConcept.java | 4 ++-- .../ca/uhn/fhir/jpa/term/snomedct/SctHandlerDescription.java | 4 ++-- .../ca/uhn/fhir/jpa/term/snomedct/SctHandlerRelationship.java | 4 ++-- 47 files changed, 94 insertions(+), 94 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IContextValidationSupport.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IContextValidationSupport.java index bcebc8bbbda..19a79b37b82 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IContextValidationSupport.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IContextValidationSupport.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.context.support; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java index 945e8227379..807512adef5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java @@ -35,9 +35,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java index c9ff4f94920..723fd56e949 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java @@ -38,9 +38,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; * 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. 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 5ae96597123..930329fffb5 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 @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java index a1a06ad597d..e9809f98873 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoMethodOutcome.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java index a037de2706e..b6a5e7e8de9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoCodeSystem.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoCodeSystem.java index 1a2b12b3210..ca5fc4d5231 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoCodeSystem.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoCodeSystem.java @@ -21,9 +21,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java index 9814a199364..05d4e147704 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemVersionDao.java @@ -18,9 +18,9 @@ import java.util.List; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDesignationDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDesignationDao.java index ad7ca7265d4..4be607a9390 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDesignationDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptDesignationDao.java @@ -12,9 +12,9 @@ import org.springframework.data.jpa.repository.JpaRepository; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptPropertyDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptPropertyDao.java index c9f8ed09029..d0906cef88f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptPropertyDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermConceptPropertyDao.java @@ -21,9 +21,9 @@ import java.util.List; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java index 55fc51cec67..8bc6722ee72 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao.dstu3; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java index bba63698fd1..04e42e6d6e4 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao.r4; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java index ea021ed1820..f5d0e9c4b5f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java index ff799c97dc1..96f2efb1109 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java @@ -28,9 +28,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java index 51b64484155..ae6d5d16910 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java index b3a5bbbe2c3..852141838eb 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyFieldBridge.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyFieldBridge.java index d10a1ac9734..917dd88268d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyFieldBridge.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyFieldBridge.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTypeEnum.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTypeEnum.java index 49062476c44..b83a3b158d0 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTypeEnum.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTypeEnum.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseTerminologyUploaderProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseTerminologyUploaderProvider.java index e4318e8ed7e..0667cb44889 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseTerminologyUploaderProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseTerminologyUploaderProvider.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.provider; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index 1e9b3eaa10c..4b48843c246 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java index b26aa5e9a28..ce5a4d4f80b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java index 5087fc312b5..67b8c86dcb1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java @@ -40,9 +40,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java index 41182ebcfa5..5800b10fa76 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java @@ -39,9 +39,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologyLoaderSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologyLoaderSvc.java index 7d025b66755..de2f12d6813 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologyLoaderSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologyLoaderSvc.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java index 26f9e47c6e0..c9ec2679a97 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java @@ -18,9 +18,9 @@ import java.util.Set; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvcR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvcR4.java index 818d758126f..a0c6d5b40de 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvcR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvcR4.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IRecordHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IRecordHandler.java index 35e0b65f34b..c0c811153d8 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IRecordHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IRecordHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java index c0112139d1b..c2d9673ae95 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TerminologyLoaderSvcImpl.java @@ -46,9 +46,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseHandler.java index 9dbc98dc6c7..31af0aeff9b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseLoincTop2000LabResultsHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseLoincTop2000LabResultsHandler.java index 8e431107827..3a937e3deb6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseLoincTop2000LabResultsHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/BaseLoincTop2000LabResultsHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListHandler.java index 29a174827c2..a7772664ba6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListLinkHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListLinkHandler.java index f16ed0cbed8..322976d40c9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListLinkHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincAnswerListLinkHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincDocumentOntologyHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincDocumentOntologyHandler.java index 09ff81684de..fa3d23b1341 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincDocumentOntologyHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincDocumentOntologyHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHandler.java index be3597489f9..62f971d8cb6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHierarchyHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHierarchyHandler.java index 02373716541..dc53a641c2a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHierarchyHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincHierarchyHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincIeeeMedicalDeviceCodeHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincIeeeMedicalDeviceCodeHandler.java index a15bc66332c..db42e7eff6b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincIeeeMedicalDeviceCodeHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincIeeeMedicalDeviceCodeHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincImagingDocumentCodeHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincImagingDocumentCodeHandler.java index ffae5fa14c7..d6fb64d19bc 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincImagingDocumentCodeHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincImagingDocumentCodeHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartHandler.java index bfcd1aea80d..0b1600aa143 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartLinkHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartLinkHandler.java index 5ec6963bd84..2aaf41a297b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartLinkHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartLinkHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java index 627048108f7..c2d48d7eae6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincRsnaPlaybookHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincRsnaPlaybookHandler.java index b2b7ba74631..ff5b85e02d5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincRsnaPlaybookHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincRsnaPlaybookHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java index 8930694a490..33678c1c402 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java index 1068349bf1b..d5f65073d1a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincUniversalOrderSetHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincUniversalOrderSetHandler.java index 71439449f02..cce69e825fe 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincUniversalOrderSetHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincUniversalOrderSetHandler.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.loinc; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerConcept.java index c1fbdb30aa9..da4cd9255f9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerConcept.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.snomedct; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerDescription.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerDescription.java index 2aa2ebc8fd8..66699d48cb8 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerDescription.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerDescription.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.snomedct; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerRelationship.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerRelationship.java index cc58cecba43..736e7161c25 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerRelationship.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/snomedct/SctHandlerRelationship.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term.snomedct; * 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. From 22bec81bffd3e0f1db52081d9a9e20bed4e60864 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Wed, 4 Apr 2018 10:11:19 -0400 Subject: [PATCH 4/5] Fix an intermittent test failure --- .../dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java index 375771e53fc..be99f609aa3 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java @@ -18,6 +18,7 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; +import org.springframework.test.context.TestPropertySource; import java.util.Collections; import java.util.List; @@ -27,6 +28,11 @@ import static org.hamcrest.Matchers.empty; import static org.junit.Assert.*; @SuppressWarnings({"unchecked", "deprecation"}) +@TestPropertySource(properties = { + // Since scheduled tasks can cause searches, which messes up the + // value returned by SearchBuilder.getLastHandlerMechanismForUnitTest() + "scheduling_disabled=true" +}) public class FhirResourceDaoDstu3UniqueSearchParamTest extends BaseJpaDstu3Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3UniqueSearchParamTest.class); From 2c818d5b4a12fae98a89b82ea722d3e807f746a8 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Fri, 6 Apr 2018 09:12:22 -0400 Subject: [PATCH 5/5] Update handler names --- .../fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java | 4 ++-- .../fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java | 4 ++-- pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java index 33678c1c402..91c7e959491 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsSiHandler.java @@ -29,8 +29,8 @@ import java.util.Map; public class LoincTop2000LabResultsSiHandler extends BaseLoincTop2000LabResultsHandler { - public static final String TOP_2000_SI_VS_ID = "TOP-2000-LABRESULTS-SI"; - public static final String TOP_2000_SI_VS_URI = "http://loinc.org/top-2000-lab-results-si"; + public static final String TOP_2000_SI_VS_ID = "top-2000-lab-observations-si"; + public static final String TOP_2000_SI_VS_URI = "http://loinc.org/vs/top-2000-lab-observations-si"; public static final String TOP_2000_SI_VS_NAME = "Top 2000 Lab Results SI"; public LoincTop2000LabResultsSiHandler(Map theCode2concept, List theValueSets, List theConceptMaps) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java index d5f65073d1a..64f11b92303 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincTop2000LabResultsUsHandler.java @@ -29,8 +29,8 @@ import java.util.Map; public class LoincTop2000LabResultsUsHandler extends BaseLoincTop2000LabResultsHandler { - public static final String TOP_2000_US_VS_ID = "TOP-2000-LABRESULTS-US"; - public static final String TOP_2000_US_VS_URI = "http://loinc.org/top-2000-lab-results-us"; + public static final String TOP_2000_US_VS_ID = "top-2000-lab-observations-us"; + public static final String TOP_2000_US_VS_URI = "http://loinc.org/vs/top-2000-lab-observations-us"; public static final String TOP_2000_US_VS_NAME = "Top 2000 Lab Results US"; public LoincTop2000LabResultsUsHandler(Map theCode2concept, List theValueSets, List theConceptMaps) { diff --git a/pom.xml b/pom.xml index 6064b0c4ba5..2b6f569bed9 100644 --- a/pom.xml +++ b/pom.xml @@ -998,7 +998,7 @@ org.javassist javassist - 3.20.0-GA + 3.22.0-GA org.mockito