summaryrefslogtreecommitdiffstats
path: root/src/lib/util/state_model.h
blob: 6ef523830e0e19c8eb0d7d6a7e135f85fa631009 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef STATE_MODEL_H
#define STATE_MODEL_H

/// @file state_model.h This file defines the class StateModel.

#include <exceptions/exceptions.h>
#include <util/labeled_value.h>
#include <boost/shared_ptr.hpp>
#include <functional>
#include <map>
#include <mutex>
#include <string>

namespace isc {
namespace util {

/// @brief Thrown if the state machine encounters a general error.
class StateModelError : public isc::Exception {
public:
    StateModelError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Define an Event.
typedef LabeledValue Event;

/// @brief Define Event pointer.
typedef LabeledValuePtr EventPtr;

/// @brief Defines a pointer to an instance method for handling a state.
typedef std::function<void()> StateHandler;

/// @brief State machine pausing modes.
///
/// Supported modes are:
/// - always pause in the given state,
/// - never pause in the given state,
/// - pause upon first transition to the given state.
enum StatePausing {
    STATE_PAUSE_ALWAYS,
    STATE_PAUSE_NEVER,
    STATE_PAUSE_ONCE
};

/// @brief Defines a State within the State Model.
///
/// This class provides the means to define a state within a set or dictionary
/// of states, and assign the state an handler method to execute the state's
/// actions.  It derives from LabeledValue which allows a set of states to be
/// keyed by integer constants.
///
/// Because a state model can be paused in selected states, this class also
/// provides the means for specifying a pausing mode and for checking whether
/// the state model should be paused when entering this state.
class State : public LabeledValue {
public:
    /// @brief Constructor
    ///
    /// @param value is the numeric value of the state
    /// @param label is the text label to assign to the state
    /// @param handler is the bound instance method which handles the state's
    /// action.
    /// @param state_pausing pausing mode selected for the given state. The
    /// default value is @c STATE_PAUSE_NEVER.
    ///
    /// A typical invocation might look this:
    ///
    /// @code
    ///     State(SOME_INT_VAL, "SOME_INT_VAL",
    ///            std::bind(&StateModelDerivation::someHandler, this));
    /// @endcode
    ///
    /// @throw StateModelError if label is null or blank.
    State(const int value, const std::string& label, StateHandler handler,
          const StatePausing& state_pausing = STATE_PAUSE_NEVER);

    /// @brief Destructor
    virtual ~State();

    /// @brief Invokes the State's handler.
    void run();

    /// @brief Indicates if the state model should pause upon entering
    /// this state.
    ///
    /// It modifies the @c was_paused_ flag if the state model should
    /// pause. That way, it keeps track of visits in this particular state,
    /// making it possible to pause only upon the first transition to the
    /// state when @c STATE_PAUSE_ONCE mode is used.
    bool shouldPause();

private:
    /// @brief Bound instance method pointer to the state's handler method.
    StateHandler handler_;

    /// @brief Specifies selected pausing mode for a state.
    StatePausing pausing_;

    /// @brief Indicates if the state machine was already paused in this
    /// state.
    bool was_paused_;
};

/// @brief Defines a shared pointer to a State.
typedef boost::shared_ptr<State> StatePtr;

/// @brief Implements a unique set or dictionary of states.
///
/// This class provides the means to construct and access a unique set of
/// states.  This provide the ability to validate state values, look up their
/// text labels, and their handlers.
class StateSet : public LabeledValueSet {
public:
    /// @brief Constructor
    StateSet();

    /// @brief Destructor
    virtual ~StateSet();

    /// @brief Adds a state definition to the set of states.
    ///
    /// @param value is the numeric value of the state
    /// @param label is the text label to assign to the state
    /// @param handler is the bound instance method which handles the state's
    /// @param state_pausing state pausing mode for the given state.
    ///
    /// @throw StateModelError if the value is already defined in the set, or
    /// if the label is null or blank.
    void add(const int value, const std::string& label, StateHandler handler,
             const StatePausing& state_pausing);

