public State<ET> call()
    {
        try
        {
            // WARNING: Must synchronize adding listener and setting
            // initial state or you can miss a notification from the state
            // machine.
            synchronized (stateMachine)
            {
                stateMachine.addListener(this);
                this.stateQueue.add(stateMachine.getState());
            }

            // Run until we finish or somebody interrupts us.
            while (!done && !Thread.interrupted())
            {
                try
                {
                    setCurrent(stateQueue.take());
                    // Use startsWith to handle parent states. 
                    if (current.getName().startsWith(expected.getName()))
                    {
                        done = true;
                        reachedExpected = true;
                    }
                    else if (endOnError && errorState != null
                            && current.equals(errorState))
                    {
                        done = true;
                        reachedError = true;
                    }
                }
                catch (InterruptedException e)
                {
                    // Interruption means somebody is trying to cancel us.
                    break;
                }
            }
        }
        finally
        {
            stateMachine.removeListener(this);
        }

        // If we are done, return the current state. Otherwise, return null.
        if (done)
            return current;
        else
            return null;
    }