package net.sourceforge.seqware.common.model;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Date;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import net.sourceforge.seqware.common.model.adapters.XmlizeIUSSortedSet;
import net.sourceforge.seqware.common.model.adapters.XmlizeLaneSortedSet;
import net.sourceforge.seqware.common.security.PermissionsAware;
import net.sourceforge.seqware.common.util.Log;
import net.sourceforge.seqware.common.util.jsontools.JsonUtil;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@XmlRootElement
/**
* <p>Sample class.</p>
*
* @author boconnor
* @version $Id: $Id
*/
public class Sample extends PermissionsAware implements Serializable, Comparable<Sample>, ParentAccessionModel,
Annotatable<SampleAttribute>, FirstTierModel {
// Attributes relied upon by seqware code
/**
* The presence of this attribute is used to identify that the sample is a library
*/
public static final String GEO_REACTION_ID_ATTR_TAG = "geo_reaction_id";
private static final long serialVersionUID = 3681367228115990568L;
private Integer sampleId;
private Experiment experiment;
private Registration owner;
private String anonymizedName;
private String individualName;
private Integer swAccession;
private String name;
private String title;
private String alias;
private String description;
private String type;
private Organism organism;
private String tags;
private String adapters;
private String regions;
private Integer expectedNumRuns;
private Integer expectedNumSpots;
private Integer expectedNumReads;
private Boolean skip;
private Date createTimestamp;
private Date updateTimestamp;
private Boolean isSelected = false;
private Boolean isHasFile = false;
private Integer countFile;
// addition form fields
private String strExpectedNumRuns;
private String strExpectedNumReads;
private SortedSet<Lane> lanes = new TreeSet<>();
private SortedSet<IUS> ius = new TreeSet<>();
private Set<Processing> processings = new TreeSet<>();
private Set<Sample> parents = new TreeSet<>(new Comparator<Sample>() {
@Override
public int compare(Sample t, Sample t1) {
if (t == null && t1 == null) {
return 0;
} else if (t == null) {
return -1;
} else if (t1 == null) {
return 1;
} else {
return t.compareTo(t1);
}
}
});
private Set<Sample> children = new TreeSet<>();
private Set<SampleAttribute> sampleAttributes = new TreeSet<>();
// non-persisted field to store organism_id
private Integer organismId;
private static final Logger LOGGER = LoggerFactory.getLogger(Sample.class);
/**
* <p>
* Constructor for Sample.
* </p>
*/
public Sample() {
super();
lanes = new TreeSet<>();
for (IUS i : ius) {
if (i.getLane() != null) {
lanes.add(i.getLane());
}
}
}
/**
* {@inheritDoc}
*
* @param that
*/
@Override
public int compareTo(Sample that) {
if (that == null) {
return -1;
}
if (Objects.equals(that.getSampleId(), this.getSampleId())) // when both names are null
{
return 0;
}
if (that.getSampleId() == null) {
return -1; // when only the other name is null
}
return (that.getSampleId().compareTo(this.getSampleId()));
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return new ToStringBuilder(this).append("sampleId", getSampleId()).toString();
}
/**
* {@inheritDoc}
*
* @param other
*/
@Override
public boolean equals(Object other) {
if ((this == other)) {
return true;
}
if (!(other instanceof Sample)) {
return false;
}
Sample castOther = (Sample) other;
return new EqualsBuilder().append(this.getSampleId(), castOther.getSampleId()).isEquals();
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return new HashCodeBuilder().append(getSampleId()).toHashCode();
}
/*
* public int compareTo(Sample that) { if(that == null) return -1;
*
* if(that.getSwAccession() == this.getSwAccession()) // when both names are null return 0;
*
* if(that.getSwAccession() == null) return -1; // when only the other name is null
*
* return(that.getSwAccession().compareTo(this.getSwAccession())); }
*
* public String toString() { return new ToStringBuilder(this) .append("sampleId", getSampleId()) .toString(); }
*
* public boolean equals(Object other) { if ( (this == other ) ) return true; if ( !(other instanceof Sample) ) return false; Sample
* castOther = (Sample) other; return new EqualsBuilder() .append(this.getSwAccession(), castOther.getSwAccession()) .isEquals(); }
*
* public int hashCode() { return new HashCodeBuilder() .append(getSwAccession()) .toHashCode(); }
*/
/**
* <p>
* Getter for the field <code>alias</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getAlias() {
return alias;
}
/**
* <p>
* Setter for the field <code>alias</code>.
* </p>
*
* @param alias
* a {@link java.lang.String} object.
*/
public void setAlias(String alias) {
this.alias = alias;
}
/**
* <p>
* Getter for the field <code>organismId</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getOrganismId() {
return organismId;
}
/**
* <p>
* Setter for the field <code>organismId</code>.
* </p>
*
* @param organismId
* a {@link java.lang.Integer} object.
*/
public void setOrganismId(Integer organismId) {
this.organismId = organismId;
}
/**
* <p>
* Getter for the field <code>adapters</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getAdapters() {
return adapters;
}
/**
* <p>
* Setter for the field <code>adapters</code>.
* </p>
*
* @param adapters
* a {@link java.lang.String} object.
*/
public void setAdapters(String adapters) {
this.adapters = adapters;
}
/**
* <p>
* Getter for the field <code>individualName</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getIndividualName() {
return individualName;
}
/**
* <p>
* Setter for the field <code>individualName</code>.
* </p>
*
* @param individualName
* a {@link java.lang.String} object.
*/
public void setIndividualName(String individualName) {
this.individualName = individualName;
}
/**
* <p>
* Getter for the field <code>title</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getTitle() {
return title;
}
/**
* <p>
* getJsonEscapeTitle.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getJsonEscapeTitle() {
return JsonUtil.forJSON(title);
}
/**
* <p>
* Setter for the field <code>title</code>.
* </p>
*
* @param title
* a {@link java.lang.String} object.
*/
public void setTitle(String title) {
this.title = title;
}
/**
* <p>
* Getter for the field <code>expectedNumRuns</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getExpectedNumRuns() {
return expectedNumRuns;
}
/**
* <p>
* Setter for the field <code>expectedNumRuns</code>.
* </p>
*
* @param expectedNumRuns
* a {@link java.lang.Integer} object.
*/
public void setExpectedNumRuns(Integer expectedNumRuns) {
if (expectedNumRuns != null) {
this.strExpectedNumRuns = expectedNumRuns.toString();
}
this.expectedNumRuns = expectedNumRuns;
}
/**
* <p>
* Getter for the field <code>expectedNumSpots</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getExpectedNumSpots() {
return expectedNumSpots;
}
/**
* <p>
* Setter for the field <code>expectedNumSpots</code>.
* </p>
*
* @param expectedNumSpots
* a {@link java.lang.Integer} object.
*/
public void setExpectedNumSpots(Integer expectedNumSpots) {
this.expectedNumSpots = expectedNumSpots;
}
/**
* <p>
* Getter for the field <code>expectedNumReads</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getExpectedNumReads() {
return expectedNumReads;
}
/**
* <p>
* Setter for the field <code>expectedNumReads</code>.
* </p>
*
* @param expectedNumReads
* a {@link java.lang.Integer} object.
*/
public void setExpectedNumReads(Integer expectedNumReads) {
if (expectedNumReads != null) {
this.strExpectedNumReads = expectedNumReads.toString();
}
this.expectedNumReads = expectedNumReads;
}
/**
* <p>
* Getter for the field <code>lanes</code>.
* </p>
*
* @return a {@link java.util.SortedSet} object.
*/
@XmlJavaTypeAdapter(XmlizeLaneSortedSet.class)
public SortedSet<Lane> getLanes() {
// having this kind of logic in a get method is madness...
// SortedSet<Lane> ln = new TreeSet<Lane>();
// Set<IUS> tempIUS = getIUS();
// for(IUS i: tempIUS){
// if(i.getLane() != null){
// ln.add(i.getLane());
// }
// }
// return ln;
return lanes;
}
/**
* <p>
* Setter for the field <code>lanes</code>.
* </p>
*
* @param lanes
* a {@link java.util.SortedSet} object.
*/
public void setLanes(SortedSet<Lane> lanes) {
this.lanes = lanes;
}
/**
* <p>
* setLanesForView.
* </p>
*
* @param lanes
* a {@link java.util.SortedSet} object.
*/
public void setLanesForView(SortedSet<Lane> lanes) {
SortedSet<IUS> localIUS = new TreeSet<>();
for (Lane lane : lanes) {
IUS newIUS = new IUS();
newIUS.setSample(this);
newIUS.setLane(lane);
newIUS.setIusId(lane.getLaneId());
localIUS.add(newIUS);
}
this.setIUS(localIUS);
// this.lanes = lanes;
}
/**
* <p>
* Getter for the field <code>sampleId</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getSampleId() {
return sampleId;
}
/**
* <p>
* Setter for the field <code>sampleId</code>.
* </p>
*
* @param sampleId
* a {@link java.lang.Integer} object.
*/
public void setSampleId(Integer sampleId) {
this.sampleId = sampleId;
}
/**
* <p>
* Getter for the field <code>experiment</code>.
* </p>
*
* @return a {@link net.sourceforge.seqware.common.model.Experiment} object.
*/
public Experiment getExperiment() {
return experiment;
}
/**
* <p>
* Setter for the field <code>experiment</code>.
* </p>
*
* @param experiment
* a {@link net.sourceforge.seqware.common.model.Experiment} object.
*/
public void setExperiment(Experiment experiment) {
this.experiment = experiment;
}
/**
* <p>
* Getter for the field <code>owner</code>.
* </p>
*
* @return a {@link net.sourceforge.seqware.common.model.Registration} object.
*/
public Registration getOwner() {
return owner;
}
/**
* <p>
* Setter for the field <code>owner</code>.
* </p>
*
* @param owner
* a {@link net.sourceforge.seqware.common.model.Registration} object.
*/
public void setOwner(Registration owner) {
this.owner = owner;
}
/**
* <p>
* Getter for the field <code>anonymizedName</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getAnonymizedName() {
return anonymizedName;
}
/**
* <p>
* Setter for the field <code>anonymizedName</code>.
* </p>
*
* @param anonymizedName
* a {@link java.lang.String} object.
*/
public void setAnonymizedName(String anonymizedName) {
this.anonymizedName = anonymizedName;
}
/**
* <p>
* Getter for the field <code>name</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getName() {
return name;
}
/**
* <p>
* getJsonEscapeName.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getJsonEscapeName() {
return JsonUtil.forJSON(name);
}
/**
* <p>
* Setter for the field <code>name</code>.
* </p>
*
* @param name
* a {@link java.lang.String} object.
*/
public void setName(String name) {
this.name = name;
}
/**
* <p>
* getJsonEscapeDescription.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getJsonEscapeDescription() {
return JsonUtil.forJSON(description);
}
/**
* <p>
* Getter for the field <code>description</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getDescription() {
return description;
}
/**
* <p>
* Setter for the field <code>description</code>.
* </p>
*
* @param description
* a {@link java.lang.String} object.
*/
public void setDescription(String description) {
this.description = description;
}
/**
* <p>
* Getter for the field <code>type</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getType() {
return type;
}
/**
* <p>
* Setter for the field <code>type</code>.
* </p>
*
* @param type
* a {@link java.lang.String} object.
*/
public void setType(String type) {
this.type = type;
}
/**
* <p>
* Getter for the field <code>tags</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getTags() {
return tags;
}
/**
* <p>
* Setter for the field <code>tags</code>.
* </p>
*
* @param tags
* a {@link java.lang.String} object.
*/
public void setTags(String tags) {
this.tags = tags;
}
/**
* <p>
* Getter for the field <code>regions</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getRegions() {
return regions;
}
/**
* <p>
* Setter for the field <code>regions</code>.
* </p>
*
* @param regions
* a {@link java.lang.String} object.
*/
public void setRegions(String regions) {
this.regions = regions;
}
/**
* <p>
* Getter for the field <code>skip</code>.
* </p>
*
* @return a {@link java.lang.Boolean} object.
*/
public Boolean getSkip() {
return skip;
}
/**
* <p>
* Setter for the field <code>skip</code>.
* </p>
*
* @param skip
* a {@link java.lang.Boolean} object.
*/
public void setSkip(Boolean skip) {
this.skip = skip;
}
/**
* <p>
* Getter for the field <code>createTimestamp</code>.
* </p>
*
* @return a {@link java.util.Date} object.
*/
public Date getCreateTimestamp() {
return createTimestamp;
}
/**
* <p>
* Setter for the field <code>createTimestamp</code>.
* </p>
*
* @param createTimestamp
* a {@link java.util.Date} object.
*/
public void setCreateTimestamp(Date createTimestamp) {
this.createTimestamp = createTimestamp;
}
/**
* <p>
* Getter for the field <code>updateTimestamp</code>.
* </p>
*
* @return a {@link java.util.Date} object.
*/
public Date getUpdateTimestamp() {
return updateTimestamp;
}
/**
* <p>
* Setter for the field <code>updateTimestamp</code>.
* </p>
*
* @param updateTimestamp
* a {@link java.util.Date} object.
*/
public void setUpdateTimestamp(Date updateTimestamp) {
this.updateTimestamp = updateTimestamp;
}
/**
* <p>
* Getter for the field <code>serialVersionUID</code>.
* </p>
*
* @return a long.
*/
public static long getSerialVersionUID() {
return serialVersionUID;
}
/**
* <p>
* Getter for the field <code>swAccession</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getSwAccession() {
return swAccession;
}
/**
* <p>
* Setter for the field <code>swAccession</code>.
* </p>
*
* @param swAccession
* a {@link java.lang.Integer} object.
*/
public void setSwAccession(Integer swAccession) {
this.swAccession = swAccession;
}
/**
* <p>
* Getter for the field <code>organism</code>.
* </p>
*
* @return a {@link net.sourceforge.seqware.common.model.Organism} object.
*/
public Organism getOrganism() {
return organism;
}
/**
* <p>
* Setter for the field <code>organism</code>.
* </p>
*
* @param organism
* a {@link net.sourceforge.seqware.common.model.Organism} object.
*/
public void setOrganism(Organism organism) {
this.organism = organism;
}
/**
* <p>
* Getter for the field <code>isSelected</code>.
* </p>
*
* @return a {@link java.lang.Boolean} object.
*/
public Boolean getIsSelected() {
return isSelected;
}
/**
* <p>
* Setter for the field <code>isSelected</code>.
* </p>
*
* @param isSelected
* a {@link java.lang.Boolean} object.
*/
public void setIsSelected(Boolean isSelected) {
this.isSelected = isSelected;
}
/**
* <p>
* Getter for the field <code>isHasFile</code>.
* </p>
*
* @return a {@link java.lang.Boolean} object.
*/
public Boolean getIsHasFile() {
return isHasFile;
}
/**
* <p>
* Setter for the field <code>isHasFile</code>.
* </p>
*
* @param isHasFile
* a {@link java.lang.Boolean} object.
*/
public void setIsHasFile(Boolean isHasFile) {
this.isHasFile = isHasFile;
}
/**
* <p>
* Getter for the field <code>countFile</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getCountFile() {
return countFile;
}
/**
* <p>
* Setter for the field <code>countFile</code>.
* </p>
*
* @param countFile
* a {@link java.lang.Integer} object.
*/
public void setCountFile(Integer countFile) {
this.countFile = countFile;
}
/**
* <p>
* Getter for the field <code>strExpectedNumRuns</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getStrExpectedNumRuns() {
return strExpectedNumRuns;
}
/**
* <p>
* Setter for the field <code>strExpectedNumRuns</code>.
* </p>
*
* @param strExpectedNumRuns
* a {@link java.lang.String} object.
*/
public void setStrExpectedNumRuns(String strExpectedNumRuns) {
this.strExpectedNumRuns = strExpectedNumRuns;
}
/**
* <p>
* Getter for the field <code>strExpectedNumReads</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getStrExpectedNumReads() {
return strExpectedNumReads;
}
/**
* <p>
* Setter for the field <code>strExpectedNumReads</code>.
* </p>
*
* @param strExpectedNumReads
* a {@link java.lang.String} object.
*/
public void setStrExpectedNumReads(String strExpectedNumReads) {
this.strExpectedNumReads = strExpectedNumReads;
}
// public SortedSet<IUS> getIus() {
// return localIUS;
// }
/**
* <p>
* getIUS.
* </p>
*
* @return a {@link java.util.SortedSet} object.
*/
@XmlJavaTypeAdapter(XmlizeIUSSortedSet.class)
public SortedSet<IUS> getIUS() {
return ius;
}
/**
* <p>
* setIUS.
* </p>
*
* @param ius
* a {@link java.util.SortedSet} object.
*/
public void setIUS(SortedSet<IUS> ius) {
this.ius = ius;
}
/**
* <p>
* Getter for the field <code>processings</code>.
* </p>
*
* @return a {@link java.util.Set} object.
*/
public Set<Processing> getProcessings() {
return processings;
}
/**
* <p>
* Setter for the field <code>processings</code>.
* </p>
*
* @param processings
* a {@link java.util.Set} object.
*/
public void setProcessings(Set<Processing> processings) {
this.processings = processings;
}
/**
* <p>
* Getter for the field <code>parents</code>.
* </p>
*
* @return a {@link java.util.Set} object.
*/
public Set<Sample> getParents() {
return parents;
}
/**
* <p>
* Setter for the field <code>parents</code>.
* </p>
*
* @param parents
* a {@link java.util.Set} object.
*/
public void setParents(Set<Sample> parents) {
this.parents = parents;
}
/**
* <p>
* Getter for the field <code>children</code>.
* </p>
*
* @return a {@link java.util.Set} object.
*/
public Set<Sample> getChildren() {
return children;
}
/**
* <p>
* Setter for the field <code>children</code>.
* </p>
*
* @param children
* a {@link java.util.Set} object.
*/
public void setChildren(Set<Sample> children) {
this.children = children;
}
/**
* <p>
* Getter for the field <code>sampleAttributes</code>.
* </p>
*
* @return a {@link java.util.Set} object.
*/
@XmlElementWrapper(name = "SampleAttributes")
@XmlElement(name = "SampleAttribute")
public Set<SampleAttribute> getSampleAttributes() {
return sampleAttributes;
}
/**
* <p>
* Setter for the field <code>sampleAttributes</code>.
* </p>
*
* @param sampleAttributes
* a {@link java.util.Set} object.
*/
public void setSampleAttributes(Set<SampleAttribute> sampleAttributes) {
this.sampleAttributes = sampleAttributes;
}
/**
* {@inheritDoc}
*
* @return
*/
@Override
public boolean givesPermissionInternal(Registration registration, Set<Integer> considered) {
if (registration.isLIMSAdmin()) {
Log.debug("Skipping permissions admin on Sample object " + swAccession);
return true;
}
boolean consideredBefore = considered.contains(this.getSwAccession());
if (!consideredBefore) {
considered.add(this.getSwAccession());
Log.debug("Checking permissions for Sample object " + swAccession);
} else {
Log.debug("Skipping permissions for Sample object " + swAccession + " , checked before");
return true;
}
boolean hasPermission;
Log.debug("registration: " + registration + " owner: " + owner);
if (experiment != null) {
hasPermission = experiment.givesPermission(registration, considered);
} else {// orphaned Sample
if (registration.equals(this.owner) || registration.isLIMSAdmin()) {
LOGGER.warn("Modifying Orphan Sample: " + this.getName());
hasPermission = true;
} else {
LOGGER.warn("Not modifying Orphan Sample: " + this.getName());
hasPermission = false;
}
}
if (!hasPermission) {
LOGGER.info("Sample does not give permission to " + registration);
throw new SecurityException("User " + registration.getEmailAddress() + " does not have permission to modify " + this.getName());
}
return hasPermission;
}
@Override
public Set<SampleAttribute> getAnnotations() {
return this.getSampleAttributes();
}
}