    /// @brief Fetches a state for the given value.
    ///
    /// @param value the numeric value of the state desired
    ///
    /// @return A constant pointer the State found.
    /// Note, this relies on dynamic cast and cannot return a pointer reference.
    ///
    /// @throw StateModelError if the value is undefined.
    const StatePtr getState(int value);
};

/// @brief Implements a finite state machine.
///
/// StateModel is an abstract class that provides the structure and mechanics
/// of a basic finite state machine.
///
/// The state model implementation used is a very basic approach. The model
/// uses numeric constants to identify events and states, and maintains
/// dictionaries of defined events and states.  Event and state definitions
/// include a text label for logging purposes.  Additionally, each state
/// definition includes a state handler. State handlers are methods which
/// implement the actions that need to occur when the model is "in" a given
/// state.  The implementation provides methods to add entries to and verify
/// the contents of both dictionaries.
///
/// During model execution, the following context is tracked:
///
/// * current state - The current state of the model
/// * previous state -  The state the model was in prior to the current state
/// * next event - The next event to be consumed
/// * last event - The event most recently consumed
///
/// When invoked, a state handler determines what it should do based upon the
/// next event including what the next state and event should be. In other
/// words the state transition knowledge is distributed among the state
/// handlers rather than encapsulated in some form of state transition table.
///
/// Events "posted" from within the state handlers are "internally" triggered
/// events.  Events "posted" from outside the state model, such as through
/// the invocation of a callback are "externally" triggered.
///
/// StateModel defines two states:
///
/// * NEW_ST - State that a model is in following instantiation. It remains in
/// this state until model execution has begun.
/// * END_ST - State that a model is in once it has reached its conclusion.
///
/// and the following events:
///
/// * START_EVT - Event used to start model execution.
/// * NOP_EVT - Event used to signify that the model stop and wait for an
/// external event, such as the completion of an asynchronous IO operation.
/// * END_EVT - Event used to trigger a normal conclusion of the model. This
/// means only that the model was traversed from start to finish, without any
/// model violations (i.e. invalid state, event, or transition) or uncaught
/// exceptions.
/// * FAIL_EVT - Event to trigger an abnormal conclusion of the model. This
/// event is posted internally when model execution fails due to a model
/// violation or uncaught exception.  It signifies that the model has reached
/// an inoperable condition.
///
/// Derivations add their own states and events appropriate for their state
/// model.  Note that NEW_ST and END_ST do not support handlers.  No work can
/// be done (events consumed) prior to starting the model nor can work be done
/// once the model has ended.
///
/// Model execution consists of iteratively invoking the state handler
/// indicated by the current state which should consume the next event. As the
/// handlers post events and/or change the state, the model is traversed. The
/// loop stops whenever the model cannot continue without an externally
/// triggered event or when it has reached its final state.  In the case of
/// the former, the loop may be re-entered upon arrival of the external event.
///
/// This loop is implemented in the runModel method.  This method accepts an
/// event as argument which it "posts" as the next event.  It then retrieves the
/// handler for the current state from the handler map and invokes it. runModel
/// repeats this process until either a NOP_EVT posts or the state changes
/// to END_ST.  In other words each invocation of runModel causes the model to
/// be traversed from the current state until it must wait or ends.
///
/// Re-entering the "loop" upon the occurrence of an external event is done by
/// invoking runModel with the appropriate event.  As before, runModel will
/// loop until either the NOP_EVT occurs or until the model reaches its end.
///
/// A StateModel (derivation) is in the NEW_ST when constructed and remains
/// there until it has been "started".  Starting the model is done by invoking
/// the startModel method which accepts a state as a parameter.  This parameter
/// specifies the "start" state and it becomes the current state.

/// The first task undertaken by startModel is to initialize and verify the
/// the event and state dictionaries.  The following virtual methods are
/// provided for this:
///
/// * defineEvents - define events
/// * verifyEvents - verifies that the expected events are defined
/// * defineStates - defines states
/// * verifyStates - verifies that the expected states are defined
///
/// The concept behind the verify methods is to provide an initial sanity
/// check of the dictionaries.  This should help avoid using undefined event
/// or state values accidentally.
///
/// These methods are intended to be implemented by each "layer" in a StateModel
/// derivation hierarchy.  This allows each layer to define additional events
/// and states.
///
/// Once the dictionaries have been properly initialized, the startModel method
/// invokes runModel with an event of START_EVT.  From this point forward and
/// until the model reaches the END_ST or fails, it is considered to be
/// "running".  If the model encounters a NOP_EVT then it is "running" and
/// "waiting".   If the model reaches END_ST with an END_EVT it is considered
/// "done".  If the  model fails (END_ST with a FAILED_EVT) it is considered
/// "done" and "failed".  There are several boolean status methods which may
/// be used to check these conditions.
/// Once the model has been started, defining new events or new states is
/// illegal. It is possible to call startModel only once.
///
/// To progress from one state to the another, state handlers invoke use
/// the method, transition.  This method accepts a state and an event as
/// parameters.  These values become the current state and the next event
/// respectively.  This has the effect of entering the given state having posted
/// the given event.  The postEvent method may be used to post a new event
/// to the current state.
///
/// Bringing the model to a normal end is done by invoking the endModel method
/// which transitions the model to END_ST with END_EVT.  Bringing the model to
/// an abnormal end is done via the abortModel method, which transitions the
/// model to END_ST with FAILED_EVT.
///
/// The model can be paused in the selected states. The states in which the
/// state model should pause (always or only once) are determined within the
/// @c StateModel::defineStates method. The state handlers can check whether
/// the state machine is paused or not by calling @c StateModel::isModelPaused
/// and act accordingy. Typically, the state handler would simply post the
/// @c NOP_EVT when it finds that the state model is paused. The model
/// remains paused until @c StateModel::unpauseModel is called.
class StateModel {
public:

