Don't install draft package contents (#2099)
* Don't install draft package contents * Add changelog * Add changelog
This commit is contained in:
parent
072e63be5a
commit
ef4f3df945
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 2099
|
||||||
|
title: "When using an NPM package spec in STORE_AND_INSTALL mode, conformance resources will only be stored if they
|
||||||
|
have a status of `active`. This fixes a bug wgere installing the US Core IG caused searches to stop working due to
|
||||||
|
draft Search Parameters."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 2099
|
||||||
|
title: "Stored SearchParameter resources with a status of DRAFT will no longer override and disable existing built-in
|
||||||
|
search parameters. This is done in order to avoid issues caused by uploading NPM packages such as US Core that
|
||||||
|
contain a large number of draft parameters."
|
|
@ -28,6 +28,7 @@ public class DaoMethodOutcome extends MethodOutcome {
|
||||||
|
|
||||||
private IBasePersistedResource myEntity;
|
private IBasePersistedResource myEntity;
|
||||||
private IBaseResource myPreviousResource;
|
private IBaseResource myPreviousResource;
|
||||||
|
private boolean myNop;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -36,6 +37,20 @@ public class DaoMethodOutcome extends MethodOutcome {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was this a NO-OP - Typically because of an update to a resource that already matched the contents provided
|
||||||
|
*/
|
||||||
|
public boolean isNop() {
|
||||||
|
return myNop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was this a NO-OP - Typically because of an update to a resource that already matched the contents provided
|
||||||
|
*/
|
||||||
|
public void setNop(boolean theNop) {
|
||||||
|
myNop = theNop;
|
||||||
|
}
|
||||||
|
|
||||||
public IBasePersistedResource getEntity() {
|
public IBasePersistedResource getEntity() {
|
||||||
return myEntity;
|
return myEntity;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
|
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
|
||||||
|
@ -128,6 +129,12 @@ public abstract class BaseStorageDao {
|
||||||
protected DaoMethodOutcome toMethodOutcome(RequestDetails theRequest, @Nonnull final IBasePersistedResource theEntity, @Nonnull IBaseResource theResource) {
|
protected DaoMethodOutcome toMethodOutcome(RequestDetails theRequest, @Nonnull final IBasePersistedResource theEntity, @Nonnull IBaseResource theResource) {
|
||||||
DaoMethodOutcome outcome = new DaoMethodOutcome();
|
DaoMethodOutcome outcome = new DaoMethodOutcome();
|
||||||
|
|
||||||
|
if (theEntity instanceof ResourceTable) {
|
||||||
|
if (((ResourceTable) theEntity).isUnchangedInCurrentOperation()) {
|
||||||
|
outcome.setNop(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IIdType id = null;
|
IIdType id = null;
|
||||||
if (theResource.getIdElement().getValue() != null) {
|
if (theResource.getIdElement().getValue() != null) {
|
||||||
id = theResource.getIdElement();
|
id = theResource.getIdElement();
|
||||||
|
|
|
@ -26,6 +26,7 @@ import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.dao.data.INpmPackageVersionDao;
|
import ca.uhn.fhir.jpa.dao.data.INpmPackageVersionDao;
|
||||||
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity;
|
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
@ -35,7 +36,6 @@ import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.param.UriParam;
|
import ca.uhn.fhir.rest.param.UriParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
|
||||||
import ca.uhn.fhir.util.FhirTerser;
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
import ca.uhn.fhir.util.SearchParameterUtil;
|
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -208,6 +208,7 @@ public class PackageInstallerSvcImpl implements IPackageInstallerSvc {
|
||||||
count[i] = resources.size();
|
count[i] = resources.size();
|
||||||
|
|
||||||
for (IBaseResource next : resources) {
|
for (IBaseResource next : resources) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
next = isStructureDefinitionWithoutSnapshot(next) ? generateSnapshot(next) : next;
|
next = isStructureDefinitionWithoutSnapshot(next) ? generateSnapshot(next) : next;
|
||||||
create(next, theOutcome);
|
create(next, theOutcome);
|
||||||
|
@ -215,6 +216,7 @@ public class PackageInstallerSvcImpl implements IPackageInstallerSvc {
|
||||||
ourLog.warn("Failed to upload resource of type {} with ID {} - Error: {}", myFhirContext.getResourceType(next), next.getIdElement().getValue(), e.toString());
|
ourLog.warn("Failed to upload resource of type {} with ID {} - Error: {}", myFhirContext.getResourceType(next), next.getIdElement().getValue(), e.toString());
|
||||||
throw new ImplementationGuideInstallationException(String.format("Error installing IG %s#%s: %s", name, version, e.toString()), e);
|
throw new ImplementationGuideInstallationException(String.format("Error installing IG %s#%s: %s", name, version, e.toString()), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -321,10 +323,11 @@ public class PackageInstallerSvcImpl implements IPackageInstallerSvc {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
ourLog.info("Updating existing resource matching {}", map.toNormalizedQueryString(myFhirContext));
|
ourLog.info("Updating existing resource matching {}", map.toNormalizedQueryString(myFhirContext));
|
||||||
theOutcome.incrementResourcesInstalled(myFhirContext.getResourceType(theResource));
|
|
||||||
theResource.setId(searchResult.getResources(0, 1).get(0).getIdElement().toUnqualifiedVersionless());
|
theResource.setId(searchResult.getResources(0, 1).get(0).getIdElement().toUnqualifiedVersionless());
|
||||||
dao.update(theResource);
|
DaoMethodOutcome outcome = dao.update(theResource);
|
||||||
|
if (!outcome.isNop()) {
|
||||||
|
theOutcome.incrementResourcesInstalled(myFhirContext.getResourceType(theResource));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -349,6 +352,13 @@ public class PackageInstallerSvcImpl implements IPackageInstallerSvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<IPrimitiveType> statusTypes = myFhirContext.newFhirPath().evaluate(theResource, "status", IPrimitiveType.class);
|
||||||
|
if (statusTypes.size() > 0) {
|
||||||
|
if (!statusTypes.get(0).getValueAsString().equals("active")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
@ -462,6 +463,24 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuiltInSearchParameterNotReplacedByDraftSearchParameter() {
|
||||||
|
myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||||
|
|
||||||
|
SearchParameter memberSp = new SearchParameter();
|
||||||
|
memberSp.setCode("family");
|
||||||
|
memberSp.addBase("Patient");
|
||||||
|
memberSp.setType(Enumerations.SearchParamType.STRING);
|
||||||
|
memberSp.setExpression("Patient.name.family");
|
||||||
|
memberSp.setStatus(Enumerations.PublicationStatus.DRAFT);
|
||||||
|
mySearchParameterDao.create(memberSp, mySrd);
|
||||||
|
|
||||||
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
|
||||||
|
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("Patient", "family");
|
||||||
|
assertEquals(RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, sp.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -49,6 +49,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -114,6 +115,20 @@ public class NpmTestR4 extends BaseJpaR4Test {
|
||||||
|
|
||||||
PackageInstallationSpec spec = new PackageInstallationSpec().setName("hl7.fhir.us.core").setVersion("3.1.0").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL).setFetchDependencies(true);
|
PackageInstallationSpec spec = new PackageInstallationSpec().setName("hl7.fhir.us.core").setVersion("3.1.0").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL).setFetchDependencies(true);
|
||||||
igInstaller.install(spec);
|
igInstaller.install(spec);
|
||||||
|
|
||||||
|
runInTransaction(()->{
|
||||||
|
SearchParameterMap map = SearchParameterMap.newSynchronous(SearchParameter.SP_BASE, new TokenParam("NamingSystem"));
|
||||||
|
IBundleProvider outcome = mySearchParameterDao.search(map);
|
||||||
|
List<IBaseResource> resources = outcome.getResources(0, outcome.sizeOrThrowNpe());
|
||||||
|
for (int i = 0; i < resources.size(); i++) {
|
||||||
|
ourLog.info("**************************************************************************");
|
||||||
|
ourLog.info("**************************************************************************");
|
||||||
|
ourLog.info("Res " + i);
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(i)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
igInstaller.install(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,7 +177,8 @@ public class NpmTestR4 extends BaseJpaR4Test {
|
||||||
myFakeNpmServlet.myResponses.put("/hl7.fhir.uv.shorthand/0.12.0", bytes);
|
myFakeNpmServlet.myResponses.put("/hl7.fhir.uv.shorthand/0.12.0", bytes);
|
||||||
|
|
||||||
PackageInstallationSpec spec = new PackageInstallationSpec().setName("hl7.fhir.uv.shorthand").setVersion("0.12.0").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
|
PackageInstallationSpec spec = new PackageInstallationSpec().setName("hl7.fhir.uv.shorthand").setVersion("0.12.0").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
|
||||||
igInstaller.install(spec);
|
PackageInstallOutcomeJson outcome = igInstaller.install(spec);
|
||||||
|
assertEquals(1, outcome.getResourcesInstalled().get("CodeSystem"));
|
||||||
|
|
||||||
// Be sure no further communication with the server
|
// Be sure no further communication with the server
|
||||||
JettyUtil.closeServer(myServer);
|
JettyUtil.closeServer(myServer);
|
||||||
|
@ -215,11 +231,25 @@ public class NpmTestR4 extends BaseJpaR4Test {
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous();
|
SearchParameterMap map = SearchParameterMap.newSynchronous();
|
||||||
map.add(StructureDefinition.SP_URL, new UriParam("http://hl7.org/fhir/uv/shorthand/CodeSystem/shorthand-code-system"));
|
map.add(StructureDefinition.SP_URL, new UriParam("http://hl7.org/fhir/uv/shorthand/CodeSystem/shorthand-code-system"));
|
||||||
IBundleProvider outcome = myCodeSystemDao.search(map);
|
IBundleProvider result = myCodeSystemDao.search(map);
|
||||||
assertEquals(1, outcome.sizeOrThrowNpe());
|
assertEquals(1, result.sizeOrThrowNpe());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInstallR4Package_DraftResourcesNotInstalled() throws Exception {
|
||||||
|
myDaoConfig.setAllowExternalReferences(true);
|
||||||
|
|
||||||
|
byte[] bytes = loadClasspathBytes("/packages/test-draft-sample.tgz");
|
||||||
|
myFakeNpmServlet.myResponses.put("/hl7.fhir.uv.shorthand/0.11.1", bytes);
|
||||||
|
|
||||||
|
PackageInstallationSpec spec = new PackageInstallationSpec().setName("hl7.fhir.uv.shorthand").setVersion("0.11.1").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
|
||||||
|
PackageInstallOutcomeJson outcome = igInstaller.install(spec);
|
||||||
|
assertEquals(0, outcome.getResourcesInstalled().size(), outcome.getResourcesInstalled().toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInstallR4Package_Twice() throws Exception {
|
public void testInstallR4Package_Twice() throws Exception {
|
||||||
myDaoConfig.setAllowExternalReferences(true);
|
myDaoConfig.setAllowExternalReferences(true);
|
||||||
|
@ -236,6 +266,11 @@ public class NpmTestR4 extends BaseJpaR4Test {
|
||||||
igInstaller.install(spec);
|
igInstaller.install(spec);
|
||||||
outcome = igInstaller.install(spec);
|
outcome = igInstaller.install(spec);
|
||||||
assertEquals(null, outcome.getResourcesInstalled().get("CodeSystem"));
|
assertEquals(null, outcome.getResourcesInstalled().get("CodeSystem"));
|
||||||
|
|
||||||
|
// Ensure that we loaded the contents
|
||||||
|
IBundleProvider searchResult = myCodeSystemDao.search(SearchParameterMap.newSynchronous("url", new UriParam("http://hl7.org/fhir/uv/shorthand/CodeSystem/shorthand-code-system")));
|
||||||
|
assertEquals(1, searchResult.sizeOrThrowNpe());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -257,9 +292,6 @@ public class NpmTestR4 extends BaseJpaR4Test {
|
||||||
assertEquals(null, pkg.description());
|
assertEquals(null, pkg.description());
|
||||||
assertEquals("UK.Core.r4", pkg.name());
|
assertEquals("UK.Core.r4", pkg.name());
|
||||||
|
|
||||||
// Ensure that we loaded the contents
|
|
||||||
IBundleProvider searchResult = myStructureDefinitionDao.search(SearchParameterMap.newSynchronous("url", new UriParam("https://fhir.nhs.uk/R4/StructureDefinition/UKCore-Patient")));
|
|
||||||
assertEquals(1, searchResult.sizeOrThrowNpe());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Binary file not shown.
|
@ -291,6 +291,9 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
if (runtimeSp == null) {
|
if (runtimeSp == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (runtimeSp.getStatus() == RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (String nextBaseName : SearchParameterUtil.getBaseAsStrings(myFhirContext, nextSp)) {
|
for (String nextBaseName : SearchParameterUtil.getBaseAsStrings(myFhirContext, nextSp)) {
|
||||||
if (isBlank(nextBaseName)) {
|
if (isBlank(nextBaseName)) {
|
||||||
|
|
Loading…
Reference in New Issue