/**
* =============================================================================
*
* ORCID (R) Open Source
* http://orcid.org
*
* Copyright (c) 2012-2014 ORCID, Inc.
* Licensed under an MIT-Style License (MIT)
* http://orcid.org/open-source-license
*
* This copyright and license information (including a link to the full license)
* shall be included in its entirety in all copies or substantial portion of
* the software.
*
* =============================================================================
*/
package org.orcid.persistence.aop;
import java.util.Date;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.orcid.persistence.dao.ProfileDao;
import org.orcid.persistence.jpa.entities.IndexingStatus;
import org.orcid.persistence.jpa.entities.ProfileAware;
import org.orcid.persistence.jpa.entities.ProfileEntity;
import org.orcid.utils.OrcidStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.PriorityOrdered;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
*
* @author Will Simpson
*
*/
@Aspect
public class ProfileLastModifiedAspect implements PriorityOrdered {
private static final int PRECEDENCE = 50;
private static String REQUEST_PROFILE_LAST_MODIFIED = "REQUEST_PROFILE_LAST_MODIFIED";
private ProfileDao profileDao;
private boolean enabled = true;
private String name = "default";
private static final Logger LOGGER = LoggerFactory.getLogger(ProfileLastModifiedAspect.class);
//@formatter:off
private static final String POINTCUT_DEFINITION_BASE = "(execution(* org.orcid.persistence.dao.*.remove*(..))"
+ "|| execution(* org.orcid.persistence.dao.*.delete*(..))" + "|| execution(* org.orcid.persistence.dao.*.update*(..))"
+ "|| execution(* org.orcid.persistence.dao.*.merge*(..))" + "|| execution(* org.orcid.persistence.dao.*.add*(..))"
+ "|| execution(* org.orcid.persistence.dao.*.persist*(..)))"
+ "&& !@annotation(org.orcid.persistence.aop.ExcludeFromProfileLastModifiedUpdate)"
+ "&& !within(org.orcid.persistence.dao.impl.WebhookDaoImpl)";
//@formatter:on
public boolean isEnabled() {
return enabled;
}
public void setProfileDao(ProfileDao profileDao) {
this.profileDao = profileDao;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setName(String name) {
this.name = name;
}
/** Runs after any method that updates a record.
* Updates the last modified and refreshes the request-scope last modified cache.
*
* @param joinPoint
* @param orcid
*/
@AfterReturning(POINTCUT_DEFINITION_BASE + " && args(orcid, ..)")
public void updateProfileLastModified(JoinPoint joinPoint, String orcid) {
if (!enabled) {
return;
}
if (LOGGER.isDebugEnabled()) {
if (!OrcidStringUtils.isValidOrcid(orcid)) {
LOGGER.debug("Invalid ORCID for last modified date update: orcid={}, join point={}", orcid, joinPoint);
}
}
//update and clear scope cache
this.updateLastModifiedDateAndIndexingStatus(orcid);
}
@AfterReturning(POINTCUT_DEFINITION_BASE + " && args(profileAware, ..)")
public void updateProfileLastModified(JoinPoint joinPoint, ProfileAware profileAware) {
if (!enabled) {
return;
}
ProfileEntity profile = profileAware.getProfile();
if (profile != null) {
String orcid = profile.getId();
updateProfileLastModified(joinPoint, orcid);
}
}
@Override
public int getOrder() {
return PRECEDENCE;
}
/** Updates the last modified date and clears the request-scope last modified cache.
*
* @param orcid
*/
public void updateLastModifiedDateAndIndexingStatus(String orcid) {
if (!enabled) {
return;
}
profileDao.updateLastModifiedDateAndIndexingStatus(orcid, IndexingStatus.PENDING);
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (sra != null)
sra.setAttribute(sraKey(orcid), null, ServletRequestAttributes.SCOPE_REQUEST);
}
/** Fetches the last modified from the request-scope last modified cache
* If not present, fetches from the DB and populates the request-scope last modified cache.
*
* @param orcid
* @return
*/
public Date retrieveLastModifiedDate(String orcid) {
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Date lastMod = null;
if (sra != null)
lastMod = (Date) sra.getAttribute(sraKey(orcid), ServletRequestAttributes.SCOPE_REQUEST);
if (lastMod == null) {
lastMod = profileDao.retrieveLastModifiedDate(orcid);
if (sra != null)
sra.setAttribute(sraKey(orcid), lastMod, ServletRequestAttributes.SCOPE_REQUEST);
}
return lastMod;
}
private String sraKey(String orcid) {
return REQUEST_PROFILE_LAST_MODIFIED + '_' + name + '_' + orcid;
}
}