    //@{ States common to all models.
    /// @brief State that a state model is in immediately after construction.
    static const int NEW_ST = 0;

    /// @brief Final state, all the state model has reached its conclusion.
    static const int END_ST = 1;

    /// @brief Value at which custom states in a derived class should begin.
    static const int SM_DERIVED_STATE_MIN = 11;
    //@}

    //@{ Events common to all state models.
    /// @brief Signifies that no event has occurred.
    /// This is event used to interrupt the event loop to allow waiting for
    /// an IO event or when there is no more work to be done.
    static const int NOP_EVT = 0;

    /// @brief Event issued to start the model execution.
    static const int START_EVT = 1;

    /// @brief Event issued to end the model execution.
    static const int END_EVT = 2;

    /// @brief Event issued to abort the model execution.
    static const int FAIL_EVT = 3;

    /// @brief Value at which custom events in a derived class should begin.
    static const int SM_DERIVED_EVENT_MIN = 11;
    //@}

    /// @brief Constructor
    StateModel();

    /// @brief Destructor
    virtual ~StateModel();

    /// @brief Begins execution of the model.
    ///
    /// This method invokes initDictionaries method to initialize the event
    /// and state dictionaries and then starts the model execution setting
    /// the current state to the given start state, and the event to START_EVT.
    /// This method can be called only once to start the state model.
    ///
    /// @param start_state is the state in which to begin execution.
    ///
    /// @throw StateModelError or others indirectly, as this method calls
    /// dictionary define and verify methods.
    void startModel(const int start_state);

    /// @brief Processes events through the state model
    ///
    /// This method implements the state model "execution loop".  It uses
    /// the given event as the next event to process and begins invoking
    /// the state handler for the current state.   As described above, the
    /// invoked state handler consumes the next event and then determines the
    /// next event and the current state as required to implement the business
    /// logic. The method continues to loop until the next event posted is
    /// NOP_EVT or the model ends.
    ///
    /// Any exception thrown during the loop is caught, logged, and the
    /// model is aborted with a FAIL_EVT.  The derivation's state
    /// model is expected to account for any possible errors so any that
    /// escape are treated as unrecoverable.
    ///
    /// @note This method is made virtual for the unit tests which require
    /// customizations allowing for more control over the state model
    /// execution.
    ///
    /// @param event is the next event to process
    ///
    /// This method is guaranteed not to throw.
    virtual void runModel(unsigned int event);

    /// @brief Conducts a normal transition to the end of the model.
    ///
    /// This method posts an END_EVT and sets the current state to END_ST.
    /// It should be called by any state handler in the model from which
    /// an exit leads to the model end.  In other words, if the transition
    /// out of a particular state is to the end of the model, that state's
    /// handler should call endModel.
    void endModel();

