package edu.harvard.iq.dataverse;
import edu.harvard.iq.dataverse.harvest.client.HarvestingClient;
import edu.harvard.iq.dataverse.authorization.DataverseRole;
import edu.harvard.iq.dataverse.search.savedsearch.SavedSearch;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
/**
*
* @author gdurand
* @author mbarsinai
*/
@NamedQueries({
@NamedQuery(name = "Dataverse.ownedObjectsById", query = "SELECT COUNT(obj) FROM DvObject obj WHERE obj.owner.id=:id"),
@NamedQuery(name = "Dataverse.findByAlias", query="SELECT dv FROM Dataverse dv WHERE LOWER(dv.alias)=:alias"),
@NamedQuery(name = "Dataverse.filterByAlias", query="SELECT dv FROM Dataverse dv WHERE LOWER(dv.alias) LIKE :alias order by dv.alias"),
@NamedQuery(name = "Dataverse.filterByAliasNameAffiliation", query="SELECT dv FROM Dataverse dv WHERE (LOWER(dv.alias) LIKE :alias) OR (LOWER(dv.name) LIKE :name) OR (LOWER(dv.affiliation) LIKE :affiliation) order by dv.alias")
})
@Entity
@Table(indexes = {@Index(columnList="defaultcontributorrole_id")
, @Index(columnList="defaulttemplate_id")
, @Index(columnList="alias")
, @Index(columnList="affiliation")
, @Index(columnList="dataversetype")
, @Index(columnList="facetroot")
, @Index(columnList="guestbookroot")
, @Index(columnList="metadatablockroot")
, @Index(columnList="templateroot")
, @Index(columnList="permissionroot")
, @Index(columnList="themeroot")})
public class Dataverse extends DvObjectContainer {
public enum DataverseType {
RESEARCHERS, RESEARCH_PROJECTS, JOURNALS, ORGANIZATIONS_INSTITUTIONS, TEACHING_COURSES, UNCATEGORIZED, LABORATORY, RESEARCH_GROUP
};
private static final long serialVersionUID = 1L;
@NotBlank(message = "Please enter a name.")
@Column( nullable = false )
private String name;
/**
* @todo add @Column(nullable = false) for the database to enforce non-null
*/
@NotBlank(message = "Please enter an alias.")
@Column(nullable = false, unique=true)
@Size(max = 60, message = "Alias must be at most 60 characters.")
@Pattern.List({@Pattern(regexp = "[a-zA-Z0-9\\_\\-]*", message = "Found an illegal character(s). Valid characters are a-Z, 0-9, '_', and '-'."),
@Pattern(regexp=".*\\D.*", message="Alias should not be a number")})
private String alias;
@Column(name = "description", columnDefinition = "TEXT")
private String description;
@Enumerated(EnumType.STRING)
@NotNull(message = "Please select a category for your dataverse.")
@Column( nullable = false )
private DataverseType dataverseType;
/**
* When {@code true}, users are not granted permissions the got for parent
* dataverses.
*/
protected boolean permissionRoot;
public DataverseType getDataverseType() {
return dataverseType;
}
public void setDataverseType(DataverseType dataverseType) {
this.dataverseType = dataverseType;
}
@Transient
private final String uncategorizedString = "Uncategorized";
/**
* @todo Don't hard code these as English.
*/
public String getFriendlyCategoryName(){
switch (this.dataverseType) {
case RESEARCHERS:
return "Researcher";
case RESEARCH_PROJECTS:
return "Research Project";
case JOURNALS:
return "Journal";
case ORGANIZATIONS_INSTITUTIONS:
return "Organization or Institution";
case TEACHING_COURSES:
return "Teaching Course";
case LABORATORY:
return "Laboratory";
case RESEARCH_GROUP:
return "Research Group";
case UNCATEGORIZED:
return uncategorizedString;
default:
return "";
}
}
public String getIndexableCategoryName() {
String friendlyName = getFriendlyCategoryName();
if (friendlyName.equals(uncategorizedString)) {
return null;
} else {
return friendlyName;
}
}
private String affiliation;
// Note: We can't have "Remove" here, as there are role assignments that refer
// to this role. So, adding it would mean violating a forign key contstraint.
@OneToMany(cascade = {CascadeType.MERGE},
fetch = FetchType.LAZY,
mappedBy = "owner")
private Set<DataverseRole> roles;
@ManyToOne
@JoinColumn(nullable = false)
private DataverseRole defaultContributorRole;
public DataverseRole getDefaultContributorRole() {
return defaultContributorRole;
}
public void setDefaultContributorRole(DataverseRole defaultContributorRole) {
this.defaultContributorRole = defaultContributorRole;
}
private boolean metadataBlockRoot;
private boolean facetRoot;
private boolean themeRoot;
private boolean templateRoot;
@OneToOne(mappedBy = "dataverse",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST}, orphanRemoval=true)
private DataverseTheme dataverseTheme;
@OneToMany(mappedBy = "dataverse",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST}, orphanRemoval=true)
@OrderBy("displayOrder")
@NotEmpty(message="At least one contact is required.")
private List<DataverseContact> dataverseContacts = new ArrayList();
@ManyToMany(cascade = {CascadeType.MERGE})
private List<MetadataBlock> metadataBlocks = new ArrayList();
@OneToMany(mappedBy = "dataverse",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST}, orphanRemoval=true)
@OrderBy("displayOrder")
private List<DataverseFacet> dataverseFacets = new ArrayList();
@ManyToMany(cascade = {CascadeType.MERGE})
@JoinTable(name = "dataverse_citationDatasetFieldTypes",
joinColumns = @JoinColumn(name = "dataverse_id"),
inverseJoinColumns = @JoinColumn(name = "citationdatasetfieldtype_id"))
private List<DatasetFieldType> citationDatasetFieldTypes = new ArrayList();
@ManyToMany
@JoinTable(name = "dataversesubjects",
joinColumns = @JoinColumn(name = "dataverse_id"),
inverseJoinColumns = @JoinColumn(name = "controlledvocabularyvalue_id"))
private Set<ControlledVocabularyValue> dataverseSubjects;
@OneToMany(mappedBy="dataverse", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
private List<DataverseFeaturedDataverse> dataverseFeaturedDataverses;
public List<DataverseFeaturedDataverse> getDataverseFeaturedDataverses() {
return dataverseFeaturedDataverses;
}
public void setDataverseFeaturedDataverses(List<DataverseFeaturedDataverse> dataverseFeaturedDataverses) {
this.dataverseFeaturedDataverses = dataverseFeaturedDataverses;
}
@OneToMany(mappedBy="featuredDataverse", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
private List<DataverseFeaturedDataverse> dataverseFeaturingDataverses;
public List<DataverseFeaturedDataverse> getDataverseFeaturingDataverses() {
return dataverseFeaturingDataverses;
}
public void setDataverseFeaturingDataverses(List<DataverseFeaturedDataverse> dataverseFeaturingDataverses) {
this.dataverseFeaturingDataverses = dataverseFeaturingDataverses;
}
@OneToMany(mappedBy="dataverse", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
private List<DataverseLinkingDataverse> dataverseLinkingDataverses;
public List<DataverseLinkingDataverse> getDataverseLinkingDataverses() {
return dataverseLinkingDataverses;
}
public void setDataverseLinkingDataverses(List<DataverseLinkingDataverse> dataverseLinkingDataverses) {
this.dataverseLinkingDataverses = dataverseLinkingDataverses;
}
@OneToMany(mappedBy="linkingDataverse", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
private List<DataverseLinkingDataverse> dataverseLinkedDataverses;
public List<DataverseLinkingDataverse> getDataverseLinkedDataverses() {
return dataverseLinkedDataverses;
}
public void setDataverseLinkedDataverses(List<DataverseLinkingDataverse> dataverseLinkedDataverses) {
this.dataverseLinkedDataverses = dataverseLinkedDataverses;
}
@OneToMany(mappedBy="linkingDataverse", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
private List<DatasetLinkingDataverse> datasetLinkingDataverses;
public List<DatasetLinkingDataverse> getDatasetLinkingDataverses() {
return datasetLinkingDataverses;
}
public void setDatasetLinkingDataverses(List<DatasetLinkingDataverse> datasetLinkingDataverses) {
this.datasetLinkingDataverses = datasetLinkingDataverses;
}
public Set<ControlledVocabularyValue> getDataverseSubjects() {
return dataverseSubjects;
}
public void setDataverseSubjects(Set<ControlledVocabularyValue> dataverseSubjects) {
this.dataverseSubjects = dataverseSubjects;
}
@OneToMany(mappedBy = "dataverse")
private List<DataverseFieldTypeInputLevel> dataverseFieldTypeInputLevels = new ArrayList();
@ManyToOne
@JoinColumn(nullable = true)
private Template defaultTemplate;
@OneToMany(mappedBy = "definitionPoint", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
private List<SavedSearch> savedSearches;
public List<SavedSearch> getSavedSearches() {
return savedSearches;
}
public void setSavedSearches(List<SavedSearch> savedSearches) {
this.savedSearches = savedSearches;
}
@OneToMany(mappedBy="dataverse", cascade = {CascadeType.MERGE, CascadeType.REMOVE})
private List<Template> templates;
@OneToMany(mappedBy="dataverse", cascade = {CascadeType.MERGE, CascadeType.REMOVE})
private List<Guestbook> guestbooks;
public List<Guestbook> getGuestbooks() {
return guestbooks;
}
public void setGuestbooks(List<Guestbook> guestbooks) {
this.guestbooks = guestbooks;
}
@OneToMany (mappedBy="dataverse", cascade={CascadeType.MERGE, CascadeType.REMOVE})
private List<HarvestingClient> harvestingClientConfigs;
public List<HarvestingClient> getHarvestingClientConfigs() {
return this.harvestingClientConfigs;
}
public void setHarvestingClientConfigs(List<HarvestingClient> harvestingClientConfigs) {
this.harvestingClientConfigs = harvestingClientConfigs;
}
/*
public boolean isHarvested() {
return harvestingClient != null;
}
*/
public List<Guestbook> getParentGuestbooks() {
List<Guestbook> retList = new ArrayList();
Dataverse testDV = this;
while (testDV.getOwner() != null){
retList.addAll(testDV.getOwner().getGuestbooks());
if(testDV.getOwner().guestbookRoot){
break;
}
testDV = testDV.getOwner();
}
return retList;
}
public List<Guestbook> getAvailableGuestbooks() {
//get all guestbooks
List<Guestbook> retList = new ArrayList();
Dataverse testDV = this;
List<Guestbook> allGbs = new ArrayList();
if (!this.guestbookRoot){
while (testDV.getOwner() != null){
allGbs.addAll(testDV.getOwner().getGuestbooks());
if (testDV.getOwner().isGuestbookRoot()) {
break;
}
testDV = testDV.getOwner();
}
}
allGbs.addAll(this.getGuestbooks());
//then only display them if they are enabled
for (Guestbook gbt : allGbs) {
if (gbt.isEnabled()) {
retList.add(gbt);
}
}
return retList;
}
private boolean guestbookRoot;
public boolean isGuestbookRoot() {
return guestbookRoot;
}
public void setGuestbookRoot(boolean guestbookRoot) {
this.guestbookRoot = guestbookRoot;
}
public void setDataverseFieldTypeInputLevels(List<DataverseFieldTypeInputLevel> dataverseFieldTypeInputLevels) {
this.dataverseFieldTypeInputLevels = dataverseFieldTypeInputLevels;
}
public List<DataverseFieldTypeInputLevel> getDataverseFieldTypeInputLevels() {
return dataverseFieldTypeInputLevels;
}
public Template getDefaultTemplate() {
return defaultTemplate;
}
public void setDefaultTemplate(Template defaultTemplate) {
this.defaultTemplate = defaultTemplate;
}
public List<Template> getTemplates() {
return templates;
}
public void setTemplates(List<Template> templates) {
this.templates = templates;
}
public List<Template> getParentTemplates() {
List<Template> retList = new ArrayList();
Dataverse testDV = this;
while (testDV.getOwner() != null){
if (!testDV.getMetadataBlocks().equals(testDV.getOwner().getMetadataBlocks())){
break;
}
retList.addAll(testDV.getOwner().getTemplates());
if(testDV.getOwner().templateRoot){
break;
}
testDV = testDV.getOwner();
}
return retList;
}
public boolean isThemeRoot() {
return themeRoot;
}
public boolean getThemeRoot() {
return themeRoot;
}
public void setThemeRoot(boolean themeRoot) {
this.themeRoot = themeRoot;
}
public boolean isTemplateRoot() {
return templateRoot;
}
public void setTemplateRoot(boolean templateRoot) {
this.templateRoot = templateRoot;
}
public List<MetadataBlock> getMetadataBlocks() {
return getMetadataBlocks(false);
}
public List<MetadataBlock> getMetadataBlocks(boolean returnActualDB) {
if (returnActualDB || metadataBlockRoot || getOwner() == null) {
return metadataBlocks;
} else {
return getOwner().getMetadataBlocks();
}
}
public Long getMetadataRootId(){
if(metadataBlockRoot || getOwner() == null){
return this.getId();
} else {
return getOwner().getMetadataRootId();
}
}
public DataverseTheme getDataverseTheme() {
return getDataverseTheme(false);
}
public DataverseTheme getDataverseTheme(boolean returnActualDB) {
if (returnActualDB || themeRoot || getOwner() == null) {
return dataverseTheme;
} else {
return getOwner().getDataverseTheme();
}
}
public String getGuestbookRootDataverseName() {
Dataverse testDV = this;
String retName = "Parent";
while (testDV.getOwner() != null) {
retName = testDV.getOwner().getDisplayName();
if (testDV.getOwner().guestbookRoot) {
break;
}
testDV = testDV.getOwner();
}
return retName;
}
public String getTemplateRootDataverseName() {
Dataverse testDV = this;
String retName = "Parent";
while (testDV.getOwner() != null) {
retName = testDV.getOwner().getDisplayName();
if (testDV.getOwner().templateRoot) {
break;
}
testDV = testDV.getOwner();
}
return retName;
}
public String getThemeRootDataverseName() {
Dataverse testDV = this;
String retName = "Parent";
while (testDV.getOwner() != null) {
retName = testDV.getOwner().getDisplayName();
if (testDV.getOwner().themeRoot) {
break;
}
testDV = testDV.getOwner();
}
return retName;
}
public String getMetadataRootDataverseName() {
Dataverse testDV = this;
String retName = "Parent";
while (testDV.getOwner() != null) {
retName = testDV.getOwner().getDisplayName();
if (testDV.getOwner().metadataBlockRoot) {
break;
}
testDV = testDV.getOwner();
}
return retName;
}
public String getFacetRootDataverseName() {
Dataverse testDV = this;
String retName = "Parent";
while (testDV.getOwner() != null) {
retName = testDV.getOwner().getDisplayName();
if (testDV.getOwner().facetRoot) {
break;
}
testDV = testDV.getOwner();
}
return retName;
}
public String getLogoOwnerId() {
if (themeRoot || getOwner()==null) {
return this.getId().toString();
} else {
return getOwner().getId().toString();
}
}
public void setDataverseTheme(DataverseTheme dataverseTheme) {
this.dataverseTheme=dataverseTheme;
}
public void setMetadataBlocks(List<MetadataBlock> metadataBlocks) {
this.metadataBlocks = metadataBlocks;
}
public List<DatasetFieldType> getCitationDatasetFieldTypes() {
return citationDatasetFieldTypes;
}
public void setCitationDatasetFieldTypes(List<DatasetFieldType> citationDatasetFieldTypes) {
this.citationDatasetFieldTypes = citationDatasetFieldTypes;
}
public List<DataverseFacet> getDataverseFacets() {
return getDataverseFacets(false);
}
public List<DataverseFacet> getDataverseFacets(boolean returnActualDB) {
if (returnActualDB || facetRoot || getOwner() == null) {
return dataverseFacets;
} else {
return getOwner().getDataverseFacets();
}
}
public Long getFacetRootId(){
if(facetRoot || getOwner() == null){
return this.getId();
} else {
return getOwner().getFacetRootId();
}
}
public void setDataverseFacets(List<DataverseFacet> dataverseFacets) {
this.dataverseFacets = dataverseFacets;
}
public List<DataverseContact> getDataverseContacts() {
return dataverseContacts;
}
/**
* Get the email addresses of the dataverse contacts as a comma-separated
* concatenation.
* @return a comma-separated concatenation of email addresses, or the empty
* string if there are no contacts.
* @author bencomp
*/
public String getContactEmails() {
if (dataverseContacts != null && !dataverseContacts.isEmpty()) {
StringBuilder buf = new StringBuilder();
Iterator<DataverseContact> it = dataverseContacts.iterator();
while (it.hasNext()) {
DataverseContact con = it.next();
buf.append(con.getContactEmail());
if (it.hasNext()) {
buf.append(",");
}
}
return buf.toString();
} else {
return "";
}
}
public void setDataverseContacts(List<DataverseContact> dataverseContacts) {
this.dataverseContacts = dataverseContacts;
}
public void addDataverseContact(int index) {
dataverseContacts.add(index, new DataverseContact(this));
}
public void removeDataverseContact(int index) {
dataverseContacts.remove(index);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getAffiliation() {
return affiliation;
}
public void setAffiliation(String affiliation) {
this.affiliation = affiliation;
}
public boolean isMetadataBlockRoot() {
return metadataBlockRoot;
}
public void setMetadataBlockRoot(boolean metadataBlockRoot) {
this.metadataBlockRoot = metadataBlockRoot;
}
public boolean isFacetRoot() {
return facetRoot;
}
public void setFacetRoot(boolean facetRoot) {
this.facetRoot = facetRoot;
}
public void addRole(DataverseRole role) {
role.setOwner(this);
if ( roles == null ) {
roles = new HashSet<>();
}
roles.add(role);
}
/**
* Note: to add a role, use {@link #addRole(edu.harvard.iq.dataverse.authorization.DataverseRole)},
* do not call this method and try to add directly to the list.
* @return the roles defined in this Dataverse.
*/
public Set<DataverseRole> getRoles() {
if ( roles == null ) {
roles = new HashSet<>();
}
return roles;
}
public List<Dataverse> getOwners() {
List owners = new ArrayList();
if (getOwner() != null) {
owners.addAll(getOwner().getOwners());
owners.add(getOwner());
}
return owners;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Dataverse)) {
return false;
}
Dataverse other = (Dataverse) object;
return Objects.equals(getId(), other.getId());
}
@Override
protected String toStringExtras() {
return "name:" + getName();
}
@Override
public <T> T accept(Visitor<T> v) {
return v.visit(this);
}
/**
* @todo implement in https://github.com/IQSS/dataverse/issues/551
*/
public String getDepositTermsOfUse() {
return "Dataverse Deposit Terms of Use will be implemented in https://github.com/IQSS/dataverse/issues/551";
}
@Override
public String getDisplayName() {
return getName() + " Dataverse";
}
@Override
public boolean isPermissionRoot() {
return permissionRoot;
}
public void setPermissionRoot(boolean permissionRoot) {
this.permissionRoot = permissionRoot;
}
@Override
public boolean isAncestorOf( DvObject other ) {
while ( other != null ) {
if ( equals(other) ) return true;
other = other.getOwner();
}
return false;
}
}