package net.sourceforge.seqware.pipeline.workflowV2; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import static net.sourceforge.seqware.common.util.Str.safe; import net.sourceforge.seqware.pipeline.workflowV2.model.AbstractJob; import net.sourceforge.seqware.pipeline.workflowV2.model.Environment; import net.sourceforge.seqware.pipeline.workflowV2.model.SqwFile; import net.sourceforge.seqware.pipeline.workflowV2.model.Workflow; /** * This is the base class for workflows. * * Methods in this class can be called by workflow authors and this can be detected as dead code when not really dead code. * * @author dyuen */ public abstract class AbstractWorkflowDataModel { private final Workflow workflow; private String name; private String version; private final Environment env; private String workflowBundleDir; private Map<String, String> tags; private Map<String, String> configs; private boolean metadataWriteBack; private Map<String, SqwFile> files; private final Collection<String> dirs; private final Collection<String> parentAccessions; private String workflow_accession; private String workflow_run_accession; private String random; private String date; private String metadata_output_file_prefix; private String metadata_output_dir; // default is pegasus private String workflow_engine; private String seqware_version; private String workflow_directory_name; private String bundle_version; // usually it is ${workflow_bundle_dir}/Workflow_Bundle_${workflow-directory-name}/${version} private String basedir; public AbstractWorkflowDataModel() { this.env = new Environment(); this.files = new LinkedHashMap<>(); this.setTags(new HashMap<String, String>()); this.configs = new HashMap<>(); this.workflow = new Workflow(); this.dirs = new ArrayList<>(); this.parentAccessions = new ArrayList<>(); } /** * Validates and potentially modifies the specified model in preparation for launching. * * @param model */ public static void prepare(AbstractWorkflowDataModel model) { Map<String, SqwFile> m = new HashMap<>(); for (Map.Entry<String, SqwFile> e : model.files.entrySet()) { String name = safe(e.getKey()); if (m.containsKey(name)) { throw new RuntimeException("Ensuring provision file job names are safe would result in colliding names: " + name); } else { m.put(name, e.getValue()); } } model.files = m; for (AbstractJob j : model.workflow.getJobs()) { // disregarding naming collisions since it won't result in losing objects, and is handled elsewhere. j.setAlgo(safe(j.getAlgo())); } } /** * to be Overridden by the workflow author. * * Called via reflection in WorkflowDataModelFactory */ public void setupDirectory() { } /** * to be Overridden by the workflow author you generally don't call this as the workflow author since it promotes hardcoding this will * typically be filled in by maven Called via reflection in WorkflowDataModelFactory */ public void setupWorkflow() { } /** * to be Overridden by the workflow author generally people don't override this. * * Called via reflection in WorkflowDataModelFactory */ public void setupEnvironment() { } /** * to be Overridden by the workflow author the place to specify inputs and outputs to the program also, a user can specify inputs and * outputs on jobs directly in which case they are still provisioned properly with respect to the job (inputs before, outputs after) * when you define inputs/outputs here they are provisioned before all jobs and after all jobs respectively * * @return */ public Map<String, SqwFile> setupFiles() { return this.files; } /** * to be Overridden by the workflow author * * Called via reflection in WorkflowDataModelFactory */ public abstract void buildWorkflow(); /** * to be Overridden by the workflow author * * Called via reflection in WorkflowDataModelFactory */ public void wrapup() { } /** * * @return pre-defined date variable */ public String getDate() { return date; } /** * set the pre-defined date variable * * @param date */ public void setDate(String date) { this.date = date; } /** * * @return the pre-defined random variable */ public String getRandom() { return random; } /** * set the pre-defined random variable * * @param random */ public void setRandom(String random) { this.random = random; } /** * * @return the workflow bundle Dir */ public String getWorkflowBundleDir() { return this.workflowBundleDir; } public void setWorkflowBundleDir(String dir) { this.workflowBundleDir = dir; } /** * * @return current workflow name */ public String getName() { return name; } /** * set the workflow name * * @param name */ public void setName(String name) { this.name = name; } /** * * @return pre-defined workflow object; */ public Workflow getWorkflow() { return this.workflow; } /** * need metadata writeback? user can override this setting by using --no-metadata or --metadata from command line * * @return */ public boolean isMetadataWriteBack() { return metadataWriteBack; } /** * need metadata writeback? user can override this setting by using --no-metadata or --metadata from command line * * @param b */ public void setMetadataWriteBack(boolean b) { this.metadataWriteBack = b; } /** * * @return the key-value properties from INI files */ public Map<String, String> getConfigs() { return this.configs; } /** * set the key-value properties for workflow * * @param configs */ public void setConfigs(Map<String, String> configs) { this.configs = configs; } /** * * @return workflow version */ public String getVersion() { return version; } /** * set workflow version * * @param version */ public void setVersion(String version) { this.version = version; } /** * * @return user defined files */ public Map<String, SqwFile> getFiles() { return files; } /** * @return ${workflow_bundle_dir}/Workflow_Bundle_${workflow-directory-name}/${version} */ public String getWorkflowBaseDir() { return this.basedir; } /** * the key-value from metadata.xml * * @return */ public Map<String, String> getTags() { return tags; } /** * set the key-value properties from metadata.xml * * @param tags */ public final void setTags(Map<String, String> tags) { this.tags = tags; } /** * * @return workflow environment */ public Environment getEnv() { return env; } /** * create a user defined directory before all jobs started * * @param name * : directory name */ public void addDirectory(String name) { this.dirs.add(name); } /** * * @return user defined directories */ public Collection<String> getDirectories() { return this.dirs; } /** * Creates a sqwfile attached to the workflow as a whole for provisioning. * * @param name * @return the created sqwfile */ public SqwFile createFile(String name) { SqwFile file = new SqwFile(); if (this.files.containsKey(name)) { throw new RuntimeException("Cannot register more than one file to the same name"); } file.setAttached(true); this.files.put(name, file); return file; } /** * * @return parent_accessions separated by "," */ public Collection<String> getParentAccessions() { return new ArrayList<>(this.parentAccessions); } /** * * @param parent_accessions * parent_accessions separated by "," */ void setParentAccessions(Collection<String> parentAccessions) { // 0.13.6.5 We actually want overridden behaviour, rather than combining workflow.ini and command-line opts, // we want just the command-line opts if present this.parentAccessions.clear(); this.parentAccessions.addAll(parentAccessions); } /** * * @return a workflow_accession number */ public String getWorkflow_accession() { return workflow_accession; } /** * set workflow_accession * * @param workflow_accession */ void setWorkflow_accession(String workflow_accession) { this.workflow_accession = workflow_accession; } /** * * @return workflow run accession number */ public String getWorkflow_run_accession() { return workflow_run_accession; } /** * set workflow run accession * * @param workflow_run_accession */ void setWorkflow_run_accession(String workflow_run_accession) { this.workflow_run_accession = workflow_run_accession; } /** * * @return output file prefix */ public String getMetadata_output_file_prefix() { return metadata_output_file_prefix; } /** * set output file prefix, used by provisionfiles output * * @param metadata_output_file_prefix */ void setMetadata_output_file_prefix(String metadata_output_file_prefix) { this.metadata_output_file_prefix = metadata_output_file_prefix; } public String getMetadata_output_dir() { return metadata_output_dir; } void setMetadata_output_dir(String metadata_output_dir) { this.metadata_output_dir = metadata_output_dir; } /** * * @return engine that workflow will run on, default is pegasus */ public String getWorkflow_engine() { return workflow_engine; } /** * default is pegasus * * @param workflow_engine */ public void setWorkflow_engine(String workflow_engine) { this.workflow_engine = workflow_engine; } /** * get the user defined INI files properties * * @param key * @return value of the key. * @throws Exception */ public String getProperty(String key) throws Exception { if (!this.configs.containsKey(key)) throw new Exception("Key " + key + " not found"); return configs.get(key); } public boolean hasProperty(String key) { return (this.configs.containsKey(key)); } public boolean hasPropertyAndNotNull(String key) { return (this.configs.containsKey(key) && configs.get(key) != null); } public String getWorkflow_directory_name() { return workflow_directory_name; } void setWorkflow_directory_name(String workflow_directory_name) { this.workflow_directory_name = workflow_directory_name; } public String getSeqware_version() { return seqware_version; } void setSeqware_version(String seqware_version) { this.seqware_version = seqware_version; } public String getBundle_version() { return bundle_version; } void setBundle_version(String bundle_version) { this.bundle_version = bundle_version; } void setWorkflowBasedir(String basedir) { this.basedir = basedir; } }