Commit 129744a0 authored by Steven Murray's avatar Steven Murray
Browse files

Added a general purpose hierarchical state machine (still to be fully tested).

The primary goal of this state machine is to help manage the complexity of the
RTCOPY (rtclientd/rtcpd) protocol within the tape aggregator.
parent b7788b34
......@@ -22,4 +22,4 @@
# @author Sebastien Ponce, sebastien.ponce@cern.ch
#
SUBDIRS = aggregator tapegateway
SUBDIRS = aggregator fsm tapegateway
/******************************************************************************
* castor/tape/fsm/AbstractCallback.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Nicola.Bessone@cern.ch Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_FSM_ABSTRACTCALLBACK
#define CASTOR_TAPE_FSM_ABSTRACTCALLBACK
namespace castor {
namespace tape {
namespace fsm {
/**
* Provides the specification for a callback functor to be used to invoke
* the actions of a finite state machine.
*/
class AbstractCallback {
public:
/**
* The operator() function where the callback will be implemented by a
* sub-class of AbstractCallback.
*/
virtual const char *operator()() const = 0;
/**
* Destructor.
*/
virtual ~AbstractCallback() {
}
};
} // namespace fsm
} // namespace tape
} // namespace castor
#endif // CASTOR_TAPE_FSM_ABSTRACTCALLBACK
/******************************************************************************
* castor/tape/fsm/Callback.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Nicola.Bessone@cern.ch Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_FSM_CALLBACK
#define CASTOR_TAPE_FSM_CALLBACK
namespace castor {
namespace tape {
namespace fsm {
/**
* A concrete callback template functor to be used to invoke the actions of a
* finite state machine.
*/
template<class T> class Callback {
public:
typedef const char*(T::*PointerToMemberFunction)();
/**
* Constructor.
*/
Callback(T &object, PointerToMemberFunction pointerToMemberFunction):
m_object(object), m_pointerToMemberFunction(pointerToMemberFunction) {
}
/**
* The operator() function where the callback is implemented.
*/
const char *operator()() {
return (m_obj.*m_memberFunctionPtr)();
}
/**
* Destructor.
*/
virtual ~Callback() {
}
private:
/**
* The object to be called back.
*/
T &m_object;
/**
* Pointer to the function to be invoked on the object to be called back.
*/
PointerToMemberFunction m_pointerToMemberFunction;
};
} // namespace fsm
} // namespace tape
} // namespace castor
#endif // CASTOR_TAPE_FSM_CALLBACK
/******************************************************************************
* castor/tape/fsm/ChildToParentState.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Nicola.Bessone@cern.ch Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_FSM_CHILDTOPARENTSTATE
#define CASTOR_TAPE_FSM_CHILDTOPARENTSTATE
namespace castor {
namespace tape {
namespace fsm {
/**
* A child state to parent state maplet.
*/
struct ChildToParentState {
const char *child;
const char *parent;
};
} // namespace fsm
} // namespace tape
} // namespace castor
#endif // CASTOR_TAPE_FSM_CHILDTOPARENTSTATE
#
# castor/tape/aggregator/Imakefile
#
# This file is part of the Castor project.
# See http://castor.web.cern.ch/castor
#
# Copyright (C) 2003 CERN
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# @author Steven Murray, Steven.Murray@cern.ch
#
CPPFLAGS = -pedantic -Wall -Werror -g -O0 -I../../../h -I../../.. $(MTCCFLAGS)
CFLAGS = -O -I../../../h -I../../.. $(THREADFLAGS)
LDFLAGS += $(MTLDFLAGS)
LD = g++
TAPEFSMLIB_SRCS = \
StateMachine.cpp
#if BuildTapeFsmLibrary
TAPEFSMLIB_OBJS = $(TAPEFSMLIB_SRCS:.cpp=.Osuf)
SharedLibraryTarget(tapefsm,$(TAPEFSMLIB_OBJS),$(DEPLIB),$(LIBS))
#endif
/******************************************************************************
* StateMachine.cpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
*
* @author Nicola.Bessone@cern.ch Steven.Murray@cern.ch
*****************************************************************************/
#include "castor/tape/fsm/StateMachine.hpp"
#include <errno.h>
#include <stdlib.h>
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
castor::tape::fsm::StateMachine::StateMachine() throw() : m_state(NULL),
m_transitions(NULL), m_stateHierarchy(NULL) {
}
//-----------------------------------------------------------------------------
// setState
//-----------------------------------------------------------------------------
void castor::tape::fsm::StateMachine::setState(const char *const state) {
m_state = state;
}
//-----------------------------------------------------------------------------
// setTransitions
//-----------------------------------------------------------------------------
void castor::tape::fsm::StateMachine::setTransitions(
const Transition *const transitions) {
m_transitions = transitions;
}
//-----------------------------------------------------------------------------
// setStateHierarchy
//-----------------------------------------------------------------------------
void castor::tape::fsm::StateMachine::setStateHierarchy(
const ChildToParentState *const stateHierarchy) {
m_stateHierarchy = stateHierarchy;
}
//-----------------------------------------------------------------------------
// dispatch
//-----------------------------------------------------------------------------
void castor::tape::fsm::StateMachine::dispatch(const char *event)
throw(castor::exception::Exception) {
// Check the state has been set
if(m_state == NULL) {
castor::exception::Exception ex(EINVAL);
ex.getMessage() << __PRETTY_FUNCTION__
<< ": State not set when dispatch() called";
throw ex;
}
const Transition *transition = NULL;
// While there is an event to be processed (the action of a transition may
// generate an internal event)
while(event != NULL) {
transition = findTransitionInHierarchy(event);
// Throw an exception if there is no transition for the event
if(transition == NULL) {
castor::exception::Exception ex(EINVAL);
ex.getMessage() << __PRETTY_FUNCTION__
<< ": No transition found "
": State = " << m_state
<< ": Event = " << event;
throw ex;
}
// Move to the next state if not a self transition
if(strcmp(transition->fromState, transition->toState) != 0) {
m_state = transition->toState;
}
// Get ready to detect an internal event
event = NULL;
// If there is an action
if(transition->action != NULL) {
// Invoke it which may generate an internal event
event = (*transition->action)();
}
}
}
//-----------------------------------------------------------------------------
// findTransition
//-----------------------------------------------------------------------------
const castor::tape::fsm::Transition
*castor::tape::fsm::StateMachine::findTransition(const char *const state,
const char *const event) throw(castor::exception::Exception) {
// Check the transitions have been set
if(m_transitions == NULL) {
castor::exception::Exception ex(EINVAL);
ex.getMessage() << __PRETTY_FUNCTION__
<< ": Transitions not set when dispatch() called";
throw ex;
}
// For each transition
for(int i=0; strcmp(m_transitions[i].fromState, "") != 0; i++) {
// If the transition has been found, then return a pointer to it
if(strcmp(m_transitions[i].fromState, state) == 0 &&
strcmp(m_transitions[i].event, event) == 0) {
return &m_transitions[i];
}
}
// Transition not found
return NULL;
}
//-----------------------------------------------------------------------------
// findParentState
//-----------------------------------------------------------------------------
const char *castor::tape::fsm::StateMachine::findParentState(
const char *const state) throw(castor::exception::Exception) {
// Check the state heirarchy has been set
if(m_stateHierarchy == NULL) {
castor::exception::Exception ex(EINVAL);
ex.getMessage() << __PRETTY_FUNCTION__
<< ": State hierarchy not set when dispatch() called";
throw ex;
}
// For each child/parent maplet
for(int i=0; strcmp(m_stateHierarchy[i].child, "") != 0; i++) {
// If the parent has been found, then return a pointer to it
if(strcmp(m_stateHierarchy[i].child, state) == 0) {
return m_stateHierarchy[i].parent;
}
}
// Parent state not found
return NULL;
}
//-----------------------------------------------------------------------------
// findTransitionInHierarchy
//-----------------------------------------------------------------------------
const castor::tape::fsm::Transition
*castor::tape::fsm::StateMachine::findTransitionInHierarchy(
const char *const event) throw(castor::exception::Exception) {
const Transition *transition = NULL;
// Start within the state hiearchy at the current state
const char *state = m_state;
// While a transition has not been found and the state is within the state
// hierarchy
while(transition == NULL && state != NULL) {
transition = findTransition(state, event);
if(transition != NULL) {
return transition;
}
state = findParentState(state);
}
// Transition not found
return NULL;
}
/******************************************************************************
* castor/tape/fsm/StateMachine.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Nicola.Bessone@cern.ch Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_FSM_STATEMACHINE
#define CASTOR_TAPE_FSM_STATEMACHINE
#include "castor/exception/Exception.hpp"
#include "castor/tape/fsm/ChildToParentState.hpp"
#include "castor/tape/fsm/Transition.hpp"
namespace castor {
namespace tape {
namespace fsm {
/**
* A hierarchical finite state machine.
*/
class StateMachine {
public:
/**
* Constructor.
*/
StateMachine() throw();
/**
* Sets the state of the state machine.
*
* Please note that this method must be called at least once before
* dispatch() is called.
*/
void setState(const char *const state);
/**
* Sets the transitions that define the dynamic behaviour of the state
* machine.
*/
void setTransitions(const Transition *const transitions);
/**
* Sets the state heirarchy of the state machine.
*/
void setStateHierarchy(const ChildToParentState *const stateHierarchy);
/**
* Dispatches the specified event.
*/
void dispatch(const char *event) throw(castor::exception::Exception);
private:
/**
* The current state of the state machine.
*/
const char *m_state;
/**
* The list of state transitions that define the dynamic behaviour of the
* state machine.
*/
const Transition *m_transitions;
/**
* The state hierarchy.
*/
const ChildToParentState *m_stateHierarchy;
/**
* Searches the state transitions for the transition with specified
* fromState and event.
*
* Please note that this function does not traverse the state hierarchy.
*
* @param state The state to be used when searching.
* @param event The event to be used when searching.
* @return A pointer to the transition if one is found, else NULL.
*/
const Transition *findTransition(const char *const state,
const char *const event) throw(castor::exception::Exception);
/**
* Searches the state hierarchy for the parent of the specified state.
*
* @param state The state whose parent is to be found.
* @return A pointer to the parent state if one is found, else NULL.
*/
const char *findParentState(const char *const state)
throw(castor::exception::Exception);
/**
* Traverses the state heirarchy starting at the current state to find
* the transition with the specified event.
*
* @param event The event triggering the transition.
* @return A pointer to the transition if it is found, else NULL.
*/
const Transition *findTransitionInHierarchy(const char *const event)
throw(castor::exception::Exception);
};
} // namespace fsm
} // namespace tape
} // namespace castor
#endif // CASTOR_TAPE_FSM_STATEMACHINE
/******************************************************************************
* castor/tape/fsm/Transition.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Nicola.Bessone@cern.ch Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_FSM
#define CASTOR_TAPE_FSM
#include "castor/tape/fsm/AbstractCallback.hpp"
namespace castor {
namespace tape {
namespace fsm {
/**
* A state transition which specifies for a given "from state" and event the
* "to state" to be transitioned to and the action to be performed whilst in
* "to state". The action to be performed is optional. A value of NULL
* specifies no action.
*
* @param fromState The "from state".
* @param toState The "to state".
* @param event The event.
* @param action A callback functor to be used to invoke the action which
* is to be performed whilst in the "to state".
*/
struct Transition {
const char *const fromState;
const char *const event;
const char *const toState;
const AbstractCallback *const action;
};
} // namespace fsm
} // namespace tape
} // namespace castor
#endif // CASTOR_TAPE_FSM
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment