'Executes a tool, creating job and tool outputs, associating them, and
submitting the job to the job queue. If history is not specified, use
trans.history as destination for tool\'s output datasets.'

def execute(self, tool, trans, incoming={}, return_job=False, set_output_hid=True, history=None, job_params=None, rerun_remap_job_id=None, mapping_over_collection=False, execution_cache=None):

    self._check_access(tool, trans)
    app = trans.app
    if (execution_cache is None):
        execution_cache = ToolExecutionCache(trans)
    current_user_roles = execution_cache.current_user_roles
    (history, inp_data, inp_dataset_collections) = self._collect_inputs(tool, trans, incoming, history, current_user_roles)
    on_text = self._get_on_text(inp_data)
    input_ext = ('data' if (tool.profile < 16.04) else 'input')
    input_dbkey = incoming.get('dbkey', '?')
    preserved_tags = {}
    for (name, data) in reversed(inp_data.items()):
        if (not data):
            data = NoneDataset(datatypes_registry=app.datatypes_registry)
            continue
        if isinstance(data, LibraryDatasetDatasetAssociation):
            data = data.to_history_dataset_association(None)
            inp_data[name] = data
        if (tool.profile < 16.04):
            input_ext = data.ext
        if (data.dbkey not in [None, '?']):
            input_dbkey = data.dbkey
        identifier = getattr(data, 'element_identifier', None)
        if (identifier is not None):
            incoming[('%s|__identifier__' % name)] = identifier
        for tag in [t for t in data.tags if (t.user_tname == 'name')]:
            preserved_tags[tag.value] = tag
    (chrom_info, db_dataset) = app.genome_builds.get_chrom_info(input_dbkey, trans=trans, custom_build_hack_get_len_from_fasta_conversion=(tool.id != 'CONVERTER_fasta_to_len'))
    if db_dataset:
        inp_data.update({'chromInfo': db_dataset})
    incoming['chromInfo'] = chrom_info
    existing_datasets = [inp for inp in inp_data.values() if inp]
    if existing_datasets:
        output_permissions = app.security_agent.guess_derived_permissions_for_datasets(existing_datasets)
    else:
        output_permissions = app.security_agent.history_get_default_permissions(history)
    incoming['dbkey'] = input_dbkey
    wrapped_params = self._wrapped_params(trans, tool, incoming)
    out_data = odict()
    input_collections = dict(((k, v[0][0]) for (k, v) in inp_dataset_collections.items()))
    output_collections = OutputCollections(trans, history, tool=tool, tool_action=self, input_collections=input_collections, mapping_over_collection=mapping_over_collection, on_text=on_text, incoming=incoming, params=wrapped_params.params, job_params=job_params)
    parent_to_child_pairs = []
    child_dataset_names = set()
    object_store_populator = ObjectStorePopulator(app)
    def handle_output(name, output, hidden=None):
        if output.parent:
            parent_to_child_pairs.append((output.parent, name))
            child_dataset_names.add(name)
        if (name in incoming):
            dataid = incoming[name]
            data = trans.sa_session.query(app.model.HistoryDatasetAssociation).get(dataid)
            assert (data is not None)
            out_data[name] = data
        else:
            ext = determine_output_format(output, wrapped_params.params, inp_data, inp_dataset_collections, input_ext)
            data = app.model.HistoryDatasetAssociation(extension=ext, create_dataset=True, flush=False)
            if (hidden is None):
                hidden = output.hidden
            if hidden:
                data.visible = False
            trans.sa_session.add(data)
            trans.app.security_agent.set_all_dataset_permissions(data.dataset, output_permissions, new=True)
        for (_, tag) in preserved_tags.items():
            data.tags.append(tag.copy())
        trans.sa_session.flush()
        object_store_populator.set_object_store_id(data)
        data.designation = name
        metadata_source = output.metadata_source
        if metadata_source:
            if isinstance(metadata_source, string_types):
                metadata_source = inp_data.get(metadata_source)
        if (metadata_source is not None):
            data.init_meta(copy_from=metadata_source)
        else:
            data.init_meta()
        data.dbkey = str(input_dbkey)
        data.blurb = 'queued'
        data.name = self.get_output_name(output, data, tool, on_text, trans, incoming, history, wrapped_params.params, job_params)
        out_data[name] = data
        if output.actions:
            output_action_params = dict(out_data)
            output_action_params.update(incoming)
            output.actions.apply_action(data, output_action_params)
        self.set_metadata_defaults(output, data, tool, on_text, trans, incoming, history, wrapped_params.params, job_params)
        return data
    for (name, output) in tool.outputs.items():
        if (not filter_output(output, incoming)):
            if output.collection:
                collections_manager = app.dataset_collections_service
                element_identifiers = []
                known_outputs = output.known_outputs(input_collections, collections_manager.type_registry)
                for output_part_def in known_outputs:
                    current_element_identifiers = element_identifiers
                    current_collection_type = output.structure.collection_type
                    for parent_id in (output_part_def.parent_ids or []):
                        current_collection_type = ':'.join(current_collection_type.split(':')[1:])
                        name_to_index = dict(((value['name'], index) for (index, value) in enumerate(current_element_identifiers)))
                        if (parent_id not in name_to_index):
                            if (parent_id not in current_element_identifiers):
                                index = len(current_element_identifiers)
                                current_element_identifiers.append(dict(name=parent_id, collection_type=current_collection_type, src='new_collection', element_identifiers=[]))
                            else:
                                index = name_to_index[parent_id]
                        current_element_identifiers = current_element_identifiers[index]['element_identifiers']
                    effective_output_name = output_part_def.effective_output_name
                    element = handle_output(effective_output_name, output_part_def.output_def, hidden=True)
                    child_dataset_names.add(effective_output_name)
                    history.add_dataset(element, set_hid=set_output_hid, quota=False)
                    trans.sa_session.add(element)
                    trans.sa_session.flush()
                    current_element_identifiers.append({'__object__': element, 'name': output_part_def.element_identifier})
                    log.info(element_identifiers)
                if output.dynamic_structure:
                    assert (not element_identifiers)
                    element_kwds = dict(elements=collections_manager.ELEMENTS_UNINITIALIZED)
                else:
                    element_kwds = dict(element_identifiers=element_identifiers)
                output_collections.create_collection(output=output, name=name, tags=preserved_tags, **element_kwds)
            else:
                handle_output_timer = ExecutionTimer()
                handle_output(name, output)
                log.info(('Handled    output    named    %s    for    tool    %s    %s' % (name, tool.id, handle_output_timer)))
    add_datasets_timer = ExecutionTimer()
    datasets_to_persist = []
    for name in out_data.keys():
        if ((name not in child_dataset_names) and (name not in incoming)):
            data = out_data[name]
            datasets_to_persist.append(data)
    history.add_datasets(trans.sa_session, datasets_to_persist, set_hid=set_output_hid, quota=False, flush=False)
    for (parent_name, child_name) in parent_to_child_pairs:
        parent_dataset = out_data[parent_name]
        child_dataset = out_data[child_name]
        parent_dataset.children.append(child_dataset)
    log.info(('Added    output    datasets    to    history    %s' % add_datasets_timer))
    job_setup_timer = ExecutionTimer()
    (job, galaxy_session) = self._new_job_for_session(trans, tool, history)
    self._record_inputs(trans, tool, job, incoming, inp_data, inp_dataset_collections, current_user_roles)
    self._record_outputs(job, out_data, output_collections)
    job.object_store_id = object_store_populator.object_store_id
    if job_params:
        job.params = dumps(job_params)
    job.set_handler(tool.get_job_handler(job_params))
    trans.sa_session.add(job)
    if (app.config.track_jobs_in_database and (rerun_remap_job_id is not None)):
        try:
            old_job = trans.sa_session.query(app.model.Job).get(rerun_remap_job_id)
            assert (old_job is not None), ('(%s/%s):    Old    job    id    is    invalid' % (rerun_remap_job_id, job.id))
            assert (old_job.tool_id == job.tool_id), ('(%s/%s):    Old    tool    id    (%s)    does    not    match    rerun    tool    id    (%s)' % (old_job.id, job.id, old_job.tool_id, job.tool_id))
            if (trans.user is not None):
                assert (old_job.user_id == trans.user.id), ('(%s/%s):    Old    user    id    (%s)    does    not    match    rerun    user    id    (%s)' % (old_job.id, job.id, old_job.user_id, trans.user.id))
            elif ((trans.user is None) and (type(galaxy_session) == trans.model.GalaxySession)):
                assert (old_job.session_id == galaxy_session.id), ('(%s/%s):    Old    session    id    (%s)    does    not    match    rerun    session    id    (%s)' % (old_job.id, job.id, old_job.session_id, galaxy_session.id))
            else:
                raise Exception(('(%s/%s):    Remapping    via    the    API    is    not    (yet)    supported' % (old_job.id, job.id)))
            for pjaa in old_job.post_job_actions:
                job.add_post_job_action(pjaa.post_job_action)
            for jtod in old_job.output_datasets:
                for (job_to_remap, jtid) in [(jtid.job, jtid) for jtid in jtod.dataset.dependent_jobs]:
                    if (((trans.user is not None) and (job_to_remap.user_id == trans.user.id)) or ((trans.user is None) and (job_to_remap.session_id == galaxy_session.id))):
                        if (job_to_remap.state == job_to_remap.states.PAUSED):
                            job_to_remap.state = job_to_remap.states.NEW
                        for hda in [dep_jtod.dataset for dep_jtod in job_to_remap.output_datasets]:
                            if (hda.state == hda.states.PAUSED):
                                hda.state = hda.states.NEW
                                hda.info = None
                        input_values = dict([(p.name, json.loads(p.value)) for p in job_to_remap.parameters])
                        update_param(jtid.name, input_values, str(out_data[jtod.name].id))
                        for p in job_to_remap.parameters:
                            p.value = json.dumps(input_values[p.name])
                        jtid.dataset = out_data[jtod.name]
                        jtid.dataset.hid = jtod.dataset.hid
                        log.info(('Job    %s    input    HDA    %s    remapped    to    new    HDA    %s' % (job_to_remap.id, jtod.dataset.id, jtid.dataset.id)))
                        trans.sa_session.add(job_to_remap)
                        trans.sa_session.add(jtid)
                jtod.dataset.visible = False
                trans.sa_session.add(jtod)
        except Exception:
            log.exception('Cannot    remap    rerun    dependencies.')
    log.info(('Setup    for    job    %s    complete,    ready    to    flush    %s' % (job.log_str(), job_setup_timer)))
    job_flush_timer = ExecutionTimer()
    trans.sa_session.flush()
    log.info(('Flushed    transaction    for    job    %s    %s' % (job.log_str(), job_flush_timer)))
    if ('REDIRECT_URL' in incoming):
        for name in inp_data.keys():
            dataset = inp_data[name]
        redirect_url = tool.parse_redirect_url(dataset, incoming)
        GALAXY_URL = incoming.get('GALAXY_URL', None)
        assert (GALAXY_URL is not None), 'GALAXY_URL    parameter    missing    in    tool    config.'
        redirect_url += ('&GALAXY_URL=%s' % GALAXY_URL)
        job.set_state(app.model.Job.states.OK)
        job.info = ('Redirected    to:    %s' % redirect_url)
        trans.sa_session.add(job)
        trans.sa_session.flush()
        trans.response.send_redirect(url_for(controller='tool_runner', action='redirect', redirect_url=redirect_url))
    else:
        app.job_queue.put(job.id, job.tool_id)
        trans.log_event(('Added    job    to    the    job    queue,    id:    %s' % str(job.id)), tool_id=job.tool_id)
        return (job, out_data)
