diff --git a/avni-server-api/src/main/java/org/avni/server/AvniSpringConfiguration.java b/avni-server-api/src/main/java/org/avni/server/AvniSpringConfiguration.java index 166b4e9a0..e93b4977b 100644 --- a/avni-server-api/src/main/java/org/avni/server/AvniSpringConfiguration.java +++ b/avni-server-api/src/main/java/org/avni/server/AvniSpringConfiguration.java @@ -116,14 +116,16 @@ protected Cache createConcurrentMapCache(final String name) { private ConcurrentMapCache getConcurrentMapCacheWithWeightedCapacityForAddressesConfig(String name) { return new ConcurrentMapCache(name, CacheBuilder.newBuilder().expireAfterWrite(timeToLiveInSeconds, - TimeUnit.SECONDS).maximumWeight(cacheMaxWeight) - .weigher((key, value) -> value == null ? 0 : (((List)value).size() / 100)+1) + TimeUnit.SECONDS).maximumWeight(cacheMaxWeight) + .weigher((key, value) -> value == null ? 0 : (((List) value).size() / 100) + 1) .build().asMap(), DISALLOW_NULL_VALUES); } private ConcurrentMapCache getConcurrentMapCacheWithMaxEntriesConfig(String name) { - return new ConcurrentMapCache(name, CacheBuilder.newBuilder().expireAfterWrite(timeToLiveInSeconds, - TimeUnit.SECONDS).maximumSize(maxEntriesToCache).build().asMap(), DISALLOW_NULL_VALUES); + return new ConcurrentMapCache(name, CacheBuilder.newBuilder() + .expireAfterWrite(timeToLiveInSeconds, TimeUnit.SECONDS) + .maximumSize(maxEntriesToCache) + .build().asMap(), DISALLOW_NULL_VALUES); } }; } diff --git a/avni-server-api/src/main/java/org/avni/server/dao/search/BaseSubjectSearchQueryBuilder.java b/avni-server-api/src/main/java/org/avni/server/dao/search/BaseSubjectSearchQueryBuilder.java index 3a4e6757d..464306d21 100644 --- a/avni-server-api/src/main/java/org/avni/server/dao/search/BaseSubjectSearchQueryBuilder.java +++ b/avni-server-api/src/main/java/org/avni/server/dao/search/BaseSubjectSearchQueryBuilder.java @@ -38,6 +38,7 @@ public class BaseSubjectSearchQueryBuilder { private final Set joinClauses = new LinkedHashSet<>(); private final Map parameters = new HashMap<>(); private boolean forCount; + private boolean findDistinctOnly; private final Set customFields = new HashSet<>(); public BaseSubjectSearchQueryBuilder() { @@ -70,7 +71,7 @@ public SqlQuery buildUsingBaseQuery(String baseQuery, String groupByClause) { .toString(); } String customFieldString = customFields.isEmpty() ? "" : ",\n".concat(String.join(",\n", customFields)); - String queryWithCustomFields = finalQuery.replace(" $CUSTOM_FIELDS", customFieldString); + String queryWithCustomFields = finalQuery.replace(" $CUSTOM_FIELDS", customFieldString).replace("$DISTINCT", findDistinctOnly ? "distinct" : ""); logger.trace(parameters.toString()); return new SqlQuery(queryWithCustomFields, parameters); } @@ -232,6 +233,7 @@ public T withSearchAll(String searchString) { whereClauses.add("(cast(i.observations as text) ilike :searchAll\n" + " or cast(penr.observations as text) ilike :searchAll)"); joinClauses.add(PROGRAM_ENROLMENT_JOIN); + this.findDistinctOnly = true; return (T) this; } @@ -253,14 +255,14 @@ public T withConceptsFilter(List concept) { addParameter(conceptUuidParam, c.getUuid()); String tableAlias = aliasMap.get(c.getSearchScope().toUpperCase()); if (c.getSearchScope().equalsIgnoreCase("encounter")) { - joinClauses.add(ENCOUNTER_JOIN); + withJoin(ENCOUNTER_JOIN, true); } if (c.getSearchScope().equalsIgnoreCase("programEnrolment")) { - joinClauses.add(PROGRAM_ENROLMENT_JOIN); + withJoin(PROGRAM_ENROLMENT_JOIN, true); } if (c.getSearchScope().equalsIgnoreCase("programEncounter")) { - joinClauses.add(PROGRAM_ENROLMENT_JOIN); - joinClauses.add(PROGRAM_ENCOUNTER_JOIN); + withJoin(PROGRAM_ENROLMENT_JOIN, true); + withJoin(PROGRAM_ENCOUNTER_JOIN, true); } if (c.getDataType().equalsIgnoreCase("CODED")) { @@ -335,8 +337,9 @@ public T withConceptsFilter(List concept) { return (T) this; } - protected T withJoin(String joinClause) { + protected T withJoin(String joinClause, boolean findDistinctOnly) { joinClauses.add(joinClause); + this.findDistinctOnly = findDistinctOnly || this.findDistinctOnly; return (T) this; } diff --git a/avni-server-api/src/main/java/org/avni/server/dao/search/SubjectSearchQueryBuilder.java b/avni-server-api/src/main/java/org/avni/server/dao/search/SubjectSearchQueryBuilder.java index bfc7394a0..2e61f9910 100644 --- a/avni-server-api/src/main/java/org/avni/server/dao/search/SubjectSearchQueryBuilder.java +++ b/avni-server-api/src/main/java/org/avni/server/dao/search/SubjectSearchQueryBuilder.java @@ -6,7 +6,7 @@ public class SubjectSearchQueryBuilder extends BaseSubjectSearchQueryBuilder implements SearchBuilder { public SqlQuery build() { - String baseQuery = "select distinct i.id as \"id\",\n" + + String baseQuery = "select $DISTINCT i.id as \"id\",\n" + " i.first_name as \"firstName\",\n" + " i.last_name as \"lastName\",\n" + " i.profile_picture as \"profilePicture\",\n" + @@ -43,7 +43,7 @@ public SubjectSearchQueryBuilder withSubjectSearchFilter(SubjectSearchRequest re public SubjectSearchQueryBuilder withEncounterDateFilter(DateRange encounterDateRange) { if (encounterDateRange == null || encounterDateRange.isEmpty()) return this; - return withJoin(ENCOUNTER_JOIN) + return withJoin(ENCOUNTER_JOIN, true) .withRangeFilter(encounterDateRange, "encounterDate", "e.encounter_date_time >= cast(:rangeParam as date)", @@ -52,8 +52,8 @@ public SubjectSearchQueryBuilder withEncounterDateFilter(DateRange encounterDate public SubjectSearchQueryBuilder withProgramEncounterDateFilter(DateRange dateRange) { if (dateRange == null || dateRange.isEmpty()) return this; - return withJoin(PROGRAM_ENROLMENT_JOIN) - .withJoin(PROGRAM_ENCOUNTER_JOIN) + return withJoin(PROGRAM_ENROLMENT_JOIN, true) + .withJoin(PROGRAM_ENCOUNTER_JOIN, true) .withRangeFilter(dateRange, "programEncounterDate", "pe.encounter_date_time >= cast(:rangeParam as date)", @@ -62,7 +62,7 @@ public SubjectSearchQueryBuilder withProgramEncounterDateFilter(DateRange dateRa public SubjectSearchQueryBuilder withProgramEnrolmentDateFilter(DateRange dateRange) { if (dateRange == null || dateRange.isEmpty()) return this; - return withJoin(PROGRAM_ENROLMENT_JOIN) + return withJoin(PROGRAM_ENROLMENT_JOIN, true) .withRangeFilter(dateRange, "programEnrolmentDate", "penr.enrolment_date_time >= cast(trim(:rangeParam) as date)", diff --git a/avni-server-api/src/main/java/org/avni/server/framework/hibernate/CacheEventLogger.java b/avni-server-api/src/main/java/org/avni/server/framework/hibernate/CacheEventLogger.java index ed7fe2cf8..1bd75e7d0 100644 --- a/avni-server-api/src/main/java/org/avni/server/framework/hibernate/CacheEventLogger.java +++ b/avni-server-api/src/main/java/org/avni/server/framework/hibernate/CacheEventLogger.java @@ -10,32 +10,48 @@ public class CacheEventLogger implements CacheEventListener { private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CacheEventLogger.class); + private String getCacheInfo(Ehcache ehcache) { + return String.format("Cache name: %s, Cache size: %d", ehcache.getName(), ehcache.getSize()); + } + + private String getElementInfo(Element element) { + return String.format("Element: %s", element.getObjectKey().toString()); + } + + private void log(String action, Ehcache cache, Element element) { + if (logger.isTraceEnabled()) { + logger.trace("{} -> {}, {}, User: {}", action, getCacheInfo(cache), getElementInfo(element), UserContextHolder.getUserName()); + } + } + @Override public void notifyElementRemoved(Ehcache cache, Element element) throws CacheException { -// logger.debug("Element added in {} : {}", cache.getName(), element); + this.log("Removed", cache, element); } @Override public void notifyElementPut(Ehcache cache, Element element) throws CacheException { - logger.info("Element added in {}: {} by {}", cache.getName(), element, UserContextHolder.getUserName()); + this.log("Put", cache, element); } @Override public void notifyElementUpdated(Ehcache cache, Element element) throws CacheException { + this.log("Updated", cache, element); } @Override public void notifyElementExpired(Ehcache cache, Element element) { -// logger.debug("Element expired in {}: {}", cache.getName(), element); + this.log("Expired", cache, element); } @Override public void notifyElementEvicted(Ehcache cache, Element element) { -// logger.debug("Element evicted in {}: {}", cache.getName(), element); + logger.debug("Evicted -> {}, {}, User: {}", getCacheInfo(cache), getElementInfo(element), UserContextHolder.getUserName()); } @Override public void notifyRemoveAll(Ehcache cache) { + logger.debug("All removed. {}", getCacheInfo(cache)); } @Override @@ -45,5 +61,6 @@ public Object clone() { @Override public void dispose() { + logger.info("Dispose called."); } } diff --git a/avni-server-api/src/main/resources/ehcache.xml b/avni-server-api/src/main/resources/ehcache.xml index 5b6a64218..ed79ebc3b 100644 --- a/avni-server-api/src/main/resources/ehcache.xml +++ b/avni-server-api/src/main/resources/ehcache.xml @@ -5,7 +5,7 @@ - Separate caches are defined so that they can be evicted selectively. These can be -->