Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 6dd06fa5 authored by Franck Desaize's avatar Franck Desaize
Browse files

Refactor

parent ccc21079
No related branches found
No related tags found
1 merge request!1Release
Showing
with 368 additions and 589 deletions
package net.ihe.gazelle.servlet;
package net.ihe.gazelle.adapter.servlet;
import java.util.ArrayList;
import java.util.List;
......@@ -14,8 +14,8 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import net.ihe.gazelle.interceptor.LegacyLoggingInterceptor;
import net.ihe.gazelle.provider.ChPatientResourceProvider;
import net.ihe.gazelle.business.interceptor.LegacyLoggingInterceptor;
import net.ihe.gazelle.business.provider.ChPatientResourceProvider;
/**
* This servlet is the actual FHIR server itself
......
package net.ihe.gazelle.adapter.servlet;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import net.ihe.gazelle.business.provider.IhePatientResourceProvider;
import javax.servlet.annotation.WebServlet;
import java.util.ArrayList;
import java.util.List;
@WebServlet(urlPatterns = {"/fhir_ihe/*"}, displayName = "FHIR Server IHE")
public class IheHapiFhirServer extends RestfulServer {
private static final long serialVersionUID = 1L;
/**
* Constructor
*/
public IheHapiFhirServer() {
super(FhirContext.forR4());
}
/**
* This method is called automatically when the
* servlet is initializing.
*/
@Override
public void initialize() {
/*
* Two resource providers are defined. Each one handles a specific
* type of resource.
*/
List<IResourceProvider> providers = new ArrayList<IResourceProvider>();
providers.add(new IhePatientResourceProvider());
setResourceProviders(providers);
//creating an interceptor to log in console an error occurring
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
loggingInterceptor.setLoggerName("test.accesslog");
loggingInterceptor.setMessageFormat("Source[$remoteAddr] Operation[${operationType}"
+ "${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]");
registerInterceptor(loggingInterceptor);
//creating an interceptor for special exception to dump the stack trace in the logs.
ExceptionHandlingInterceptor exceptionInterceptor = new ExceptionHandlingInterceptor();
exceptionInterceptor.setReturnStackTracesForExceptionTypes(InternalErrorException.class, NullPointerException.class);
registerInterceptor(exceptionInterceptor);
/*
* Use a narrative generator. This is a completely optional step,
* but can be useful as it causes HAPI to generate narratives for
* resources which don't otherwise have one.
*/
INarrativeGenerator narrativeGen = new DefaultThymeleafNarrativeGenerator();
getFhirContext().setNarrativeGenerator(narrativeGen);
}
}
package net.ihe.gazelle.interceptor;
package net.ihe.gazelle.business.interceptor;
import java.io.IOException;
......
package net.ihe.gazelle.interceptor;
package net.ihe.gazelle.business.interceptor;
import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Pointcut;
......
package net.ihe.gazelle.provider;
package net.ihe.gazelle.business.provider;
import java.net.MalformedURLException;
import java.net.URL;
......@@ -181,7 +181,7 @@ public class ChPatientResourceProvider implements IResourceProvider {
@Operation(name="$ihe-pix", idempotent = true)
public Parameters findPatientsByIdentifier(@OperationParam(name = "sourceIdentifier") TokenParam sourceIdentifier,
@OperationParam(name = "targetSystem") StringAndListParam targetSystem)
throws PatientResourceProviderException, ForbiddenOperationException, ResourceNotFoundException {
throws PatientResourceProviderException, ForbiddenOperationException, ResourceNotFoundException {
Parameters results = new Parameters();
......@@ -461,10 +461,10 @@ public class ChPatientResourceProvider implements IResourceProvider {
/**
* Method used to generate a Parameter Component representing an error in the the Fhir Resource Model
* Permits to display the error.
*
*
* @param errorType : the code of the error as a String.
* Will be translated as an OperationOutcome.IssueType
* @return A ParametersParameterComponent representing the http error as a Fhir resource
* @return A ParametersParameterComponent representing the http error as a Fhir resource
*/
private ParametersParameterComponent generateErrorReturn(String errorCode) {
OperationOutcome error = new OperationOutcome();
......
package net.ihe.gazelle.business.provider;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import net.ihe.gazelle.app.patientregistryapi.application.SearchCrossReferenceException;
import net.ihe.gazelle.app.patientregistryapi.business.EntityIdentifier;
import net.ihe.gazelle.app.patientregistryapi.business.PatientAliases;
import net.ihe.gazelle.app.patientregistryapi.business.PersonName;
import net.ihe.gazelle.app.patientregistryxrefsearchclient.adapter.XRefSearchClient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Address.AddressUse;
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.r4.model.HumanName.NameUse;
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
/**
* This is a resource provider which stores Patient resources in memory using a HashMap. This is obviously not a production-ready solution for many
* reasons,
* but it is useful to help illustrate how to build a fully-functional server.
*/
public class IhePatientResourceProvider implements IResourceProvider {
/**
* The getResourceType method comes from IResourceProvider, and must be overridden to indicate what type of resource this provider supplies.
*/
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
private static final Logger patientLogger = LoggerFactory.getLogger(IhePatientResourceProvider.class);
/**
* This map has a resource ID as a key, and each key maps to a Deque list containing all versions of the resource with that ID.
*/
private Map<Long, Deque<Patient>> myIdToPatientVersions = new HashMap<Long, Deque<Patient>>();
/**
* Search method for a Patient using the source identifier required parameter
* and an optional list of target system
*
* @param sourceIdentifierParam : the source identifier of the patient, should be formatted "urn:oid:x.x.x.x.x.x.x.x.x.x|value"
* @param targetSystemParam: the target System(s) we want to find the Patient on, should be formatted "urn:oid:x.x.x.x.x.x.x.x.x.x,urn:oid:x
* .x.x.x
* .x.x.x.x.x.x,"
* @return a Parameters element composed of a list of target identifier for every Patient found, and an url to the Patient in the server.
*/
@Operation(name = "$ihe-pix", idempotent = true)
public Parameters findPatientsByIdentifier(@OperationParam(name = "sourceIdentifier", min = 1, max = 1) TokenParam sourceIdentifierParam,
@OperationParam(name = "targetSystem") StringAndListParam targetSystemParam) throws PatientResourceProviderException, ForbiddenOperationException, ResourceNotFoundException {
EntityIdentifier sourceIdentifier = createEntityIdentifierFromSourceIdentifier(sourceIdentifierParam);
List<String> targetSystemList = createTargetSystemListFromParam(targetSystemParam);
Parameters results = new Parameters();
PatientAliases response;
int log = 0;
try {
URL url = new URL("https://qualification.ihe-europe.net/patient-registry/CrossReferenceService/xref-processing-service?wsdl");
XRefSearchClient searchClient = new XRefSearchClient(url);
patientLogger.info(targetSystemList.toString());
response = searchClient.search(sourceIdentifier, targetSystemList);
patientLogger.info(Integer.toString(log++));
} catch (MalformedURLException e) {
throw new PatientResourceProviderException("Could not find target url for Patient Registry, The given URL might be wrong.", e);
} catch (SearchCrossReferenceException e) {
//results.addParameter(generateErrorReturn("code-invalid"));
return results;
//throw new ResourceNotFoundException("Could not find Patient in Patient Registry");
}
patientLogger.info(Integer.toString(log++));
if (response.getMembers().size() == 0) {
// results.addParameter(generateErrorReturn("notfound"));
return results;
//throw new ResourceNotFoundException("No crossReferenced Patient found.");
}
patientLogger.info("Number of patents found : " + response.getMembers().size());
for (net.ihe.gazelle.app.patientregistryapi.business.Patient pat : response.getMembers()) {
// long id = myNextId++;
patientLogger.info(pat.getNames().get(0).getFamily());
Patient translated = this.translatePatientToR4(pat);
for (EntityIdentifier entity : pat.getIdentifiers()) {
patientLogger.info(Integer.toString(log++));
Identifier r4Identifier = new Identifier();
r4Identifier.setSystem(entity.getSystemIdentifier());
r4Identifier.setValue(entity.getValue());
translated.addIdentifier(r4Identifier);
ParametersParameterComponent alias = new ParametersParameterComponent();
alias.setName("target Identifier");
alias.setValue(r4Identifier);
results.addParameter(alias);
}
ParametersParameterComponent targetId = new ParametersParameterComponent();
targetId.setName("targetId");
Reference ref = new Reference();
// targetId.setValue(ref);
results.addParameter(targetId);
patientLogger.info(Integer.toString(log++));
// translated.setId(Long.toString(id));
LinkedList<Patient> listToAdd = new LinkedList<>();
listToAdd.add(translated);
// myIdToPatientVersions.put(id, listToAdd);
}
// results.setId(Long.toString(myNextId++));
patientLogger.info(Integer.toString(log++));
return results;
}
@Search
public List<Patient> findPatientsUsingArbitraryCriteria() {
LinkedList<Patient> retVal = new LinkedList<Patient>();
for (Deque<Patient> nextPatientList : myIdToPatientVersions.values()) {
Patient nextPatient = nextPatientList.getLast();
retVal.add(nextPatient);
}
return retVal;
}
/**
* Private Method called to translate a Patient between the model in Patient Registry to the fhir model
* We need to translate a Patient in order to have it in the list of Patient contained in the fhir server
* To later have access to it (through an URL given when searched)
*
* @param patReg : the Patient in the Patient Registry Model
* @return the same Patient translated in the FHIR r4 model.
*/
private Patient translatePatientToR4(net.ihe.gazelle.app.patientregistryapi.business.Patient patReg) {
Patient translatedPatient = new Patient();
translatedPatient.setActive(patReg.isActive());
List<HumanName> nameList = new ArrayList<>();
for (PersonName pName : patReg.getNames()) {
HumanName name = new HumanName();
name.setFamily(pName.getFamily());
List<StringType> givenNames = new ArrayList<>();
for (String given : pName.getGivens()) {
givenNames.add(new StringType(given));
}
name.setGiven(givenNames);
name.addPrefix(pName.getPrefix());
name.addSuffix(pName.getSuffix());
name.setUse(NameUse.fromCode(pName.getUse()));
nameList.add(name);
}
translatedPatient.setName(nameList);
translatedPatient.setGender(AdministrativeGender.fromCode(patReg.getGender().toString().toLowerCase()));
List<Address> addresses = new ArrayList<>();
for (net.ihe.gazelle.app.patientregistryapi.business.Address pAddress : patReg.getAddresses()) {
Address address = new Address();
address.setUse(AddressUse.fromCode(pAddress.getUse().toString().toLowerCase()));
address.setCity(pAddress.getCity());
address.setCountry(pAddress.getCountryIso3());
address.setPostalCode(pAddress.getPostalCode());
address.setState(pAddress.getState());
for (String addressLine : pAddress.getLines())
address.addLine(addressLine);
addresses.add(address);
}
translatedPatient.setAddress(addresses);
translatedPatient.setBirthDate(patReg.getDateOfBirth());
return translatedPatient;
}
private EntityIdentifier createEntityIdentifierFromSourceIdentifier(TokenParam sourceIdentifier) {
if (sourceIdentifier == null) {
throw new InvalidRequestException("Invalid request : sourceIdentifier is a mandatory parameter");
}
String sourceIdentifierSystem = sourceIdentifier.getSystem();
String sourceIdentifierValue = sourceIdentifier.getValue();
if (sourceIdentifierSystem == null) {
throw new InvalidRequestException("Invalid request : sourceIdentifier is wrong");
}
if (sourceIdentifierValue == null) {
throw new InvalidRequestException("Invalid request : sourceIdentifier is wrong");
}
if (sourceIdentifierSystem.isBlank() || sourceIdentifierValue.isBlank()) {
throw new InvalidRequestException("Invalid request : sourceIdentifier is wrong");
}
patientLogger.info("Searching Patient with given sourceIdentifier: " + sourceIdentifier);
EntityIdentifier wellFormedEntityIdentifier = new EntityIdentifier();
if (sourceIdentifierSystem.contains("urn:oid:")) {
wellFormedEntityIdentifier.setSystemIdentifier(sourceIdentifierSystem.replace("urn:oid:", ""));
wellFormedEntityIdentifier.setType("ISO");
wellFormedEntityIdentifier.setValue(sourceIdentifierValue);
} else if (sourceIdentifierSystem.contains("http")) {
wellFormedEntityIdentifier.setSystemIdentifier(sourceIdentifierSystem);
wellFormedEntityIdentifier.setType("ISO");
wellFormedEntityIdentifier.setValue(sourceIdentifierValue);
} else {
throw new InvalidRequestException("Invalid request : sourceIdentifier system is malformed");
}
return wellFormedEntityIdentifier;
}
private List<String> createTargetSystemListFromParam(StringAndListParam targetSystemParam) {
List<String> targetSystemList = new ArrayList<>();
if (targetSystemParam != null) {
for (StringOrListParam listParam : targetSystemParam.getValuesAsQueryTokens()) {
List<StringParam> queryStrings = listParam.getValuesAsQueryTokens();
for (StringParam singleParam : queryStrings) {
String singleParamValue = singleParam.getValue();
if (singleParamValue.contains("urn:oid:")) {
singleParamValue = singleParamValue.replace("urn:oid:", "");
}
if (singleParamValue.equals("")) {
throw new InvalidRequestException("Invalid request : targetDomain can not be empty");
}
targetSystemList.add(singleParamValue);
}
}
}
return targetSystemList;
}
}
package net.ihe.gazelle.provider;
package net.ihe.gazelle.business.provider;
public class PatientResourceProviderException extends Exception {
......
package net.ihe.gazelle.provider;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Address;
import org.hl7.fhir.r4.model.Address.AddressUse;
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.r4.model.HumanName;
import org.hl7.fhir.r4.model.HumanName.NameUse;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.InstantType;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.StringType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import net.ihe.gazelle.app.patientregistryapi.application.SearchCrossReferenceException;
import net.ihe.gazelle.app.patientregistryapi.business.EntityIdentifier;
import net.ihe.gazelle.app.patientregistryapi.business.PatientAliases;
import net.ihe.gazelle.app.patientregistryapi.business.PersonName;
import net.ihe.gazelle.app.patientregistryxrefsearchclient.adapter.XRefSearchClient;
/**
* This is a resource provider which stores Patient resources in memory using a HashMap. This is obviously not a production-ready solution for many reasons,
* but it is useful to help illustrate how to build a fully-functional server.
*/
public class IhePatientResourceProvider implements IResourceProvider {
private static final Logger patientLogger = LoggerFactory.getLogger(IhePatientResourceProvider.class);
/**
* This map has a resource ID as a key, and each key maps to a Deque list containing all versions of the resource with that ID.
*/
private Map<Long, Deque<Patient>> myIdToPatientVersions = new HashMap<Long, Deque<Patient>>();
/**
* This is used to generate new IDs
*/
private long myNextId = 1;
/**
* Constructor, which pre-populates the provider with one resource instance.
*/
public IhePatientResourceProvider() {
long resourceId = myNextId++;
Patient patient = new Patient();
patient.setId(Long.toString(resourceId));
patient.addIdentifier();
patient.getIdentifier().get(0).setSystem("urn:oid");
patient.getIdentifier().get(0).setValue("00002");
patient.addName().setFamily("Test");
patient.getName().get(0).addGiven("PatientOne");
patient.setGender(AdministrativeGender.FEMALE);
LinkedList<Patient> list = new LinkedList<Patient>();
list.add(patient);
myIdToPatientVersions.put(resourceId, list);
}
/**
* Stores a new version of the patient in memory so that it can be retrieved later.
*
* @param thePatient The patient resource to store
* @param theId The ID of the patient to retrieve
*/
private void addNewVersion(Patient thePatient, Long theId) {
if (!myIdToPatientVersions.containsKey(theId)) {
myIdToPatientVersions.put(theId, new LinkedList<Patient>());
}
thePatient.getMeta().setLastUpdatedElement(InstantType.withCurrentTime());
Deque<Patient> existingVersions = myIdToPatientVersions.get(theId);
// We just use the current number of versions as the next version number
String newVersion = Integer.toString(existingVersions.size());
// Create an ID with the new version and assign it back to the resource
IdType newId = new IdType("Patient", Long.toString(theId), newVersion);
thePatient.setId(newId);
existingVersions.add(thePatient);
}
/**
* The "@Create" annotation indicates that this method implements "create=type", which adds a
* new instance of a resource to the server.
*/
@Create()
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
validateResource(thePatient);
// Here we are just generating IDs sequentially
long id = myNextId++;
addNewVersion(thePatient, id);
// Let the caller know the ID of the newly created resource
return new MethodOutcome(new IdType(id));
}
/**
* The "@Search" annotation indicates that this method supports the search operation. You may have many different method annotated with this annotation, to support many different search criteria.
* This example searches by family name.
*
* @param theFamilyName This operation takes one parameter which is the search criteria. It is annotated with the "@Required" annotation. This annotation takes one argument, a string containing the name of
* the search criteria. The datatype here is StringDt, but there are other possible parameter types depending on the specific search criteria.
* @return This method returns a list of Patients. This list may contain multiple matching resources, or it may also be empty.
*/
@Search()
public List<Patient> findPatientsByName(@RequiredParam(name = Patient.SP_FAMILY) StringType theFamilyName) {
LinkedList<Patient> retVal = new LinkedList<Patient>();
/*
* Look for all patients matching the name
*/
for (Deque<Patient> nextPatientList : myIdToPatientVersions.values()) {
Patient nextPatient = nextPatientList.getLast();
NAMELOOP:
for (HumanName nextName : nextPatient.getName()) {
String nextFamily = nextName.getFamily();
if (theFamilyName.equals(nextFamily)) {
retVal.add(nextPatient);
break NAMELOOP;
}
}
}
return retVal;
}
/**
* Search method for a Patient using the source identifier required parameter
* and an optional list of target system
*
* @param sourceIdentifier : the source identifier of the patient, should be formated "urn:oid:x.x.x.x.x.x.x.x.x.x|value"
* @param targetSystem: the target System(s) we want to find the Patient on, should be formated "urn:oid:x.x.x.x.x.x.x.x.x.x,urn:oid:x.x.x.x.x.x.x.x.x.x,"
*
* @return a Parameters element composed of a list of target identifier for every Patient found, and an url to the Patient in the server.
*/
@Operation(name="$ihe-pix", idempotent = true)
public Parameters findPatientsByIdentifier(@OperationParam(name = "sourceIdentifier",min = 1,max = 1) TokenParam sourceIdentifier,
@OperationParam(name = "targetSystem") StringAndListParam targetSystem) throws PatientResourceProviderException, ForbiddenOperationException, ResourceNotFoundException {
Parameters results = new Parameters();
patientLogger.info("Searching Patient " + sourceIdentifier);
PatientAliases response = new PatientAliases();
int log = 0;
if (sourceIdentifier ==null){
throw new InvalidRequestException("Missing parameter");
}
try {
URL url = new URL("https://qualification.ihe-europe.net/patient-registry/CrossReferenceService/xref-processing-service?wsdl");
XRefSearchClient searchClient = new XRefSearchClient(url);
EntityIdentifier wellFormedEntityIdentifier = new EntityIdentifier();
if (sourceIdentifier.getSystem().contains("urn:oid:")) {
wellFormedEntityIdentifier.setSystemIdentifier(sourceIdentifier.getSystem().replace("urn:oid:", ""));
wellFormedEntityIdentifier.setType("ISO");
}
wellFormedEntityIdentifier.setValue(sourceIdentifier.getValue());
patientLogger.info(wellFormedEntityIdentifier.getValue());
List<String> listTargetSystem = new ArrayList<String>();
if (null != targetSystem) {
for (StringOrListParam nextList : targetSystem.getValuesAsQueryTokens()) {
List<StringParam> queryStrings = nextList.getValuesAsQueryTokens();
for (StringParam singleParam : queryStrings) {
if (singleParam.getValue().equals("")) {
results.addParameter(generateErrorReturn("code-invalid"));
return results;
//throw new ForbiddenOperationException("Won't accept empty targetSystem");
}
listTargetSystem.add(singleParam.getValue());
}
}
}
patientLogger.info(listTargetSystem.toString());
response = searchClient.search(wellFormedEntityIdentifier, listTargetSystem);
patientLogger.info(Integer.toString(log++));
} catch (MalformedURLException e) {
throw new PatientResourceProviderException("Could not find target url for Patient Registry, The given URL might be wrong.", e);
} catch (SearchCrossReferenceException e) {
results.addParameter(generateErrorReturn("code-invalid"));
return results;
//throw new ResourceNotFoundException("Could not find Patient in Patient Registry");
}
patientLogger.info(Integer.toString(log++));
if ( response.getMembers().size() == 0 ) {
results.addParameter(generateErrorReturn("notfound"));
return results;
//throw new ResourceNotFoundException("No crossReferenced Patient found.");
}
patientLogger.info("Number of patents found : " + response.getMembers().size());
for (net.ihe.gazelle.app.patientregistryapi.business.Patient pat : response.getMembers()) {
long id = myNextId++;
patientLogger.info(pat.getNames().get(0).getFamily());
Patient translated = this.translatePatientToR4(pat);
for (EntityIdentifier entity : pat.getIdentifiers()) {
patientLogger.info(Integer.toString(log++));
Identifier r4Identifier = new Identifier();
r4Identifier.setSystem(entity.getSystemIdentifier());
r4Identifier.setValue(entity.getValue());
translated.addIdentifier(r4Identifier);
ParametersParameterComponent alias = new ParametersParameterComponent();
alias.setName("target Identifier");
alias.setValue(r4Identifier);
results.addParameter(alias);
}
ParametersParameterComponent targetId = new ParametersParameterComponent();
targetId.setName("targetId");
Reference ref = new Reference();
ref.setReference("pixm_fhir_server/fhir/Patient/" + id);
targetId.setValue(ref);
results.addParameter(targetId);
patientLogger.info(Integer.toString(log++));
translated.setId(Long.toString(id));
LinkedList<Patient> listToAdd = new LinkedList<>();
listToAdd.add(translated);
myIdToPatientVersions.put(id, listToAdd);
}
results.setId(Long.toString(myNextId++));
patientLogger.info(Integer.toString(log++));
return results;
}
@Search
public List<Patient> findPatientsUsingArbitraryCriteria() {
LinkedList<Patient> retVal = new LinkedList<Patient>();
for (Deque<Patient> nextPatientList : myIdToPatientVersions.values()) {
Patient nextPatient = nextPatientList.getLast();
retVal.add(nextPatient);
}
return retVal;
}
/**
* The getResourceType method comes from IResourceProvider, and must be overridden to indicate what type of resource this provider supplies.
*/
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
/**
* This is the "read" operation. The "@Read" annotation indicates that this method supports the read and/or vread operation.
* <p>
* Read operations take a single parameter annotated with the {@link IdParam} paramater, and should return a single resource instance.
* </p>
*
* @param theId The read operation takes one parameter, which must be of type IdDt and must be annotated with the "@Read.IdParam" annotation.
* @return Returns a resource matching this identifier, or null if none exists.
*/
@Read(version = true)
public Patient readPatient(@IdParam IdType theId) {
Deque<Patient> retVal;
patientLogger.warn("ReadingPatient " + theId.getIdPart());
try {
retVal = myIdToPatientVersions.get(theId.getIdPartAsLong());
} catch (NumberFormatException e) {
/*
* If we can't parse the ID as a long, it's not valid so this is an unknown resource
*/
throw new ResourceNotFoundException(theId);
}
if (retVal == null) {
throw new ResourceNotFoundException(theId);
}
if (theId.hasVersionIdPart() == false) {
return retVal.getLast();
} else {
patientLogger.info("Patient found");
for (Patient nextVersion : retVal) {
String nextVersionId = nextVersion.getIdElement().getVersionIdPart();
if (theId.getVersionIdPart().equals(nextVersionId)) {
return nextVersion;
}
}
patientLogger.warn("Could not find ressource");
// No matching version
throw new ResourceNotFoundException("Unknown version: " + theId.getValue());
}
}
/**
* The "@Update" annotation indicates that this method supports replacing an existing
* resource (by ID) with a new instance of that resource.
*
* @param theId This is the ID of the patient to update
* @param thePatient This is the actual resource to save
* @return This method returns a "MethodOutcome"
*/
@Update()
public MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient) {
validateResource(thePatient);
Long id;
try {
id = theId.getIdPartAsLong();
} catch (DataFormatException e) {
throw new InvalidRequestException("Invalid ID " + theId.getValue() + " - Must be numeric");
}
/*
* Throw an exception (HTTP 404) if the ID is not known
*/
if (!myIdToPatientVersions.containsKey(id)) {
throw new ResourceNotFoundException(theId);
}
addNewVersion(thePatient, id);
return new MethodOutcome();
}
/**
* This method just provides simple business validation for resources we are storing.
*
* @param thePatient The patient to validate
*/
private void validateResource(Patient thePatient) {
/*
* Our server will have a rule that patients must have a family name or we will reject them
*/
if (thePatient.getNameFirstRep().getFamily().isEmpty()) {
OperationOutcome outcome = new OperationOutcome();
outcome.addIssue().setSeverity(IssueSeverity.FATAL).setDiagnostics("No family name provided, Patient resources must have at least one family name.");
throw new UnprocessableEntityException(FhirContext.forDstu3(), outcome);
}
}
/**
* Private Method called to translate a Patient between the model in Patient Registry to the fhir model
* We need to translate a Patient in order to have it in the list of Patient contained in the fhir server
* To later have access to it (through an URL given when searched)
*
* @param patReg : the Patient in the Patient Registry Model
* @return the same Patient translated in the FHIR r4 model.
*/
private Patient translatePatientToR4(net.ihe.gazelle.app.patientregistryapi.business.Patient patReg) {
Patient translatedPatient = new Patient();
translatedPatient.setActive(patReg.isActive());
List<HumanName> nameList = new ArrayList<>();
for (PersonName pName : patReg.getNames()) {
HumanName name = new HumanName();
name.setFamily(pName.getFamily());
List<StringType> givenNames = new ArrayList<>();
for (String given : pName.getGivens()) {
givenNames.add(new StringType(given));
}
name.setGiven(givenNames);
name.addPrefix(pName.getPrefix());
name.addSuffix(pName.getSuffix());
name.setUse(NameUse.fromCode(pName.getUse()));
nameList.add(name);
}
translatedPatient.setName(nameList);
translatedPatient.setGender(AdministrativeGender.fromCode(patReg.getGender().toString().toLowerCase()));
List<Address> addresses = new ArrayList<>();
for (net.ihe.gazelle.app.patientregistryapi.business.Address pAddress : patReg.getAddresses()) {
Address address = new Address();
address.setUse(AddressUse.fromCode(pAddress.getUse().toString().toLowerCase()));
address.setCity(pAddress.getCity());
address.setCountry(pAddress.getCountryIso3());
address.setPostalCode(pAddress.getPostalCode());
address.setState(pAddress.getState());
for(String addressLine : pAddress.getLines())
address.addLine(addressLine);
addresses.add(address);
}
translatedPatient.setAddress(addresses);
translatedPatient.setBirthDate(patReg.getDateOfBirth());
return translatedPatient;
}
/**
* Method used to generate a Parameter Component representing an error in the the Fhir Resource Model
* Permits to display the error.
*
* @param errorType : the code of the error as a String.
* Will be translated as an OperationOutcome.IssueType
* @return A ParametersParameterComponent representing the http error as a Fhir resource
*/
private ParametersParameterComponent generateErrorReturn(String errorType) {
OperationOutcome error = new OperationOutcome();
OperationOutcomeIssueComponent issue = new OperationOutcomeIssueComponent();
issue.setCode(OperationOutcome.IssueType.fromCode(errorType));
error.addIssue(issue);
ParametersParameterComponent errorReturned = new ParametersParameterComponent();
errorReturned.setResource(error);
return errorReturned;
}
}
package net.ihe.gazelle.servlet;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.annotation.WebServlet;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import net.ihe.gazelle.interceptor.LegacyLoggingInterceptor;
import net.ihe.gazelle.provider.IhePatientResourceProvider;
/**
* This servlet is the actual FHIR server itself
*/
@WebServlet(urlPatterns= {"/fhir_ihe/*"}, displayName="FHIR Server IHE")
public class IheHapiFhirServer extends RestfulServer {
private static final long serialVersionUID = 1L;
/**
* Constructor
*/
public IheHapiFhirServer() {
super(FhirContext.forR4()); // This is an R4 server
}
/**
* This method is called automatically when the
* servlet is initializing.
*/
@Override
public void initialize() {
/*
* Two resource providers are defined. Each one handles a specific
* type of resource.
*/
List<IResourceProvider> providers = new ArrayList<IResourceProvider>();
providers.add(new IhePatientResourceProvider());
setResourceProviders(providers);
//creating an interceptor to log in console an error occurring
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
loggingInterceptor.setLoggerName("test.accesslog");
loggingInterceptor.setMessageFormat("Source[$remoteAddr] Operation[${operationType}"
+ "${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]");
registerInterceptor(loggingInterceptor);
//creating an interceptor for special excpetion to dump the stack trace in the logs.
ExceptionHandlingInterceptor exceptionInterceptor = new ExceptionHandlingInterceptor();
exceptionInterceptor.setReturnStackTracesForExceptionTypes(InternalErrorException.class, NullPointerException.class);
registerInterceptor(exceptionInterceptor);
/*
* Use a narrative generator. This is a completely optional step,
* but can be useful as it causes HAPI to generate narratives for
* resources which don't otherwise have one.
*/
INarrativeGenerator narrativeGen = new DefaultThymeleafNarrativeGenerator();
getFhirContext().setNarrativeGenerator(narrativeGen);
}
}
This diff is collapsed.
package net.ihe.gazelle.provider;
import net.ihe.gazelle.business.provider.IhePatientResourceProvider;
import net.ihe.gazelle.business.provider.PatientResourceProviderException;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
import net.ihe.gazelle.provider.IhePatientResourceProvider;
import net.ihe.gazelle.provider.PatientResourceProviderException;
public class ProviderTestClass {
public static final IhePatientResourceProvider provider = new IhePatientResourceProvider();
@Test
public void createPatientTest() {
Patient pat = new Patient();
MethodOutcome ret = provider.createPatient(pat);
Assert.assertNotNull(ret);
}
// @Test
// public void createPatientTest() {
// Patient pat = new Patient();
// MethodOutcome ret = provider.createPatient(pat);
// Assert.assertNotNull(ret);
// }
@Test
public void findPatientsByNameTest() {
StringType param = new StringType("WALTERS");
Assert.assertNotNull(provider.findPatientsByName(param));
}
// @Test
// public void findPatientsByNameTest() {
// StringType param = new StringType("WALTERS");
// Assert.assertNotNull(provider.findPatientsByName(param));
// }
//
@Test
public void findPatientsByIdentifierTest() {
TokenParam sourceIdentifier = new TokenParam();
......@@ -60,14 +57,14 @@ public class ProviderTestClass {
Assert.assertNotNull(provider.findPatientsUsingArbitraryCriteria());
}
@Test
public void readPatientTest() {
IdType param = new IdType();
param.setId("3");
Assert.assertNotNull(provider.readPatient(param));
}
// @Test
// public void readPatientTest() {
// IdType param = new IdType();
// param.setId("3");
//
// Assert.assertNotNull(provider.readPatient(param));
// }
//
@Test
public void updatePatientTest() {
IdType idParam = new IdType();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment