Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

latest from Tx Server #621

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.opencds.cqf.fhir.cr.visitor;

import static org.opencds.cqf.fhir.utility.adapter.IAdapterFactory.createAdapterForResource;

import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
Expand Down Expand Up @@ -31,8 +33,10 @@
import org.opencds.cqf.fhir.utility.SearchHelper;
import org.opencds.cqf.fhir.utility.adapter.IAdapterFactory;
import org.opencds.cqf.fhir.utility.adapter.IDependencyInfo;
import org.opencds.cqf.fhir.utility.adapter.IEndpointAdapter;
import org.opencds.cqf.fhir.utility.adapter.IKnowledgeArtifactAdapter;
import org.opencds.cqf.fhir.utility.adapter.ILibraryAdapter;
import org.opencds.cqf.fhir.utility.client.TerminologyServerClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -41,19 +45,23 @@ public class ReleaseVisitor extends BaseKnowledgeArtifactVisitor {
private static final String ACTIVE = "active";
private Logger logger = LoggerFactory.getLogger(ReleaseVisitor.class);
private static final String DEPENDSON = "depends-on";
protected final TerminologyServerClient terminologyServerClient;

public ReleaseVisitor(Repository repository) {
super(repository);
terminologyServerClient = new TerminologyServerClient(fhirContext());
}

@SuppressWarnings("unchecked")
@Override
public IBase visit(IKnowledgeArtifactAdapter rootAdapter, IBaseParameters operationParameters) {
Optional<Boolean> latestFromTxServer =
VisitorHelper.getBooleanParameter("latestFromTxServer", operationParameters);
// This check is to avoid partial releases and should be removed once the argument is supported.
if (latestFromTxServer.isPresent()) {
throw new NotImplementedOperationException("Support for 'latestFromTxServer' is not yet implemented.");
var latestFromTxServer = VisitorHelper.getBooleanParameter("latestFromTxServer", operationParameters)
.orElse(false);
Optional<IEndpointAdapter> terminologyEndpoint = VisitorHelper.getResourceParameter(
"terminologyEndpoint", operationParameters)
.map(r -> (IEndpointAdapter) createAdapterForResource(r));
if (latestFromTxServer && !terminologyEndpoint.isPresent()) {
throw new UnprocessableEntityException("latestFromTxServer = true but no terminologyEndpoint is available");
}
var version = VisitorHelper.getStringParameter("version", operationParameters)
.orElseThrow(() -> new UnprocessableEntityException("Version must be present"));
Expand Down Expand Up @@ -81,10 +89,11 @@ public IBase visit(IKnowledgeArtifactAdapter rootAdapter, IBaseParameters operat
rootAdapter,
releaseVersion,
rootEffectivePeriod,
latestFromTxServer.orElse(false),
latestFromTxServer,
requireNonExperimental,
new Date(),
new HashSet<>());
new HashSet<>(),
terminologyEndpoint.orElse(null));
var rootArtifactOriginalDependencies = new ArrayList<IDependencyInfo>(rootAdapter.getDependencies());
// Get list of extensions which need to be preserved
var originalDependenciesWithExtensions = rootArtifactOriginalDependencies.stream()
Expand Down Expand Up @@ -114,7 +123,9 @@ public IBase visit(IKnowledgeArtifactAdapter rootAdapter, IBaseParameters operat
releasedResources,
new HashMap<>(),
systemVersionParams,
canonicalVersionParams);
canonicalVersionParams,
latestFromTxServer,
terminologyEndpoint.orElse(null));
if (rootAdapter.get().fhirType().equals("Library")) {
((ILibraryAdapter) rootAdapter).setExpansionParameters(systemVersionParams, canonicalVersionParams);
}
Expand Down Expand Up @@ -184,7 +195,8 @@ private List<IDomainResource> internalRelease(
boolean latestFromTxServer,
Optional<String> experimentalBehavior,
Date current,
Set<String> releasedResources)
Set<String> releasedResources,
IEndpointAdapter endpoint)
throws NotImplementedOperationException, ResourceNotFoundException {
var resourcesToUpdate = new ArrayList<IDomainResource>();
if (releasedResources.contains(artifactAdapter.getCanonical())) {
Expand All @@ -205,32 +217,52 @@ private List<IDomainResource> internalRelease(
// If a version IS specified then `tryGetLatestVersion`
// will return that version.
var alreadyUpdated = checkIfReferenceInList(preReleaseReference, resourcesToUpdate);
if (IKnowledgeArtifactAdapter.checkIfRelatedArtifactIsOwned(component) && !alreadyUpdated.isPresent()) {
// get the latest version regardless of status because it's owned and we're releasing it
var latest = VisitorHelper.tryGetLatestVersion(preReleaseReference, repository);
if (latest.isPresent()) {
checkNonExperimental(latest.get().get(), experimentalBehavior, repository);
// release components recursively
resourcesToUpdate.addAll(internalRelease(
latest.get(),
version,
rootEffectivePeriod,
latestFromTxServer,
experimentalBehavior,
current,
releasedResources));
if (!alreadyUpdated.isPresent()) {
var resourceType = Canonicals.getResourceType(preReleaseReference);
var prereleaseReferenceVersion = Canonicals.getVersion(preReleaseReference);
if (resourceType != null
&& resourceType.equals("ValueSet")
&& prereleaseReferenceVersion == null
&& latestFromTxServer) {
var latest =
terminologyServerClient.getResource(endpoint, preReleaseReference, this.fhirVersion());
if (latest.isPresent()) {
checkNonExperimental(latest.get(), experimentalBehavior, repository);
// release components recursively
resourcesToUpdate.addAll(internalRelease(
IAdapterFactory.forFhirVersion(fhirVersion())
.createKnowledgeArtifactAdapter(latest.get()),
version,
rootEffectivePeriod,
latestFromTxServer,
experimentalBehavior,
current,
releasedResources,
endpoint));
}
} else if (IKnowledgeArtifactAdapter.checkIfRelatedArtifactIsOwned(component)) {
// get the latest version regardless of status because it's owned and we're releasing it
var latest = VisitorHelper.tryGetLatestVersion(preReleaseReference, repository);
if (latest.isPresent()) {
checkNonExperimental(latest.get().get(), experimentalBehavior, repository);
// release components recursively
resourcesToUpdate.addAll(internalRelease(
latest.get(),
version,
rootEffectivePeriod,
latestFromTxServer,
experimentalBehavior,
current,
releasedResources,
endpoint));
}
} else {
// if missing throw because it's an owned resource
throw new ResourceNotFoundException(String.format(
"Resource with URL '%s' is Owned by this repository and referenced by resource '%s', but no active version was found on the server.",
preReleaseReference, artifactAdapter.getUrl()));
// if it's a not-owned component just try to get the latest active version
VisitorHelper.tryGetLatestVersionWithStatus(preReleaseReference, repository, ACTIVE)
.ifPresent(latestActive ->
// check if it's experimental
checkNonExperimental(latestActive.get(), experimentalBehavior, repository));
}
} else if (!alreadyUpdated.isPresent()) {
// if it's a not-owned component just try to get the latest active version
VisitorHelper.tryGetLatestVersionWithStatus(preReleaseReference, repository, ACTIVE)
.ifPresent(latestActive ->
// check if it's experimental
checkNonExperimental(latestActive.get(), experimentalBehavior, repository));
}
}
}
Expand All @@ -245,7 +277,9 @@ private void gatherDependencies(
List<IDomainResource> releasedResources,
Map<String, IDomainResource> alreadyUpdatedDependencies,
List<String> systemVersionExpansionParameters,
List<String> canonicalVersionExpansionParameters) {
List<String> canonicalVersionExpansionParameters,
Boolean latestFromTxServer,
IEndpointAdapter endpoint) {
if (artifactAdapter == null) {
return;
}
Expand Down Expand Up @@ -317,23 +351,23 @@ private void gatherDependencies(
releasedResources,
alreadyUpdatedDependencies,
systemVersionExpansionParameters,
canonicalVersionExpansionParameters);
canonicalVersionExpansionParameters,
latestFromTxServer,
endpoint);
} else {
// try to get versions from expansion parameters if they are available
var resourceType = Canonicals.getResourceType(dependency.getReference()) == null
? null
: SearchHelper.getResourceType(repository, dependency);
String resourceType = getResourceType(dependency);
if (StringUtils.isBlank(Canonicals.getVersion(dependency.getReference()))) {
// This needs to be updated once we support requireVersionedDependencies
Optional<String> expansionParametersVersion = Optional.empty();
// assume if we can't figure out the resource type it's a CodeSystem
if (resourceType == null || resourceType.getSimpleName().equals("CodeSystem")) {
if (resourceType == null || resourceType.equals("CodeSystem")) {
expansionParametersVersion = systemVersionExpansionParameters.stream()
.filter(canonical -> !StringUtils.isBlank(Canonicals.getUrl(canonical)))
.filter(canonical ->
Canonicals.getUrl(canonical).equals(dependency.getReference()))
.findAny();
} else if (resourceType.getSimpleName().equals("ValueSet")) {
} else if (resourceType.equals("ValueSet")) {
expansionParametersVersion = canonicalVersionExpansionParameters.stream()
.filter(canonical ->
Canonicals.getUrl(canonical).equals(dependency.getReference()))
Expand All @@ -350,15 +384,19 @@ private void gatherDependencies(
// dependency
if (StringUtils.isBlank(Canonicals.getVersion(dependency.getReference()))) {
final var url = dependencyUrl;
maybeAdapter = VisitorHelper.tryGetLatestVersionWithStatus(
dependency.getReference(), repository, ACTIVE)
.map(adapter -> {
String versionedReference =
addVersionToReference(dependency.getReference(), adapter);
dependency.setReference(versionedReference);
alreadyUpdatedDependencies.put(url, adapter.get());
return adapter;
});
if (resourceType != null && resourceType.equals("ValueSet") && latestFromTxServer) {
maybeAdapter = terminologyServerClient
.getResource(endpoint, dependency.getReference(), this.fhirVersion())
.map(r -> (IKnowledgeArtifactAdapter) createAdapterForResource(r));
} else {
maybeAdapter = VisitorHelper.tryGetLatestVersionWithStatus(
dependency.getReference(), repository, ACTIVE);
}
maybeAdapter.ifPresent(adapter -> {
String versionedReference = addVersionToReference(dependency.getReference(), adapter);
dependency.setReference(versionedReference);
alreadyUpdatedDependencies.put(url, adapter.get());
});
} else {
// This is a versioned reference, just get the dependency
maybeAdapter =
Expand All @@ -374,7 +412,9 @@ private void gatherDependencies(
releasedResources,
alreadyUpdatedDependencies,
systemVersionExpansionParameters,
canonicalVersionExpansionParameters);
canonicalVersionExpansionParameters,
latestFromTxServer,
endpoint);
} else {
alreadyUpdatedDependencies.put(dependencyUrl, null);
}
Expand All @@ -394,6 +434,12 @@ private void gatherDependencies(
}
}

private String getResourceType(IDependencyInfo dependency) {
return Canonicals.getResourceType(dependency.getReference()) == null
? null
: SearchHelper.getResourceType(repository, dependency).getSimpleName();
}

private void checkNonExperimental(
IDomainResource resource, Optional<String> experimentalBehavior, Repository repository)
throws UnprocessableEntityException {
Expand Down Expand Up @@ -447,15 +493,14 @@ private IKnowledgeArtifactAdapter getArtifactByCanonical(String inputReference,
List<IKnowledgeArtifactAdapter> matchingResources = VisitorHelper.getMetadataResourcesFromBundle(
SearchHelper.searchRepositoryByCanonicalWithPaging(repository, inputReference))
.stream()
.map(r -> IAdapterFactory.forFhirVersion(r.getStructureFhirVersionEnum())
.createKnowledgeArtifactAdapter(r))
.map(r -> (IKnowledgeArtifactAdapter) createAdapterForResource(r))
.collect(Collectors.toList());
if (matchingResources.isEmpty()) {
return null;
} else if (matchingResources.size() == 1) {
return matchingResources.get(0);
} else {
logger.info("Multiple resources found matching {}", inputReference);
logger.info("Multiple resources found matching {}, used the first one", inputReference);
return matchingResources.get(0);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.CodeType;
Expand Down Expand Up @@ -484,31 +483,6 @@ void releaseResource_propagate_effective_period() {
repo);
}

@Test
void releaseResource_latestFromTx_NotSupported_test() {
Bundle bundle = (Bundle) jsonParser.parseResource(
ReleaseVisitorTests.class.getResourceAsStream("Bundle-small-approved-draft.json"));
repo.transaction(bundle);

String actualErrorMessage = "";

Parameters params = parameters(
part("version", "1.2.3"),
part("versionBehavior", new CodeType("default")),
part("latestFromTxServer", new BooleanType(true)));
var releaseVisitor = new ReleaseVisitor(repo);
Library library = repo.read(Library.class, new IdType("Library/SpecificationLibrary"))
.copy();
ILibraryAdapter libraryAdapter = new AdapterFactory().createLibrary(library);

try {
libraryAdapter.accept(releaseVisitor, params);
} catch (Exception e) {
actualErrorMessage = e.getMessage();
}
assertTrue(actualErrorMessage.contains("not yet implemented"));
}

@Test
void release_missing_approvalDate_validation_test() {
Bundle bundle = (Bundle) jsonParser.parseResource(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Optional;
import java.util.stream.Collectors;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.CanonicalType;
Expand Down Expand Up @@ -459,31 +458,6 @@ void releaseResource_propagate_effective_period() {
repo);
}

@Test
void releaseResource_latestFromTx_NotSupported_test() {
Bundle bundle = (Bundle) jsonParser.parseResource(
ReleaseVisitorTests.class.getResourceAsStream("Bundle-small-approved-draft.json"));
repo.transaction(bundle);

String actualErrorMessage = "";

Parameters params = parameters(
part("version", "1.2.3"),
part("versionBehavior", new CodeType("default")),
part("latestFromTxServer", new BooleanType(true)));
ReleaseVisitor releaseVisitor = new ReleaseVisitor(repo);
Library library = repo.read(Library.class, new IdType("Library/SpecificationLibrary"))
.copy();
ILibraryAdapter libraryAdapter = new AdapterFactory().createLibrary(library);

try {
libraryAdapter.accept(releaseVisitor, params);
} catch (Exception e) {
actualErrorMessage = e.getMessage();
}
assertTrue(actualErrorMessage.contains("not yet implemented"));
}

@Test
void release_missing_approvalDate_validation_test() {
Bundle bundle = (Bundle) jsonParser.parseResource(
Expand Down
Loading
Loading