package edu.harvard.iq.dataverse;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
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.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.Version;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.Pattern;
/**
*
* @author skraffmiller
*/
@Table(indexes = {@Index(columnList="datafile_id"), @Index(columnList="datasetversion_id")} )
@Entity
public class FileMetadata implements Serializable {
private static final long serialVersionUID = 1L;
private static final DateFormat displayDateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
private static final Logger logger = Logger.getLogger(FileMetadata.class.getCanonicalName());
@Pattern(regexp="^[^:<>;#/\"\\*\\|\\?\\\\]*$",
message = "File Name cannot contain any of the following characters: \\ / : * ? \" < > | ; # .")
@NotBlank(message = "Please specify a file name.")
@Column( nullable=false )
private String label = "";
@Pattern(regexp="|[^/\\\\]|^[^/\\\\]+.*[^/\\\\]+$",
message = "Directory Name cannot contain leading or trailing file separators.")
@Column ( nullable=true )
private String directoryLabel;
@Column(columnDefinition = "TEXT")
private String description = "";
private boolean restricted;
@ManyToOne
@JoinColumn(nullable=false)
private DatasetVersion datasetVersion;
@ManyToOne
@JoinColumn(nullable=false)
private DataFile dataFile;
/**
* Creates a copy of {@code this}, with identical business logic fields.
* E.g., {@link #label} would be duplicated; {@link #version} will not.
*
* @return A copy of {@code this}, except for the DB-related data.
*/
public FileMetadata createCopy() {
FileMetadata fmd = new FileMetadata();
fmd.setCategories(new LinkedList<>(getCategories()) );
fmd.setDataFile( getDataFile() );
fmd.setDatasetVersion( getDatasetVersion() );
fmd.setDescription( getDescription() );
fmd.setLabel( getLabel() );
fmd.setRestricted( isRestricted() );
return fmd;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getDirectoryLabel() {
return directoryLabel;
}
public void setDirectoryLabel(String directoryLabel) {
this.directoryLabel = directoryLabel;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isRestricted() {
return restricted;
}
public void setRestricted(boolean restricted) {
this.restricted = restricted;
}
/*
* File Categories to which this version of the DataFile belongs:
*/
@ManyToMany
@JoinTable(indexes = {@Index(columnList="filecategories_id"),@Index(columnList="filemetadatas_id")})
@OrderBy("name")
private List<DataFileCategory> fileCategories;
public List<DataFileCategory> getCategories() {
return fileCategories;
}
public void setCategories(List<DataFileCategory> fileCategories) {
this.fileCategories = fileCategories;
}
public void addCategory(DataFileCategory category) {
if (fileCategories == null) {
fileCategories = new ArrayList<>();
}
fileCategories.add(category);
}
public List<String> getCategoriesByName() {
ArrayList<String> ret = new ArrayList<>();
if (fileCategories != null) {
for (int i = 0; i < fileCategories.size(); i++) {
ret.add(fileCategories.get(i).getName());
}
}
return ret;
}
// alternative, experimental method:
public void setCategoriesByName(List<String> newCategoryNames) {
setCategories(null); // ?? TODO: investigate!
if (newCategoryNames != null) {
for (int i = 0; i < newCategoryNames.size(); i++) {
// Dataset.getCategoryByName() will check if such a category
// already exists for the parent dataset; it will be created
// if not. The method will return null if the supplied
// category name is null or empty. -- L.A. 4.0 beta 10
DataFileCategory fileCategory = null;
try {
// Using "try {}" to catch any null pointer exceptions,
// just in case:
fileCategory = this.getDatasetVersion().getDataset().getCategoryByName(newCategoryNames.get(i));
} catch (Exception ex) {
fileCategory = null;
}
if (fileCategory != null) {
this.addCategory(fileCategory);
fileCategory.addFileMetadata(this);
}
}
}
}
/*
note that this version only *adds* new categories, but does not
remove the ones that has been unchecked!
public void setCategoriesByName(List<String> newCategoryNames) {
if (newCategoryNames != null) {
Collection<String> oldCategoryNames = getCategoriesByName();
for (int i = 0; i < newCategoryNames.size(); i++) {
if (!oldCategoryNames.contains(newCategoryNames.get(i))) {
// Dataset.getCategoryByName() will check if such a category
// already exists for the parent dataset; it will be created
// if not. The method will return null if the supplied
// category name is null or empty. -- L.A. 4.0 beta 10
DataFileCategory fileCategory = null;
try {
// Using "try {}" to catch any null pointer exceptions,
// just in case:
fileCategory = this.getDatasetVersion().getDataset().getCategoryByName(newCategoryNames.get(i));
} catch (Exception ex) {
fileCategory = null;
}
if (fileCategory != null) {
this.addCategory(fileCategory);
fileCategory.addFileMetadata(this);
}
}
}
}
}
*/
public void addCategoryByName(String newCategoryName) {
if (newCategoryName != null && !newCategoryName.equals("")) {
Collection<String> oldCategoryNames = getCategoriesByName();
if (!oldCategoryNames.contains(newCategoryName)) {
DataFileCategory fileCategory = null;
// Dataset.getCategoryByName() will check if such a category
// already exists for the parent dataset; it will be created
// if not. The method will return null if the supplied
// category name is null or empty. -- L.A. 4.0 beta 10
try {
// Using "try {}" to catch any null pointer exceptions,
// just in case:
fileCategory = this.getDatasetVersion().getDataset().getCategoryByName(newCategoryName);
} catch (Exception ex) {
fileCategory = null;
}
if (fileCategory != null) {
logger.log(Level.FINE, "Found file category for {0}", newCategoryName);
this.addCategory(fileCategory);
fileCategory.addFileMetadata(this);
} else {
logger.log(Level.INFO, "Could not find file category for {0}", newCategoryName);
}
} else {
// don't do anything - this file metadata already belongs to
// this category.
}
}
}
public String getFileDateToDisplay() {
Date fileDate = null;
DataFile datafile = this.getDataFile();
if (datafile != null) {
boolean fileHasBeenReleased = datafile.isReleased();
if (fileHasBeenReleased) {
Timestamp filePublicationTimestamp = datafile.getPublicationDate();
if (filePublicationTimestamp != null) {
fileDate = filePublicationTimestamp;
}
} else {
Timestamp fileCreateTimestamp = datafile.getCreateDate();
if (fileCreateTimestamp != null) {
fileDate = fileCreateTimestamp;
}
}
}
if (fileDate != null) {
return displayDateFormat.format(fileDate);
}
return "";
}
public String getFileCitation(){
return getFileCitation(false);
}
public String getFileCitation(boolean html){
String citation = this.getDatasetVersion().getCitation(html);
/*
", #{FilePage.fileMetadata.label} [fileName]"
<h:outputText value=", #{FilePage.file.unf}" rendered="#{FilePage.file.tabularData and !(empty FilePage.file.unf)}"/>
*/
citation += "; " + this.getLabel() + " [fileName]" ;
if (this.dataFile.isTabularData() && this.dataFile.getUnf() != null && !this.dataFile.getUnf().isEmpty()){
citation += ", " + this.dataFile.getUnf() + " [fileUNF]";
}
return citation;
}
public DatasetVersion getDatasetVersion() {
return datasetVersion;
}
public void setDatasetVersion(DatasetVersion datasetVersion) {
this.datasetVersion = datasetVersion;
}
public DataFile getDataFile() {
return dataFile;
}
public void setDataFile(DataFile dataFile) {
this.dataFile = dataFile;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* Getter for property id.
* @return Value of property id.
*/
public Long getId() {
return this.id;
}
/**
* Setter for property id.
* @param id New value of property id.
*/
public void setId(Long id) {
this.id = id;
}
@Version
private Long version;
/**
* Getter for property version.
* @return Value of property version.
*/
public Long getVersion() {
return this.version;
}
/**
* Setter for property version.
* @param version New value of property version.
*/
public void setVersion(Long version) {
this.version = version;
}
@Transient
private boolean selected;
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
@Transient
private boolean restrictedUI;
public boolean isRestrictedUI() {
return restrictedUI;
}
public void setRestrictedUI(boolean restrictedUI) {
this.restrictedUI = restrictedUI;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof FileMetadata)) {
return false;
}
FileMetadata other = (FileMetadata) object;
return !((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id)));
}
/*
* An experimental method for comparing 2 file metadatas *by content*; i.e.,
* this would be for checking 2 metadatas from 2 different versions, to
* determine if any of the actual metadata fields have changed between
* versions.
*/
public boolean contentEquals(FileMetadata other) {
if (other == null) {
return false;
}
if (this.getLabel() != null) {
if (!this.getLabel().equals(other.getLabel())) {
return false;
}
} else if (other.getLabel() != null) {
return false;
}
if (this.getDirectoryLabel() != null) {
if (!this.getDirectoryLabel().equals(other.getDirectoryLabel())) {
return false;
}
} else if (other.getDirectoryLabel() != null) {
return false;
}
if (this.getDescription() != null) {
if (!this.getDescription().equals(other.getDescription())) {
return false;
}
} else if (other.getDescription() != null) {
return false;
}
return true;
}
@Override
public String toString() {
return "edu.harvard.iq.dvn.core.study.FileMetadata[id=" + id + "]";
}
public static final Comparator<FileMetadata> compareByLabel = new Comparator<FileMetadata>() {
@Override
public int compare(FileMetadata o1, FileMetadata o2) {
return o1.getLabel().toUpperCase().compareTo(o2.getLabel().toUpperCase());
}
};
}