/** * ============================================================================= * * 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.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.orcid.core.exception.WrongSourceException; import org.orcid.core.manager.OrcidJaxbCopyManager; import org.orcid.core.manager.SourceManager; import org.orcid.core.security.visibility.OrcidVisibilityDefaults; import org.orcid.jaxb.model.message.ActivitiesContainer; import org.orcid.jaxb.model.message.Activity; import org.orcid.jaxb.model.message.Address; import org.orcid.jaxb.model.message.Affiliation; import org.orcid.jaxb.model.message.Affiliations; import org.orcid.jaxb.model.message.Biography; import org.orcid.jaxb.model.message.Claimed; import org.orcid.jaxb.model.message.ContactDetails; import org.orcid.jaxb.model.message.CreditName; import org.orcid.jaxb.model.message.Email; import org.orcid.jaxb.model.message.ExternalIdentifiers; import org.orcid.jaxb.model.message.Funding; import org.orcid.jaxb.model.message.FundingList; import org.orcid.jaxb.model.message.Keywords; import org.orcid.jaxb.model.message.OrcidBio; import org.orcid.jaxb.model.message.OrcidHistory; import org.orcid.jaxb.model.message.OrcidWork; import org.orcid.jaxb.model.message.OrcidWorks; import org.orcid.jaxb.model.message.OtherNames; import org.orcid.jaxb.model.message.PersonalDetails; import org.orcid.jaxb.model.message.ResearcherUrls; import org.orcid.jaxb.model.message.Source; import org.orcid.jaxb.model.message.SourceClientId; import org.orcid.jaxb.model.message.SourceOrcid; import org.orcid.jaxb.model.message.Visibility; import org.orcid.pojo.ajaxForm.PojoUtil; import org.orcid.utils.OrcidStringUtils; import org.springframework.util.Assert; /** * Simple class containing static methods to copy values from updated profiles * to the existing one, whilst preserving or setting the visibility. If neither * the updated nor existing property contains a value for visbility a default * will be set using the {@link OrcidVisibilityDefaults}. * <p/> * It is important to note that the it is intentional that the values are copied * from the updated to the existing, in order to preserve values that would * otherwise be overwritten. Some of the values can only perform 'best shot' at * matching them, in which case it will use the defaults if not able to match * <p/> * * @author Declan Newman (declan) Date: 13/03/2012 */ public class OrcidJaxbCopyManagerImpl implements OrcidJaxbCopyManager { @Resource private SourceManager sourceManager; @Override public void copyRelevantUpdatedHistoryElements(OrcidHistory existing, OrcidHistory updated) { Assert.notNull(updated, "The updated history is null"); Assert.notNull(existing, "The existing history is null"); if (updated.isClaimed() && !existing.isClaimed()) { existing.setClaimed(new Claimed(true)); } if (existing.getCompletionDate() == null && updated.getCompletionDate() != null) { existing.setCompletionDate(updated.getCompletionDate()); } // TODO: There may be some others that need to be added to this. } @Override public void copyUpdatedBioToExistingWithVisibility(OrcidBio existing, OrcidBio updated) { Assert.notNull(updated, "The updated bio is null"); Assert.notNull(existing, "The existing bio is null"); copyUpdatedPersonalDetailsToExistingPreservingVisibility(existing, updated); copyUpdatedResearcherUrlPreservingVisbility(existing, updated); copyUpdatedContactDetailsToExistingPreservingVisibility(existing, updated); copyUpdatedKeywordsToExistingPreservingVisibility(existing, updated); copyUpdatedShortDescriptionToExistingPreservingVisibility(existing, updated); copyUpdatedExternalIdentifiersToExistingPreservingVisibility(existing, updated); } @Override public void copyAffiliationsToExistingPreservingVisibility(Affiliations existingAffiliations, Affiliations updatedAffiliations) { copyActivitiesToExistingPreservingVisibility(existingAffiliations, updatedAffiliations, OrcidVisibilityDefaults.AFFILIATE_NAME_DEFAULT.getVisibility()); } @SuppressWarnings({ "unchecked", "rawtypes" }) private void copyActivitiesToExistingPreservingVisibility(ActivitiesContainer existingActivities, ActivitiesContainer updatedActivities, Visibility defaultVisibility) { if (updatedActivities == null) { return; } if (existingActivities == null) { try { existingActivities = updatedActivities.getClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } Map<String, ? extends Activity> updatedActivitiesMap = updatedActivities.retrieveActivitiesAsMap(); Source targetSource = createSource(sourceManager.retrieveSourceOrcid()); for (Iterator<? extends Activity> existingActivitiesIterator = existingActivities.retrieveActivities().iterator(); existingActivitiesIterator.hasNext();) { Activity existingActivity = existingActivitiesIterator.next(); Activity updatedActivity = updatedActivitiesMap.get(existingActivity.getPutCode()); if (updatedActivity == null) { if (!(Visibility.PRIVATE.equals(existingActivity.getVisibility()) || isFromDifferentSource(existingActivity))) { // Remove existing activities unless they are private (we // need to keep those because the API user won't even know // they are there) or they are from another source existingActivitiesIterator.remove(); } } else { // Check the source of the existing activity is the same as // the current source checkSource(existingActivity); if (updatedActivity.getVisibility() == null || !updatedActivity.getVisibility().equals(existingActivity.getVisibility())) { // Keep the visibility from the existing activity unless // was set by API user updatedActivity.setVisibility(existingActivity.getVisibility()); } addSourceToActivity(updatedActivity, targetSource); // Can remove existing object because will be replaced by // incoming existingActivitiesIterator.remove(); } } for (Activity updatedActivity : updatedActivities.retrieveActivities()) { // Set default visibility for any remaining incoming affiliations if (updatedActivity.getVisibility() == null) { updatedActivity.setVisibility(defaultVisibility); } if (updatedActivity.getPutCode() == null) { // Check source is correct for any newly added activities, if // mentioned addSourceToActivity(updatedActivity, targetSource); } } existingActivities.retrieveActivities().addAll((List) updatedActivities.retrieveActivities()); } private void addSourceToActivity(Activity updatedActivity, Source targetSource) { if(updatedActivity instanceof OrcidWork) { ((OrcidWork) updatedActivity).setSource(targetSource); } else if(updatedActivity instanceof Funding) { ((Funding) updatedActivity).setSource(targetSource); } else if(updatedActivity instanceof Affiliation) { ((Affiliation) updatedActivity).setSource(targetSource); } } private void checkSource(Activity activity) { if (isFromDifferentSource(activity)) { Map<String, String> params = new HashMap<String, String>(); params.put("activity", "activity"); throw new WrongSourceException(params); } } private Source createSource(String amenderOrcid) { Source source = new Source(); if (OrcidStringUtils.isValidOrcid(amenderOrcid)) { source.setSourceOrcid(new SourceOrcid(amenderOrcid)); source.setSourceClientId(null); } else { source.setSourceClientId(new SourceClientId(amenderOrcid)); source.setSourceOrcid(null); } return source; } private boolean isFromDifferentSource(Activity activity) { String currentSource = sourceManager.retrieveSourceOrcid(); if (currentSource == null) { // Not under Spring security so anything goes return false; } return !currentSource.equals(activity.retrieveSourcePath()); } @Override public void copyFundingListToExistingPreservingVisibility(FundingList existingFundings, FundingList updatedFundings) { copyActivitiesToExistingPreservingVisibility(existingFundings, updatedFundings, OrcidVisibilityDefaults.FUNDING_DEFAULT.getVisibility()); } @Override public void copyUpdatedExternalIdentifiersToExistingPreservingVisibility(OrcidBio existing, OrcidBio updated) { if (updated.getExternalIdentifiers() == null) { return; } ExternalIdentifiers existingExternalIdentifiers = existing.getExternalIdentifiers(); ExternalIdentifiers updatedExternalIdentifiers = updated.getExternalIdentifiers(); Visibility existingExternalIdentifiersVisibility = existingExternalIdentifiers != null ? existingExternalIdentifiers.getVisibility() : null; Visibility updatedExternalIdentifiersVisibility = updatedExternalIdentifiers.getVisibility(); if (updatedExternalIdentifiersVisibility == null && existingExternalIdentifiersVisibility == null) { updatedExternalIdentifiers.setVisibility(OrcidVisibilityDefaults.EXTERNAL_IDENTIFIER_DEFAULT.getVisibility()); } else if (updatedExternalIdentifiersVisibility == null && existingExternalIdentifiersVisibility != null) { updatedExternalIdentifiers.setVisibility(existingExternalIdentifiersVisibility); } existing.setExternalIdentifiers(updatedExternalIdentifiers); } @Override public void copyUpdatedShortDescriptionToExistingPreservingVisibility(OrcidBio existing, OrcidBio updated) { if (updated.getBiography() == null) { return; } Biography existingShortDescription = existing.getBiography(); Biography updatedShortDescription = updated.getBiography(); Visibility existingShortDescriptionVisibility = existingShortDescription != null ? existingShortDescription.getVisibility() : OrcidVisibilityDefaults.SHORT_DESCRIPTION_DEFAULT.getVisibility(); Visibility updatedShortDescriptionVisibility = updatedShortDescription != null ? updatedShortDescription.getVisibility() : existingShortDescriptionVisibility; if (updatedShortDescriptionVisibility == null && existingShortDescriptionVisibility == null) { updatedShortDescription.setVisibility(OrcidVisibilityDefaults.SHORT_DESCRIPTION_DEFAULT.getVisibility()); } else if (updatedShortDescriptionVisibility == null && existingShortDescriptionVisibility != null) { updatedShortDescription.setVisibility(existingShortDescriptionVisibility); } if(existingShortDescription != null) { if(existingShortDescription.getVisibility() != null && !existingShortDescription.getVisibility().equals(Visibility.PRIVATE)) { existing.setBiography(updatedShortDescription); } } else { existing.setBiography(updatedShortDescription); } } @Override public void copyUpdatedKeywordsToExistingPreservingVisibility(OrcidBio existing, OrcidBio updated) { if (updated.getKeywords() == null) { return; } Visibility existingKeywordsVisibility = existing.getKeywords() != null && existing.getKeywords().getVisibility() != null ? existing.getKeywords().getVisibility() : OrcidVisibilityDefaults.KEYWORD_DEFAULT.getVisibility(); Visibility updatedKeywordsVisibility = updated.getKeywords().getVisibility() != null ? updated.getKeywords().getVisibility() : existingKeywordsVisibility; Keywords updatedKeywords = updated.getKeywords(); updatedKeywords.setVisibility(updatedKeywordsVisibility); existing.setKeywords(updatedKeywords); } @Override public void copyUpdatedContactDetailsToExistingPreservingVisibility(OrcidBio existing, OrcidBio updated) { ContactDetails existingContactDetails = existing.getContactDetails(); ContactDetails updatedContactDetails = updated.getContactDetails(); // copyUpdatedEmails(existingContactDetails, updatedContactDetails); copyUpdatedAddress(existingContactDetails, updatedContactDetails); } //Not being used now as the client is not allowed to add or edit emails. @SuppressWarnings("unused") private void copyUpdatedEmails(ContactDetails existingContactDetails, ContactDetails updatedContactDetails) { String clientId = sourceManager.retrieveSourceOrcid(); List<Email> allEmails = new ArrayList<Email>(); List<Email> existingEmails = existingContactDetails.getEmail(); for(Email oldEmail : existingEmails) { Email tempEmail = null; if(updatedContactDetails != null) { tempEmail = updatedContactDetails.getEmailByString(oldEmail.getValue()); } String oldEmSource = (oldEmail.getSourceClientId() == null) ? oldEmail.getSource() : oldEmail.getSourceClientId(); if(clientId == null || (clientId != null && !clientId.equals(oldEmSource))) { allEmails.add(oldEmail); if(tempEmail != null) { updatedContactDetails.getEmail().remove(tempEmail); } } else { if(oldEmail.isPrimary()) { if(tempEmail != null) { updatedContactDetails.getEmail().remove(tempEmail); if(!Visibility.PRIVATE.equals(oldEmail.getVisibility())) { oldEmail.setVisibility(tempEmail.getVisibility()); } } allEmails.add(oldEmail); } else if(Visibility.PRIVATE.equals(oldEmail.getVisibility())) { if(tempEmail != null) { updatedContactDetails.getEmail().remove(tempEmail); } allEmails.add(oldEmail); } else { if(tempEmail != null) { updatedContactDetails.getEmail().remove(tempEmail); tempEmail.setPrimary(false); allEmails.add(tempEmail); } } } } //Set primary = false for each remaining new email. if(updatedContactDetails != null) { for(Email newEmail : updatedContactDetails.getEmail()) { newEmail.setPrimary(false); allEmails.add(newEmail); } } for(Email email : allEmails) { if(email.getVisibility() == null) { email.setVisibility(OrcidVisibilityDefaults.ALTERNATIVE_EMAIL_DEFAULT.getVisibility()); } } existingContactDetails.setEmail(allEmails); } private void copyUpdatedAddress(ContactDetails existingContactDetails, ContactDetails updatedContactDetails) { if(updatedContactDetails == null) { return; } if (existingContactDetails.getAddress() == null) { existingContactDetails.setAddress(updatedContactDetails.getAddress()); } else { Address existingAddress = existingContactDetails.getAddress(); Address updatedAddress = updatedContactDetails.getAddress(); if (updatedAddress != null) { if (existingAddress.getCountry() != null) { if (!Visibility.PRIVATE.equals(existingAddress.getCountry().getVisibility())) { if(updatedAddress.getCountry() != null) { existingAddress.getCountry().setValue(updatedAddress.getCountry().getValue()); } } } else { existingAddress.setCountry(updatedAddress.getCountry()); } } } if (existingContactDetails.getAddress() != null && existingContactDetails.getAddress().getCountry() != null && existingContactDetails.getAddress().getCountry().getVisibility() == null) { existingContactDetails.getAddress().getCountry().setVisibility(OrcidVisibilityDefaults.COUNTRY_DEFAULT.getVisibility()); } } @Override public void copyUpdatedResearcherUrlPreservingVisbility(OrcidBio existing, OrcidBio updated) { if (updated.getResearcherUrls() == null) { return; } ResearcherUrls existingResearcherUrls = existing.getResearcherUrls(); ResearcherUrls updatedResearcherUrls = updated.getResearcherUrls(); Visibility existingVisibility = (existingResearcherUrls != null && existingResearcherUrls.getVisibility() != null) ? existingResearcherUrls.getVisibility() : OrcidVisibilityDefaults.RESEARCHER_URLS_DEFAULT.getVisibility(); Visibility updatedVisibility = (updatedResearcherUrls != null && updatedResearcherUrls.getVisibility() != null) ? updatedResearcherUrls.getVisibility() : existingVisibility; // now visibility has been preserved, overwrite the content updatedResearcherUrls.setVisibility(updatedVisibility); existing.setResearcherUrls(updatedResearcherUrls); } @Override public void copyUpdatedPersonalDetailsToExistingPreservingVisibility(OrcidBio existing, OrcidBio updated) { PersonalDetails existingPersonalDetails = existing.getPersonalDetails(); PersonalDetails updatedPersonalDetails = updated.getPersonalDetails(); // if no update, nothing to do if (updatedPersonalDetails == null) { return; } // if existing null, update unconditionally - we've no previous to // compare to if (existingPersonalDetails == null) { existing.setPersonalDetails(updatedPersonalDetails); return; } // otherwise preserve visibility of other names && credit names copyOtherNamesPreservingVisibility(existingPersonalDetails, updatedPersonalDetails); copyCreditNamePreservingVisibility(existingPersonalDetails, updatedPersonalDetails); if(updatedPersonalDetails.getFamilyName() != null && !PojoUtil.isEmpty(updatedPersonalDetails.getFamilyName().getContent())) { existingPersonalDetails.setFamilyName(updatedPersonalDetails.getFamilyName()); } if(updatedPersonalDetails.getGivenNames() != null && !PojoUtil.isEmpty(updatedPersonalDetails.getGivenNames().getContent())) { existingPersonalDetails.setGivenNames(updatedPersonalDetails.getGivenNames()); } } private void copyOtherNamesPreservingVisibility(PersonalDetails existingPersonalDetails, PersonalDetails updatedPersonalDetails) { OtherNames existingOtherNames = existingPersonalDetails.getOtherNames(); OtherNames updatedOtherNames = updatedPersonalDetails.getOtherNames(); // if no update, nothing to do if (updatedOtherNames == null) { return; } // otherwise take into account the visibility of updated and existing Visibility existingVisibility = existingOtherNames.getVisibility() != null ? existingOtherNames.getVisibility() : OrcidVisibilityDefaults.OTHER_NAMES_DEFAULT .getVisibility(); updatedOtherNames.setVisibility(updatedOtherNames.getVisibility() != null ? updatedOtherNames.getVisibility() : existingVisibility); // now visibility has been preserved, overwrite the content existingPersonalDetails.setOtherNames(updatedOtherNames); } private void copyCreditNamePreservingVisibility(PersonalDetails existingPersonalDetails, PersonalDetails updatedPersonalDetails) { CreditName existingCreditName = existingPersonalDetails.getCreditName(); CreditName updatedCreditName = updatedPersonalDetails.getCreditName(); // if no update, nothing to do if (updatedCreditName == null) { return; } // otherwise take into account the visibility of updated and existing Visibility existingVisibility = (existingCreditName != null && existingCreditName.getVisibility() != null) ? existingCreditName.getVisibility() : OrcidVisibilityDefaults.NAMES_DEFAULT.getVisibility(); // If it is private, ignore the request if (!existingVisibility.equals(Visibility.PRIVATE)) { Visibility updatedVisibility = (updatedCreditName != null && updatedCreditName.getVisibility() != null) ? updatedCreditName.getVisibility() : existingVisibility; updatedCreditName.setVisibility(updatedVisibility); // now visibility has been preserved, overwrite the content existingPersonalDetails.setCreditName(updatedCreditName); } } @Override public void copyUpdatedWorksPreservingVisbility(OrcidWorks existingWorks, OrcidWorks updatedWorks) { copyActivitiesToExistingPreservingVisibility(existingWorks, updatedWorks, OrcidVisibilityDefaults.WORKS_DEFAULT.getVisibility()); } @Override public void copyUpdatedFundingListVisibilityInformationOnlyPreservingVisbility(FundingList existingFundingList, FundingList updatedFundingList) { throw new RuntimeException("Not implemented!"); } public void setSourceManager(SourceManager sourceManager) { this.sourceManager = sourceManager; } }