From 2290a0df76bb98002fa3296ac3ce96c3ab4a1980 Mon Sep 17 00:00:00 2001
From: pm <pmvanhouteghem@gmail.com>
Date: Mon, 12 Jul 2021 09:27:53 +0200
Subject: [PATCH] Documentation & few sonar fixes

---
 README.md                                     |  72 ++++-
 .../adapter/servlet/ChHapiFhirServer.java     |   3 -
 .../PatientRegistryXRefSearchClient.java      |   2 +-
 .../interceptor/LegacyLoggingInterceptor.java |   2 +
 .../provider/ChPatientResourceProvider.java   | 280 +-----------------
 5 files changed, 70 insertions(+), 289 deletions(-)

diff --git a/README.md b/README.md
index c5859f8..274d2bf 100644
--- a/README.md
+++ b/README.md
@@ -33,22 +33,82 @@ After building the project through Maven, the artifact created just has to be ad
 
 Once the project deployed on your WildFly, you can now call it to request a cross Referenced Patient in the Patient Registry.
 
+Parameters allowed are :
+
+- The Patient Identifier and the Target System attributed to this identifier
+- The Target System you want the cross reference from.
+- The format returned.
+
+Cardinality for these parameters will be described in each profile since it's the main difference between each.
+
+#### IHE Profile
+
 The URL to call is 
 ```http
     {wildfly18.address}/pixm_fhir_server/fhir_ihe/Patient/$ihe-pix
 ```
-Parameters allowed are :
 
-- The Patient Identifier and the Target System attributed to this identifier
-- The Target System you want the cross reference from.
+
+|Parameter name|Cardinality|Parameter Type|Description|
+|--------------|-----------|--------------|-----------|
+|sourceIdentifier|1..1|Token|The Patient identifier search parameter that will be used by the Patient Identifier Cross-reference Manager to find cross matching identifiers associated with the Patient Resource
+|targetSystem|0..*|uri|The target Patient Identifier Assigning Authority from which the returned identifiers should be selected.|
+|_format|0..1|mime-type|The requested format of the response. Accepted values : JSON and XML|
+
+#### CH Profile
+
+The URL to call is 
+```http
+    {wildfly18.address}/pixm_fhir_server/fhir_ch/Patient/$ihe-pix
+```
+
+
+|Parameter name|Cardinality|Parameter Type|Description|
+|--------------|-----------|--------------|-----------|
+|sourceIdentifier|1..1|Token|The Patient identifier search parameter that will be used by the Patient Identifier Cross-reference Manager to find cross matching identifiers associated with the Patient Resource
+|targetSystem|1..2|uri|The target Patient Identifier Assigning Authority from which the returned identifiers should be selected.|
+|_format|0..1|mime-type|The requested format of the response. Accepted values : JSON and XML|
 
 For example :
-Given the Patient with the ID 69420 in the Target System 1:2:3:4:5023:31520
-And you want the cross referenced patient in the target system 5:6:7:8:0587:79085
+Given the Patient with the ID 69420 in the Target System 1.3.6.1.4.1.21367.13.20.3000
+And you want the cross referenced patient in the target system 1.3.6.1.4.1.21367.13.20.1000
 
 The corresponding url will be :
 
