/*!
 * Демонстрация описания одного и того же агента в нотации SObjectizer4
 * и предполагаемой нотации SObjectizer5.
 *
 * Для того, чтобы демонстрация выглядела более наглядной, исходники
 * располагаются рядом друг с другом в таблице. В исходных текстах
 * оставлены только те комментации, которые должны помочь понять
 * описание агента (в реальном проекте, из которого взят данный класс,
 * комментариев в несколько раз больше). Из исходных текстов удален
 * весь лишний код, который не связан с механизмами описания агента для
 * SObjectizer.
 *
 * Краткое пояснение назначения агента.
 *
 * Этот агент является менеджером дочерних процессов (в каждом из которых сидят
 * собственные агенты-исполнители). Его задачей является получение двух типов
 * запросов (phase_c и phase_p), передача этих запросов в подходящие дочерние
 * процессы, получение ответов от дочерних процессов (phase_c_result,
 * phase_p_result), преобразование ответов в нужный формат, контроль за
 * работоспособностью и наличию связи с дочерними процессами, поддержание
 * актуальной оперативной мониторинговой информации о текущем состоянии.
 * Информация о запросах/результатах, а также уведомления о проблемах с
 * дочерними процессами приходит асинхронно, в произвольном порядке. Контроль
 * состояния и обновление мониторинговой информации нужно делать по таймеру.
 *
 * Небольшое пояснение по поводу использования длинных имен пространств имен
 * в примере SObjectizer4. Это необходимо из-за того, что SObjectizer4
 * должен сохранять у себя строковые описания всех типов сообщений. И для
 * того, чтобы эти имена были уникальными в рамках большого проекта, приходится
 * в макросах SOL4_* использовать полные имена типов. В SObjectizer5 такой
 * необходимости нет и, поэтому, разумное использование using namespace
 * способно освободить разработчика от дублирования полных имен типов
 * для классов агентов и сообщений.
 */
SObjectizer-5 SObjectizer-4
class a_processor_t
  : public so_sysconf_3::agent_with_fatal_state_t
  {
  public :
    /*!
     * \name Типы сообщений, которыми владеет данный агент.
     * \{
     */
    //! Принудительная переконфигурация агента.
    struct msg_reconfigure
      : public so_5::message_t
      {
        std::string m_cfg_file_name
      };

    //! Сигнал о необходимости сборки мусора.
    struct msg_garbage_collection
      : public so_5::message_t
      {}
 
    //! Сигнал о необходимости контроля за дочерними процессами.
    struct msg_control_child_processes
      : public so_5::message_t
      {}
 
    //! Сигнал о необходимости обновления мониторинговой информации.
    struct msg_update_gemont_data
      : public so_5::message_t
      {}

    /*!
     * \}
     */

    /*!
     * \name Состояния данного агента.
     * \{
     */
    //! Единственное собственное состояние.
    so_5::state_t st_normal;
    /*!
     * \}
     */

    //! Идентифкатор почтового ящика этого агента.
    so_5::local_mbox_t m_self_mbox;

    //! В конструкторе все состояния должны
    //! быть проинициализированны.
    a_processor_t( /* какие-то параметры */ )
      : // Инициализация базового типа и каких-то других атрибутов.
      // Инициализация доменов сообщений. Каждый домен должен
      // быть связан с агентом.
      // Инициализация состояний.
      , st_normal( so_self() )
      {}

    //! Описание агента для SObjectizer.
    virtual void
    so_define_agent()
      {
        // Начальным состояние должно быть состояние st_normal.
        // Если этого не сказать, то начальным будет унаследованное
        // из agent_with_fatal_state_t состояние st_fatal.
        so_initial_state( st_normal );

        // Подписка событий агента на сообщения.
        // Эти сообщения идут на собственный mbox агента.
        so_subscribe( m_self_mbox )
            .in( st_normal )
                .event( &a_processor_t::evt_garbage_collection )
                .event( &a_processor_t::evt_control_child_processes )
                .event( &a_processor_t::evt_update_gemont_data )
                .event( &a_processor_t::evt_reconfigure );

        // Эти сообщения идут на другой mbox.
        so_subscribe( so_runtime().lockup_mbox( "child_iface" ) )
            .in( st_normal )
                .event( &a_processor_t::evt_child_hello )
                .event( &a_processor_t::evt_phase_c_result )
                .event( &a_processor_t::evt_phase_p_result );

        // Эти сообщения идут еще на один mbox.
        so_subscribe( so_runtime().lockup_mbox( "producer" ) )
            .in( st_normal )
                .event( &a_processor_t::evt_phase_p )
                .event( &a_processor_t::evt_phase_c );

        // А это сообщение идет еще на один mbox.
        // Это один из штатных mbox-ов SObjectizer. Поэтому
        // не нужно его искать, а можно сразу получить к нему доступ.
        so_subscribe( so_runtime().communicator_mbox() )
            .in( st_normal )
                .event( &a_processor_t::evt_client_disconnected );
      }

    /*!
     * \name Обработчики событий.
     * \{
     */
    void
    evt_garbage_collection(
      const so_5::event_t< msg_garbage_collection > & );

    void
    evt_control_child_processes(
      const so_5::event_t< msg_control_child_processes > & );

    void
    evt_update_gemont_data(
      const so_5::event_t< msg_update_gemont_data > & );

    void
    evt_reconfigure(
      const so_5::event_t< msg_reconfigure > & );

    void
    evt_child_hello(
      const so_5::event_t< a_child_iface_t::mgs_hello > & );

    void
    evt_client_disconnected(
      const so_5::event_t< a_communicator_t::msg_client_disconnected > & );

    void
    evt_phase_c(
      const so_5::event_t< a_request_producer_t::msg_phase_c > & );

    void
    evt_phase_c_result(
      const so_5::event_t< a_child_iface_t::msg_phase_c_result > & );

    void
    evt_phase_p(
      const so_5::event_t< a_request_producer_t::msg_phase_p > & );

    void
    evt_phase_p_result(
      const so_5::event_t< a_child_iface_t::msg_phase_p_result > & );
    /*!
     * \}
     */
  };
