package net.sourceforge.seqware.common.model;
import io.seqware.common.model.ProcessingStatus;
import java.io.Serializable;
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 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.slf4j.Logger;
import org.slf4j.LoggerFactory;
@XmlRootElement
/**
* <p>Lane class.</p>
*
* @author boconnor
* @version $Id: $Id
*/
public class Lane extends PermissionsAware implements Serializable, Comparable<Lane>, ParentAccessionModel, Annotatable<LaneAttribute>,
FirstTierModel {
private static final long serialVersionUID = 5681328115923390568L;
private Integer laneId;
private Integer laneIndex;
private SequencerRun sequencerRun;
private Sample sample;
private String name;
private String cycleDescriptor;
// private String sampleName;
private String sampleCode;
private String description;
private String organism;
private String sampleType;
private String tags;
private String regions;
private String skipTxt;
private Boolean skip;
private Registration owner;
private Date createTimestamp;
private Date updateTimestamp;
private Set<Processing> processings = new TreeSet<>();
private Integer swAccession;
private SortedSet<IUS> ius = new TreeSet<>();
private Set<WorkflowRun> workflowRuns = new TreeSet<>();
private Set<LaneAttribute> laneAttributes = new TreeSet<>();
private Boolean isSelected = false;
private Boolean isHasFile = false;
private StudyType studyType;
private LibraryStrategy libraryStrategy;
private LibrarySelection librarySelection;
private LibrarySource librarySource;
private static final Logger LOGGER = LoggerFactory.getLogger(Lane.class);
/**
* <p>
* Constructor for Lane.
* </p>
*/
public Lane() {
super();
}
/**
* {@inheritDoc}
*
* @param that
*/
@Override
public int compareTo(Lane that) {
if (that == null || getLaneId() == null) {
return -1;
}
if (Objects.equals(that.getLaneId(), this.getLaneId())) // when both names are null
{
return 0;
}
if (that.getLaneId() == null) {
return -1; // when only the other name is null
}
return (that.getLaneId().compareTo(this.getLaneId()));
}
/** {@inheritDoc} */
@Override
public String toString() {
return "Lane{" + "laneId=" + laneId + ", laneIndex=" + laneIndex + ", sequencerRun=" + sequencerRun + ", sample=" + sample
+ ", name=" + name + ", cycleDescriptor=" + cycleDescriptor + ", sampleCode=" + sampleCode + ", description=" + description
+ ", organism=" + organism + ", sampleType=" + sampleType + ", tags=" + tags + ", regions=" + regions + ", skipTxt="
+ skipTxt + ", skip=" + skip + ", owner=" + owner + ", createTimestamp=" + createTimestamp + ", updateTimestamp="
+ updateTimestamp + ", swAccession=" + swAccession + ", isSelected=" + isSelected + ", isHasFile=" + isHasFile + '}';
}
/**
* {@inheritDoc}
*
* @param other
*/
@Override
public boolean equals(Object other) {
if ((this == other)) {
return true;
}
if (!(other instanceof Lane)) {
return false;
}
Lane castOther = (Lane) other;
return new EqualsBuilder().append(this.getLaneId(), castOther.getLaneId()).isEquals();
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return new HashCodeBuilder().append(getLaneId()).toHashCode();
}
/*
* public int compareTo(Lane that) { if(that == null || getSwAccession() == 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("laneId", getLaneId()) .toString(); }
*
* public boolean equals(Object other) { if ( (this == other ) ) return true; if ( !(other instanceof Lane) ) return false; Lane
* castOther = (Lane) other; return new EqualsBuilder() .append(this.getSwAccession(), castOther.getSwAccession()) .isEquals(); }
*
* public int hashCode() { return new HashCodeBuilder() .append(getSwAccession()) .toHashCode(); }
*/
/**
* <p>
* getErrorCnt.
* </p>
*
* @return a int.
*/
public int getErrorCnt() {
int errorCnt = 0;
for (Processing proc : getAllProcessings()) {
errorCnt += recursiveCountProcErrors(proc);
}
return (errorCnt);
}
private int recursiveCountProcErrors(Processing proc) {
int errorCnt = 0;
if (proc != null && (ProcessingStatus.failed == proc.getStatus())) {
errorCnt++;
}
for (Processing childProc : proc.getChildren()) {
errorCnt += recursiveCountProcErrors(childProc);
}
return (errorCnt);
}
/**
* <p>
* getProcessingCnt.
* </p>
*
* @return a int.
*/
public int getProcessingCnt() {
int cnt = 0;
for (Processing proc : getAllProcessings()) {
cnt += recursiveCountProcRunning(proc);
}
return (cnt);
}
private int recursiveCountProcRunning(Processing proc) {
int runCnt = 0;
if (proc != null && (proc.getStatus() == ProcessingStatus.running || proc.getStatus() == ProcessingStatus.pending)) {
runCnt++;
}
for (Processing childProc : proc.getChildren()) {
runCnt += recursiveCountProcRunning(childProc);
}
return (runCnt);
}
/**
* <p>
* getProcessedCnt.
* </p>
*
* @return a int.
*/
public int getProcessedCnt() {
int cnt = 0;
for (Processing proc : getAllProcessings()) {
cnt += recursiveCountProcessed(proc);
}
return (cnt);
}
/**
* <p>
* getAllProcessings.
* </p>
*
* @return a {@link java.util.Set} object.
*/
public Set<Processing> getAllProcessings() {
Set<Processing> allProcessing = new TreeSet<>();
allProcessing.addAll(getProcessings());
if (getIUS() != null) {
for (IUS i : getIUS()) {
allProcessing.addAll(i.getProcessings());
}
}
return allProcessing;
}
private int recursiveCountProcessed(Processing proc) {
int runCnt = 0;
if (proc != null && (proc.getStatus() == ProcessingStatus.success)) {
runCnt++;
}
for (Processing childProc : proc.getChildren()) {
runCnt += recursiveCountProcessed(childProc);
}
return (runCnt);
}
/**
* <p>
* Getter for the field <code>ius</code>.
* </p>
*
* @return a {@link java.util.SortedSet} object.
*/
public SortedSet<IUS> getIus() {
return ius;
}
/**
* <p>
* getIUS.
* </p>
*
* @return a {@link java.util.SortedSet} object.
*/
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>laneIndex</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getLaneIndex() {
return laneIndex;
}
/**
* <p>
* Setter for the field <code>laneIndex</code>.
* </p>
*
* @param laneIndex
* a {@link java.lang.Integer} object.
*/
public void setLaneIndex(Integer laneIndex) {
this.laneIndex = laneIndex;
}
/**
* <p>
* Getter for the field <code>cycleDescriptor</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getCycleDescriptor() {
return cycleDescriptor;
}
/**
* <p>
* Setter for the field <code>cycleDescriptor</code>.
* </p>
*
* @param cycleDescriptor
* a {@link java.lang.String} object.
*/
public void setCycleDescriptor(String cycleDescriptor) {
this.cycleDescriptor = cycleDescriptor;
}
/**
* <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>processings</code>.
* </p>
*
* @return a {@link java.util.Set} object.
*/
public Set<Processing> getProcessings() {
/*
* Set<Processing> pr = new TreeSet<Processing>(); SortedSet<IUS> setIUS = getIUS(); for (IUS ius : setIUS) {
* pr.addAll(ius.getProcessings()); } return pr;
*/
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>
* setProcessingsForView.
* </p>
*
* @param processings
* a {@link java.util.Set} object.
*/
public void setProcessingsForView(Set<Processing> processings) {
IUS newIUS = new IUS();
newIUS.setProcessings(processings);
newIUS.setIusId(this.getLaneId());
SortedSet<IUS> i = new TreeSet<>();
i.add(newIUS);
this.setIUS(i);
}
/**
* <p>
* addProcessing.
* </p>
*
* @param processing
* a {@link net.sourceforge.seqware.common.model.Processing} object.
*/
public void addProcessing(Processing processing) {
this.getProcessings().add(processing);
// processing.getLanes().add(this);
}
/**
* <p>
* getSamples.
* </p>
*
* @return a {@link java.util.SortedSet} object.
*/
public SortedSet<Sample> getSamples() {
SortedSet<Sample> samples = new TreeSet<>();
SortedSet<IUS> setIUS = getIUS();
for (IUS i : setIUS) {
if (i.getSample() != null) {
samples.add(i.getSample());
}
}
return samples;
}
/**
* <p>
* Getter for the field <code>sample</code>.
* </p>
*
* @return a {@link net.sourceforge.seqware.common.model.Sample} object.
*/
public Sample getSample() {
Sample firstSample = null;
SortedSet<IUS> setIUS = getIUS();
for (IUS i : setIUS) {
if (i.getSample() != null) {
firstSample = i.getSample();
break;
}
}
return firstSample;
// return sample;
}
/**
* <p>
* Setter for the field <code>sample</code>.
* </p>
*
* @param sample
* a {@link net.sourceforge.seqware.common.model.Sample} object.
*/
public void setSample(Sample sample) {
this.sample = sample;
}
/**
* <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>
* 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>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>laneId</code>.
* </p>
*
* @return a {@link java.lang.Integer} object.
*/
public Integer getLaneId() {
return laneId;
}
/**
* <p>
* Setter for the field <code>laneId</code>.
* </p>
*
* @param laneId
* a {@link java.lang.Integer} object.
*/
public void setLaneId(Integer laneId) {
this.laneId = laneId;
}
/**
* <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>
* Getter for the field <code>organism</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getOrganism() {
return organism;
}
/**
* <p>
* Setter for the field <code>organism</code>.
* </p>
*
* @param organism
* a {@link java.lang.String} object.
*/
public void setOrganism(String organism) {
this.organism = organism;
}
/**
* <p>
* Getter for the field <code>sampleType</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getSampleType() {
return sampleType;
}
/**
* <p>
* Setter for the field <code>sampleType</code>.
* </p>
*
* @param sampleType
* a {@link java.lang.String} object.
*/
public void setSampleType(String sampleType) {
this.sampleType = sampleType;
}
/*
* public String getSampleName() { return sampleName; }
*
* public void setSampleName(String sampleName) { this.sampleName = sampleName; }
*/
/**
* <p>
* Getter for the field <code>sampleCode</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getSampleCode() {
return sampleCode;
}
/**
* <p>
* Setter for the field <code>sampleCode</code>.
* </p>
*
* @param sampleCode
* a {@link java.lang.String} object.
*/
public void setSampleCode(String sampleCode) {
this.sampleCode = sampleCode;
}
/**
* <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) {
if (skip != null && !Objects.equals(this.skip, skip)) {
Log.debug("Skipping lane " + getSwAccession());
this.skip = skip;
if (ius != null) {
for (IUS i : ius) {
i.setSkip(skip);
}
}
}
}
/**
* <p>
* Getter for the field <code>sequencerRun</code>.
* </p>
*
* @return a {@link net.sourceforge.seqware.common.model.SequencerRun} object.
*/
public SequencerRun getSequencerRun() {
return sequencerRun;
}
/**
* <p>
* Setter for the field <code>sequencerRun</code>.
* </p>
*
* @param sequencerRun
* a {@link net.sourceforge.seqware.common.model.SequencerRun} object.
*/
public void setSequencerRun(SequencerRun sequencerRun) {
this.sequencerRun = sequencerRun;
}
/**
* <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>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>workflowRuns</code>.
* </p>
*
* @return a {@link java.util.Set} object.
*/
public Set<WorkflowRun> getWorkflowRuns() {
return workflowRuns;
}
/**
* <p>
* Setter for the field <code>workflowRuns</code>.
* </p>
*
* @param workflowRuns
* a {@link java.util.Set} object.
*/
public void setWorkflowRuns(Set<WorkflowRun> workflowRuns) {
this.workflowRuns = workflowRuns;
}
/**
* <p>
* Getter for the field <code>laneAttributes</code>.
* </p>
*
* @return a {@link java.util.Set} object.
*/
@XmlElementWrapper(name = "LaneAttributes")
@XmlElement(name = "LaneAttribute")
public Set<LaneAttribute> getLaneAttributes() {
return laneAttributes;
}
/**
* <p>
* Setter for the field <code>laneAttributes</code>.
* </p>
*
* @param laneAttributes
* a {@link java.util.Set} object.
*/
public void setLaneAttributes(Set<LaneAttribute> laneAttributes) {
this.laneAttributes = laneAttributes;
}
@Override
public boolean givesPermissionInternal(Registration registration, Set<Integer> considered) {
if (registration.isLIMSAdmin()) {
Log.debug("Skipping permissions admin on Lane object " + swAccession);
return true;
}
boolean consideredBefore = considered.contains(this.getSwAccession());
if (!consideredBefore) {
considered.add(this.getSwAccession());
Log.debug("Checking permissions for Lane object " + swAccession);
} else {
Log.debug("Skipping permissions for Lane object " + swAccession + " , checked before");
return true;
}
boolean hasPermission = true;
if (sample != null) {
hasPermission = sample.givesPermission(registration, considered);
}
// if one of the IUSes doesn't have permission, we can't touch this Lane
// object...
if (ius != null && !ius.isEmpty()) {
for (IUS i : ius) {
if (!i.givesPermission(registration, considered)) {
hasPermission = false;
}
}
}
// this object is orphaned, but does the person own it?
if (sample == null && ius == null) {
if (registration.equals(this.owner) || registration.isLIMSAdmin()) {
LOGGER.warn("Modifying Orphan Lane: " + toString());
hasPermission = true;
} else if (owner == null) {
LOGGER.warn("Orphan Lane has no owner! Allowing modifications: " + toString());
hasPermission = true;
} else {
LOGGER.warn("Not modifying Orphan Lane: " + toString());
hasPermission = false;
}
}
if (!hasPermission) {
LOGGER.info("Lane does not give permission");
throw new SecurityException("User " + registration.getEmailAddress() + " does not have permission to modify " + toString());
}
return hasPermission;
}
public StudyType getStudyType() {
return studyType;
}
public void setStudyType(StudyType studyType) {
this.studyType = studyType;
}
public LibraryStrategy getLibraryStrategy() {
return libraryStrategy;
}
public void setLibraryStrategy(LibraryStrategy libraryStrategy) {
this.libraryStrategy = libraryStrategy;
}
public LibrarySelection getLibrarySelection() {
return librarySelection;
}
public void setLibrarySelection(LibrarySelection librarySelection) {
this.librarySelection = librarySelection;
}
public LibrarySource getLibrarySource() {
return librarySource;
}
public void setLibrarySource(LibrarySource librarySource) {
this.librarySource = librarySource;
}
@Override
public Set<LaneAttribute> getAnnotations() {
return this.getLaneAttributes();
}
}