+```http 
+    {wildfly18.address}/pixm_fhir_server/fhir_ihe/Patient/$ihe-pix?sourceIdentifier=urn:oid:1.3.6.1.4.1.21367.13.20.3000|69420&targetSystem=urn:oid:1.3.6.1.4.1.21367.13.20.1000
+```
+
+---
+### Error returned
+Malformed requests can cause different types of error, here is a quick overview of how to troubleshoot them :
+
+![nice cat](http://http.cat/400)
+An error 400 Bad Request is returned when the source domain given within the source identifier parameter is not recognized by the Patient Registry as an asigning authority.
+In the case of our request above, the value "urn:oid:1.3.6.1.4.1.21367.13.20.3000" is not a valid source domain able to register Patients
+
+Common mistakes with the source domain include :
+- Forgetting the namespace in front of the adress (urn:oid:)
+- Malformed source domain.
+The source domain can have the form of an url 
 ```http
-    {wildfly18.address}/pixm_fhir_server/fhir_ihe/Patient/$ihe-pix?sourceIdentifier=urn:oid:1:2:3:4:5023:31520|69420&targetSystem=5:6:7:8:0587:79085
+sourceIdentifier=https://your.domain|id
 ```
+or of an adress, which must follows the pattern x.x.x.x.x.x.x.x.x.x
+```http
+sourceIdentifier=urn:oid:x.x.x.x.x.x.x.x.x.x|id
+```
+
+---
+![dumb cat](http://http.cat/403)
+
+An error 403 Forbidden is returned when a target domain given in the target system parameter is not recognized by the Patient Registry.
+In the case of our request above, the value "urn:oid:1.3.6.1.4.1.21367.13.20.1000" is not recognized as a valid target domain containing Patients.
+
+Common mistakes with the target system are the same as the aformentioned error 400 since the target system and the source domain have the same representation.
+
+---
+![cute cat](http://http.cat/404)
 
+An error 404 Not Found is returned when the patient identifier given within the source identifier parameter is not recognized by the Patient registry.
+In the case of our request above, the value "69420" is not a valid Identifier linked to an existing Patient.
diff --git a/src/main/java/net/ihe/gazelle/adapter/servlet/ChHapiFhirServer.java b/src/main/java/net/ihe/gazelle/adapter/servlet/ChHapiFhirServer.java
index 70ce408..95ecb2e 100644
--- a/src/main/java/net/ihe/gazelle/adapter/servlet/ChHapiFhirServer.java
+++ b/src/main/java/net/ihe/gazelle/adapter/servlet/ChHapiFhirServer.java
@@ -14,10 +14,7 @@ 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.business.interceptor.LegacyLoggingInterceptor;
 import net.ihe.gazelle.business.provider.ChPatientResourceProvider;
-import net.ihe.gazelle.business.provider.IhePatientResourceProvider;
 
 /**
  * This servlet is the actual FHIR server itself
diff --git a/src/main/java/net/ihe/gazelle/application/PatientRegistryXRefSearchClient.java b/src/main/java/net/ihe/gazelle/application/PatientRegistryXRefSearchClient.java
index eaac73d..dcafd02 100644
--- a/src/main/java/net/ihe/gazelle/application/PatientRegistryXRefSearchClient.java
+++ b/src/main/java/net/ihe/gazelle/application/PatientRegistryXRefSearchClient.java
@@ -225,7 +225,7 @@ public class PatientRegistryXRefSearchClient {
         try {
             ip = InetAddress.getLocalHost();
             serverUrl = ip.getCanonicalHostName();
-            System.out.println("Your current Hostname : " + serverUrl);
+            logger.info(String.format("Your current Hostname : %s", serverUrl));
 
         } catch (UnknownHostException exception) {
             logger.error("Unable to find serverUrl");
diff --git a/src/main/java/net/ihe/gazelle/business/interceptor/LegacyLoggingInterceptor.java b/src/main/java/net/ihe/gazelle/business/interceptor/LegacyLoggingInterceptor.java
index 3bf84bc..6bfc937 100644
--- a/src/main/java/net/ihe/gazelle/business/interceptor/LegacyLoggingInterceptor.java
+++ b/src/main/java/net/ihe/gazelle/business/interceptor/LegacyLoggingInterceptor.java
@@ -28,6 +28,7 @@ public class LegacyLoggingInterceptor extends InterceptorAdapter {
 		return true; // Processing should continue
 	}
 
+	@Override
 	@Hook(Pointcut.SERVER_HANDLE_EXCEPTION)
 	public boolean handleException(
 			RequestDetails theRequestDetails,
@@ -48,6 +49,7 @@ public class LegacyLoggingInterceptor extends InterceptorAdapter {
 		return false;
 	}	
 
+	@Override
 	@Hook(Pointcut.SERVER_OUTGOING_RESPONSE)
 	public boolean outgoingResponse(RequestDetails theRequestDetails) {
 		ServletRequestDetails details = (ServletRequestDetails) theRequestDetails;
diff --git a/src/main/java/net/ihe/gazelle/business/provider/ChPatientResourceProvider.java b/src/main/java/net/ihe/gazelle/business/provider/ChPatientResourceProvider.java
index 391036c..609ec60 100644
--- a/src/main/java/net/ihe/gazelle/business/provider/ChPatientResourceProvider.java
+++ b/src/main/java/net/ihe/gazelle/business/provider/ChPatientResourceProvider.java
@@ -41,114 +41,6 @@ public class ChPatientResourceProvider implements IResourceProvider {
     private PatientRegistryXRefSearchClient patientRegistryXRefSearchClient;
     private static final Logger patientLogger = LoggerFactory.getLogger(ChPatientResourceProvider.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 ChPatientResourceProvider() {
-        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
@@ -174,18 +66,6 @@ public class ChPatientResourceProvider implements IResourceProvider {
         return parametersResults;
     }
 
-    @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.
@@ -193,165 +73,7 @@ public class ChPatientResourceProvider implements IResourceProvider {
     @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 errorCode) {
-        OperationOutcome error = new OperationOutcome();
-        OperationOutcomeIssueComponent issue = new OperationOutcomeIssueComponent();
-        issue.setCode(OperationOutcome.IssueType.fromCode(errorCode));
-        error.addIssue(issue);
-        ParametersParameterComponent errorReturned = new ParametersParameterComponent();
-        errorReturned.setResource(error);
-        return errorReturned;
-    }
-
+    } 	
 
     private EntityIdentifier createEntityIdentifierFromSourceIdentifier(TokenParam sourceIdentifier) {
         if (sourceIdentifier == null) {
-- 
GitLab