/* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * . * */ static const char* const StateInterface_cxx_Version = "$Id: StateInterface.cxx,v 1.2 2001/08/10 04:02:04 icahoon Exp $"; #include "global.h" #include #include "StateInterface.hxx" #include "Stimulus.hxx" #include "Action.hxx" #include "VLog.hxx" using Vocal::Behavioral::StateInterface; using Vocal::Behavioral::Stimulus; using Vocal::Behavioral::Action; using Vocal::Logging::VLog; using Vocal::ReturnCode; StateInterface::StateInterface( const char * name, Action * onEntry, Action * onExit ) : myName(name ? name : "NullState"), myEntry(onEntry), myExit(onExit) { const string fn("StateInterface::StateInterface"); VLog log(fn); VDEBUG(log) << fn << ": " << *this << VDEBUG_END(log); } StateInterface::~StateInterface() { const string fn("StateInterface::~StateInterface"); VLog log(fn); VDEBUG(log) << fn << ": " << myName << VDEBUG_END(log); } void StateInterface::addAction( const Stimulus & stimulus, Action & action, StateInterface & nextState ) { const string fn("StateInterface::addAction"); VLog log(fn); bool rc = stimulusTable_.insert( StimulusPair(stimulus, StimulusData(action, nextState, 0)) ).second; assert( rc ); VDEBUG(log) << fn << "\n\tState :\t" << myName << "\n\tStimulus :\t" << stimulus << "\n\tAction :\t" << action << "\n\tNextState :\t" << nextState.name() << VDEBUG_END(log); } void StateInterface::addAction( const Stimulus & stimulus, Action & action, StateInterface & nextState, StateInterface & nextStateOnFail ) { const string fn("StateInterface::addAction"); VLog log(fn); bool rc = stimulusTable_.insert( StimulusPair(stimulus, StimulusData(action, nextState, &nextStateOnFail)) ).second; assert( rc ); VDEBUG(log) << fn << "\n\tState :\t" << myName << "\n\tStimulus :\t" << stimulus << "\n\tAction :\t" << action << "\n\tNextState :\t" << nextState.name() << "\n\tNextStateOnFail:\t" << nextStateOnFail.name() << VDEBUG_END(log); } void StateInterface::entryAction(Action & onEntry) { myEntry = &onEntry; } void StateInterface::exitAction(Action & onExit) { myExit = &onExit; } void StateInterface::enter() throw () { const string fn("StateInterface::enter"); VLog log(fn); if ( myEntry ) { VDEBUG(log) << fn << ": State: " << myName << ": Action: " << *myEntry << VDEBUG_END(log); myEntry->action(); } } StateInterface & StateInterface::stimulate( const Stimulus & stimulus ) throw () { const string fn("StateInterface::stimuluate"); VLog log(fn); VDEBUG(log) << fn << "\n\tState: " << myName << ",\t\tStimulus: " << stimulus << VDEBUG_END(log); // Lookup the stimulus in the stimulus table. // StimulusTable::iterator it = stimulusTable_.find(stimulus); // If it doesn't exist, do nothing. // if ( it == stimulusTable_.end() ) { VDEBUG(log) << fn << "\n\tState: " << myName << ",\t\tAction: No Action" << VDEBUG_END(log); return ( *this ); } // If the stimulus exists first perform the exit action on this state, // then perform the action associated with the stimulus, and finally // perform the entry action on the next state. // // Note that the exit action, the action associated with this stimulus, // and the entry action of the next state may throw an exception. // exit(); Action & action = (*it).second.action_; VDEBUG(log) << fn << "\n\tState: " << myName << ",\t\tAction: " << action << VDEBUG_END(log); ReturnCode rc = action.action(stimulus); StateInterface & nextState = ( rc != SUCCESS && (*it).second.nextStateOnFail_ ? *(*it).second.nextStateOnFail_ : (*it).second.nextState_ ); VDEBUG(log) << fn << "\n\tState: " << myName << ",\t\tNext State: " << nextState.name() << VDEBUG_END(log); nextState.enter(); return ( nextState ); } void StateInterface::exit() throw () { const string fn("StateInterface::enter"); VLog log(fn); if ( myExit ) { VDEBUG(log) << fn << "\n\tState: " << myName << ",\t\tAction: " << *myExit << VDEBUG_END(log); myExit->action(); } } ostream & StateInterface::writeTo(ostream & out) const { out << name() << "\n\tEntry:\t" << ( myEntry ? *myEntry : Action() ) << "\n\tExit:\t" << ( myExit ? *myExit : Action() ) << "\n\tStimuli:\n\t{"; for ( StimulusTable::const_iterator it = stimulusTable_.begin(); it != stimulusTable_.end(); it++ ) { out << "\n\t\tStimulus :\t" << (*it).first << "\n\t\tAction :\t" << (*it).second.action_ << "\n\t\tNextState :\t" << (*it).second.nextState_.name(); if ( (*it).second.nextStateOnFail_ ) { out << "\n\t\tNextStateOnFail:\t" << (*it).second.nextStateOnFail_->name(); } out << '\n'; } return ( out << "\n\t}" ); } const string & StateInterface::name() const { return ( myName ); } StateInterface::StimulusData::StimulusData( Action & action, StateInterface & nextState, StateInterface * nextStateOnFail ) : action_(action), nextState_(nextState), nextStateOnFail_(nextStateOnFail) { }