class a_processor_t
  : public so_sysconf_2::agent_with_fatal_state_t
  {
  public :
    /*!
     * \name Сообщения агента.
     * \{
     */
    //! Периодическое сообщение о необходимости сборки мусора.
    struct msg_garbage_collection {};

    //! Периодическое сообщение для проверки того, что дочерние
    //! процессы работают.
    struct msg_control_child_processes {};

    //! Периодическое сообщение для обновления мониторинговой информации.
    struct msg_update_gemont_data {};

    //! Сообщение для перезагрузки конфигурации.
    struct msg_reconfigure
      {
        std::string m_cfg_file_name;
      };
    /*!
     * \}
     */

    //! Конструктор агента.
    a_processor_t( /* какие-то параметры */ )
      :  // Инициализация базового типа и каких-то других атрибутов.
      {}

    // Этот метод должен быть задекларирован,
    // но его реализация спрятана в макросах SOL4_CLASS_*.
    virtual const char *
    so_query_type() const;

    //! Подписка событий агента.
    virtual void
    so_on_subscription()
      {
        so_4::api::make_global_agent(
            a_child_iface_t::agent_name(),
            a_child_iface_t::agent_type() );

        so_subscribe(
            "evt_start",
            so_4::rt::sobjectizer_agent_name(),
            "msg_start" );

        so_subscribe(
            "evt_child_process_hello",
            a_child_iface_t::agent_name(),
            "msg_hello" );

        so_subscribe(
            "evt_client_disconnected",
            so_4::rt::comm::communicator_agent_name(),
            "msg_client_disconnected" );

        so_subscribe(
            "evt_phase_c",
            a_request_producer_t::agent_name(),
            "msg_phase_c" );

        so_subscribe(
            "evt_phase_c_result_received",
            a_child_iface_t::agent_name(),
            "msg_phase_c_result" );

        so_subscribe(
            "evt_phase_p",
            a_request_producer_t::agent_name(),
            "msg_phase_p" );

        so_subscribe(
            "evt_phase_p_result_received",
            a_child_iface_t::agent_name(),
            "msg_phase_p_result" );

        so_subscribe(
            "evt_control_child_processes",
            "msg_control_child_processes" );
        so_subscribe(
            "evt_garbage_collection",
            "msg_garbage_collection" );
        so_subscribe(
            "evt_update_gemont_data",
            "msg_update_gemont_data" );

        so_subscribe(
            "evt_reconfigure",
            "msg_reconfigure" );
      }

    /*!
     * \name Обработчики событий.
     * \{
     */
    void
    evt_start();

    void
    evt_child_process_hello(
      const so_4::rt::event_data_t & event_data,
      const a_child_iface_t::msg_hello & cmd );

    void
    evt_client_disconnected(
      const so_4::rt::comm::msg_client_disconnected & cmd );

    void
    evt_phase_c(
      const a_request_producer_t::msg_phase_c & cmd );

    void
    evt_phase_c_result_received(
      const so_4::rt::event_data_t & event_data,
      const a_child_iface_t::msg_phase_c_result & cmd );

    void
    evt_phase_p(
      const a_request_producer_t::msg_phase_p & cmd );

    void
    evt_phase_p_result_received(
      const so_4::rt::event_data_t & event_data,
      const a_child_iface_t::msg_phase_p_result & cmd );

    void
    evt_control_child_processes();

    void
    evt_garbage_collection();

    void
    evt_update_gemont_data();

    void
    evt_reconfigure(
      const msg_reconfigure & cmd );
    /*!
     * \}
     */
  };

// Описание класса агента для SObjectizer.
// Должна быть сделана в .cpp файле с помощью макрсов.
SOL4_CLASS_START( sample_project::child_processor::processor::a_processor_t )
  SOL4_SUPER_CLASS( so_sysconf_2::agent_with_fatal_state_t )

  SOL4_MSG_START( msg_garbage_collection,
      sample_project::child_processor::processor::a_processor_t::
          msg_garbage_collection )
  SOL4_MSG_FINISH()

  SOL4_MSG_START( msg_control_child_processes,
      sample_project::child_processor::processor::a_processor_t::
          msg_control_child_processes )
  SOL4_MSG_FINISH()

  SOL4_MSG_START( msg_update_gemont_data,
      sample_project::child_processor::processor::a_processor_t::
          msg_update_gemont_data )
  SOL4_MSG_FINISH()

  SOL4_MSG_START( msg_reconfigure,
      sample_project::child_processor::processor::a_processor_t::
          msg_reconfigure )

    SOL4_MSG_FIELD( m_cfg_file_name )
  SOL4_MSG_FINISH()

  SOL4_EVENT( evt_start )

  SOL4_EVENT_STC(
    evt_child_process_hello,
    sample_project::child_processor::child_iface::a_child_iface_t::
        msg_hello )

  SOL4_EVENT_STC(
    evt_phase_c,
    a_request_producer_t::msg_phase_c )
  SOL4_EVENT_STC(
    evt_phase_c_result_received,
    sample_project::child_processor::child_iface::a_child_iface_t::
        msg_phase_c_result )
  SOL4_EVENT_STC(
    evt_client_disconnected,
    so_4::rt::comm::msg_client_disconnected )

  SOL4_EVENT_STC(
    evt_phase_p,
    a_request_producer_t::msg_phase_p )
  SOL4_EVENT_STC(
    evt_phase_p_result_received,
    sample_project::child_processor::child_iface::a_child_iface_t::
        msg_phase_p_result )

  SOL4_EVENT( evt_control_child_processes )
  SOL4_EVENT( evt_garbage_collection )
  SOL4_EVENT( evt_update_gemont_data )

  SOL4_EVENT_STC(
    evt_reconfigure,
    sample_project::child_processor::processor::a_processor_t::
        msg_reconfigure )

  SOL4_INITIAL_STATE( st_normal )

  SOL4_STATE_START( st_normal )
    SOL4_STATE_EVENT( evt_start )
    SOL4_STATE_EVENT( evt_child_process_hello )
    SOL4_STATE_EVENT( evt_client_disconnected )
    SOL4_STATE_EVENT( evt_phase_c )
    SOL4_STATE_EVENT( evt_phase_c_result_received )
    SOL4_STATE_EVENT( evt_phase_p )
    SOL4_STATE_EVENT( evt_phase_p_result_received )
    SOL4_STATE_EVENT( evt_control_child_processes )
    SOL4_STATE_EVENT( evt_garbage_collection )
    SOL4_STATE_EVENT( evt_update_gemont_data )
    SOL4_STATE_EVENT( evt_reconfigure )
  SOL4_STATE_FINISH()

SOL4_CLASS_FINISH()
Hosted by uCoz