All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.unit.nva.model.Publication Maven / Gradle / Ivy

There is a newer version: 0.23.2
Show newest version
package no.unit.nva.model;

import static java.util.Objects.hash;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static no.unit.nva.model.PublicationStatus.DRAFT_FOR_DELETION;
import static nva.commons.core.attempt.Try.attempt;
import static nva.commons.core.ioutils.IoUtils.stringFromResources;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.github.bibsysdev.ResourcesBuildConfig;
import java.net.URI;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import no.unit.nva.WithAssociatedArtifact;
import no.unit.nva.WithIdentifier;
import no.unit.nva.WithInternal;
import no.unit.nva.WithMetadata;
import no.unit.nva.commons.json.JsonUtils;
import no.unit.nva.identifiers.SortableIdentifier;
import no.unit.nva.model.associatedartifacts.AssociatedArtifact;
import no.unit.nva.model.associatedartifacts.AssociatedArtifactList;
import no.unit.nva.model.exceptions.InvalidPublicationStatusTransitionException;
import no.unit.nva.model.funding.Funding;
import no.unit.nva.model.funding.FundingList;
import nva.commons.core.JacocoGenerated;
import nva.commons.core.StringUtils;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@SuppressWarnings({"PMD.ExcessivePublicCount", "PMD.TooManyFields", "PMD.GodClass"})
public class Publication
    implements WithIdentifier, WithInternal, WithAssociatedArtifact, WithMetadata, WithCopy {

    public static final Map> validStatusTransitionsMap = Map.of(
        PublicationStatus.NEW, List.of(PublicationStatus.DRAFT),
        PublicationStatus.DRAFT, List.of(PublicationStatus.PUBLISHED, DRAFT_FOR_DELETION)
    );

    private static final String MODEL_VERSION = ResourcesBuildConfig.RESOURCES_MODEL_VERSION;
    private static final String BASE_URI = "__BASE_URI__";
    private static final String PUBLICATION_CONTEXT = stringFromResources(Path.of("publicationContext.json"));
    private static final String ONTOLOGY = stringFromResources(Path.of("publication-ontology.ttl"));
    public static final String MUST_PRESERVE_EXISTING_IMPORT_DETAILS = "Must preserve existing importDetails";

    private SortableIdentifier identifier;
    private PublicationStatus status;
    private ResourceOwner resourceOwner;
    private Organization publisher;
    private Instant createdDate;
    private Instant modifiedDate;
    private Instant publishedDate;
    private Instant indexedDate;
    private URI handle;
    private URI doi;
    private URI link;
    private EntityDescription entityDescription;
    private List projects;
    private FundingList fundings;
    private Set additionalIdentifiers;
    private List subjects;
    private AssociatedArtifactList associatedArtifacts;
    private String rightsHolder;
    private URI duplicateOf;

    private List publicationNotes;
    private Set curatingInstitutions;
    private List importDetails;

    public Publication() {
        // Default constructor, use setters.
    }

    public URI getDuplicateOf() {
        return duplicateOf;
    }

    public void setDuplicateOf(URI duplicateOf) {
        this.duplicateOf = duplicateOf;
    }

    public Set getAdditionalIdentifiers() {
        return nonNull(additionalIdentifiers) ? additionalIdentifiers : Collections.emptySet();
    }

    public void setAdditionalIdentifiers(Set additionalIdentifiers) {
        this.additionalIdentifiers = additionalIdentifiers;
    }

    @Override
    public Instant getCreatedDate() {
        return createdDate;
    }

    @Override
    public void setCreatedDate(Instant createdDate) {
        this.createdDate = createdDate;
    }

    @Override
    public PublicationStatus getStatus() {
        return status;
    }

    @Override
    public void setStatus(PublicationStatus status) {
        this.status = status;
    }

    @Override
    public URI getHandle() {
        return handle;
    }

    @Override
    public void setHandle(URI handle) {
        this.handle = handle;
    }

    @Override
    public Instant getPublishedDate() {
        return publishedDate;
    }

    @Override
    public void setPublishedDate(Instant publishedDate) {
        this.publishedDate = publishedDate;
    }

    @Override
    public Instant getModifiedDate() {
        return modifiedDate;
    }

    @Override
    public void setModifiedDate(Instant modifiedDate) {
        this.modifiedDate = modifiedDate;
    }

    @Override
    public ResourceOwner getResourceOwner() {
        return resourceOwner;
    }

    @Override
    public void setResourceOwner(ResourceOwner resourceOwner) {
        this.resourceOwner = resourceOwner;
    }

    @Override
    public Instant getIndexedDate() {
        return indexedDate;
    }

    @Override
    public void setIndexedDate(Instant indexedDate) {
        this.indexedDate = indexedDate;
    }

    @Override
    public URI getLink() {
        return link;
    }

    @Override
    public void setLink(URI link) {
        this.link = link;
    }

    @Override
    public Organization getPublisher() {
        return publisher;
    }

    @Override
    public void setPublisher(Organization publisher) {
        this.publisher = publisher;
    }

    @Override
    public URI getDoi() {
        return doi;
    }

    @Override
    public void setDoi(URI doi) {
        this.doi = doi;
    }

    @Override
    public SortableIdentifier getIdentifier() {
        return identifier;
    }

    @Override
    public void setIdentifier(SortableIdentifier identifier) {
        this.identifier = identifier;
    }

    @Override
    public EntityDescription getEntityDescription() {
        return entityDescription;
    }

    @Override
    public void setEntityDescription(EntityDescription entityDescription) {
        this.entityDescription = entityDescription;
    }

    @Override
    public List getProjects() {
        return nonNull(projects) ? projects : Collections.emptyList();
    }

    @Override
    public void setProjects(List projects) {
        this.projects = projects;
    }

    @Override
    public List getSubjects() {
        return nonNull(subjects) ? subjects : Collections.emptyList();
    }

    @Override
    public void setSubjects(List subjects) {
        this.subjects = subjects;
    }

    @Override
    public List getFundings() {
        return nonNull(fundings) ? fundings : Collections.emptyList();
    }

    @Override
    public void setFundings(List fundings) {
        this.fundings = new FundingList(fundings);
    }

    @Override
    public String getRightsHolder() {
        return rightsHolder;
    }

    @Override
    public void setRightsHolder(String rightsHolder) {
        this.rightsHolder = rightsHolder;
    }

    @JsonProperty("modelVersion")
    public String getModelVersion() {
        return MODEL_VERSION;
    }

    @JsonProperty("modelVersion")
    public void setModelVersion() {
        // NO-OP
    }

    @JsonGetter
    public List getPublicationNotes() {
        return nonNull(publicationNotes) ? publicationNotes : Collections.emptyList();
    }

    public void setPublicationNotes(List publicationNotes) {
        this.publicationNotes = publicationNotes;
    }

    @Override
    public AssociatedArtifactList getAssociatedArtifacts() {
        return nonNull(associatedArtifacts)
                   ? associatedArtifacts
                   : AssociatedArtifactList.empty();
    }

    @Override
    public void setAssociatedArtifacts(AssociatedArtifactList associatedArtifacts) {
        this.associatedArtifacts = associatedArtifacts;
    }

    @Override
    public Builder copy() {
        return new Builder()
                   .withIdentifier(getIdentifier())
                   .withStatus(getStatus())
                   .withResourceOwner(getResourceOwner())
                   .withPublisher(getPublisher())
                   .withCreatedDate(getCreatedDate())
                   .withModifiedDate(getModifiedDate())
                   .withPublishedDate(getPublishedDate())
                   .withIndexedDate(getIndexedDate())
                   .withHandle(getHandle())
                   .withDoi(getDoi())
                   .withLink(getLink())
                   .withEntityDescription(getEntityDescription())
                   .withProjects(getProjects())
                   .withFundings(getFundings())
                   .withAdditionalIdentifiers(getAdditionalIdentifiers())
                   .withAssociatedArtifacts(getAssociatedArtifacts())
                   .withSubjects(getSubjects())
                   .withFundings(getFundings())
                   .withRightsHolder(getRightsHolder())
                   .withPublicationNotes(getPublicationNotes())
                   .withDuplicateOf(getDuplicateOf())
                   .withCuratingInstitutions(getCuratingInstitutions())
                   .withImportDetails(getImportDetails());
    }

    /**
     * Updates the status of the publication using rules for valid status transitions.
     *
     * @param nextStatus the status to update to
     * @throws InvalidPublicationStatusTransitionException if the status transition is not allowed
     */
    public void updateStatus(PublicationStatus nextStatus) throws InvalidPublicationStatusTransitionException {
        verifyStatusTransition(nextStatus);
        setStatus(nextStatus);
    }

    @JacocoGenerated
    @Override
    public int hashCode() {
        return hash(getIdentifier(), getStatus(), getPublisher(), getCreatedDate(), getModifiedDate(),
                    getPublishedDate(), getIndexedDate(), getHandle(), getDoi(), getLink(),
                    getEntityDescription(), getProjects(), getFundings(), getAdditionalIdentifiers(), getSubjects(),
                    getAssociatedArtifacts(), getRightsHolder(), getPublicationNotes(), getDuplicateOf(),
                    getCuratingInstitutions(), getImportDetails());
    }

    @JacocoGenerated
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Publication)) {
            return false;
        }
        Publication that = (Publication) o;
        boolean firstHalf = Objects.equals(getIdentifier(), that.getIdentifier())
                            && getStatus() == that.getStatus()
                            && Objects.equals(getResourceOwner(), that.getResourceOwner())
                            && Objects.equals(getPublisher(), that.getPublisher())
                            && Objects.equals(getCreatedDate(), that.getCreatedDate())
                            && Objects.equals(getModifiedDate(), that.getModifiedDate())
                            && Objects.equals(getPublishedDate(), that.getPublishedDate());
        boolean secondHalf = Objects.equals(getIndexedDate(), that.getIndexedDate())
                             && Objects.equals(getHandle(), that.getHandle())
                             && Objects.equals(getDoi(), that.getDoi())
                             && Objects.equals(getLink(), that.getLink())
                             && Objects.equals(getEntityDescription(), that.getEntityDescription())
                             && Objects.equals(getAssociatedArtifacts(), that.getAssociatedArtifacts())
                             && Objects.equals(getProjects(), that.getProjects())
                             && Objects.equals(getFundings(), that.getFundings())
                             && Objects.equals(getAdditionalIdentifiers(), that.getAdditionalIdentifiers())
                             && Objects.equals(getSubjects(), that.getSubjects())
                             && Objects.equals(getRightsHolder(), that.getRightsHolder())
                             && Objects.equals(getPublicationNotes(), that.getPublicationNotes())
                             && Objects.equals(getDuplicateOf(), that.getDuplicateOf())
                             && Objects.equals(getCuratingInstitutions(), that.getCuratingInstitutions())
                             && Objects.equals(getImportDetails(), that.getImportDetails());
        return firstHalf && secondHalf;
    }

    @Override
    public String toString() {
        return attempt(() -> JsonUtils.dtoObjectMapper.writeValueAsString(this)).orElseThrow();
    }

    @JsonIgnore
    @Deprecated
    public String getJsonLdContext() {
        return stringFromResources(Path.of("publicationContextDeprecated.json"));
    }

    @JsonIgnore
    public static String getJsonLdContext(URI baseUri) {
        return PUBLICATION_CONTEXT.replace(BASE_URI, baseUri.toString());
    }

    @JsonIgnore
    public static String getOntology(URI baseUri) {
        return ONTOLOGY.replace(BASE_URI, baseUri.toString());
    }

    @JsonIgnore
    public boolean isPublishable() {
        return !DRAFT_FOR_DELETION.equals(getStatus()) && hasMainTitle();
    }

    public boolean satisfiesFindableDoiRequirements() {
        return FindableDoiRequirementsValidator.meetsFindableDoiRequirements(this);
    }

    public Set getCuratingInstitutions() {
        return nonNull(curatingInstitutions) ? curatingInstitutions : Collections.emptySet();
    }

    public void setCuratingInstitutions(Set curatingInstitutions) {
        this.curatingInstitutions = curatingInstitutions;
    }

    @Override
    public List getImportDetails() {
        return nonNull(importDetails) ? importDetails : Collections.emptyList();
    }

    @Override
    public void setImportDetails(Collection importDetails) {
        if (importDetails == null || !new HashSet<>(importDetails).containsAll(getImportDetails())) {
            throw new IllegalArgumentException(MUST_PRESERVE_EXISTING_IMPORT_DETAILS);
        }

        this.importDetails = new ArrayList<>(importDetails);
    }

    public void addImportDetail(ImportDetail importDetail) {
        if (isNull(importDetail)) {
            return;
        }

        if (isNull(importDetails)) {
            importDetails = new ArrayList<>();
        }

        importDetails.add(importDetail);
    }

    private void verifyStatusTransition(PublicationStatus nextStatus)
        throws InvalidPublicationStatusTransitionException {
        final PublicationStatus currentStatus = getStatus();
        if (!validStatusTransitionsMap.get(currentStatus).contains(nextStatus)) {
            throw new InvalidPublicationStatusTransitionException(currentStatus, nextStatus);
        }
    }

    private boolean hasMainTitle() {
        return Optional.ofNullable(getEntityDescription())
                   .map(EntityDescription::getMainTitle)
                   .filter(string -> !StringUtils.isEmpty(string))
                   .isPresent();
    }

    public static final class Builder {

        private final Publication publication;

        public Builder() {
            publication = new Publication();
        }

        public Builder withIdentifier(SortableIdentifier identifier) {
            publication.setIdentifier(identifier);
            return this;
        }

        public Builder withStatus(PublicationStatus status) {
            publication.setStatus(status);
            return this;
        }

        public Builder withPublisher(Organization publisher) {
            publication.setPublisher(publisher);
            return this;
        }

        public Builder withCreatedDate(Instant createdDate) {
            publication.setCreatedDate(createdDate);
            return this;
        }

        public Builder withModifiedDate(Instant modifiedDate) {
            publication.setModifiedDate(modifiedDate);
            return this;
        }

        public Builder withPublishedDate(Instant publishedDate) {
            publication.setPublishedDate(publishedDate);
            return this;
        }

        public Builder withIndexedDate(Instant indexedDate) {
            publication.setIndexedDate(indexedDate);
            return this;
        }

        public Builder withHandle(URI handle) {
            publication.setHandle(handle);
            return this;
        }

        public Builder withDoi(URI doi) {
            publication.setDoi(doi);
            return this;
        }

        public Builder withLink(URI link) {
            publication.setLink(link);
            return this;
        }

        public Builder withEntityDescription(EntityDescription entityDescription) {
            publication.setEntityDescription(entityDescription);
            return this;
        }

        public Builder withAssociatedArtifacts(List associatedArtifacts) {
            publication.setAssociatedArtifacts(new AssociatedArtifactList(associatedArtifacts));
            return this;
        }

        public Builder withProjects(List projects) {
            publication.setProjects(projects);
            return this;
        }

        public Builder withFundings(List fundings) {
            publication.setFundings(fundings);
            return this;
        }

        public Builder withAdditionalIdentifiers(Set additionalIdentifiers) {
            publication.setAdditionalIdentifiers(additionalIdentifiers);
            return this;
        }

        public Builder withSubjects(List subjects) {
            publication.setSubjects(subjects);
            return this;
        }

        public Builder withResourceOwner(ResourceOwner randomResourceOwner) {
            publication.setResourceOwner(randomResourceOwner);
            return this;
        }


        public Builder withRightsHolder(String rightsHolder) {
            this.publication.setRightsHolder(rightsHolder);
            return this;
        }

        public Builder withPublicationNotes(List publicationNotes) {
            publication.setPublicationNotes(publicationNotes);
            return this;
        }

        public Builder withDuplicateOf(URI duplicateOf) {
            publication.setDuplicateOf(duplicateOf);
            return this;
        }

        public Builder withCuratingInstitutions(Set curatingInstitutions) {
            publication.setCuratingInstitutions(curatingInstitutions);
            return this;
        }

        public Builder withImportDetails(List importDetails) {
            publication.setImportDetails(importDetails);
            return this;
        }

        public Publication build() {
            return publication;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy