Skip to content

Commit

Permalink
OpenConceptLab/ocl_issues#338 codesystem lookup operation
Browse files Browse the repository at this point in the history
  • Loading branch information
Harsh Patel committed Oct 28, 2020
1 parent e7a737f commit 8a8fb9e
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
import org.openconceptlab.fhir.util.OclFhirUtil;

import static org.openconceptlab.fhir.util.OclFhirConstants.*;
import static org.openconceptlab.fhir.util.OclFhirUtil.badRequest;
import static org.openconceptlab.fhir.util.OclFhirUtil.notFound;
import static org.openconceptlab.fhir.util.OclFhirUtil.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
Expand Down Expand Up @@ -43,14 +42,7 @@ public OclFhirController(CodeSystemResourceProvider codeSystemResourceProvider,

@GetMapping(path = {"/orgs/{org}/CodeSystem/{id}"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getCodeSystemByOrg(@PathVariable(name = ORG) String org, @PathVariable(name = ID) String id) {
try {
String resource = searchResource(CodeSystem.class, OWNER, formatOrg(org), ID, id);
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
return handleSearchResource(CodeSystem.class, OWNER, formatOrg(org), ID, id);
}

@GetMapping(path = {"/orgs/{org}/CodeSystem/{id}/version",
Expand All @@ -59,32 +51,34 @@ public ResponseEntity<String> getCodeSystemByOrg(@PathVariable(name = ORG) Strin
public ResponseEntity<String> getCodeSystemVersionsByOrg(@PathVariable(name = ORG) String org,
@PathVariable(name = ID) String id,
@PathVariable(name = VERSION) Optional<String> version) {
try {
String resource = searchResource(CodeSystem.class, OWNER, formatOrg(org), ID, id,
VERSION, version.orElse(ALL));
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
return handleSearchResource(CodeSystem.class, OWNER, formatOrg(org), ID, id, VERSION, version.orElse(ALL));
}

@GetMapping(path = {"/orgs/{org}/CodeSystem"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public String searchCodeSystemsByOrg(@PathVariable String org) {
return searchResource(CodeSystem.class, OWNER, formatOrg(org));
public ResponseEntity<String> searchCodeSystemsByOrg(@PathVariable String org) {
return handleSearchResource(CodeSystem.class, OWNER, formatOrg(org));
}

@GetMapping(path = {"/orgs/{org}/CodeSystem/$lookup"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> lookUpCodeSystemsByOrg(@PathVariable String org,
@RequestParam(name = SYSTEM) String system,
@RequestParam(name = CODE) String code,
@RequestParam(name = VERSION, required = false) String version,
@RequestParam(name = DISP_LANG, required = false) String displayLanguage) {
Parameters parameters = generateParameters(system, code, version, displayLanguage, formatOrg(org));
return handleLookup(parameters);
}

@PostMapping(path = {"/orgs/{org}/CodeSystem/$lookup"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> lookUpCodeSystemsByOrg(@PathVariable String org, @RequestBody String parameters){
Parameters params = (Parameters) getResource(parameters);
params.addParameter().setName(PROPERTY).setValue(new StringType(formatOrg(org)));
return handleLookup(params);
}

@GetMapping(path = {"/orgs/{org}/ValueSet/{id}"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getValueSetByOrg(@PathVariable String org, @PathVariable String id) {
try {
String resource = searchResource(ValueSet.class, OWNER, formatOrg(org), ID, id);
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
return handleSearchResource(ValueSet.class, OWNER, formatOrg(org), ID, id);
}

@GetMapping(path = {"/orgs/{org}/ValueSet/{id}/version",
Expand All @@ -93,32 +87,17 @@ public ResponseEntity<String> getValueSetByOrg(@PathVariable String org, @PathVa
public ResponseEntity<String> getValueSetVersionsByOrg(@PathVariable(name = ORG) String org,
@PathVariable(name = ID) String id,
@PathVariable(name = VERSION) Optional<String> version) {
try {
String resource = searchResource(ValueSet.class, OWNER, formatOrg(org), ID, id,
VERSION, version.orElse(ALL));
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
return handleSearchResource(ValueSet.class, OWNER, formatOrg(org), ID, id, VERSION, version.orElse(ALL));
}

@GetMapping(path = {"/orgs/{org}/ValueSet"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public String searchValueSetsByOrg(@PathVariable String org) {
return searchResource(ValueSet.class, OWNER, formatOrg(org));
public ResponseEntity<String> searchValueSetsByOrg(@PathVariable String org) {
return handleSearchResource(ValueSet.class, OWNER, formatOrg(org));
}

@GetMapping(path = {"/users/{user}/CodeSystem/{id}"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getCodeSystemByUser(@PathVariable String user, @PathVariable String id) {
try {
String resource = searchResource(CodeSystem.class, OWNER, formatUser(user), ID, id);
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
return handleSearchResource(CodeSystem.class, OWNER, formatUser(user), ID, id);
}

@GetMapping(path = {"/users/{user}/CodeSystem/{id}/version",
Expand All @@ -127,32 +106,34 @@ public ResponseEntity<String> getCodeSystemByUser(@PathVariable String user, @Pa
public ResponseEntity<String> getCodeSystemVersionsByUser(@PathVariable(name = USER) String user,
@PathVariable(name = ID) String id,
@PathVariable(name = VERSION) Optional<String> version) {
try {
String resource = searchResource(CodeSystem.class, OWNER, formatUser(user), ID, id,
VERSION, version.orElse(ALL));
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
return handleSearchResource(CodeSystem.class, OWNER, formatUser(user), ID, id, VERSION, version.orElse(ALL));
}

@GetMapping(path = {"/users/{user}/CodeSystem"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public String searchCodeSystemsByUser(@PathVariable String user) {
return searchResource(CodeSystem.class, OWNER, formatUser(user));
public ResponseEntity<String> searchCodeSystemsByUser(@PathVariable String user) {
return handleSearchResource(CodeSystem.class, OWNER, formatUser(user));
}

@GetMapping(path = {"/users/{user}/CodeSystem/$lookup"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> lookUpCodeSystemsByUser(@PathVariable String user,
@RequestParam(name = SYSTEM) String system,
@RequestParam(name = CODE) String code,
@RequestParam(name = VERSION, required = false) String version,
@RequestParam(name = DISP_LANG, required = false) String displayLanguage) {
Parameters parameters = generateParameters(system, code, version, displayLanguage, formatUser(user));
return handleLookup(parameters);
}

@PostMapping(path = {"/users/{user}/CodeSystem/$lookup"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> lookUpCodeSystemsByUser(@PathVariable String user, @RequestBody String parameters){
Parameters params = (Parameters) getResource(parameters);
params.addParameter().setName(PROPERTY).setValue(new StringType(formatUser(user)));
return handleLookup(params);
}

@GetMapping(path = {"/users/{user}/ValueSet/{id}"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getValueSetByUser(@PathVariable String user, @PathVariable String id) {
try {
String resource = searchResource(ValueSet.class, OWNER, formatUser(user), ID, id);
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
return handleSearchResource(ValueSet.class, OWNER, formatUser(user), ID, id);
}

@GetMapping(path = {"/users/{user}/ValueSet/{id}/version",
Expand All @@ -161,9 +142,17 @@ public ResponseEntity<String> getValueSetByUser(@PathVariable String user, @Path
public ResponseEntity<String> getValueSetVersionsByUser(@PathVariable(name = USER) String user,
@PathVariable(name = ID) String id,
@PathVariable(name = VERSION) Optional<String> version) {
return handleSearchResource(ValueSet.class, OWNER, formatUser(user), ID, id, VERSION, version.orElse(ALL));
}

@GetMapping(path = {"/users/{user}/ValueSet"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> searchValueSetsByUser(@PathVariable String user) {
return handleSearchResource(ValueSet.class, OWNER, formatUser(user));
}

private ResponseEntity<String> handleSearchResource(final Class<? extends MetadataResource> resourceClass, final String... args) {
try {
String resource = searchResource(ValueSet.class, OWNER, formatUser(user), ID, id,
VERSION, version.orElse(ALL));
String resource = searchResource(resourceClass, args);
return ResponseEntity.ok(resource);
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
Expand All @@ -172,9 +161,14 @@ public ResponseEntity<String> getValueSetVersionsByUser(@PathVariable(name = USE
}
}

@GetMapping(path = {"/users/{user}/ValueSet"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public String searchValueSetsByUser(@PathVariable String user) {
return searchResource(ValueSet.class, OWNER, formatUser(user));
private ResponseEntity<String> handleLookup(Parameters parameters) {
try {
return ResponseEntity.ok(oclFhirUtil.getResourceAsString(lookUpCodeSystem(parameters)));
} catch (ResourceNotFoundException e) {
return notFound(e.getStatusCode(), e.getResponseBody());
} catch (Exception e) {
return badRequest();
}
}

private String searchResource(final Class<? extends MetadataResource> resourceClass, final String... filters) {
Expand All @@ -189,7 +183,28 @@ private String searchResource(final Class<? extends MetadataResource> resourceCl
}
}
Bundle bundle = (Bundle) q.execute();
return oclFhirUtil.getResource(bundle);
return oclFhirUtil.getResourceAsString(bundle);
}

private Parameters lookUpCodeSystem(Parameters parameters) {
return oclFhirUtil.getClient()
.operation()
.onType(CodeSystem.class)
.named(LOOKUP)
.withParameters(parameters)
.execute();
}

private Parameters generateParameters(String system, String code, String version, String displayLanguage, String owner) {
Parameters parameters = new Parameters();
parameters.addParameter().setName(SYSTEM).setValue(new UriType(system));
parameters.addParameter().setName(CODE).setValue(new CodeType(code));
if (isValid(version))
parameters.addParameter().setName(VERSION).setValue(new StringType(version));
if (isValid(displayLanguage))
parameters.addParameter().setName(DISP_LANG).setValue(new CodeType(displayLanguage));
parameters.addParameter().setName(PROPERTY).setValue(new StringType(owner));
return parameters;
}

private static String formatOrg(String org) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.openconceptlab.fhir.converter;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
Expand Down Expand Up @@ -223,6 +224,92 @@ private void addFilter(CodeSystem codeSystem, String code, JsonElement descripti
}
}

public Parameters getLookupParameters(final Source source, final CodeType code, final CodeType displayLanguage) {
Optional<Concept> conceptOpt = source.getConceptsSources().parallelStream()
.map(ConceptsSource::getConcept)
.filter(c -> c.getMnemonic().equals(code.getCode()))
.max(Comparator.comparing(Concept::getId));
if (conceptOpt.isPresent()) {
Concept concept = conceptOpt.get();
Parameters parameters = new Parameters();
parameters.addParameter(getParameter(NAME, source.getName()));
parameters.addParameter(getParameter(VERSION, source.getVersion()));
AtomicBoolean preferred = new AtomicBoolean(false);
concept.getConceptsNames().stream().map(ConceptsName::getLocalizedText).forEach(lt -> {
// Populates 'display' based on displayLanguage if provided.
// sets first preferred or first non-preferred value as 'display'
if (isValid(displayLanguage) && displayLanguage.getCode().equals(lt.getLocale())) {
if (lt.getLocalePreferred()) {
if (parameters.getParameter(DISPLAY) == null) {
parameters.addParameter(getParameter(DISPLAY, lt.getName()));
preferred.set(true);
}
} else {
if (!preferred.get()) {
if (parameters.getParameter(DISPLAY) == null) {
parameters.addParameter(getParameter(DISPLAY, lt.getName()));
}
}
}
}
addDesignationParameters(parameters, lt, displayLanguage);
});
// default value of 'display'
if (!isValid(displayLanguage)) {
Optional<LocalizedText> display = concept.getConceptsNames().stream()
.map(ConceptsName::getLocalizedText)
.filter(c -> c.getLocale().equals(source.getDefaultLocale()))
.findAny();
if (display.isPresent()) {
parameters.addParameter(getParameter(DISPLAY, display.get().getName()));
} else {
concept.getConceptsNames().stream()
.map(ConceptsName::getLocalizedText)
.map(LocalizedText::getName)
.findAny().ifPresent(name -> parameters.addParameter(getParameter(DISPLAY, name)));
}
}
return parameters;
}
return null;
}

private void addDesignationParameters(Parameters parameters, final LocalizedText text, final CodeType displayLanguage) {
if (isValid(displayLanguage) && !displayLanguage.getCode().equals(text.getLocale())) return;
parameters.addParameter().setName(DISPLAY).setPart(getDesignationParameters(text));
}

private List<Parameters.ParametersParameterComponent> getDesignationParameters(final LocalizedText text) {
List<Parameters.ParametersParameterComponent> componentList = new ArrayList<>();
if (isValid(text.getLocale()))
componentList.add(getParameter(LANGUAGE, new CodeType(text.getLocale())));
if (isValid(text.getType()))
componentList.add(getParameter(USE, new Coding(EMPTY, EMPTY, text.getType())));
if (isValid(text.getName()))
componentList.add(getParameter(VALUE, new StringType(text.getName())));
return componentList;
}

private Parameters.ParametersParameterComponent getParameter(String name, Type value) {
Parameters.ParametersParameterComponent component = new Parameters.ParametersParameterComponent();
component.setName(name).setValue(value);
return component;
}

private Parameters.ParametersParameterComponent getParameter(String name, String value) {
Parameters.ParametersParameterComponent component = new Parameters.ParametersParameterComponent();
component.setName(name).setValue(new StringType(value));
return component;
}

private void addParameter(String name, String value, Parameters parameters) {
addParameter(name, new StringType(value), parameters);
}

private void addParameter(String name, Type value, Parameters parameters) {
parameters.addParameter().setName(name).setValue(value);
}

/**
* TODO: Update when ready to implement POST
* @param codeSystem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private RuleBuilder getDefaultRuleBuilder() {
.allow().write().resourcesOfType(CodeSystem.class).withAnyId().andThen()
.allow().write().resourcesOfType(ValueSet.class).withAnyId().andThen()
.allow().write().resourcesOfType(ConceptMap.class).withAnyId().andThen()
.allow().operation().withAnyName();
.allow().operation().withAnyName().atAnyLevel().andAllowAllResponses();
return ruleBuilder;
}

Expand Down
Loading

0 comments on commit 8a8fb9e

Please sign in to comment.