public void execute()
        throws Exception
    {
        // Set up threads for command execution
        boolean prepared = true;
        for (Enumeration command_scan = _commands.elements();
             command_scan.hasMoreElements();)
        {
            Command command =
                (Command) command_scan.nextElement();
            try
            { command.prepareToExecute(); }
            catch (Throwable t)
            {
                _exceptions.addElement(t);
                prepared = false;
            }
        }

        if (prepared)
        {
            // Pipe output of one command to input of next
            Command previous_command = null;
            for (Enumeration command_scan = _commands.elements();
                 command_scan.hasMoreElements();)
            {
                Command command =
                    (Command) command_scan.nextElement();
                if (previous_command != null)
                    Command.connectOutputToInput
                        (previous_command, command);
                previous_command = command;
            }
    
            // Run everything and collect outcomes
            Vector outcomes = new Vector();
            for (Enumeration command_scan = _commands.elements();
                 command_scan.hasMoreElements();)
            {
                Command command =
                    (Command) command_scan.nextElement();
                outcomes.addElement(command.startWork());
            }
    
            // Gather exceptions. terminationReason blocks until
            // execution is complete.
            for (Enumeration outcome_scan = outcomes.elements();
                 outcome_scan.hasMoreElements();)
            {
                PooledThread.Outcome outcome =
                    (PooledThread.Outcome) outcome_scan.nextElement();
                Throwable exception = outcome.terminationReason();
                if (exception != null)
                    _exceptions.addElement(exception);
            }
        }
    }