    /// @brief Unpauses state model.
    void unpauseModel();

    /// @brief An empty state handler.
    ///
    /// This method is primarily used to permit special states, NEW_ST and
    /// END_ST to be included in the state dictionary.  Currently it is an
    /// empty method.
    void nopStateHandler();

protected:

    /// @brief Initializes the event and state dictionaries.
    ///
    /// This method invokes the define and verify methods for both events and
    /// states to initialize their respective dictionaries.
    /// This method can be called only once to initialize the state model.
    ///
    /// @throw StateModelError or others indirectly, as this method calls
    /// dictionary define and verify methods.
    void initDictionaries();

    /// @brief Populates the set of events.
    ///
    /// This method is used to construct the set of valid events. Each class
    /// within a StateModel derivation hierarchy uses this method to add any
    /// events it defines to the set.  Each derivation's implementation must
    /// also call its superclass's implementation.  This allows each class
    /// within the hierarchy to make contributions to the set of defined
    /// events. Implementations use the method, defineEvent(), to add event
    /// definitions.  An example of the derivation's implementation follows:
    ///
    /// @code
    /// void StateModelDerivation::defineEvents() {
    ///     // Call the superclass implementation.
    ///     StateModelDerivation::defineEvents();
    ///
    ///     // Add the events defined by the derivation.
    ///     defineEvent(SOME_CUSTOM_EVT_1, "CUSTOM_EVT_1");
    ///     defineEvent(SOME_CUSTOM_EVT_2, "CUSTOM_EVT_2");
    ///     :
    /// }
    /// @endcode
    ///
    /// This method is called in a thread safe context from
    /// @ref initDictionaries.
    virtual void defineEvents();

    /// @brief Adds an event value and associated label to the set of events.
    ///
    /// This method is called in a thread safe context from @ref defineEvents.
    ///
    /// @param value is the numeric value of the event
    /// @param label is the text label of the event used in log messages and
    /// exceptions.
    ///
    /// @throw StateModelError if the model has already been started, if
    /// the value is already defined, or if the label is empty.
    void defineEvent(unsigned int value, const std::string& label);

    /// @brief Fetches the event referred to by value.
    ///
    /// This method is called in a thread safe context from @ref verifyEvents.
    ///
    /// @param value is the numeric value of the event desired.
    ///
    /// @return returns a constant pointer reference to the event if found
    ///
    /// @throw StateModelError if the event is not defined.
    const EventPtr& getEvent(unsigned int value);

    /// @brief Validates the contents of the set of events.
    ///
    /// This method is invoked immediately after the defineEvents method and
    /// is used to verify that all the required events are defined.  If the
    /// event set is determined to be invalid this method should throw a
    /// StateModelError.  As with the defineEvents method, each class within
    /// a StateModel derivation hierarchy must supply an implementation
    /// which calls its superclass's implementation as well as verifying any
    /// events added by the derivation.  Validating an event is accomplished
    /// by simply attempting to fetch an event by its value from the event set.
    /// An example of the derivation's implementation follows:
    ///
    /// @code
    /// void StateModelDerivation::verifyEvents() {
    ///     // Call the superclass implementation.
    ///     StateModelDerivation::verifyEvents();
    ///
    ///     // Verify the events defined by the derivation.
    ///     getEvent(SOME_CUSTOM_EVT_1, "CUSTOM_EVT_1");
    ///     getEvent(SOME_CUSTOM_EVT_2, "CUSTOM_EVT_2");
    ///     :
    /// }
    /// @endcode
    ///
    /// This method is called in a thread safe context from
    /// @ref initDictionaries.
    virtual void verifyEvents();

