package edu.harvard.iq.dataverse; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.NotBlank; /** * * @author skraffmiller */ @Entity @Table(indexes = {@Index(columnList="dataverse_id")}) public class Template implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; public Template() { } //Constructor for create public Template(Dataverse dataverseIn) { dataverse = dataverseIn; datasetFields = initDatasetFields(); initMetadataBlocksForCreate(); } public Long getId() { return this.id; } @NotBlank(message = "Please add in a name for the dataset template.") @Size(max = 255, message = "Name must be at most 255 characters.") @Column( nullable = false ) private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } private Long usageCount; public Long getUsageCount() { return usageCount; } public void setUsageCount(Long usageCount) { this.usageCount = usageCount; } @Temporal(value = TemporalType.TIMESTAMP) @Column( nullable = false ) private Date createTime; public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getCreateDate() { return new SimpleDateFormat("MMMM d, yyyy").format(createTime); } @OneToOne(cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST}, orphanRemoval=true) @JoinColumn(name = "termsOfUseAndAccess_id") private TermsOfUseAndAccess termsOfUseAndAccess; public TermsOfUseAndAccess getTermsOfUseAndAccess() { return termsOfUseAndAccess; } public void setTermsOfUseAndAccess(TermsOfUseAndAccess termsOfUseAndAccess) { this.termsOfUseAndAccess = termsOfUseAndAccess; } @OneToMany(mappedBy = "template", orphanRemoval = true, cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST}) //@OrderBy("datasetField.displayOrder") private List<DatasetField> datasetFields = new ArrayList<>(); public List<DatasetField> getDatasetFields() { return datasetFields; } @Transient private Map<MetadataBlock, List<DatasetField>> metadataBlocksForView = new HashMap<>(); @Transient private Map<MetadataBlock, List<DatasetField>> metadataBlocksForEdit = new HashMap<>(); @Transient private boolean isDefaultForDataverse; public boolean isIsDefaultForDataverse() { return isDefaultForDataverse; } public void setIsDefaultForDataverse(boolean isDefaultForDataverse) { this.isDefaultForDataverse = isDefaultForDataverse; } @Transient private List<Dataverse> dataversesHasAsDefault; public List<Dataverse> getDataversesHasAsDefault() { return dataversesHasAsDefault; } public void setDataversesHasAsDefault(List<Dataverse> dataversesHasAsDefault) { this.dataversesHasAsDefault = dataversesHasAsDefault; } public Map<MetadataBlock, List<DatasetField>> getMetadataBlocksForView() { return metadataBlocksForView; } public void setMetadataBlocksForView(Map<MetadataBlock, List<DatasetField>> metadataBlocksForView) { this.metadataBlocksForView = metadataBlocksForView; } public Map<MetadataBlock, List<DatasetField>> getMetadataBlocksForEdit() { return metadataBlocksForEdit; } public void setMetadataBlocksForEdit(Map<MetadataBlock, List<DatasetField>> metadataBlocksForEdit) { this.metadataBlocksForEdit = metadataBlocksForEdit; } @ManyToOne @JoinColumn(nullable=true) private Dataverse dataverse; public Dataverse getDataverse() { return dataverse; } public void setDataverse(Dataverse dataverse) { this.dataverse = dataverse; } private List<DatasetField> initDatasetFields() { //retList - Return List of values List<DatasetField> retList = new ArrayList<>(); for (DatasetField dsf : this.getDatasetFields()) { retList.add(initDatasetField(dsf)); } //Test to see that there are values for // all fields in this dataset via metadata blocks //only add if not added above for (MetadataBlock mdb : this.getDataverse().getMetadataBlocks()) { for (DatasetFieldType dsfType : mdb.getDatasetFieldTypes()) { if (!dsfType.isSubField()) { boolean add = true; //don't add if already added as a val for (DatasetField dsf : retList) { if (dsfType.equals(dsf.getDatasetFieldType())) { add = false; break; } } if (add) { retList.add(DatasetField.createNewEmptyDatasetField(dsfType, this)); } } } } //sort via display order on dataset field Collections.sort(retList, new Comparator<DatasetField>() { public int compare(DatasetField d1, DatasetField d2) { int a = d1.getDatasetFieldType().getDisplayOrder(); int b = d2.getDatasetFieldType().getDisplayOrder(); return Integer.valueOf(a).compareTo(Integer.valueOf(b)); } }); return sortDatasetFields(retList); } private List<DatasetField> sortDatasetFields(List<DatasetField> dsfList) { Collections.sort(dsfList, new Comparator<DatasetField>() { public int compare(DatasetField d1, DatasetField d2) { int a = d1.getDatasetFieldType().getDisplayOrder(); int b = d2.getDatasetFieldType().getDisplayOrder(); return Integer.valueOf(a).compareTo(Integer.valueOf(b)); } }); return dsfList; } private void initMetadataBlocksForCreate() { metadataBlocksForView.clear(); metadataBlocksForEdit.clear(); for (MetadataBlock mdb : this.getDataverse().getMetadataBlocks()) { List<DatasetField> datasetFieldsForView = new ArrayList<>(); List<DatasetField> datasetFieldsForEdit = new ArrayList<>(); for (DatasetField dsf : this.getDatasetFields()) { if (dsf.getDatasetFieldType().getMetadataBlock().equals(mdb)) { datasetFieldsForEdit.add(dsf); } } if (!datasetFieldsForView.isEmpty()) { metadataBlocksForView.put(mdb, sortDatasetFields(datasetFieldsForView)); } if (!datasetFieldsForEdit.isEmpty()) { metadataBlocksForEdit.put(mdb, sortDatasetFields(datasetFieldsForEdit)); } } } public void setMetadataValueBlocks() { //TODO: A lot of clean up on the logic of this method metadataBlocksForView.clear(); metadataBlocksForEdit.clear(); List<DatasetField> filledInFields = this.getDatasetFields(); List <MetadataBlock> actualMDB = new ArrayList<>(); actualMDB.addAll(this.getDataverse().getMetadataBlocks()); for (DatasetField dsfv : filledInFields) { if (!dsfv.isEmptyForDisplay()) { MetadataBlock mdbTest = dsfv.getDatasetFieldType().getMetadataBlock(); if (!actualMDB.contains(mdbTest)) { actualMDB.add(mdbTest); } } } for (MetadataBlock mdb : actualMDB) { List<DatasetField> datasetFieldsForView = new ArrayList<>(); List<DatasetField> datasetFieldsForEdit = new ArrayList<>(); for (DatasetField dsf : this.getDatasetFields()) { if (dsf.getDatasetFieldType().getMetadataBlock().equals(mdb)) { datasetFieldsForEdit.add(dsf); if (!dsf.isEmpty()) { datasetFieldsForView.add(dsf); } } } if (!datasetFieldsForView.isEmpty()) { metadataBlocksForView.put(mdb, sortDatasetFields(datasetFieldsForView)); } if (!datasetFieldsForEdit.isEmpty()) { metadataBlocksForEdit.put(mdb, sortDatasetFields(datasetFieldsForEdit)); } } } // TODO: clean up init methods and get them to work, cascading all the way down. // right now, only work for one level of compound objects private DatasetField initDatasetField(DatasetField dsf) { if (dsf.getDatasetFieldType().isCompound()) { for (DatasetFieldCompoundValue cv : dsf.getDatasetFieldCompoundValues()) { // for each compound value; check the datasetfieldTypes associated with its type for (DatasetFieldType dsfType : dsf.getDatasetFieldType().getChildDatasetFieldTypes()) { boolean add = true; for (DatasetField subfield : cv.getChildDatasetFields()) { if (dsfType.equals(subfield.getDatasetFieldType())) { add = false; break; } } if (add) { cv.getChildDatasetFields().add(DatasetField.createNewEmptyChildDatasetField(dsfType, cv)); } } sortDatasetFields(cv.getChildDatasetFields()); } } return dsf; } public Template cloneNewTemplate(Template source) { Template newTemplate = new Template(); Template latestVersion = source; //if the latest version has values get them copied over if (latestVersion.getDatasetFields() != null && !latestVersion.getDatasetFields().isEmpty()) { newTemplate.setDatasetFields(newTemplate.copyDatasetFields(source.getDatasetFields())); } TermsOfUseAndAccess terms; if(source.getTermsOfUseAndAccess() != null){ terms = source.getTermsOfUseAndAccess().copyTermsOfUseAndAccess(); } else { terms = new TermsOfUseAndAccess(); terms.setLicense(TermsOfUseAndAccess.defaultLicense); } newTemplate.setTermsOfUseAndAccess(terms); return newTemplate; } public List<DatasetField> copyDatasetFields(List<DatasetField> copyFromList) { List<DatasetField> retList = new ArrayList<>(); for (DatasetField sourceDsf : copyFromList) { //the copy needs to have the current version retList.add(sourceDsf.copy(this)); } return retList; } public void setDatasetFields(List<DatasetField> datasetFields) { for (DatasetField dsf : datasetFields) { dsf.setTemplate(this); } this.datasetFields = datasetFields; } public List<DatasetField> getFlatDatasetFields() { return getFlatDatasetFields(getDatasetFields()); } private List<DatasetField> getFlatDatasetFields(List<DatasetField> dsfList) { List<DatasetField> retList = new LinkedList<>(); for (DatasetField dsf : dsfList) { retList.add(dsf); if (dsf.getDatasetFieldType().isCompound()) { for (DatasetFieldCompoundValue compoundValue : dsf.getDatasetFieldCompoundValues()) { retList.addAll(getFlatDatasetFields(compoundValue.getChildDatasetFields())); } } } return retList; } @Override public int hashCode() { int hash = 0; hash += (this.id != null ? this.id.hashCode() : 0); return hash; } @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 Template)) { return false; } Template other = (Template) object; if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) { return false; } return true; } }