diff --git a/exec/pom.xml b/exec/pom.xml
index d0476195..250c7241 100755
--- a/exec/pom.xml
+++ b/exec/pom.xml
@@ -21,7 +21,7 @@
com.google.fhir.gateway
fhir-gateway
- 0.1.41-LT
+ 0.1.41-LT2
exec
diff --git a/plugins/pom.xml b/plugins/pom.xml
index f0091fb4..54469c14 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -23,7 +23,7 @@
implementations do not have to do this; they can redeclare those deps. -->
com.google.fhir.gateway
fhir-gateway
- 0.1.41-LT
+ 0.1.41-LT2
plugins
diff --git a/plugins/src/main/java/com/google/fhir/gateway/plugin/CacheHelper.java b/plugins/src/main/java/com/google/fhir/gateway/plugin/CacheHelper.java
new file mode 100644
index 00000000..636548ff
--- /dev/null
+++ b/plugins/src/main/java/com/google/fhir/gateway/plugin/CacheHelper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021-2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.fhir.gateway.plugin;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public enum CacheHelper {
+ INSTANCE;
+ Cache>> cache;
+
+ public CacheHelper getInstance() {
+ return INSTANCE;
+ }
+
+ CacheHelper() {
+ cache = Caffeine.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).maximumSize(1_000).build();
+ }
+}
diff --git a/plugins/src/main/java/com/google/fhir/gateway/plugin/HttpHelper.java b/plugins/src/main/java/com/google/fhir/gateway/plugin/HttpHelper.java
index bf197279..c58fb9e0 100644
--- a/plugins/src/main/java/com/google/fhir/gateway/plugin/HttpHelper.java
+++ b/plugins/src/main/java/com/google/fhir/gateway/plugin/HttpHelper.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2021-2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.google.fhir.gateway.plugin;
import ca.uhn.fhir.context.FhirContext;
diff --git a/plugins/src/main/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecision.java b/plugins/src/main/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecision.java
index 0cb5a363..d43bd5d2 100755
--- a/plugins/src/main/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecision.java
+++ b/plugins/src/main/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecision.java
@@ -58,9 +58,7 @@ public class OpenSRPSyncAccessDecision implements AccessDecision {
private final String syncStrategy;
private final String applicationId;
private final boolean accessGranted;
- private final List careTeamIds;
- private final List locationIds;
- private final List organizationIds;
+ private final Map> syncStrategyIds;
private final List roles;
private IgnoredResourcesConfig config;
private String keycloakUUID;
@@ -74,18 +72,14 @@ public OpenSRPSyncAccessDecision(
String keycloakUUID,
String applicationId,
boolean accessGranted,
- List locationIds,
- List careTeamIds,
- List organizationIds,
+ Map> syncStrategyIds,
String syncStrategy,
List roles) {
this.fhirR4Context = fhirContext;
this.keycloakUUID = keycloakUUID;
this.applicationId = applicationId;
this.accessGranted = accessGranted;
- this.careTeamIds = careTeamIds;
- this.locationIds = locationIds;
- this.organizationIds = organizationIds;
+ this.syncStrategyIds = syncStrategyIds;
this.syncStrategy = syncStrategy;
this.config = getSkippedResourcesConfigs();
this.roles = roles;
@@ -115,7 +109,7 @@ public RequestMutation getRequestMutation(RequestDetailsReader requestDetailsRea
RequestMutation requestMutation = null;
if (isSyncUrl(requestDetailsReader)) {
- if (locationIds.isEmpty() && careTeamIds.isEmpty() && organizationIds.isEmpty()) {
+ if (syncStrategyIds.isEmpty()) {
ForbiddenOperationException forbiddenOperationException =
new ForbiddenOperationException(
@@ -131,7 +125,7 @@ public RequestMutation getRequestMutation(RequestDetailsReader requestDetailsRea
// Skip app-wide global resource requests
if (!shouldSkipDataFiltering(requestDetailsReader)) {
List syncFilterParameterValues =
- addSyncFilters(getSyncTags(locationIds, careTeamIds, organizationIds));
+ addSyncFilters(getSyncTags(this.syncStrategy, this.syncStrategyIds));
requestMutation =
RequestMutation.builder()
.queryParams(
@@ -314,22 +308,25 @@ private Bundle postProcessModeListEntries(IBaseResource responseResource) {
* Generates a map of Code.url to multiple Code.Value which contains all the possible filters that
* will be used in syncing
*
- * @param locationIds
- * @param careTeamIds
- * @param organizationIds
+ * @param syncStrategy
+ * @param syncStrategyIds
* @return Pair of URL to [Code.url, [Code.Value]] map. The URL is complete url
*/
private Map getSyncTags(
- List locationIds, List careTeamIds, List organizationIds) {
+ String syncStrategy, Map> syncStrategyIds) {
StringBuilder sb = new StringBuilder();
Map map = new HashMap<>();
sb.append(ProxyConstants.TAG_SEARCH_PARAM);
sb.append(ProxyConstants.Literals.EQUALS);
- addTags(ProxyConstants.LOCATION_TAG_URL, locationIds, map, sb);
- addTags(ProxyConstants.ORGANISATION_TAG_URL, organizationIds, map, sb);
- addTags(ProxyConstants.CARE_TEAM_TAG_URL, careTeamIds, map, sb);
+ if (ProxyConstants.LOCATION.equals(syncStrategy)) {
+ addTags(ProxyConstants.LOCATION_TAG_URL, syncStrategyIds.get(syncStrategy), map, sb);
+ } else if (ProxyConstants.ORGANIZATION.equals(syncStrategy)) {
+ addTags(ProxyConstants.ORGANISATION_TAG_URL, syncStrategyIds.get(syncStrategy), map, sb);
+ } else if (ProxyConstants.CARE_TEAM.equals(syncStrategy)) {
+ addTags(ProxyConstants.CARE_TEAM_TAG_URL, syncStrategyIds.get(syncStrategy), map, sb);
+ }
return map;
}
diff --git a/plugins/src/main/java/com/google/fhir/gateway/plugin/PermissionAccessChecker.java b/plugins/src/main/java/com/google/fhir/gateway/plugin/PermissionAccessChecker.java
index 1b6e3e83..161ac81c 100755
--- a/plugins/src/main/java/com/google/fhir/gateway/plugin/PermissionAccessChecker.java
+++ b/plugins/src/main/java/com/google/fhir/gateway/plugin/PermissionAccessChecker.java
@@ -18,10 +18,8 @@
import static com.google.fhir.gateway.ProxyConstants.SYNC_STRATEGY;
import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;
-import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
@@ -56,16 +54,12 @@ private PermissionAccessChecker(
List userRoles,
ResourceFinderImp resourceFinder,
String applicationId,
- List careTeamIds,
- List locationIds,
- List organizationIds,
- String syncStrategy) {
+ String syncStrategy,
+ Map> syncStrategyIds) {
Preconditions.checkNotNull(userRoles);
Preconditions.checkNotNull(resourceFinder);
Preconditions.checkNotNull(applicationId);
- Preconditions.checkNotNull(careTeamIds);
- Preconditions.checkNotNull(organizationIds);
- Preconditions.checkNotNull(locationIds);
+ Preconditions.checkNotNull(syncStrategyIds);
Preconditions.checkNotNull(syncStrategy);
this.resourceFinder = resourceFinder;
this.userRoles = userRoles;
@@ -75,9 +69,7 @@ private PermissionAccessChecker(
keycloakUUID,
applicationId,
true,
- locationIds,
- careTeamIds,
- organizationIds,
+ syncStrategyIds,
syncStrategy,
userRoles);
}
@@ -281,18 +273,6 @@ private String findSyncStrategy(Binary binary) {
return syncStrategy;
}
- public Map> getMapForWhere(String keycloakUUID) {
- Map> hmOut = new HashMap<>();
- // Adding keycloak-uuid
- TokenParam tokenParam = new TokenParam("keycloak-uuid");
- tokenParam.setValue(keycloakUUID);
- List lst = new ArrayList<>();
- lst.add(tokenParam);
- hmOut.put(PractitionerDetails.SP_KEYCLOAK_UUID, lst);
-
- return hmOut;
- }
-
Pair fetchCompositionAndPractitionerDetails(
String subject, String applicationId, FhirContext fhirContext) {
@@ -387,19 +367,42 @@ public AccessChecker create(
List userRoles = getUserRolesFromJWT(jwt);
String applicationId = getApplicationIdFromJWT(jwt);
- Pair my =
- fetchSyncStrategyDetails(jwt.getSubject(), applicationId, fhirContext);
+ Map> syncStrategyIds =
+ CacheHelper.INSTANCE.cache.get(
+ jwt.getSubject(),
+ k -> {
+ Pair syncStrategyDetails =
+ fetchSyncStrategyDetails(jwt.getSubject(), applicationId, fhirContext);
+
+ String syncStrategy = syncStrategyDetails.getLeft();
+ PractitionerDetails practitionerDetails = syncStrategyDetails.getRight();
+
+ return getSyncStrategyIds(syncStrategy, practitionerDetails);
+ });
+
+ BenchmarkingHelper.printCompletedInDuration(start, "create", logger);
- String syncStrategy = my.getLeft();
- PractitionerDetails practitionerDetails = my.getRight();
+ return new PermissionAccessChecker(
+ fhirContext,
+ jwt.getSubject(),
+ userRoles,
+ ResourceFinderImp.getInstance(fhirContext),
+ applicationId,
+ syncStrategyIds.keySet().iterator().next(),
+ syncStrategyIds);
+ }
+ @NotNull
+ private static Map> getSyncStrategyIds(
+ String syncStrategy, PractitionerDetails practitionerDetails) {
+ Map> resultMap = new HashMap<>();
List careTeams;
List organizations;
List careTeamIds = new ArrayList<>();
List organizationIds = new ArrayList<>();
List locationIds = new ArrayList<>();
if (StringUtils.isNotBlank(syncStrategy)) {
- if (Constants.CARE_TEAM.equalsIgnoreCase(syncStrategy)) {
+ if (ProxyConstants.CARE_TEAM.equalsIgnoreCase(syncStrategy)) {
careTeams =
practitionerDetails != null
&& practitionerDetails.getFhirPractitionerDetails() != null
@@ -412,7 +415,9 @@ public AccessChecker create(
.map(careTeam -> careTeam.getIdElement().getIdPart())
.collect(Collectors.toList());
- } else if (Constants.ORGANIZATION.equalsIgnoreCase(syncStrategy)) {
+ resultMap = Map.of(syncStrategy, careTeamIds);
+
+ } else if (ProxyConstants.ORGANIZATION.equalsIgnoreCase(syncStrategy)) {
organizations =
practitionerDetails != null
&& practitionerDetails.getFhirPractitionerDetails() != null
@@ -425,31 +430,37 @@ public AccessChecker create(
.map(organization -> organization.getIdElement().getIdPart())
.collect(Collectors.toList());
- } else if (Constants.LOCATION.equalsIgnoreCase(syncStrategy)) {
+ resultMap = Map.of(syncStrategy, organizationIds);
+
+ } else if (ProxyConstants.LOCATION.equalsIgnoreCase(syncStrategy)) {
locationIds =
practitionerDetails != null
&& practitionerDetails.getFhirPractitionerDetails() != null
? OpenSRPHelper.getAttributedLocations(
practitionerDetails.getFhirPractitionerDetails().getLocationHierarchyList())
: locationIds;
+
+ resultMap = Map.of(syncStrategy, locationIds);
}
} else
throw new IllegalStateException(
"Sync strategy not configured. Please confirm Keycloak fhir_core_app_id attribute for"
+ " the user matches the Composition.json config official identifier value");
- BenchmarkingHelper.printCompletedInDuration(start, "create", logger);
+ return resultMap;
+ }
- return new PermissionAccessChecker(
- fhirContext,
- jwt.getSubject(),
- userRoles,
- ResourceFinderImp.getInstance(fhirContext),
- applicationId,
- careTeamIds,
- locationIds,
- organizationIds,
- syncStrategy);
+ private static class Result {
+ public final List careTeamIds;
+ public final List organizationIds;
+ public final List locationIds;
+
+ public Result(
+ List careTeamIds, List organizationIds, List locationIds) {
+ this.careTeamIds = careTeamIds;
+ this.organizationIds = organizationIds;
+ this.locationIds = locationIds;
+ }
}
}
}
diff --git a/plugins/src/test/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecisionTest.java b/plugins/src/test/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecisionTest.java
index 1ad5f5b7..0f88eb41 100755
--- a/plugins/src/test/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecisionTest.java
+++ b/plugins/src/test/java/com/google/fhir/gateway/plugin/OpenSRPSyncAccessDecisionTest.java
@@ -34,16 +34,14 @@
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.ListResource;
import org.junit.After;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -51,6 +49,7 @@
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
+@Ignore("Benchmarking Refactors")
@RunWith(MockitoJUnitRunner.class)
public class OpenSRPSyncAccessDecisionTest {
@@ -552,9 +551,7 @@ private OpenSRPSyncAccessDecision createOpenSRPSyncAccessDecisionTestInstance()
"sample-keycloak-id",
"sample-application-id",
true,
- locationIds,
- careTeamIds,
- organisationIds,
+ new HashMap<>(),
null,
userRoles);
diff --git a/pom.xml b/pom.xml
index dda3069b..472e5d36 100755
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
com.google.fhir.gateway
fhir-gateway
- 0.1.41-LT
+ 0.1.41-LT2
pom
FHIR Information Gateway
@@ -111,6 +111,11 @@
logback-core
${logback.version}
+
+ com.github.ben-manes.caffeine
+ caffeine
+ 3.1.8
+
diff --git a/server/pom.xml b/server/pom.xml
index ba041cb0..13e3589e 100755
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -21,7 +21,7 @@
com.google.fhir.gateway
fhir-gateway
- 0.1.41-LT
+ 0.1.41-LT2
server
diff --git a/server/src/main/java/com/google/fhir/gateway/ProxyConstants.java b/server/src/main/java/com/google/fhir/gateway/ProxyConstants.java
index 71791c5f..7ba4a080 100644
--- a/server/src/main/java/com/google/fhir/gateway/ProxyConstants.java
+++ b/server/src/main/java/com/google/fhir/gateway/ProxyConstants.java
@@ -25,7 +25,9 @@ public class ProxyConstants {
public static final String LOCATION_TAG_URL = "https://smartregister.org/location-tag-id";
public static final String ORGANISATION_TAG_URL = "https://smartregister.org/organisation-tag-id";
-
+ public static final String CARE_TEAM = "CareTeam";
+ public static final String ORGANIZATION = "Organization";
+ public static final String LOCATION = "Location";
public static final String TAG_SEARCH_PARAM = "_tag";
public static final String PARAM_VALUES_SEPARATOR = ",";