    /// @brief Populates the set of states.
    ///
    /// This method is used to construct the set of valid states. Each class
    /// within a StateModel derivation hierarchy uses this method to add any
    /// states it defines to the set.  Each derivation's implementation must
    /// also call its superclass's implementation.  This allows each class
    /// within the hierarchy to make contributions to the set of defined
    /// states. Implementations use the method, defineState(), to add state
    /// definitions.  An example of the derivation's implementation follows:
    ///
    /// @code
    /// void StateModelDerivation::defineStates() {
    ///     // Call the superclass implementation.
    ///     StateModelDerivation::defineStates();
    ///
    ///     // Add the states defined by the derivation.
    ///     defineState(SOME_ST, "SOME_ST",
    ///                 std::bind(&StateModelDerivation::someHandler, this));
    ///     :
    /// }
    /// @endcode
    ///
    /// This method is called in a thread safe context from
    /// @ref initDictionaries.
    virtual void defineStates();

    /// @brief Adds an state value and associated label to the set of states.
    ///
    /// This method is called in a thread safe context from @ref defineStates.
    ///
    /// @param value is the numeric value of the state
    /// @param label is the text label of the state used in log messages and
    /// exceptions.
    /// @param handler is the bound instance method which implements the state's
    /// actions.
    /// @param state_pausing pausing mode selected for the given state. The
    /// default value is @c STATE_PAUSE_NEVER.
    ///
    /// @throw StateModelError if the model has already been started, if
    /// the value is already defined, or if the label is empty.
    void defineState(unsigned int value, const std::string& label,
                     StateHandler handler,
                     const StatePausing& state_pausing = STATE_PAUSE_NEVER);

    /// @brief Fetches the state referred to by value.
    ///
    /// @param value is the numeric value of the state desired.
    ///
    /// @return returns a constant pointer to the state if found
    ///
    /// @throw StateModelError if the state is not defined.
    const StatePtr getState(unsigned int value);

    /// @brief Validates the contents of the set of states.
    ///
    /// This method is invoked immediately after the defineStates method and
    /// is used to verify that all the required states are defined.  If the
    /// state set is determined to be invalid this method should throw a
    /// StateModelError.  As with the defineStates method, each class within
    /// a StateModel derivation hierarchy must supply an implementation
    /// which calls its superclass's implementation as well as verifying any
    /// states added by the derivation.  Validating an state is accomplished
    /// by simply attempting to fetch the state by its value from the state set.
    /// An example of the derivation's implementation follows:
    ///
    /// @code
    /// void StateModelDerivation::verifyStates() {
    ///     // Call the superclass implementation.
    ///     StateModelDerivation::verifyStates();
    ///
    ///     // Verify the states defined by the derivation.
    ///     getState(SOME_CUSTOM_EVT_2);
    ///     :
    /// }
    /// @endcode
    ///
    /// This method is called in a thread safe context from
    /// @ref initDictionaries.
    virtual void verifyStates();

    /// @brief Handler for fatal model execution errors.
    ///
    /// This method is called when an unexpected error renders during
    /// model execution, such as a state handler throwing an exception.
    /// It provides derivations an opportunity to act accordingly by setting
    /// the appropriate status or taking other remedial action.   This allows
    /// the model execution loop to remain exception safe.  This default
    /// implementation does nothing.
    ///
    /// @param explanation text detailing the error and state machine context
    virtual void onModelFailure(const std::string& explanation);

    /// @brief Sets up the model to transition into given state with a given
    /// event.
    ///
    /// This updates the model's notion of the current state and the next
    /// event to process.  State handlers use this method to move from one state
    /// to the next.
    ///
    /// @param state the new value to assign to the current state.
    /// @param event the new value to assign to the next event.
    ///
    /// @throw StateModelError if the state is invalid.
    void transition(unsigned int state, unsigned int event);

    /// @brief Aborts model execution.
    ///
    /// This method posts a FAILED_EVT and sets the current state to END_ST.
    /// It is called internally when a model violation occurs. Violations are
    /// any sort of inconsistency such as attempting to reference an invalid
    /// state, or if the next event is not valid for the current state, or a
    /// state handler throws an uncaught exception.
    ///
    /// @param explanation is text detailing the reason for aborting.
    void abortModel(const std::string& explanation);

    /// @brief Sets the current state to the given state value.
    ///
    /// This updates the model's notion of the current state and is the
    /// state whose handler will be executed on the next iteration of the run
    /// loop.  This is intended primarily for internal use and testing. It is
    /// unlikely that transitioning to a new state without a new event is of
    /// much use.
    ///
    /// @param state the new value to assign to the current state.
    ///
    /// @throw StateModelError if the state is invalid.
    void setState(unsigned int state);

