'Indicate job failure by setting state and message on all output
datasets.'

def fail(self, message, exception=False, stdout='', stderr='', exit_code=None):

    job = self.get_job()
    self.sa_session.refresh(job)
    if (not (job.state == job.states.DELETED)):
        if exception:
            job.traceback = traceback.format_exc()
            (etype, evalue, tb) = sys.exc_info()
        outputs_to_working_directory = util.asbool(self.get_destination_configuration('outputs_to_working_directory', False))
        if outputs_to_working_directory:
            for dataset_path in self.get_output_fnames():
                try:
                    shutil.move(dataset_path.false_path, dataset_path.real_path)
                    log.debug(('fail():    Moved    %s    to    %s' % (dataset_path.false_path, dataset_path.real_path)))
                except (IOError, OSError) as e:
                    log.error(('fail():    Missing    output    file    in    working    directory:    %s' % e))
        for dataset_assoc in (job.output_datasets + job.output_library_datasets):
            dataset = dataset_assoc.dataset
            self.sa_session.refresh(dataset)
            dataset.state = dataset.states.ERROR
            dataset.blurb = 'tool    error'
            dataset.info = message
            dataset.set_size()
            dataset.dataset.set_total_size()
            dataset.mark_unhidden()
            if (dataset.ext == 'auto'):
                dataset.extension = 'data'
            self.__update_output(job, dataset)
            for dep_job_assoc in dataset.dependent_jobs:
                self.pause(dep_job_assoc.job, "Execution    of    this    dataset's    job    is    paused    because    its    input    datasets    are    in    an    error    state.")
            self.sa_session.add(dataset)
            self.sa_session.flush()
        job.set_final_state(job.states.ERROR)
        job.command_line = unicodify(self.command_line)
        job.info = message
        job.set_streams(stdout, stderr)
        if (exit_code is not None):
            job.exit_code = exit_code
        self.sa_session.add(job)
        self.sa_session.flush()
    else:
        for dataset_assoc in job.output_datasets:
            dataset = dataset_assoc.dataset
            self.__update_output(job, dataset, clean_only=True)
    self._report_error()
    for pja in [pjaa.post_job_action for pjaa in job.post_job_actions if (pjaa.post_job_action.action_type == 'EmailAction')]:
        ActionBox.execute(self.app, self.sa_session, pja, job)
    if self.tool:
        self.tool.job_failed(self, message, exception)
    cleanup_job = self.cleanup_job
    delete_files = ((cleanup_job == 'always') or ((cleanup_job == 'onsuccess') and (job.state == job.states.DELETED)))
    self.cleanup(delete_files=delete_files)
