/**
* =============================================================================
*
* 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.core.manager.impl;
import java.util.Collection;
import java.util.Date;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.orcid.core.adapter.Jpa2JaxbAdapter;
import org.orcid.core.adapter.JpaJaxbEntityAdapter;
import org.orcid.core.locale.LocaleManager;
import org.orcid.core.manager.EncryptionManager;
import org.orcid.core.manager.LoadOptions;
import org.orcid.core.manager.OrcidProfileCacheManager;
import org.orcid.core.manager.OrcidProfileManagerReadOnly;
import org.orcid.core.manager.ProfileEntityManager;
import org.orcid.core.manager.SourceManager;
import org.orcid.core.security.visibility.OrcidVisibilityDefaults;
import org.orcid.core.security.visibility.aop.VisibilityControl;
import org.orcid.jaxb.model.message.Claimed;
import org.orcid.jaxb.model.message.GivenNames;
import org.orcid.jaxb.model.message.LastModifiedDate;
import org.orcid.jaxb.model.message.OrcidBio;
import org.orcid.jaxb.model.message.OrcidDeprecated;
import org.orcid.jaxb.model.message.OrcidHistory;
import org.orcid.jaxb.model.message.OrcidIdentifier;
import org.orcid.jaxb.model.message.OrcidProfile;
import org.orcid.jaxb.model.message.PersonalDetails;
import org.orcid.jaxb.model.message.Source;
import org.orcid.jaxb.model.message.Visibility;
import org.orcid.persistence.dao.ProfileDao;
import org.orcid.persistence.jpa.entities.ProfileEntity;
import org.orcid.utils.DateUtils;
import org.orcid.utils.NullUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
public class OrcidProfileManagerReadOnlyImpl implements OrcidProfileManagerReadOnly {
@Resource
private ProfileEntityManager profileEntityManager;
@Resource
private ProfileDao profileDao;
@Resource
protected SourceManager sourceManager;
@Resource
protected Jpa2JaxbAdapter jpaJaxbAdapter;
protected int claimWaitPeriodDays = 10;
@Resource
protected LocaleManager localeManager;
@Resource
protected EncryptionManager encryptionManager;
@Resource
protected OrcidProfileCacheManager orcidProfileCacheManager;
@Resource
protected JpaJaxbEntityAdapter adapter;
protected TransactionTemplate transactionTemplate;
protected static final Logger LOG = LoggerFactory.getLogger(OrcidProfileManagerReadOnlyImpl.class);
public void setProfileDao(ProfileDao profileDao) {
this.profileDao = profileDao;
}
public void setOrcidProfileCacheManager(OrcidProfileCacheManager orcidProfileCacheManager) {
this.orcidProfileCacheManager = orcidProfileCacheManager;
}
public void setClaimWaitPeriodDays(int claimWaitPeriodDays) {
this.claimWaitPeriodDays = claimWaitPeriodDays;
}
@Required
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
/**
* Retrieves the orcid fundings given an identifier
*
* @param orcid
* the identifier
* @return the orcid profile with only the funding list populated
*/
@Override
public OrcidProfile retrieveClaimedFundings(String orcid) {
OrcidProfile profile = retrieveClaimedOrcidProfile(orcid);
if (profile != null) {
profile.downgradeToFundingsOnly();
}
return profile;
}
/**
* Retrieves the orcid works given an identifier
*
* @param orcid
* the identifier
* @return the orcid profile with only the works populated
*/
@Override
public OrcidProfile retrieveClaimedOrcidWorks(String orcid) {
OrcidProfile profile = retrieveClaimedOrcidProfile(orcid);
if (profile != null) {
profile.downgradeToWorksOnly();
}
return profile;
}
@Override
public OrcidProfile retrieveOrcidProfile(String orcid) {
return retrieveOrcidProfile(orcid, LoadOptions.ALL);
}
@Override
public OrcidProfile retrieveOrcidProfile(String orcid, LoadOptions loadOptions) {
if (LoadOptions.ALL.equals(loadOptions))
return orcidProfileCacheManager.retrieve(orcid);
if (LoadOptions.BIO_AND_INTERNAL_ONLY.equals(loadOptions))
return orcidProfileCacheManager.retrieveProfileBioAndInternal(orcid);
return retrieveFreshOrcidProfile(orcid, loadOptions);
}
@Override
public OrcidProfile retrieveFreshOrcidProfile(final String orcid, final LoadOptions loadOptions) {
return transactionTemplate.execute(new TransactionCallback<OrcidProfile>() {
public OrcidProfile doInTransaction(TransactionStatus status) {
return doRetrieveFreshOrcidProfileInTransaction(orcid, loadOptions);
}
});
}
private OrcidProfile doRetrieveFreshOrcidProfileInTransaction(String orcid, LoadOptions loadOptions) {
LOG.debug("About to obtain fresh profile: " + orcid);
profileDao.flushWithoutTransactional();
ProfileEntity profileEntity = profileDao.find(orcid);
if (profileEntity != null) {
OrcidProfile freshOrcidProfile = convertToOrcidProfile(profileEntity, loadOptions);
return freshOrcidProfile;
}
return null;
}
@Override
public OrcidProfile retrieveClaimedOrcidProfile(String orcid){
return retrieveClaimedOrcidProfile(orcid, LoadOptions.ALL);
}
@Override
public OrcidProfile retrieveClaimedOrcidProfile(String orcid, LoadOptions loadOptions) {
OrcidProfile orcidProfile = retrieveOrcidProfile(orcid, loadOptions);
if (orcidProfile != null) {
if (Boolean.TRUE.equals(orcidProfile.getOrcidHistory().getClaimed().isValue()) || orcidProfile.isDeactivated() || isBeingAccessedByCreator(orcidProfile)
|| haveSystemRole() || isOldEnough(orcidProfile)) {
return orcidProfile;
} else {
if (orcidProfile.getOrcidDeprecated() != null && orcidProfile.getOrcidDeprecated().getPrimaryRecord() != null)
return createReservedForClaimOrcidProfile(orcid, orcidProfile.getOrcidDeprecated(), orcidProfile.getOrcidHistory().getLastModifiedDate());
else
return createReservedForClaimOrcidProfile(orcid, orcidProfile.getOrcidHistory().getLastModifiedDate());
}
}
return null;
}
/**
* Retrieves the orcid external identifiers given an identifier
*
* @param orcid
* the identifier
* @return the orcid profile with only the bio populated
*/
@Override
public OrcidProfile retrieveClaimedExternalIdentifiers(String orcid) {
OrcidProfile profile = retrieveClaimedOrcidProfile(orcid);
if (profile != null) {
profile.downgradeToExternalIdentifiersOnly();
}
return profile;
}
/**
* Retrieves the orcid bio given an identifier
*
* @param orcid
* the identifier
* @return the orcid profile with only the bio populated
*/
@Override
public OrcidProfile retrieveClaimedOrcidBio(String orcid) {
OrcidProfile profile = retrieveClaimedOrcidProfile(orcid);
if (profile != null) {
profile.downgradeToBioOnly();
}
return profile;
}
/**
* Retrieves the orcid affiliations given an identifier
*
* @param orcid
* the identifier
* @return the orcid profile with only the affiliations populated
*/
@Override
public OrcidProfile retrieveClaimedAffiliations(String orcid) {
OrcidProfile profile = retrieveClaimedOrcidProfile(orcid);
if (profile != null) {
profile.downgradeToAffiliationsOnly();
}
return profile;
}
@Override
@VisibilityControl(visibilities = Visibility.PUBLIC)
public OrcidProfile retrievePublicOrcidProfile(String orcid) {
return retrievePublicOrcidProfile(orcid, LoadOptions.ALL);
}
@Override
@VisibilityControl(visibilities = Visibility.PUBLIC)
public OrcidProfile retrievePublicOrcidProfile(String orcid, LoadOptions loadOptions) {
return retrieveClaimedOrcidProfile(orcid, loadOptions);
}
@Override
public Date retrieveLastModifiedDate(String orcid) {
return profileEntityManager.getLastModifiedDate(orcid);
}
@Deprecated
protected boolean isOldEnough(OrcidProfile orcidProfile) {
return DateUtils.olderThan(orcidProfile.getOrcidHistory().getSubmissionDate().getValue().toGregorianCalendar().getTime(), claimWaitPeriodDays);
}
protected boolean isBeingAccessedByCreator(OrcidProfile orcidProfile) {
String amenderOrcid = sourceManager.retrieveSourceOrcid();
Source source = orcidProfile.getOrcidHistory().getSource();
if (NullUtils.noneNull(amenderOrcid, source)) {
return amenderOrcid.equals(source.retrieveSourcePath());
}
return false;
}
protected boolean haveSystemRole() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
if (authorities != null) {
return authorities.contains(new SimpleGrantedAuthority("ROLE_SYSTEM"));
}
}
return false;
}
protected OrcidProfile createReservedForClaimOrcidProfile(String orcid, LastModifiedDate lastModifiedDate) {
return createReservedForClaimOrcidProfile(orcid, null, lastModifiedDate);
}
protected OrcidProfile createReservedForClaimOrcidProfile(String orcid, OrcidDeprecated deprecatedInfo, LastModifiedDate lastModifiedDate) {
OrcidProfile op = new OrcidProfile();
if (jpaJaxbAdapter != null) {
op.setOrcidIdentifier(new OrcidIdentifier(jpaJaxbAdapter.getOrcidIdBase(orcid)));
} else {
op.setOrcidIdentifier(orcid);
}
if (deprecatedInfo != null)
op.setOrcidDeprecated(deprecatedInfo);
OrcidHistory oh = new OrcidHistory();
oh.setClaimed(new Claimed(false));
oh.setLastModifiedDate(lastModifiedDate);
op.setOrcidHistory(oh);
GivenNames gn = new GivenNames();
PersonalDetails pd = new PersonalDetails();
gn.setContent(localeManager.resolveMessage("orcid.reserved_for_claim"));
gn.setVisibility(OrcidVisibilityDefaults.NAMES_DEFAULT.getVisibility());
pd.setGivenNames(gn);
OrcidBio ob = new OrcidBio();
ob.setPersonalDetails(pd);
op.setOrcidBio(ob);
return op;
}
protected OrcidProfile convertToOrcidProfile(ProfileEntity profileEntity, LoadOptions loadOptions) {
LOG.debug("About to convert profile entity to orcid profile: " + profileEntity.getId());
profileDao.refresh(profileEntity);
OrcidProfile orcidProfile = adapter.toOrcidProfile(profileEntity, loadOptions);
String verificationCode = profileEntity.getEncryptedVerificationCode();
String securityAnswer = profileEntity.getEncryptedSecurityAnswer();
orcidProfile.setVerificationCode(decrypt(verificationCode));
orcidProfile.setSecurityQuestionAnswer(decrypt(securityAnswer));
return orcidProfile;
}
protected String decrypt(String encrypted) {
if (StringUtils.isNotBlank(encrypted)) {
return encryptionManager.decryptForInternalUse(encrypted);
} else {
return null;
}
}
}