diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/aop/ProfileLastModifiedAspect.java b/orcid-core/src/main/java/org/orcid/core/aop/ProfileLastModifiedAspect.java similarity index 89% rename from orcid-persistence/src/main/java/org/orcid/persistence/aop/ProfileLastModifiedAspect.java rename to orcid-core/src/main/java/org/orcid/core/aop/ProfileLastModifiedAspect.java index b75c439a1d9..d7d43cd04a3 100644 --- a/orcid-persistence/src/main/java/org/orcid/persistence/aop/ProfileLastModifiedAspect.java +++ b/orcid-core/src/main/java/org/orcid/core/aop/ProfileLastModifiedAspect.java @@ -1,17 +1,21 @@ -package org.orcid.persistence.aop; +package org.orcid.core.aop; import java.util.Date; +import javax.annotation.Resource; + import org.apache.commons.lang.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; +import org.orcid.core.utils.cache.redis.RedisClient; import org.orcid.persistence.dao.ProfileLastModifiedDao; import org.orcid.persistence.jpa.entities.IndexingStatus; import org.orcid.persistence.jpa.entities.OrcidAware; import org.orcid.persistence.util.OrcidStringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.core.PriorityOrdered; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -40,6 +44,12 @@ public class ProfileLastModifiedAspect implements PriorityOrdered { private static final String UPDATE_PROFILE_LAST_MODIFIED_AND_INDEXING_STATUS = "@annotation(org.orcid.persistence.aop.UpdateProfileLastModifiedAndIndexingStatus)"; + @Resource + private RedisClient redisClient; + + @Value("${org.orcid.core.utils.cache.redis.summary.enabled:false}") + private boolean isSummaryCacheEnabled; + public boolean isEnabled() { return enabled; } @@ -125,7 +135,10 @@ public void updateLastModifiedDateAndIndexingStatus(String orcid) { ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (sra != null) - sra.setAttribute(sraKey(orcid), null, ServletRequestAttributes.SCOPE_REQUEST); + sra.setAttribute(sraKey(orcid), null, ServletRequestAttributes.SCOPE_REQUEST); + + // Clear redis caches + evictCaches(orcid); } /** Updates the last modified date and clears the request-scope last modified cache. @@ -144,7 +157,10 @@ public void updateLastModifiedDate(String orcid) { ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (sra != null) - sra.setAttribute(sraKey(orcid), null, ServletRequestAttributes.SCOPE_REQUEST); + sra.setAttribute(sraKey(orcid), null, ServletRequestAttributes.SCOPE_REQUEST); + + // Clear redis caches + evictCaches(orcid); } /** Fetches the last modified from the request-scope last modified cache @@ -169,4 +185,9 @@ public Date retrieveLastModifiedDate(String orcid) { private String sraKey(String orcid) { return REQUEST_PROFILE_LAST_MODIFIED + '_' + name + '_' + orcid; } + + public void evictCaches(String orcid) { + // Evict the summary cache + redisClient.remove(orcid + "-summary"); + } } diff --git a/orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java b/orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java index 86d4e47bf45..0bc95590116 100644 --- a/orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/common/manager/impl/SummaryManagerImpl.java @@ -22,6 +22,8 @@ import org.orcid.core.manager.v3.read_only.RecordManagerReadOnly; import org.orcid.core.manager.v3.read_only.RecordNameManagerReadOnly; import org.orcid.core.manager.v3.read_only.WorkManagerReadOnly; +import org.orcid.core.utils.JsonUtils; +import org.orcid.core.utils.cache.redis.RedisClient; import org.orcid.jaxb.model.v3.release.common.FuzzyDate; import org.orcid.jaxb.model.v3.release.common.Source; import org.orcid.jaxb.model.v3.release.common.Visibility; @@ -43,6 +45,7 @@ import org.orcid.pojo.summary.ExternalIdentifiersSummary; import org.orcid.pojo.summary.RecordSummary; import org.orcid.utils.DateUtils; +import org.springframework.beans.factory.annotation.Value; public class SummaryManagerImpl implements SummaryManager { @@ -72,9 +75,28 @@ public class SummaryManagerImpl implements SummaryManager { @Resource private WorksCacheManager worksCacheManager; + + @Resource + private RedisClient redisClient; + + @Value("${org.orcid.core.utils.cache.redis.summary.enabled:false}") + private boolean isSummaryCacheEnabled; + + // Set the cache TTL for the summary, 1 day by default + @Value("${org.orcid.core.utils.cache.redis.summary.ttl:86400}") + private int summaryCacheTTL; @Override public RecordSummary getRecordSummary(String orcid) { + String cacheKey = getCacheKey(orcid); + // Check the cache + if(isSummaryCacheEnabled) { + String summaryString = redisClient.get(cacheKey); + if(StringUtils.isNotBlank(summaryString)) { + return JsonUtils.readObjectFromJsonString(summaryString, RecordSummary.class); + } + } + RecordSummary recordSummary = new RecordSummary(); // Set ORCID uri @@ -102,13 +124,16 @@ public RecordSummary getRecordSummary(String orcid) { // Generate the peer review summary generatePeerReviewSummary(recordSummary, orcid); recordSummary.setStatus("active"); + + // Set the summary in the cache + if(isSummaryCacheEnabled) { + redisClient.set(cacheKey, JsonUtils.convertToJsonString(recordSummary), summaryCacheTTL); + } return recordSummary; } public void generateWorksSummary(RecordSummary recordSummary, String orcid) { Works works = worksCacheManager.getGroupedWorks(orcid); - // TODO Remove non public elements - // TODO There should be a manager that does this, but, the one we have already returns a list of work summaries, so, we need to refactor it to return the same Works element Iterator workGroupIt = works.getWorkGroup().iterator(); while (workGroupIt.hasNext()) { WorkGroup workGroup = workGroupIt.next(); @@ -274,4 +299,8 @@ private void sortAffiliationsByEndDate(List affiliations) { // Remove the end on the affiliations summariesWithOutEndDate.forEach(s -> s.setEndDate(null)); } + + private String getCacheKey(String orcid) { + return orcid + "-summary"; + } } diff --git a/orcid-core/src/main/java/org/orcid/core/manager/impl/SourceNameCacheManagerImpl.java b/orcid-core/src/main/java/org/orcid/core/manager/impl/SourceNameCacheManagerImpl.java index 7b252d7f08e..c567e21a9d7 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/impl/SourceNameCacheManagerImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/impl/SourceNameCacheManagerImpl.java @@ -91,6 +91,7 @@ private String getCacheKey(String sourceId) { } private String getClientSourceName(String clientId) { + LOGGER.debug("Fetching client name from DB: " + clientId); if (clientDetailsDao.existsAndIsNotPublicClient(clientId)) { ClientDetailsEntity clientDetails = clientDetailsDao.find(clientId); return clientDetails != null ? clientDetails.getClientName() : null; @@ -110,6 +111,7 @@ private String getProfileSourceNameFromRequest(String orcid) { } private String getProfileSourceNameFromDb(String orcid) { + LOGGER.debug("Fetching user name from DB: " + orcid); try { if (!recordNameDao.exists(orcid)) { throw new IllegalArgumentException("Unable to find source name for: " + orcid); diff --git a/orcid-core/src/main/java/org/orcid/core/manager/read_only/ManagerReadOnlyBase.java b/orcid-core/src/main/java/org/orcid/core/manager/read_only/ManagerReadOnlyBase.java index 26e1b91bef4..616affef7d3 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/read_only/ManagerReadOnlyBase.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/read_only/ManagerReadOnlyBase.java @@ -2,7 +2,7 @@ import java.util.Date; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; +import org.orcid.core.aop.ProfileLastModifiedAspect; public interface ManagerReadOnlyBase { void setProfileLastModifiedAspect(ProfileLastModifiedAspect profileLastModifiedAspect); diff --git a/orcid-core/src/main/java/org/orcid/core/manager/read_only/impl/ManagerReadOnlyBaseImpl.java b/orcid-core/src/main/java/org/orcid/core/manager/read_only/impl/ManagerReadOnlyBaseImpl.java index ccdc57641ec..a2cdab05ea7 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/read_only/impl/ManagerReadOnlyBaseImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/read_only/impl/ManagerReadOnlyBaseImpl.java @@ -2,8 +2,8 @@ import java.util.Date; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.manager.read_only.ManagerReadOnlyBase; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; public class ManagerReadOnlyBaseImpl implements ManagerReadOnlyBase { protected ProfileLastModifiedAspect profileLastModifiedAspect; diff --git a/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/ManagerReadOnlyBase.java b/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/ManagerReadOnlyBase.java index 764420d2246..13a3525081e 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/ManagerReadOnlyBase.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/ManagerReadOnlyBase.java @@ -2,7 +2,7 @@ import java.util.Date; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; +import org.orcid.core.aop.ProfileLastModifiedAspect; public interface ManagerReadOnlyBase { void setProfileLastModifiedAspect(ProfileLastModifiedAspect profileLastModifiedAspect); diff --git a/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/impl/ManagerReadOnlyBaseImpl.java b/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/impl/ManagerReadOnlyBaseImpl.java index 236bda69447..385ee0ca254 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/impl/ManagerReadOnlyBaseImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/v3/read_only/impl/ManagerReadOnlyBaseImpl.java @@ -2,8 +2,8 @@ import java.util.Date; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.manager.v3.read_only.ManagerReadOnlyBase; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; public class ManagerReadOnlyBaseImpl implements ManagerReadOnlyBase { protected ProfileLastModifiedAspect profileLastModifiedAspect; diff --git a/orcid-core/src/main/java/org/orcid/core/utils/ContributorUtils.java b/orcid-core/src/main/java/org/orcid/core/utils/ContributorUtils.java index 7876eccee5d..58dd2480f41 100644 --- a/orcid-core/src/main/java/org/orcid/core/utils/ContributorUtils.java +++ b/orcid-core/src/main/java/org/orcid/core/utils/ContributorUtils.java @@ -3,6 +3,7 @@ import com.google.common.collect.Iterables; import org.apache.commons.lang3.StringUtils; import org.ehcache.Cache; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.contributors.roles.credit.CreditRole; import org.orcid.core.manager.ActivityManager; import org.orcid.core.manager.ProfileEntityManager; @@ -14,7 +15,6 @@ import org.orcid.jaxb.model.record_v2.FundingContributor; import org.orcid.jaxb.model.record_v2.Work; import org.orcid.jaxb.model.record_v2.WorkBulk; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; import org.orcid.persistence.dao.RecordNameDao; import org.orcid.persistence.jpa.entities.RecordNameEntity; import org.orcid.pojo.ContributorsRolesAndSequencesV2; diff --git a/orcid-core/src/main/java/org/orcid/core/utils/cache/redis/RedisClient.java b/orcid-core/src/main/java/org/orcid/core/utils/cache/redis/RedisClient.java index 07c9672ba45..4d62057301b 100644 --- a/orcid-core/src/main/java/org/orcid/core/utils/cache/redis/RedisClient.java +++ b/orcid-core/src/main/java/org/orcid/core/utils/cache/redis/RedisClient.java @@ -32,7 +32,7 @@ public class RedisClient { private final int cacheExpiryInSecs; private final int clientTimeoutInMillis; private JedisPool pool; - private SetParams setParams; + private SetParams defaultSetParams; @Resource private SlackManager slackManager; @@ -70,7 +70,7 @@ private void init() { JedisClientConfig config = DefaultJedisClientConfig.builder().connectionTimeoutMillis(this.clientTimeoutInMillis).timeoutMillis(this.clientTimeoutInMillis) .socketTimeoutMillis(this.clientTimeoutInMillis).password(this.redisPassword).ssl(true).build(); pool = new JedisPool(new HostAndPort(this.redisHost, this.redisPort), config); - setParams = new SetParams().ex(this.cacheExpiryInSecs); + defaultSetParams = new SetParams().ex(this.cacheExpiryInSecs); // Pool test try(Jedis jedis = pool.getResource()) { if(jedis.isConnected()) { @@ -99,16 +99,25 @@ private void init() { } public boolean set(String key, String value) { + return set(key, value, defaultSetParams); + } + + public boolean set(String key, String value, int cacheExpiryInSecs) { + SetParams params = new SetParams().ex(cacheExpiryInSecs); + return set(key, value, params); + } + + private boolean set(String key, String value, SetParams params) { if(enabled && pool != null) { try (Jedis jedis = pool.getResource()) { LOG.debug("Setting Key: {}", key); - String result = jedis.set(key, value, setParams); + String result = jedis.set(key, value, params); return "OK".equalsIgnoreCase(result); } } return false; } - + public String get(String key) { if(enabled && pool != null) { try (Jedis jedis = pool.getResource()) { diff --git a/orcid-core/src/main/java/org/orcid/core/utils/v3/ContributorUtils.java b/orcid-core/src/main/java/org/orcid/core/utils/v3/ContributorUtils.java index e1160f04ffc..2dd41a5e2ab 100644 --- a/orcid-core/src/main/java/org/orcid/core/utils/v3/ContributorUtils.java +++ b/orcid-core/src/main/java/org/orcid/core/utils/v3/ContributorUtils.java @@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils; import org.ehcache.Cache; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.contributors.roles.credit.CreditRole; import org.orcid.core.manager.ClientDetailsEntityCacheManager; import org.orcid.core.manager.SourceNameCacheManager; @@ -25,7 +26,6 @@ import org.orcid.jaxb.model.v3.release.record.FundingContributor; import org.orcid.jaxb.model.v3.release.record.Work; import org.orcid.jaxb.model.v3.release.record.WorkBulk; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; import org.orcid.persistence.dao.RecordNameDao; import org.orcid.persistence.dao.WorkDao; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; diff --git a/orcid-core/src/main/resources/orcid-core-context.xml b/orcid-core/src/main/resources/orcid-core-context.xml index c0c77f1452d..5bf56885446 100644 --- a/orcid-core/src/main/resources/orcid-core-context.xml +++ b/orcid-core/src/main/resources/orcid-core-context.xml @@ -1221,4 +1221,16 @@ + + + + + + + + + + + + diff --git a/orcid-core/src/test/java/org/orcid/core/utils/ContributorUtilsTest.java b/orcid-core/src/test/java/org/orcid/core/utils/ContributorUtilsTest.java index 58cb77099cc..903810bf1ce 100644 --- a/orcid-core/src/test/java/org/orcid/core/utils/ContributorUtilsTest.java +++ b/orcid-core/src/test/java/org/orcid/core/utils/ContributorUtilsTest.java @@ -20,6 +20,7 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.manager.ActivityManager; import org.orcid.core.manager.ProfileEntityCacheManager; import org.orcid.core.manager.ProfileEntityManager; @@ -36,7 +37,6 @@ import org.orcid.jaxb.model.record_v2.WorkBulk; import org.orcid.jaxb.model.record_v2.WorkContributors; import org.orcid.jaxb.model.record_v2.WorkTitle; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; import org.orcid.persistence.dao.RecordNameDao; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.RecordNameEntity; diff --git a/orcid-core/src/test/java/org/orcid/core/utils/v3/ContributorUtilsTest.java b/orcid-core/src/test/java/org/orcid/core/utils/v3/ContributorUtilsTest.java index 1971989295a..70f87e13ac0 100644 --- a/orcid-core/src/test/java/org/orcid/core/utils/v3/ContributorUtilsTest.java +++ b/orcid-core/src/test/java/org/orcid/core/utils/v3/ContributorUtilsTest.java @@ -20,6 +20,7 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.manager.ProfileEntityCacheManager; import org.orcid.core.manager.v3.ActivityManager; import org.orcid.core.manager.v3.ProfileEntityManager; @@ -36,7 +37,6 @@ import org.orcid.jaxb.model.v3.release.record.WorkBulk; import org.orcid.jaxb.model.v3.release.record.WorkContributors; import org.orcid.jaxb.model.v3.release.record.WorkTitle; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; import org.orcid.persistence.dao.RecordNameDao; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.RecordNameEntity; diff --git a/orcid-persistence/src/main/resources/orcid-persistence-context.xml b/orcid-persistence/src/main/resources/orcid-persistence-context.xml index 7110cf1484a..285312d0a1b 100644 --- a/orcid-persistence/src/main/resources/orcid-persistence-context.xml +++ b/orcid-persistence/src/main/resources/orcid-persistence-context.xml @@ -26,18 +26,6 @@ - - - - - - - - - - - - diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/BaseWorkspaceController.java b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/BaseWorkspaceController.java index 975997b4d02..7ab1b0ac170 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/BaseWorkspaceController.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/BaseWorkspaceController.java @@ -15,6 +15,7 @@ import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.manager.CountryManager; import org.orcid.core.manager.EncryptionManager; import org.orcid.core.manager.v3.ActivityManager; @@ -22,7 +23,6 @@ import org.orcid.core.security.visibility.filter.VisibilityFilter; import org.orcid.frontend.web.util.NumberList; import org.orcid.frontend.web.util.YearsList; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; import org.orcid.pojo.ajaxForm.Contributor; import org.orcid.pojo.ajaxForm.Date; import org.orcid.pojo.ajaxForm.PojoUtil; diff --git a/orcid-web/src/test/java/org/orcid/frontend/web/controllers/ManageProfileControllerTest.java b/orcid-web/src/test/java/org/orcid/frontend/web/controllers/ManageProfileControllerTest.java index 3323573e4bf..947034cc458 100644 --- a/orcid-web/src/test/java/org/orcid/frontend/web/controllers/ManageProfileControllerTest.java +++ b/orcid-web/src/test/java/org/orcid/frontend/web/controllers/ManageProfileControllerTest.java @@ -29,6 +29,7 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.orcid.core.aop.ProfileLastModifiedAspect; import org.orcid.core.locale.LocaleManager; import org.orcid.core.manager.EncryptionManager; import org.orcid.core.manager.ProfileEntityCacheManager; @@ -56,7 +57,6 @@ import org.orcid.jaxb.model.v3.release.record.FamilyName; import org.orcid.jaxb.model.v3.release.record.GivenNames; import org.orcid.jaxb.model.v3.release.record.Name; -import org.orcid.persistence.aop.ProfileLastModifiedAspect; import org.orcid.persistence.jpa.entities.EmailEntity; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.pojo.AddEmail;