    /// @brief Sets the next event to the given event value.
    ///
    /// This updates the model's notion of the next event and is the
    /// event that will be passed into the current state's handler on the next
    /// iteration of the run loop.
    ///
    /// @param event the numeric event value to post as the next event.
    ///
    /// @throw StateModelError if the event is undefined
    void postNextEvent(unsigned int event);

    /// @brief Checks if on entry flag is true.
    ///
    /// This method acts as a one-shot test of whether or not  the model is
    /// transitioning into a new state.  It returns true if the on-entry flag
    /// is true upon entering this method and will set the flag false prior
    /// to exit.  It may be used within state handlers to perform steps that
    /// should only occur upon entry into the state.
    ///
    /// @return true if the on entry flag is true, false otherwise.
    bool doOnEntry();

    /// @brief Checks if on exit flag is true.
    ///
    /// This method acts as a one-shot test of whether or not the model is
    /// transitioning out of the current state.  It returns true if the
    /// on-exit flag is true upon entering this method and will set the flag
    /// false prior to exiting.  It may be used within state handlers to perform
    /// steps that should only occur upon exiting out of the current state.
    ///
    /// @return true if the on entry flag is true, false otherwise.
    bool doOnExit();

public:

    /// @brief Fetches the model's current state.
    ///
    /// This returns the model's notion of the current state. It is the
    /// state whose handler will be executed on the next iteration of the run
    /// loop.
    ///
    /// @return An unsigned int representing the current state.
    unsigned int getCurrState() const;

    /// @brief Fetches the model's previous state.
    ///
    /// @return An unsigned int representing the previous state.
    unsigned int getPrevState() const;

    /// @brief Fetches the model's last event.
    ///
    /// @return An unsigned int representing the last event.
    unsigned int getLastEvent() const;

    /// @brief Fetches the model's next event.
    ///
    /// This returns the model's notion of the next event. It is the
    /// event that will be passed into the current state's handler on the next
    /// iteration of the run loop.
    ///
    /// @return An unsigned int representing the next event.
    unsigned int getNextEvent() const;

    /// @brief Returns whether or not the model is new.
    ///
    /// @return Boolean true if the model has not been started.
    bool isModelNew() const;

    /// @brief Returns whether or not the model is running.
    ///
    /// @return Boolean true if the model has been started but has not yet
    /// ended.
    bool isModelRunning() const;

    /// @brief Returns whether or not the model is waiting.
    ///
    /// @return Boolean true if the model is running but is waiting for an
    /// external event for resumption.
    bool isModelWaiting() const;

    /// @brief Returns whether or not the model has finished execution.
    ///
    /// @return Boolean true if the model has reached the END_ST.
    bool isModelDone() const;

    /// @brief Returns whether or not the model is paused.
    ///
    /// @return Boolean true if the model is paused, false otherwise.
    bool isModelPaused() const;

    /// @brief Returns whether or not the model failed.
    ///
    /// @return Boolean true if the model has reached the END_ST and the last
    /// event indicates a model violation, FAILED_EVT.
    bool didModelFail() const;

    /// @brief Fetches the label associated with an event value.
    ///
    /// @param event is the numeric event value for which the label is desired.
    ///
    /// @return Returns a string containing the event label or
    /// LabeledValueSet::UNDEFINED_LABEL if the value is undefined.
    std::string getEventLabel(const int event) const;

    /// @brief Fetches the label associated with an state value.
    ///
    /// @param state is the numeric state value for which the label is desired.
    ///
    /// @return Returns a const char* containing the state label or
    /// LabeledValueSet::UNDEFINED_LABEL if the value is undefined.
    std::string getStateLabel(const int state) const;

    /// @brief Convenience method which returns a string rendition of the
    /// current state and next event.
    ///
    /// The string will be of the form:
    ///
    ///   current state: [ {state} {label} ] next event: [ {event} {label} ]
    ///
    /// @return Returns a std::string of the format described above.
    std::string getContextStr() const;

