/**
* =============================================================================
*
* 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.api.t2.server.delegator.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.datatype.XMLGregorianCalendar;
import org.orcid.api.t2.server.delegator.T2OrcidApiServiceDelegator;
import org.orcid.core.exception.OrcidBadRequestException;
import org.orcid.core.exception.OrcidDeprecatedException;
import org.orcid.core.exception.OrcidValidationException;
import org.orcid.core.locale.LocaleManager;
import org.orcid.core.manager.EmailManager;
import org.orcid.core.manager.ProfileEntityCacheManager;
import org.orcid.core.manager.ValidationBehaviour;
import org.orcid.core.manager.ValidationManager;
import org.orcid.core.manager.impl.OrcidUrlManager;
import org.orcid.core.manager.impl.ValidationManagerImpl;
import org.orcid.core.version.OrcidMessageVersionConverterChain;
import org.orcid.jaxb.model.message.Email;
import org.orcid.jaxb.model.message.OrcidHistory;
import org.orcid.jaxb.model.message.OrcidMessage;
import org.orcid.persistence.jpa.entities.EmailEntity;
import org.orcid.persistence.jpa.entities.ProfileEntity;
import org.orcid.pojo.ajaxForm.PojoUtil;
import org.orcid.utils.DateUtils;
/**
*
* @author Will Simpson
*
*/
public class T2OrcidApiServiceVersionedDelegatorImpl implements T2OrcidApiServiceDelegator {
@Resource(name = "orcidT2ServiceDelegator")
private T2OrcidApiServiceDelegator t2OrcidApiServiceDelegator;
@Resource
private OrcidMessageVersionConverterChain orcidMessageVersionConverterChain;
private ValidationManager incomingValidationManager;
private ValidationManager outgoingValidationManager;
private String externalVersion = OrcidMessage.DEFAULT_VERSION;
private boolean supportsAffiliations = true;
@Resource
private EmailManager emailManager;
@Resource
private LocaleManager localeManager;
@Resource(name = "profileEntityCacheManager")
private ProfileEntityCacheManager profileEntityCacheManager;
@Resource
private OrcidUrlManager orcidUrlManager;
public void setExternalVersion(String externalVersion) {
this.externalVersion = externalVersion;
}
public void setIncomingValidationManager(ValidationManager incomingValidationManager) {
this.incomingValidationManager = incomingValidationManager;
}
public void setOutgoingValidationManager(ValidationManager outgoingValidationManager) {
this.outgoingValidationManager = outgoingValidationManager;
}
public void setSupportsAffiliations(boolean supportsAffiliations) {
this.supportsAffiliations = supportsAffiliations;
}
@Override
public Response viewStatusText() {
return t2OrcidApiServiceDelegator.viewStatusText();
}
public void autoConfigureValidators() {
if (incomingValidationManager == null) {
ValidationManagerImpl incomingValidationManagerImpl = new ValidationManagerImpl();
incomingValidationManagerImpl.setValidationBehaviour(ValidationBehaviour.THROW_VALIDATION_EXCEPTION);
incomingValidationManagerImpl.setVersion(externalVersion);
incomingValidationManagerImpl.setRequireOrcidProfile(true);
incomingValidationManagerImpl.setValidateTitle(true);
setIncomingValidationManager(incomingValidationManagerImpl);
}
if (outgoingValidationManager == null) {
ValidationManagerImpl outgoingValidationManagerImpl = new ValidationManagerImpl();
outgoingValidationManagerImpl.setVersion(externalVersion);
setOutgoingValidationManager(outgoingValidationManagerImpl);
}
}
@Override
public Response findBioDetails(String orcid) {
Response response = t2OrcidApiServiceDelegator.findBioDetails(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findBioDetailsFromPublicCache(String orcid) {
Response response = t2OrcidApiServiceDelegator.findBioDetailsFromPublicCache(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findExternalIdentifiers(String orcid) {
Response response = t2OrcidApiServiceDelegator.findExternalIdentifiers(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findExternalIdentifiersFromPublicCache(String orcid) {
Response response = t2OrcidApiServiceDelegator.findExternalIdentifiersFromPublicCache(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findFullDetails(String orcid) {
Response response = t2OrcidApiServiceDelegator.findFullDetails(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findFullDetailsFromPublicCache(String orcid) {
Response response = t2OrcidApiServiceDelegator.findFullDetailsFromPublicCache(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findAffiliationsDetails(String orcid) {
Response response = t2OrcidApiServiceDelegator.findAffiliationsDetails(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findAffiliationsDetailsFromPublicCache(String orcid) {
Response response = t2OrcidApiServiceDelegator.findAffiliationsDetailsFromPublicCache(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findFundingDetails(String orcid) {
Response response = t2OrcidApiServiceDelegator.findFundingDetails(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findFundingDetailsFromPublicCache(String orcid) {
Response response = t2OrcidApiServiceDelegator.findFundingDetailsFromPublicCache(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findWorksDetails(String orcid) {
Response response = t2OrcidApiServiceDelegator.findWorksDetails(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response findWorksDetailsFromPublicCache(String orcid) {
Response response = t2OrcidApiServiceDelegator.findWorksDetailsFromPublicCache(orcid);
return downgradeAndValidateResponse(response);
}
@Override
public Response redirectClientToGroup(String clientId) {
return t2OrcidApiServiceDelegator.redirectClientToGroup(clientId);
}
@Override
public Response searchByQuery(Map<String, List<String>> queryMap) {
Response response = t2OrcidApiServiceDelegator.searchByQuery(queryMap);
return downgradeAndValidateResponse(response);
}
@Override
public Response publicSearchByQuery(Map<String, List<String>> queryMap) {
return searchByQuery(queryMap);
}
@Override
public Response createProfile(UriInfo uriInfo, OrcidMessage orcidMessage) {
Response response = null;
validateRegistrationMessage(orcidMessage);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
response = t2OrcidApiServiceDelegator.createProfile(uriInfo, upgradedMessage);
return response;
}
@Override
public Response updateBioDetails(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
Response response = null;
validateBioUpdateMessage(orcidMessage);
validateEmailAvailability(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
response = t2OrcidApiServiceDelegator.updateBioDetails(uriInfo, orcid, upgradedMessage);
return downgradeAndValidateResponse(response);
}
@Override
public Response addWorks(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
Response response = null;
validateIncomingMessage(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
response = t2OrcidApiServiceDelegator.addWorks(uriInfo, orcid, upgradedMessage);
return response;
}
@Override
public Response updateWorks(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
Response response = null;
validateIncomingMessage(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
response = t2OrcidApiServiceDelegator.updateWorks(uriInfo, orcid, upgradedMessage);
return downgradeAndValidateResponse(response);
}
@Override
public Response addExternalIdentifiers(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
Response response = null;
validateIncomingMessage(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
response = t2OrcidApiServiceDelegator.addExternalIdentifiers(uriInfo, orcid, upgradedMessage);
return downgradeAndValidateResponse(response);
}
@Override
public Response deleteProfile(UriInfo uriInfo, String orcid) {
return t2OrcidApiServiceDelegator.deleteProfile(uriInfo, orcid);
}
@Override
public Response registerWebhook(UriInfo uriInfo, String orcid, String webhookUri) {
return t2OrcidApiServiceDelegator.registerWebhook(uriInfo, orcid, webhookUri);
}
@Override
public Response unregisterWebhook(UriInfo uriInfo, String orcid, String webhookUri) {
return t2OrcidApiServiceDelegator.unregisterWebhook(uriInfo, orcid, webhookUri);
}
private void validateRegistrationMessage(OrcidMessage orcidMessage) {
try {
if(orcidMessage != null && orcidMessage.getOrcidProfile() != null && orcidMessage.getOrcidProfile().getOrcidHistory() != null) {
OrcidHistory history = orcidMessage.getOrcidProfile().getOrcidHistory();
if(history.getClaimed() != null) {
throw new OrcidValidationException(new Throwable(localeManager.resolveMessage("apiError.validation_claimedstatus.exception")));
} else if(history.getCreationMethod() != null) {
throw new OrcidValidationException(new Throwable(localeManager.resolveMessage("apiError.validation_creationmethod.exception")));
} else if(history.getCompletionDate() != null) {
throw new OrcidValidationException(new Throwable(localeManager.resolveMessage("apiError.validation_completiondate.exception")));
} else if(history.getSubmissionDate() != null) {
throw new OrcidValidationException(new Throwable(localeManager.resolveMessage("apiError.validation_submissiondate.exception")));
} else if(history.getLastModifiedDate() != null) {
throw new OrcidValidationException(new Throwable(localeManager.resolveMessage("apiError.validation_lastmodifieddate.exception")));
}
}
validateIncomingMessage(orcidMessage, null);
} catch (OrcidValidationException e) {
Throwable cause = e.getCause();
if (cause == null) {
cause = e;
} else {
Throwable underlyingCause = cause.getCause();
if (underlyingCause != null) {
cause = underlyingCause;
}
}
Object params[] = {cause.toString()};
throw new OrcidValidationException(localeManager.resolveMessage("apiError.validation_invalidmessage.exception", params));
}
}
private void validateIncomingMessage(OrcidMessage orcidMessage, String orcid) {
try {
incomingValidationManager.validateMessage(orcidMessage);
if(!PojoUtil.isEmpty(orcid)) {
checkDeprecation(orcid);
}
} catch (OrcidValidationException e) {
Throwable cause = e.getCause();
if (cause == null) {
cause = e;
} else {
Throwable underlyingCause = cause.getCause();
if (underlyingCause != null) {
cause = underlyingCause;
}
}
Object params[] = {cause.toString()};
throw new OrcidValidationException(localeManager.resolveMessage("apiError.validation_invalidmessage.exception", params));
}
}
private void validateBioUpdateMessage(OrcidMessage orcidMessage) {
try {
incomingValidationManager.validateBioMessage(orcidMessage);
} catch (OrcidValidationException e) {
Throwable cause = e.getCause();
if (cause == null) {
cause = e;
} else {
Throwable underlyingCause = cause.getCause();
if (underlyingCause != null) {
cause = underlyingCause;
}
}
Object params[] = {cause.toString()};
throw new OrcidValidationException(localeManager.resolveMessage("apiError.validation_invalidmessage.exception", params));
}
}
/**
* Checks if an account is deprecated
*
* @param orcidMessage
* OrcidMessage, for it we can get the orcid to check for
* deprecation
* @throws DeprecatedException
* if the account is deprecated
* */
private void checkDeprecation(String orcid) {
ProfileEntity entity = profileEntityCacheManager.retrieve(orcid);
if (entity != null) {
if(entity.getDeprecatedDate() != null) {
Map<String, String> params = new HashMap<String, String>();
StringBuffer primary = new StringBuffer(orcidUrlManager.getBaseUrl()).append("/").append(entity.getPrimaryRecord().getId());
params.put(OrcidDeprecatedException.ORCID, primary.toString());
if(entity.getDeprecatedDate() != null) {
XMLGregorianCalendar calendar = DateUtils.convertToXMLGregorianCalendar(entity.getDeprecatedDate());
params.put(OrcidDeprecatedException.DEPRECATED_DATE, calendar.toString());
}
throw new OrcidDeprecatedException(params);
}
}
}
/**
* Verify if the orcid message is deprecated, if so, builds a reponse object
* with 301 status
*
* @param response
* The current response object.
* @return a response object.
* */
protected Response checkProfileStatus(Response response) {
OrcidMessage orcidMessage = (OrcidMessage) response.getEntity();
if (orcidMessage != null && orcidMessage.getOrcidProfile() != null && orcidMessage.getOrcidProfile().getOrcidDeprecated() != null) {
Map<String, String> params = new HashMap<String, String>();
params.put(OrcidDeprecatedException.ORCID, orcidMessage.getOrcidProfile().getOrcidDeprecated().getPrimaryRecord().getOrcidIdentifier().getUri());
params.put(OrcidDeprecatedException.DEPRECATED_DATE, orcidMessage.getOrcidProfile().getOrcidDeprecated().getDate().getValue().toXMLFormat());
throw new OrcidDeprecatedException(params);
}
return response;
}
private void validateOutgoingResponse(Response response) {
OrcidMessage orcidMessage = (OrcidMessage) response.getEntity();
outgoingValidationManager.validateMessage(orcidMessage);
}
private OrcidMessage upgradeMessage(OrcidMessage orcidMessage) {
return orcidMessageVersionConverterChain.upgradeMessage(orcidMessage, OrcidMessage.DEFAULT_VERSION);
}
private Response downgradeResponse(Response response) {
OrcidMessage orcidMessage = (OrcidMessage) response.getEntity();
if (orcidMessage != null) {
orcidMessageVersionConverterChain.downgradeMessage(orcidMessage, externalVersion);
}
return Response.fromResponse(response).entity(orcidMessage).build();
}
private Response downgradeAndValidateResponse(Response response) {
checkProfileStatus(response);
Response downgradedResponse = downgradeResponse(response);
validateOutgoingResponse(downgradedResponse);
return downgradedResponse;
}
@Override
public Response addAffiliations(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
checkAffiliationsSupport();
validateIncomingMessage(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
return t2OrcidApiServiceDelegator.addAffiliations(uriInfo, orcid, upgradedMessage);
}
@Override
public Response updateAffiliations(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
checkAffiliationsSupport();
validateIncomingMessage(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
return t2OrcidApiServiceDelegator.updateAffiliations(uriInfo, orcid, upgradedMessage);
}
private void checkAffiliationsSupport() {
if (!supportsAffiliations) {
throw new OrcidBadRequestException(localeManager.resolveMessage("apiError.badrequest_affiliations_notsupported.exception"));
}
}
@Override
public Response addFunding(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
validateIncomingMessage(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
return t2OrcidApiServiceDelegator.addFunding(uriInfo, orcid, upgradedMessage);
}
@Override
public Response updateFunding(UriInfo uriInfo, String orcid, OrcidMessage orcidMessage) {
validateIncomingMessage(orcidMessage, orcid);
OrcidMessage upgradedMessage = upgradeMessage(orcidMessage);
return t2OrcidApiServiceDelegator.updateFunding(uriInfo, orcid, upgradedMessage);
}
private void validateEmailAvailability(OrcidMessage orcidMessage, String targetOrcid) {
if(orcidMessage != null && orcidMessage.getOrcidProfile() != null && orcidMessage.getOrcidProfile().getOrcidBio() != null && orcidMessage.getOrcidProfile().getOrcidBio().getContactDetails() != null) {
List<Email> emailList = orcidMessage.getOrcidProfile().getOrcidBio().getContactDetails().getEmail();
for(Email email : emailList) {
if(!PojoUtil.isEmpty(email.getValue())) {
EmailEntity emailEntity = emailManager.findCaseInsensitive(email.getValue());
if(emailEntity != null) {
String emailOrcid = emailEntity.getProfile().getId();
if(!targetOrcid.equals(emailOrcid)) {
Object params[] = {email.getValue()};
throw new OrcidValidationException(localeManager.resolveMessage("apiError.validation_invalidmessage_email.exception", params));
}
}
}
}
}
}
}