diff --git a/.gitignore b/.gitignore
index 108173a..82bf165 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,72 @@
-target/
-.project
-.classpath
-.settings/
-.DS_Store
-.idea/
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+.idea/artifacts
+.idea/compiler.xml
+.idea/jarRepositories.xml
+.idea/modules.xml
+.idea/*.iml
+.idea/modules
*.iml
*.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
*.iws
-logfile
-*.log*
\ No newline at end of file
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+target/
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..c89a2f0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/../../../../../../../:\Users\khannan\source\repos\hfr-mediator\.idea/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..919ce1f
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..4361200
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/All_Tests.xml b/.idea/runConfigurations/All_Tests.xml
new file mode 100644
index 0000000..0f5b76a
--- /dev/null
+++ b/.idea/runConfigurations/All_Tests.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Build.xml b/.idea/runConfigurations/Build.xml
new file mode 100644
index 0000000..5f179c6
--- /dev/null
+++ b/.idea/runConfigurations/Build.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 67f9db7..9c2783c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,28 @@
file:///${project.basedir}/local-maven-repo
+
+
+ dnchembi_at_softmed_dot_co_dot_tz
+ Danford Nchembi
+ SoftMed Technologies
+
+
+ ilakozejumanne_at_softmed_dot_co_dot_tz
+ Ilakoze Jumanne
+ SoftMed Technologies
+
+
+ ibrahimmo_at_hhsc_dot_ca
+ Mohamed Ibrahim
+ Hamilton Health Sciences
+
+
+ khannani_at_hhsc_dot_ca
+ Nityan Khanna
+ Hamilton Health Sciences
+
+
@@ -21,8 +43,8 @@
maven-compiler-plugin
3.2
-
- 1.7
+
+ 1.8
@@ -41,7 +63,7 @@
- tz.go.moh.him.elmis.mediator.e9.MediatorMain
+ tz.go.moh.him.hfr.mediator.MediatorMain
@@ -84,6 +106,32 @@
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.2.0
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
@@ -101,7 +149,7 @@
junit
junit
- 4.12
+ 4.13.1
test
diff --git a/src/main/java/tz/go/moh/him/hfr/mediator/DefaultOrchestrator.java b/src/main/java/tz/go/moh/him/hfr/mediator/DefaultOrchestrator.java
deleted file mode 100644
index 1b45ca3..0000000
--- a/src/main/java/tz/go/moh/him/hfr/mediator/DefaultOrchestrator.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package tz.go.moh.him.hfr.mediator;
-
-import akka.actor.UntypedActor;
-import akka.event.Logging;
-import akka.event.LoggingAdapter;
-import org.apache.http.HttpStatus;
-import org.openhim.mediator.engine.MediatorConfig;
-import org.openhim.mediator.engine.messages.FinishRequest;
-import org.openhim.mediator.engine.messages.MediatorHTTPRequest;
-
-public class DefaultOrchestrator extends UntypedActor {
- LoggingAdapter log = Logging.getLogger(getContext().system(), this);
-
- private final MediatorConfig config;
-
-
- public DefaultOrchestrator(MediatorConfig config) {
- this.config = config;
- }
-
- @Override
- public void onReceive(Object msg) throws Exception {
- if (msg instanceof MediatorHTTPRequest) {
- FinishRequest finishRequest = new FinishRequest("A message from my new mediator!", "text/plain", HttpStatus.SC_OK);
- ((MediatorHTTPRequest) msg).getRequestHandler().tell(finishRequest, getSelf());
- } else {
- unhandled(msg);
- }
- }
-}
diff --git a/src/main/java/tz/go/moh/him/hfr/mediator/MediatorMain.java b/src/main/java/tz/go/moh/him/hfr/mediator/MediatorMain.java
index d7cf1e2..a891678 100644
--- a/src/main/java/tz/go/moh/him/hfr/mediator/MediatorMain.java
+++ b/src/main/java/tz/go/moh/him/hfr/mediator/MediatorMain.java
@@ -6,36 +6,61 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.openhim.mediator.engine.*;
+import tz.go.moh.him.hfr.mediator.orchestrator.AcknowledgementOrchestrator;
+import tz.go.moh.him.hfr.mediator.orchestrator.FacilityOrchestrator;
+
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
+/**
+ * Represents the main application.
+ */
public class MediatorMain {
+ /**
+ * Represents the mediator registration info.
+ */
+ private static final String MEDIATOR_REGISTRATION_INFO = "mediator-registration-info.json";
+
+ /**
+ * Builds the routing table.
+ *
+ * @return Returns the routing table.
+ * @throws RoutingTable.RouteAlreadyMappedException if the route is already mapped
+ */
private static RoutingTable buildRoutingTable() throws RoutingTable.RouteAlreadyMappedException {
RoutingTable routingTable = new RoutingTable();
- //TODO Configure routes here
- //...
- routingTable.addRoute("/hfr", DefaultOrchestrator.class);
+ routingTable.addRoute("/hfr", FacilityOrchestrator.class);
+ routingTable.addRoute("/hfr-ack", AcknowledgementOrchestrator.class);
return routingTable;
}
+ /**
+ * Builds the startup actors configuration.
+ *
+ * @return Returns the startup actors configuration.
+ */
private static StartupActorsConfig buildStartupActorsConfig() {
- StartupActorsConfig startupActors = new StartupActorsConfig();
-
- //TODO Add own startup actors here
- //...
-
- return startupActors;
+ return new StartupActorsConfig();
}
+ /**
+ * Loads the configuration.
+ *
+ * @param configPath The path of the configuration.
+ * @return Returns the configuration instance.
+ * @throws IOException if an IO exception occurs
+ * @throws RoutingTable.RouteAlreadyMappedException if the route is already mapped
+ */
private static MediatorConfig loadConfig(String configPath) throws IOException, RoutingTable.RouteAlreadyMappedException {
MediatorConfig config = new MediatorConfig();
- if (configPath!=null) {
+ if (configPath != null) {
Properties props = new Properties();
File conf = new File(configPath);
InputStream in = FileUtils.openInputStream(conf);
@@ -49,7 +74,7 @@ private static MediatorConfig loadConfig(String configPath) throws IOException,
config.setName(config.getProperty("mediator.name"));
config.setServerHost(config.getProperty("mediator.host"));
- config.setServerPort( Integer.parseInt(config.getProperty("mediator.port")) );
+ config.setServerPort(Integer.parseInt(config.getProperty("mediator.port")));
config.setRootTimeout(Integer.parseInt(config.getProperty("mediator.timeout")));
config.setCoreHost(config.getProperty("core.host"));
@@ -62,18 +87,31 @@ private static MediatorConfig loadConfig(String configPath) throws IOException,
config.setRoutingTable(buildRoutingTable());
config.setStartupActors(buildStartupActorsConfig());
- InputStream regInfo = MediatorMain.class.getClassLoader().getResourceAsStream("mediator-registration-info.json");
- RegistrationConfig regConfig = new RegistrationConfig(regInfo);
+ InputStream registrationInformation = MediatorMain.class.getClassLoader().getResourceAsStream(MEDIATOR_REGISTRATION_INFO);
+
+ if (registrationInformation == null) {
+ throw new FileNotFoundException("Unable to locate " + MEDIATOR_REGISTRATION_INFO);
+ }
+
+ RegistrationConfig regConfig = new RegistrationConfig(registrationInformation);
+
config.setRegistrationConfig(regConfig);
- if (config.getProperty("mediator.heartbeats")!=null && "true".equalsIgnoreCase(config.getProperty("mediator.heartbeats"))) {
+ if (config.getProperty("mediator.heartbeats") != null && "true".equalsIgnoreCase(config.getProperty("mediator.heartbeats"))) {
config.setHeartbeatsEnabled(true);
}
return config;
}
+ /**
+ * The main entry point of the application.
+ *
+ * @param args The arguments.
+ * @throws Exception if an exception occurs
+ */
public static void main(String... args) throws Exception {
+
//setup actor system
final ActorSystem system = ActorSystem.create("mediator");
//setup logger for main
@@ -83,7 +121,7 @@ public static void main(String... args) throws Exception {
log.info("Initializing mediator actors...");
String configPath = null;
- if (args.length==2 && args[0].equals("--conf")) {
+ if (args != null && args.length == 2 && args[0].equals("--conf")) {
configPath = args[1];
log.info("Loading mediator configuration from '" + configPath + "'...");
} else {
@@ -91,17 +129,17 @@ public static void main(String... args) throws Exception {
}
MediatorConfig config = loadConfig(configPath);
+
+ config.setSSLContext(new MediatorConfig.SSLContext(true));
+
final MediatorServer server = new MediatorServer(system, config);
//setup shutdown hook
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() {
- log.info("Shutting down mediator");
- server.stop();
- system.shutdown();
- }
- });
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ log.info("Shutting down mediator");
+ server.stop();
+ system.shutdown();
+ }));
log.info("Starting mediator server...");
server.start();
diff --git a/src/main/java/tz/go/moh/him/hfr/mediator/domain/Ack.java b/src/main/java/tz/go/moh/him/hfr/mediator/domain/Ack.java
new file mode 100644
index 0000000..ba02dff
--- /dev/null
+++ b/src/main/java/tz/go/moh/him/hfr/mediator/domain/Ack.java
@@ -0,0 +1,77 @@
+package tz.go.moh.him.hfr.mediator.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents an acknowledgement.
+ */
+public class Ack {
+
+ /**
+ * The transaction id number.
+ */
+ @JsonProperty("IL_IDNumber")
+ @SerializedName("IL_IDNumber")
+ private String transactionIdNumber;
+
+ /**
+ * The status.
+ */
+ @JsonProperty("status")
+ @SerializedName("status")
+ private String status;
+
+ /**
+ * Initializes a new instance of the {@link Ack} class.
+ */
+ public Ack() {
+ }
+
+ /**
+ * Initializes a new instance of the {@link Ack} class.
+ *
+ * @param transactionIdNumber The transaction id number.
+ * @param status The status.
+ */
+ public Ack(String transactionIdNumber, String status) {
+ this.setTransactionIdNumber(transactionIdNumber);
+ this.setStatus(status);
+ }
+
+ /**
+ * Gets the transaction id number.
+ *
+ * @return Returns the transaction id number.
+ */
+ public String getTransactionIdNumber() {
+ return transactionIdNumber;
+ }
+
+ /**
+ * Sets the transaction id number.
+ *
+ * @param transactionIdNumber The transaction id number.
+ */
+ public void setTransactionIdNumber(String transactionIdNumber) {
+ this.transactionIdNumber = transactionIdNumber;
+ }
+
+ /**
+ * Gets the status.
+ *
+ * @return Returns the status.
+ */
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the status.
+ *
+ * @param status The status.
+ */
+ public void setStatus(String status) {
+ this.status = status;
+ }
+}
diff --git a/src/main/java/tz/go/moh/him/hfr/mediator/domain/HfrRequest.java b/src/main/java/tz/go/moh/him/hfr/mediator/domain/HfrRequest.java
new file mode 100644
index 0000000..afdf9f8
--- /dev/null
+++ b/src/main/java/tz/go/moh/him/hfr/mediator/domain/HfrRequest.java
@@ -0,0 +1,447 @@
+package tz.go.moh.him.hfr.mediator.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.HashMap;
+
+/**
+ * Represents a Health Facility Registry request message.
+ */
+public class HfrRequest {
+
+ /**
+ * Represents the operation map for the post or update field.
+ */
+ public static final HashMap OPERATION_MAP = new HashMap() {{
+ put("P", "POST");
+ put("U", "PUT");
+ }};
+
+ /**
+ * The transaction id number from the IL.
+ */
+ @JsonProperty("IL_IDNumber")
+ @SerializedName("IL_IDNumber")
+ private String transactionIdNumber;
+ /**
+ * The facility id number.
+ */
+ @JsonProperty("Fac_IDNumber")
+ @SerializedName("Fac_IDNumber")
+ private String facilityIdNumber;
+ /**
+ * The facility name.
+ */
+ @JsonProperty("Name")
+ @SerializedName("Name")
+ private String name;
+ /**
+ * The common facility name.
+ */
+ @JsonProperty("Comm_FacName")
+ @SerializedName("Comm_FacName")
+ private String commonFacilityName;
+ /**
+ * The zone.
+ */
+ @JsonProperty("Zone")
+ @SerializedName("Zone")
+ private String zone;
+ /**
+ * The region.
+ */
+ @JsonProperty("Region")
+ @SerializedName("Region")
+ private String region;
+ /**
+ * The region code.
+ */
+ @JsonProperty("RegionCode")
+ @SerializedName("RegionCode")
+ private String regionCode;
+ /**
+ * The district.
+ */
+ @JsonProperty("District")
+ @SerializedName("District")
+ private String district;
+ /**
+ * The district code.
+ */
+ @JsonProperty("DistrictCode")
+ @SerializedName("DistrictCode")
+ private String districtCode;
+ /**
+ * The council.
+ */
+ @JsonProperty("Council")
+ @SerializedName("Council")
+ private String council;
+ /**
+ * The council code.
+ */
+ @JsonProperty("CouncilCode")
+ @SerializedName("CouncilCode")
+ private String councilCode;
+ /**
+ * The ward.
+ */
+ @JsonProperty("Ward")
+ @SerializedName("Ward")
+ private String ward;
+ /**
+ * The village street.
+ */
+ @JsonProperty("VillageMtaa")
+ @SerializedName("VillageMtaa")
+ private String villageMtaa;
+ /**
+ * The facility type group.
+ */
+ @JsonProperty("FacilityTypeGroup")
+ @SerializedName("FacilityTypeGroup")
+ private String facilityTypeGroup;
+ /**
+ * The facility type group code.
+ */
+ @JsonProperty("FacilityTypeGroupCode")
+ @SerializedName("FacilityTypeGroupCode")
+ private String facilityTypeGroupCode;
+ /**
+ * The facility type.
+ */
+ @JsonProperty("FacilityType")
+ @SerializedName("FacilityType")
+ private String facilityType;
+ /**
+ * The facility type code.
+ */
+ @JsonProperty("FacilityTypeCode")
+ @SerializedName("FacilityTypeCode")
+ private String facilityTypeCode;
+ /**
+ * The ownership group.
+ */
+ @JsonProperty("OwnershipGroup")
+ @SerializedName("OwnershipGroup")
+ private String ownershipGroup;
+ /**
+ * The ownership group code.
+ */
+ @JsonProperty("OwnershipGroupCode")
+ @SerializedName("OwnershipGroupCode")
+ private String ownershipGroupCode;
+ /**
+ * The ownership.
+ */
+ @JsonProperty("Ownership")
+ @SerializedName("Ownership")
+ private String ownership;
+ /**
+ * The ownership code.
+ */
+ @JsonProperty("OwnershipCode")
+ @SerializedName("OwnershipCode")
+ private String ownershipCode;
+ /**
+ * The operating status.
+ */
+ @JsonProperty("OperatingStatus")
+ @SerializedName("OperatingStatus")
+ private String operatingStatus;
+ /**
+ * The latitude.
+ */
+ @JsonProperty("Latitude")
+ @SerializedName("Latitude")
+ private String latitude;
+ /**
+ * The longitude.
+ */
+ @JsonProperty("Longitude")
+ @SerializedName("Longitude")
+ private String longitude;
+ /**
+ * The registration status.
+ */
+ @JsonProperty("RegistrationStatus")
+ @SerializedName("RegistrationStatus")
+ private String registrationStatus;
+ /**
+ * The date time at which the record was created.
+ */
+ @JsonProperty("CreatedAt")
+ @SerializedName("CreatedAt")
+ private String createdAt;
+ /**
+ * The date time at which the record was updated.
+ */
+ @JsonProperty("UpdatedAt")
+ @SerializedName("UpdatedAt")
+ private String updatedAt;
+ /**
+ * The indicator as to whether the operating status changed from open to closed.
+ */
+ @JsonProperty("OSchangeOpenedtoClose")
+ @SerializedName("OSchangeOpenedtoClose")
+ private String operatingStatusChangeOpenToClosed;
+ /**
+ * The indicator as to whether the operating status changed from closed to operational.
+ */
+ @JsonProperty("OSchangeClosedtoOperational")
+ @SerializedName("OSchangeClosedtoOperational")
+ private String operatingStatusChangeClosedToOperational;
+ /**
+ * The indicator as to whether this message is a create or update.
+ */
+ @JsonProperty("PostorUpdate")
+ @SerializedName("PostorUpdate")
+ private String postOrUpdate;
+
+ /**
+ * Initializes a new instance of the {@link HfrRequest} class.
+ */
+ public HfrRequest() {
+ }
+
+ public String getFacilityIdNumber() {
+ return facilityIdNumber;
+ }
+
+ public void setFacilityIdNumber(String facilityIdNumber) {
+ this.facilityIdNumber = facilityIdNumber;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getCommonFacilityName() {
+ return commonFacilityName;
+ }
+
+ public void setCommonFacilityName(String commonFacilityName) {
+ this.commonFacilityName = commonFacilityName;
+ }
+
+ public String getZone() {
+ return zone;
+ }
+
+ public void setZone(String zone) {
+ this.zone = zone;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public void setRegion(String region) {
+ this.region = region;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public void setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ }
+
+ public String getDistrict() {
+ return district;
+ }
+
+ public void setDistrict(String district) {
+ this.district = district;
+ }
+
+ public String getDistrictCode() {
+ return districtCode;
+ }
+
+ public void setDistrictCode(String districtCode) {
+ this.districtCode = districtCode;
+ }
+
+ public String getCouncil() {
+ return council;
+ }
+
+ public void setCouncil(String council) {
+ this.council = council;
+ }
+
+ public String getCouncilCode() {
+ return councilCode;
+ }
+
+ public void setCouncilCode(String councilCode) {
+ this.councilCode = councilCode;
+ }
+
+ public String getWard() {
+ return ward;
+ }
+
+ public void setWard(String ward) {
+ this.ward = ward;
+ }
+
+ public String getVillageMtaa() {
+ return villageMtaa;
+ }
+
+ public void setVillageMtaa(String villageMtaa) {
+ this.villageMtaa = villageMtaa;
+ }
+
+ public String getFacilityTypeGroup() {
+ return facilityTypeGroup;
+ }
+
+ public void setFacilityTypeGroup(String facilityTypeGroup) {
+ this.facilityTypeGroup = facilityTypeGroup;
+ }
+
+ public String getFacilityTypeGroupCode() {
+ return facilityTypeGroupCode;
+ }
+
+ public void setFacilityTypeGroupCode(String facilityTypeGroupCode) {
+ this.facilityTypeGroupCode = facilityTypeGroupCode;
+ }
+
+ public String getFacilityType() {
+ return facilityType;
+ }
+
+ public void setFacilityType(String facilityType) {
+ this.facilityType = facilityType;
+ }
+
+ public String getFacilityTypeCode() {
+ return facilityTypeCode;
+ }
+
+ public void setFacilityTypeCode(String facilityTypeCode) {
+ this.facilityTypeCode = facilityTypeCode;
+ }
+
+ public String getOwnershipGroup() {
+ return ownershipGroup;
+ }
+
+ public void setOwnershipGroup(String ownershipGroup) {
+ this.ownershipGroup = ownershipGroup;
+ }
+
+ public String getOwnershipGroupCode() {
+ return ownershipGroupCode;
+ }
+
+ public void setOwnershipGroupCode(String ownershipGroupCode) {
+ this.ownershipGroupCode = ownershipGroupCode;
+ }
+
+ public String getOwnership() {
+ return ownership;
+ }
+
+ public void setOwnership(String ownership) {
+ this.ownership = ownership;
+ }
+
+ public String getOwnershipCode() {
+ return ownershipCode;
+ }
+
+ public void setOwnershipCode(String ownershipCode) {
+ this.ownershipCode = ownershipCode;
+ }
+
+ public String getOperatingStatus() {
+ return operatingStatus;
+ }
+
+ public void setOperatingStatus(String operatingStatus) {
+ this.operatingStatus = operatingStatus;
+ }
+
+ public String getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(String latitude) {
+ this.latitude = latitude;
+ }
+
+ public String getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(String longitude) {
+ this.longitude = longitude;
+ }
+
+ public String getRegistrationStatus() {
+ return registrationStatus;
+ }
+
+ public void setRegistrationStatus(String registrationStatus) {
+ this.registrationStatus = registrationStatus;
+ }
+
+ public String getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(String createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public String getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(String updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public String getOperatingStatusChangeOpenToClosed() {
+ return operatingStatusChangeOpenToClosed;
+ }
+
+ public void setOperatingStatusChangeOpenToClosed(String operatingStatusChangeOpenToClosed) {
+ this.operatingStatusChangeOpenToClosed = operatingStatusChangeOpenToClosed;
+ }
+
+ public String getOperatingStatusChangeClosedToOperational() {
+ return operatingStatusChangeClosedToOperational;
+ }
+
+ public void setOperatingStatusChangeClosedToOperational(String operatingStatusChangeClosedToOperational) {
+ this.operatingStatusChangeClosedToOperational = operatingStatusChangeClosedToOperational;
+ }
+
+ public String getPostOrUpdate() {
+ return postOrUpdate;
+ }
+
+ public void setPostOrUpdate(String postOrUpdate) {
+ this.postOrUpdate = postOrUpdate;
+ }
+
+ public String getTransactionIdNumber() {
+ return transactionIdNumber;
+ }
+
+ public void setTransactionIdNumber(String transactionIdNumber) {
+ this.transactionIdNumber = transactionIdNumber;
+ }
+}
diff --git a/src/main/java/tz/go/moh/him/hfr/mediator/orchestrator/AcknowledgementOrchestrator.java b/src/main/java/tz/go/moh/him/hfr/mediator/orchestrator/AcknowledgementOrchestrator.java
new file mode 100644
index 0000000..ff1bde8
--- /dev/null
+++ b/src/main/java/tz/go/moh/him/hfr/mediator/orchestrator/AcknowledgementOrchestrator.java
@@ -0,0 +1,138 @@
+package tz.go.moh.him.hfr.mediator.orchestrator;
+
+import akka.actor.ActorSelection;
+import akka.actor.UntypedActor;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import com.google.gson.Gson;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.http.HttpStatus;
+import org.json.JSONObject;
+import org.openhim.mediator.engine.MediatorConfig;
+import org.openhim.mediator.engine.messages.FinishRequest;
+import org.openhim.mediator.engine.messages.MediatorHTTPRequest;
+import org.openhim.mediator.engine.messages.MediatorHTTPResponse;
+import tz.go.moh.him.hfr.mediator.domain.Ack;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents an acknowledgement orchestrator.
+ */
+public class AcknowledgementOrchestrator extends UntypedActor {
+ /**
+ * The logger instance.
+ */
+ private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+ /**
+ * The mediator configuration.
+ */
+ private final MediatorConfig config;
+
+ /**
+ * Represents an EPICOR ACK.
+ */
+ private Ack ack;
+
+ /**
+ * Represents a mediator request.
+ */
+ private MediatorHTTPRequest workingRequest;
+
+ /**
+ * Initializes a new instance of the {@link AcknowledgementOrchestrator} class.
+ *
+ * @param config The mediator configuration.
+ */
+ public AcknowledgementOrchestrator(MediatorConfig config) {
+ this.config = config;
+ }
+
+ /**
+ * Handles the received message.
+ *
+ * @param msg The received message.
+ */
+ @Override
+ public void onReceive(Object msg) {
+ if (msg instanceof MediatorHTTPRequest) {
+ this.workingRequest = (MediatorHTTPRequest) msg;
+ this.ack = new Gson().fromJson(((MediatorHTTPRequest) msg).getBody(), Ack.class);
+ obtainOpenHIMTransactionByTransactionId(ack.getTransactionIdNumber());
+ } else if (msg instanceof MediatorHTTPResponse) {
+ this.log.info("Received feedback from core");
+ this.log.debug("Core Response code: " + ((MediatorHTTPResponse) msg).getStatusCode());
+ this.log.debug("Core Response body: " + ((MediatorHTTPResponse) msg).getBody());
+ updateOpenHIMTransactionByTransactionId(new JSONObject(((MediatorHTTPResponse) msg).getBody()));
+
+ FinishRequest finishRequest = new FinishRequest("", "text/plain", HttpStatus.SC_OK);
+
+ this.workingRequest.getRequestHandler().tell(finishRequest, getSelf());
+ }
+ }
+
+ /**
+ * Retrieves the OpenHIM transaction by id.
+ *
+ * @param transactionId The transaction id.
+ */
+ private void obtainOpenHIMTransactionByTransactionId(String transactionId) {
+
+ Map headers = new HashMap<>();
+
+ headers.put("Content-Type", "application/json");
+
+ List> params = new ArrayList<>();
+
+ MediatorHTTPRequest obtainOpenHIMTransactionRequest = new MediatorHTTPRequest(
+ (this.workingRequest).getRequestHandler(), getSelf(), "Obtaining OpenHIM Transaction by transactionId", "GET", this.config.getProperty("core.scheme"),
+ this.config.getProperty("core.host"), Integer.parseInt(config.getProperty("core.api.port")), "/transactions/" + transactionId,
+ null, headers, params
+ );
+
+ ActorSelection coreApiConnector = getContext().actorSelection(config.userPathFor("core-api-connector"));
+
+ coreApiConnector.tell(obtainOpenHIMTransactionRequest, getSelf());
+ }
+
+ /**
+ * Updates the OpenHIM transaction status.
+ *
+ * @param transaction The transaction.
+ */
+ private void updateOpenHIMTransactionByTransactionId(JSONObject transaction) {
+ this.log.debug("Updating OpenHIM Transaction with ACK");
+
+ if (this.ack.getStatus().equals("Success")) {
+ transaction.getJSONObject("response").put("status", HttpStatus.SC_OK);
+ transaction.put("status", "Successful");
+ } else {
+ transaction.getJSONObject("response").put("status", HttpStatus.SC_BAD_REQUEST);
+ transaction.put("status", "Failed");
+ }
+
+ transaction.getJSONObject("response").put("body", new Gson().toJson(this.ack));
+ transaction.getJSONObject("response").put("timestamp", new Timestamp(System.currentTimeMillis()));
+
+ Map headers = new HashMap<>();
+
+ headers.put("Content-Type", "application/json");
+
+ List> params = new ArrayList<>();
+
+ MediatorHTTPRequest obtainOpenHIMTransactionRequest = new MediatorHTTPRequest(
+ (this.workingRequest).getRequestHandler(), getSelf(), "Updating OpenHIM Transaction by transactionId", "PUT", this.config.getProperty("epicor.scheme"),
+ this.config.getProperty("core.host"), Integer.parseInt(this.config.getProperty("core.api.port")), "/transactions/" + this.ack.getTransactionIdNumber(),
+ transaction.toString(), headers, params
+ );
+
+ ActorSelection coreApiConnector = getContext().actorSelection(config.userPathFor("core-api-connector"));
+
+ coreApiConnector.tell(obtainOpenHIMTransactionRequest, getSelf());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/tz/go/moh/him/hfr/mediator/orchestrator/FacilityOrchestrator.java b/src/main/java/tz/go/moh/him/hfr/mediator/orchestrator/FacilityOrchestrator.java
new file mode 100644
index 0000000..84e24b3
--- /dev/null
+++ b/src/main/java/tz/go/moh/him/hfr/mediator/orchestrator/FacilityOrchestrator.java
@@ -0,0 +1,92 @@
+package tz.go.moh.him.hfr.mediator.orchestrator;
+
+import akka.actor.ActorSelection;
+import akka.actor.UntypedActor;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import com.google.gson.Gson;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.tuple.Pair;
+import org.openhim.mediator.engine.MediatorConfig;
+import org.openhim.mediator.engine.messages.MediatorHTTPRequest;
+import org.openhim.mediator.engine.messages.MediatorHTTPResponse;
+import tz.go.moh.him.hfr.mediator.domain.HfrRequest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a facility orchestrator.
+ */
+public class FacilityOrchestrator extends UntypedActor {
+ /**
+ * The logger instance.
+ */
+ protected final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+ /**
+ * The mediator configuration.
+ */
+ protected final MediatorConfig config;
+
+ /**
+ * Represents a mediator request.
+ */
+ protected MediatorHTTPRequest workingRequest;
+
+ /**
+ * Initializes a new instance of the {@link FacilityOrchestrator} class.
+ *
+ * @param config The mediator configuration.
+ */
+ public FacilityOrchestrator(MediatorConfig config) {
+ this.config = config;
+ }
+
+ /**
+ * Handles the received message.
+ *
+ * @param msg The received message.
+ */
+ @Override
+ public void onReceive(Object msg) {
+ if (msg instanceof MediatorHTTPRequest) {
+
+ workingRequest = (MediatorHTTPRequest) msg;
+
+ log.info("Received request: " + workingRequest.getHost() + " " + workingRequest.getMethod() + " " + workingRequest.getPath());
+
+ Map headers = new HashMap<>();
+
+ headers.put("Content-Type", "application/json");
+
+ if (Boolean.TRUE.toString().equals(config.getProperty("destination.auth.local.enabled"))) {
+ headers.put("Authorization", String.format("Basic: %s", Base64.encodeBase64String(String.format("%s:%s", config.getProperty("destination.auth.local.username"), config.getProperty("destination.auth.local.password")).getBytes())));
+ } else if (Boolean.TRUE.toString().equals(config.getProperty("destination.auth.external.enabled"))) {
+ headers.put("Authorization", workingRequest.getHeaders().get("Authorization"));
+ }
+
+ List> parameters = new ArrayList<>();
+
+ Gson gson = new Gson();
+
+ HfrRequest hfrRequest = gson.fromJson(workingRequest.getBody(), HfrRequest.class);
+
+ hfrRequest.setTransactionIdNumber(workingRequest.getHeaders().get("x-openhim-transactionid"));
+
+ MediatorHTTPRequest request = new MediatorHTTPRequest(workingRequest.getRequestHandler(), getSelf(), "Sending data", HfrRequest.OPERATION_MAP.get(hfrRequest.getPostOrUpdate()),
+ config.getProperty("destination.scheme"), config.getProperty("destination.host"), Integer.parseInt(config.getProperty("destination.api.port")), config.getProperty("destination.api.path"),
+ gson.toJson(hfrRequest), headers, parameters);
+
+ ActorSelection httpConnector = getContext().actorSelection(config.userPathFor("http-connector"));
+ httpConnector.tell(request, getSelf());
+
+ } else if (msg instanceof MediatorHTTPResponse) {
+ workingRequest.getRequestHandler().tell(((MediatorHTTPResponse) msg).toFinishRequest(), getSelf());
+ } else {
+ unhandled(msg);
+ }
+ }
+}
diff --git a/src/main/resources/error-messages.json b/src/main/resources/error-messages.json
new file mode 100644
index 0000000..4bee033
--- /dev/null
+++ b/src/main/resources/error-messages.json
@@ -0,0 +1,3 @@
+{
+ "ERR01": ""
+}
\ No newline at end of file
diff --git a/src/main/resources/mediator-registration-info.json b/src/main/resources/mediator-registration-info.json
index 655cc67..292c3ca 100644
--- a/src/main/resources/mediator-registration-info.json
+++ b/src/main/resources/mediator-registration-info.json
@@ -1,26 +1,35 @@
{
- "urn": "urn:uuid:a02f38d0-4fe0-11eb-a36e-65769507fb41",
+ "urn": "urn:uuid:83c54769-5622-4cec-9f58-ccfc0ad24382",
"version": "0.1.0",
- "name": "HFR-Mediator",
- "description": "An openHIM mediator for handling integration between Health Facility Registry and various health systems",
+ "name": "HFR Mediator",
+ "description": "A mediator for handling sharing of health facilities information from Health Facility Registry to other health information systems",
"endpoints": [
{
- "name": "HFR-Mediator Route",
+ "name": "HFR Mediator Route",
"host": "localhost",
"port": "3003",
"path": "/hfr",
"type": "http"
+ },
+ {
+ "name": "HFR Mediator Route",
+ "host": "localhost",
+ "port": "3003",
+ "path": "/hfr-ack",
+ "type": "http"
}
],
"defaultChannelConfig": [
{
- "name": "HFR-Mediator",
+ "name": "HFR Mediator",
"urlPattern": "^/hfr$",
"type": "http",
- "allow": ["hfr-mediator"],
+ "allow": [
+ "hfr-mediator"
+ ],
"routes": [
{
- "name": "HFR-Mediator Route",
+ "name": "HFR Mediator Route",
"host": "localhost",
"port": "3003",
"path": "/hfr",
@@ -28,6 +37,24 @@
"primary": "true"
}
]
+ },
+ {
+ "name": "HFR ACK Mediator",
+ "urlPattern": "^/hfr-ack$",
+ "description": "An OpenHIM mediator for handling acknowledgments",
+ "type": "http",
+ "allow": [
+ "hfr-mediator"
+ ],
+ "routes": [
+ {
+ "name": "ACK",
+ "host": "localhost",
+ "port": "3003",
+ "path": "/hfr-ack",
+ "type": "http"
+ }
+ ]
}
]
}
diff --git a/src/main/resources/mediator.properties b/src/main/resources/mediator.properties
index cef97f4..5bdcbf4 100644
--- a/src/main/resources/mediator.properties
+++ b/src/main/resources/mediator.properties
@@ -5,7 +5,19 @@ mediator.port=3003
mediator.timeout=60000
mediator.heartbeats=true
+core.scheme=http
core.host=localhost
core.api.port=8080
core.api.user=root@openhim.org
core.api.password=openhim-password
+
+destination.host=localhost
+destination.api.port=9000
+destination.api.path=/epicor
+destination.scheme=http
+
+destination.auth.local.enabled=true
+destination.auth.local.username=username
+destination.auth.local.password=password
+
+destination.auth.external.enabled=false
\ No newline at end of file
diff --git a/src/test/java/tz/go/moh/him/hfr/mediator/DefaultOrchestratorTest.java b/src/test/java/tz/go/moh/him/hfr/mediator/DefaultOrchestratorTest.java
deleted file mode 100644
index 9afeda0..0000000
--- a/src/test/java/tz/go/moh/him/hfr/mediator/DefaultOrchestratorTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package tz.go.moh.him.hfr.mediator;
-
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.Props;
-import akka.testkit.JavaTestKit;
-import java.util.Collections;
-import org.apache.commons.lang3.tuple.Pair;
-import org.junit.*;
-import org.openhim.mediator.engine.MediatorConfig;
-import org.openhim.mediator.engine.messages.FinishRequest;
-import org.openhim.mediator.engine.messages.MediatorHTTPRequest;
-
-import static org.junit.Assert.*;
-
-public class DefaultOrchestratorTest {
-
- static ActorSystem system;
-
- @BeforeClass
- public static void setup() {
- system = ActorSystem.create();
- }
-
- @AfterClass
- public static void teardown() {
- JavaTestKit.shutdownActorSystem(system);
- system = null;
- }
-
- @Before
- public void setUp() throws Exception {
- }
-
- @After
- public void tearDown() throws Exception {
- }
-
- @Test
- public void testMediatorHTTPRequest() throws Exception {
- new JavaTestKit(system) {{
- final MediatorConfig testConfig = new MediatorConfig("hfr-mediator", "localhost", 3003);
- final ActorRef defaultOrchestrator = system.actorOf(Props.create(DefaultOrchestrator.class, testConfig));
-
- MediatorHTTPRequest POST_Request = new MediatorHTTPRequest(
- getRef(),
- getRef(),
- "unit-test",
- "POST",
- "http",
- null,
- null,
- "/hfr",
- "test message",
- Collections.singletonMap("Content-Type", "text/plain"),
- Collections.>emptyList()
- );
-
- defaultOrchestrator.tell(POST_Request, getRef());
-
- final Object[] out =
- new ReceiveWhile