    /// @brief Convenience method which returns a string rendition of the
    /// previous state and last event.
    ///
    /// The string will be of the form:
    ///
    ///   previous state: [ {state} {label} ] last event: [ {event} {label} ]
    ///
    /// @return Returns a std::string of the format described above.
    std::string getPrevContextStr() const;

protected:

    /// @brief Fetches the state referred to by value.
    ///
    /// This method should be called in a thread safe context.
    ///
    /// @param value is the numeric value of the state desired.
    ///
    /// @return returns a constant pointer to the state if found
    ///
    /// @throw StateModelError if the state is not defined.
    const StatePtr getStateInternal(unsigned int value);

private:

    /// @brief Sets the current state to the given state value.
    ///
    /// This updates the model's notion of the current state and is the
    /// state whose handler will be executed on the next iteration of the run
    /// loop.  This is intended primarily for internal use and testing. It is
    /// unlikely that transitioning to a new state without a new event is of
    /// much use.
    /// This method should be called in a thread safe context.
    ///
    /// @param state the new value to assign to the current state.
    ///
    /// @throw StateModelError if the state is invalid.
    void setStateInternal(unsigned int state);

    /// @brief Sets the next event to the given event value.
    ///
    /// This updates the model's notion of the next event and is the
    /// event that will be passed into the current state's handler on the next
    /// iteration of the run loop.
    /// This method should be called in a thread safe context.
    ///
    /// @param event the numeric event value to post as the next event.
    ///
    /// @throw StateModelError if the event is undefined
    void postNextEventInternal(unsigned int event);

    /// @brief Returns whether or not the model is new.
    ///
    /// This method should be called in a thread safe context.
    ///
    /// @return Boolean true if the model has not been started.
    bool isModelNewInternal() const;

    /// @brief Fetches the label associated with an event value.
    ///
    /// This method should be called in a thread safe context.
    ///
    /// @param event is the numeric event value for which the label is desired.
    ///
    /// @return Returns a string containing the event label or
    /// LabeledValueSet::UNDEFINED_LABEL if the value is undefined.
    std::string getEventLabelInternal(const int event) const;

    /// @brief Fetches the label associated with an state value.
    ///
    /// This method should be called in a thread safe context.
    ///
    /// @param state is the numeric state value for which the label is desired.
    ///
    /// @return Returns a const char* containing the state label or
    /// LabeledValueSet::UNDEFINED_LABEL if the value is undefined.
    std::string getStateLabelInternal(const int state) const;

    /// @brief Convenience method which returns a string rendition of the
    /// current state and next event.
    ///
    /// The string will be of the form:
    ///
    ///   current state: [ {state} {label} ] next event: [ {event} {label} ]
    ///
    /// This method should be called in a thread safe context.
    ///
    /// @return Returns a std::string of the format described above.
    std::string getContextStrInternal() const;

    /// @brief Convenience method which returns a string rendition of the
    /// previous state and last event.
    ///
    /// The string will be of the form:
    ///
    ///   previous state: [ {state} {label} ] last event: [ {event} {label} ]
    ///
    /// This method should be called in a thread safe context.
    ///
    /// @return Returns a std::string of the format described above.
    std::string getPrevContextStrInternal() const;

    /// @brief The dictionary of valid events.
    LabeledValueSet events_;

    /// @brief The dictionary of valid states.
    StateSet states_;

    /// @brief Indicates if the event and state dictionaries have been initted.
    bool dictionaries_initted_;

    /// @brief The current state within the model's state model.
    unsigned int curr_state_;

    /// @brief The previous state within the model's state model.
    unsigned int prev_state_;

    /// @brief The event last processed by the model.
    unsigned int last_event_;

    /// @brief The event the model should process next.
    unsigned int next_event_;

    /// @brief Indicates if state entry logic should be executed.
    bool on_entry_flag_;

    /// @brief Indicates if state exit logic should be executed.
    bool on_exit_flag_;

    /// @brief Indicates if the state model is paused.
    bool paused_;

    /// @brief Protects against concurrent transitions.
    boost::shared_ptr<std::mutex> mutex_;
};

/// @brief Defines a pointer to a StateModel.
typedef boost::shared_ptr<StateModel> StateModelPtr;

} // namespace isc::util
} // namespace isc
#endif