package net.sourceforge.seqware.common.model; import com.google.common.collect.ImmutableSet; import io.seqware.common.model.WorkflowRunStatus; import java.io.Serializable; import java.util.Date; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import net.sourceforge.seqware.common.business.IUSService; import net.sourceforge.seqware.common.business.LaneService; import net.sourceforge.seqware.common.business.ProcessingService; import net.sourceforge.seqware.common.business.RegistrationService; import net.sourceforge.seqware.common.business.SampleService; import net.sourceforge.seqware.common.business.WorkflowRunService; import net.sourceforge.seqware.common.factory.BeanFactory; import net.sourceforge.seqware.common.model.adapters.XmlizeXML; 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.NotImplementedException; 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; /** * <p> * WorkflowRun class. * </p> * * @author boconnor * @version $Id: $Id */ public class WorkflowRun extends PermissionsAware implements Serializable, Comparable<WorkflowRun>, Annotatable<WorkflowRunAttribute>, FirstTierModel { private static final long serialVersionUID = 1L; private Integer workflowRunId; private Workflow workflow; private Integer swAccession; private String name; private Date createTimestamp; private Date updateTimestamp; private Boolean isSelected = false; private Registration owner; private SortedSet<Processing> processings; private SortedSet<Processing> offspringProcessings; private SortedSet<Sample> samples; // many-to-many link private SortedSet<IUS> ius; private SortedSet<Lane> lanes; private SortedSet<ShareWorkflowRun> sharedWorkflowRuns; private SortedSet<WorkflowRunParam> workflowRunParams; private String html; private Boolean isHasFile = false; // additional fields private WorkflowRunStatus status; private String statusCmd; private String seqwareRevision; private String host; private String currentWorkingDir; private String userName; private String command; private String template; private String dax; private String iniFile; private String stdErr; private String stdOut; private Set<WorkflowRunAttribute> workflowRunAttributes = new TreeSet<>(); private String workflowEngine; private Set<Integer> inputFileAccessions = new HashSet<>(); // artificial fields for SEQWARE-1134, we will need to populate these artificially // this is an ugly hack, need to get a better solution private Integer workflowAccession; private String ownerUserName; private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowRun.class); /** * Lists the properties that can be used to easily filter this entity */ public static final Set<String> USABLE_CONSTRAINTS = ImmutableSet.of("status", "statusCmd", "host", "currentWorkingDir", "workflowEngine", "ownerUserName"); /** * <p> * Constructor for WorkflowRun. * </p> */ public WorkflowRun() { super(); } /** * <p> * compareTo. * </p> * * @param that * a {@link net.sourceforge.seqware.common.model.Workflow} object. * @return a int. */ public int compareTo(Workflow that) { if (that == null) { return -1; } if (Objects.equals(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())); } /** {@inheritDoc} */ @Override public String toString() { return new ToStringBuilder(this).append("swAccession", getSwAccession()).toString(); } /** * {@inheritDoc} * * @param other */ @Override public boolean equals(Object other) { if ((this == other)) { return true; } if (!(other instanceof WorkflowRun)) { return false; } WorkflowRun castOther = (WorkflowRun) other; return new EqualsBuilder().append(this.getSwAccession(), castOther.getSwAccession()).isEquals(); } /** {@inheritDoc} */ @Override public int hashCode() { return new HashCodeBuilder().append(getSwAccession()).toHashCode(); } /** * <p> * Getter for the field <code>template</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getTemplate() { return template; } /** * <p> * Setter for the field <code>template</code>. * </p> * * @param template * a {@link java.lang.String} object. */ public void setTemplate(String template) { this.template = template; } /** * <p> * Getter for the field <code>command</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getCommand() { return command; } /** * <p> * Setter for the field <code>command</code>. * </p> * * @param command * a {@link java.lang.String} object. */ public void setCommand(String command) { this.command = command; } /** * <p> * Getter for the field <code>workflowRunId</code>. * </p> * * @return a {@link java.lang.Integer} object. */ public Integer getWorkflowRunId() { return workflowRunId; } /** * <p> * Setter for the field <code>workflowRunId</code>. * </p> * * @param workflowRunId * a {@link java.lang.Integer} object. */ public void setWorkflowRunId(Integer workflowRunId) { this.workflowRunId = workflowRunId; } /** * <p> * Getter for the field <code>workflow</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.model.Workflow} object. */ public Workflow getWorkflow() { return workflow; } /** * <p> * Setter for the field <code>workflow</code>. * </p> * * @param workflow * a {@link net.sourceforge.seqware.common.model.Workflow} object. */ public void setWorkflow(Workflow workflow) { this.workflow = workflow; if (workflow != null && workflow.getSwAccession() != null) { this.setWorkflowAccession(workflow.getSwAccession()); } } /** * <p> * Getter for the field <code>swAccession</code>. * </p> * * @return a {@link java.lang.Integer} object. */ @Override 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>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>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>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; if (owner != null && owner.getEmailAddress() != null) { this.setOwnerUserName(owner.getEmailAddress()); } } /** * <p> * Getter for the field <code>processings</code>. * </p> * * @return a {@link java.util.SortedSet} object. */ public SortedSet<Processing> getProcessings() { return processings; } /** * <p> * Setter for the field <code>processings</code>. * </p> * * @param processings * a {@link java.util.SortedSet} object. */ public void setProcessings(SortedSet<Processing> processings) { this.processings = processings; } /** * <p> * Getter for the field <code>offspringProcessings</code>. * </p> * * @return a {@link java.util.SortedSet} object. */ public SortedSet<Processing> getOffspringProcessings() { return offspringProcessings; } /** * <p> * Setter for the field <code>offspringProcessings</code>. * </p> * * @param offspringProcessings * a {@link java.util.SortedSet} object. */ public void setOffspringProcessings(SortedSet<Processing> offspringProcessings) { this.offspringProcessings = offspringProcessings; } /** * <p> * Getter for the field <code>samples</code>. * </p> * * @return a {@link java.util.SortedSet} object. */ public SortedSet<Sample> getSamples() { return samples; } /** * <p> * Setter for the field <code>samples</code>. * </p> * * @param samples * a {@link java.util.SortedSet} object. */ public void setSamples(SortedSet<Sample> samples) { this.samples = samples; } /** * <p> * Getter for the field <code>sharedWorkflowRuns</code>. * </p> * * @return a {@link java.util.SortedSet} object. */ public SortedSet<ShareWorkflowRun> getSharedWorkflowRuns() { return sharedWorkflowRuns; } /** * <p> * Setter for the field <code>sharedWorkflowRuns</code>. * </p> * * @param sharedWorkflowRuns * a {@link java.util.SortedSet} object. */ public void setSharedWorkflowRuns(SortedSet<ShareWorkflowRun> sharedWorkflowRuns) { if (sharedWorkflowRuns == null) { this.sharedWorkflowRuns = sharedWorkflowRuns; } else { this.sharedWorkflowRuns.clear(); this.sharedWorkflowRuns.addAll(sharedWorkflowRuns); } } /** * <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>html</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getHtml() { return html; } /** * <p> * Setter for the field <code>html</code>. * </p> * * @param html * a {@link java.lang.String} object. */ public void setHtml(String html) { this.html = html; } /** * <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>status</code>. * </p> * * @return the status of the workflow run */ public WorkflowRunStatus getStatus() { return status; } /** * <p> * Setter for the field <code>status</code>. * </p> * * @param status * the status of the workflow run */ public void setStatus(WorkflowRunStatus status) { this.status = status; } /** * <p> * Getter for the field <code>statusCmd</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getStatusCmd() { return statusCmd; } /** * <p> * Setter for the field <code>statusCmd</code>. * </p> * * @param statusCmd * a {@link java.lang.String} object. */ public void setStatusCmd(String statusCmd) { this.statusCmd = statusCmd; } /** * <p> * Getter for the field <code>seqwareRevision</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getSeqwareRevision() { return seqwareRevision; } /** * <p> * Setter for the field <code>seqwareRevision</code>. * </p> * * @param seqwareRevision * a {@link java.lang.String} object. */ public void setSeqwareRevision(String seqwareRevision) { this.seqwareRevision = seqwareRevision; } /** * <p> * Getter for the field <code>host</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getHost() { return host; } /** * <p> * Setter for the field <code>host</code>. * </p> * * @param host * a {@link java.lang.String} object. */ public void setHost(String host) { this.host = host; } /** * <p> * Getter for the field <code>currentWorkingDir</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getCurrentWorkingDir() { return currentWorkingDir; } /** * <p> * Setter for the field <code>currentWorkingDir</code>. * </p> * * @param currentWorkingDir * a {@link java.lang.String} object. */ public void setCurrentWorkingDir(String currentWorkingDir) { this.currentWorkingDir = currentWorkingDir; } /** * <p> * Getter for the field <code>userName</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getUserName() { return userName; } /** * <p> * Setter for the field <code>userName</code>. * </p> * * @param username * a {@link java.lang.String} object. */ public void setUserName(String username) { this.userName = username; } /** * <p> * Getter for the field <code>workflowRunParams</code>. * </p> * * @return a {@link java.util.SortedSet} object. */ public SortedSet<WorkflowRunParam> getWorkflowRunParams() { return workflowRunParams; } /** * <p> * Setter for the field <code>workflowRunParams</code>. * </p> * * @param workflowRunParams * a {@link java.util.SortedSet} object. */ public void setWorkflowRunParams(SortedSet<WorkflowRunParam> workflowRunParams) { this.workflowRunParams = workflowRunParams; } // @XmlJavaTypeAdapter(XmlizeIUSSortedSet.class) /** * <p> * Getter for the field <code>ius</code>. * </p> * * @return a {@link java.util.SortedSet} object. */ public SortedSet<IUS> getIus() { return ius; } /** * <p> * Setter for the field <code>ius</code>. * </p> * * @param ius * a {@link java.util.SortedSet} object. */ public void setIus(SortedSet<IUS> ius) { this.ius = ius; } /** * <p> * Getter for the field <code>dax</code>. * </p> * * @return a {@link java.lang.String} object. */ @XmlJavaTypeAdapter(XmlizeXML.class) public String getDax() { return dax; } /** * <p> * Setter for the field <code>dax</code>. * </p> * * @param dax * a {@link java.lang.String} object. */ public void setDax(String dax) { this.dax = dax; } /** * <p> * Getter for the field <code>iniFile</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getIniFile() { return iniFile; } /** * <p> * Setter for the field <code>iniFile</code>. * </p> * * @param iniFile * a {@link java.lang.String} object. */ public void setIniFile(String iniFile) { this.iniFile = iniFile; } // @XmlJavaTypeAdapter(XmlizeLaneSortedSet.class) /** * <p> * Getter for the field <code>lanes</code>. * </p> * * @return a {@link java.util.SortedSet} object. */ public SortedSet<Lane> getLanes() { 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> * Getter for the field <code>stdErr</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getStdErr() { return stdErr; } /** * <p> * Setter for the field <code>stdErr</code>. * </p> * * @param stdErr * a {@link java.lang.String} object. */ public void setStdErr(String stdErr) { this.stdErr = stdErr; } /** * <p> * Getter for the field <code>stdOut</code>. * </p> * * @return a {@link java.lang.String} object. */ public String getStdOut() { return stdOut; } /** * <p> * Setter for the field <code>stdOut</code>. * </p> * * @param stdOut * a {@link java.lang.String} object. */ public void setStdOut(String stdOut) { this.stdOut = stdOut; } /** * <p> * cloneToHibernate. * </p> * * @param newWR * a {@link net.sourceforge.seqware.common.model.WorkflowRun} object. * @return a {@link net.sourceforge.seqware.common.model.WorkflowRun} object. */ public static WorkflowRun cloneToHibernate(WorkflowRun newWR) { WorkflowRunService wrs = BeanFactory.getWorkflowRunServiceBean(); WorkflowRun wr = wrs.findByID(newWR.getWorkflowRunId()); wr.setCommand(newWR.getCommand()); wr.setCurrentWorkingDir(newWR.getCurrentWorkingDir()); wr.setDax(newWR.getDax()); wr.setHost(newWR.getHost()); wr.setHtml(newWR.getHtml()); wr.setIniFile(newWR.getIniFile()); wr.setIsHasFile(newWR.getIsHasFile()); wr.setIsSelected(newWR.getIsSelected()); wr.setName(newWR.getName()); wr.setSeqwareRevision(newWR.getSeqwareRevision()); wr.setStatus(newWR.getStatus()); wr.setStatusCmd(newWR.getStatusCmd()); wr.setTemplate(newWR.getTemplate()); wr.setUpdateTimestamp(newWR.getUpdateTimestamp()); wr.setUserName(newWR.getUserName()); wr.setStdErr(newWR.getStdErr()); wr.setStdOut(newWR.getStdOut()); Registration owner = newWR.getOwner(); if (owner != null) { RegistrationService rs = BeanFactory.getRegistrationServiceBean(); Registration o = rs.findByEmailAddressAndPassword(owner.getEmailAddress(), owner.getPassword()); if (o != null) { wr.setOwner(o); } } SortedSet<Lane> newLanes = newWR.getLanes(); SortedSet<IUS> iuses = newWR.getIus(); SortedSet<Processing> offProcessings = newWR.getOffspringProcessings(); SortedSet<Processing> newProcessings = newWR.getProcessings(); SortedSet<Sample> newSamples = newWR.getSamples(); SortedSet<ShareWorkflowRun> sharedWRs = newWR.getSharedWorkflowRuns(); SortedSet<WorkflowRunParam> wrParams = newWR.getWorkflowRunParams(); if (newLanes != null && !newLanes.isEmpty()) { LaneService ls = BeanFactory.getLaneServiceBean(); for (Lane lane : newLanes) { wr.getLanes().add(ls.findByID(lane.getLaneId())); } } if (iuses != null && !iuses.isEmpty()) { IUSService is = BeanFactory.getIUSServiceBean(); for (IUS i : iuses) { wr.getIus().add(is.findByID(i.getIusId())); } } if (offProcessings != null && !offProcessings.isEmpty()) { ProcessingService ps = BeanFactory.getProcessingServiceBean(); for (Processing p : offProcessings) { wr.getOffspringProcessings().add(ps.findByID(p.getProcessingId())); } } if (newProcessings != null && !newProcessings.isEmpty()) { ProcessingService ps = BeanFactory.getProcessingServiceBean(); for (Processing p : newProcessings) { wr.getProcessings().add(ps.findByID(p.getProcessingId())); } } if (newSamples != null && !newSamples.isEmpty()) { SampleService ss = BeanFactory.getSampleServiceBean(); for (Sample s : newSamples) { wr.getSamples().add(ss.findByID(s.getSampleId())); } } if (sharedWRs != null && !sharedWRs.isEmpty()) { throw new NotImplementedException("Adding ShareWorkflowRuns is not implemented"); } if (wrParams != null && !wrParams.isEmpty()) { throw new NotImplementedException("Adding WorkflowRunParams is not implemented"); } return wr; } /** * {@inheritDoc} * * @param that */ @Override public int compareTo(WorkflowRun that) { // TODO Auto-generated method stub if (that == null) { return -1; } if (Objects.equals(that.getSwAccession(), this.getSwAccession())) // when both names are // null { return 0; } if (that.getSwAccession() == null) { return -1; // when only the other name is null } if (this.getSwAccession() == null) { return 1; } return (that.getSwAccession().compareTo(this.getSwAccession())); } /** * {@inheritDoc} * * @return */ @Override public boolean givesPermissionInternal(Registration registration, Set<Integer> considered) { if (registration.isLIMSAdmin()) { Log.debug("Skipping permissions admin on Workflow Run object " + swAccession); return true; } boolean consideredBefore = considered.contains(this.getSwAccession()); if (!consideredBefore) { considered.add(this.getSwAccession()); Log.debug("Checking permissions for WorkflowRun object " + swAccession); } else { Log.debug("Skipping permissions for WorkflowRun object " + swAccession + " , checked before"); return true; } boolean hasPermission = true; if (workflow != null) { workflow.givesPermission(registration, considered); if (ius != null) { for (IUS i : ius) { i.givesPermission(registration, considered); } } if (lanes != null) { for (Lane l : lanes) { l.givesPermission(registration, considered); } } } else {// orphaned WorkflowRun if (registration.equals(this.owner) || registration.isLIMSAdmin()) { LOGGER.warn("Modifying Orphan WorkflowRun: " + this.getCommand()); hasPermission = true; } else { LOGGER.warn("Not modifying Orphan WorkflowRun: " + this.getCommand()); hasPermission = false; } } if (!hasPermission) { LOGGER.info("WorkflowRun does not give permission"); throw new SecurityException("User " + registration.getEmailAddress() + " does not have permission to modify " + this.getCommand()); } return hasPermission; } /** * <p> * Getter for the field <code>workflowRunAttributes</code>. * </p> * * @return a {@link java.util.Set} object. */ public Set<WorkflowRunAttribute> getWorkflowRunAttributes() { return workflowRunAttributes; } /** * <p> * Setter for the field <code>workflowRunAttributes</code>. * </p> * * @param workflowRunAttributes * a {@link java.util.Set} object. */ public void setWorkflowRunAttributes(Set<WorkflowRunAttribute> workflowRunAttributes) { this.workflowRunAttributes = workflowRunAttributes; } public String getWorkflowEngine() { return workflowEngine; } public void setWorkflowEngine(String workflowEngine) { this.workflowEngine = workflowEngine; } public Integer getWorkflowAccession() { return workflowAccession; } public void setWorkflowAccession(Integer workflowAccession) { this.workflowAccession = workflowAccession; } public String getOwnerUserName() { return ownerUserName; } public void setOwnerUserName(String ownerUserName) { this.ownerUserName = ownerUserName; } /** * @return the parentAccessions */ public Set<Integer> getInputFileAccessions() { return inputFileAccessions; } /** * @param inputFiles */ public void setInputFileAccessions(Set<Integer> inputFiles) { this.inputFileAccessions = inputFiles; } @Override public Set<WorkflowRunAttribute> getAnnotations() { return this.getWorkflowRunAttributes(); } }