ACE动态服务配置的实例代码分析

下面对ACE-6.0.0提供的动态服务配置的实例代码进行分析。

1. DLL代码

Service_Config_DLL.cpp 文件 (在\ACE-6.0.0\ACE_wrappers\tests目录下)

// -*- C++ -*-
//=============================================================================
/**
 *  @file    Service_Config_DLL.cpp
 *
 *  $Id: Service_Config_DLL.cpp 91673 2010-09-08 18:49:47Z johnnyw $
 *
 *  This file is related to, and used with, Service_Config_Test. It's
 *  used when testing the reentrance/thread-safety of the
 *  Service Configurator, in addition to testing the Service
 *  Configurator's ability to handle nested processing of Service
 *  Configurator directives.
 *
 *  @author Ossama Othman <[email protected]>
 */
//=============================================================================

#include "Service_Config_DLL.h"
#include "ace/Service_Config.h"
#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_string.h"

static ACE_THR_FUNC_RETURN
invoke_service_config (void *arg)
{
  const ACE_TCHAR *directive = reinterpret_cast<const ACE_TCHAR *> (arg);

  // Process a Service Configurator directive in the current thread.
  
  // process_directive 方法分析配置语句,调用DLL的导出函数。
  
  if (ACE_Service_Config::process_directive (directive) != 0)
    ACE_ERROR ((LM_ERROR,
                ACE_TEXT ("(%P|%t) Service_Config_DLL::svc() - ")
                ACE_TEXT ("process_directive() failed for:\n")
                ACE_TEXT ("\"%s\"\n"),
                directive));

  return 0;
}

Service_Config_DLL::Service_Config_DLL (void)
{
  ACE_OS::memset (this->directive_[0], 0, BUFSIZ * sizeof (ACE_TCHAR));
  ACE_OS::memset (this->directive_[1], 0, BUFSIZ * sizeof (ACE_TCHAR));
}

int
Service_Config_DLL::init (int argc, ACE_TCHAR *argv[])
{
  if (argc == 2)
    {
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("Loading Test_Object_%s and Test_Object_%s\n"),
                  argv[0],
                  argv[1]));

      ACE_OS::sprintf (this->directive_[0],
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
                       ACE_TEXT ("dynamic Test_Object_%s Service_Object * Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_%s\""),
#else
                       ACE_TEXT ("<?xml version='1.0'?> <dynamic id='Test_Object_%s' type='service_object'> <initializer init='_make_Service_Config_DLL' 

path='Service_Config_DLL' params='Test_Object_%s'/> </dynamic>"),
#endif
                       argv[0],
                       argv[0]);

      ACE_OS::sprintf (this->directive_[1],
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
                       ACE_TEXT ("dynamic Test_Object_%s Service_Object * Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_%s\""),
#else
                       ACE_TEXT ("<?xml version='1.0'?> <dynamic id='Test_Object_%s' type='service_object'> <initializer init='_make_Service_Config_DLL' 

path='Service_Config_DLL' params='Test_Object_%s'/> </dynamic>"),
#endif

                       argv[1],
                       argv[1]);

      if (ACE_Service_Config::process_directive (this->directive_[0]) != 0)
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("(%P|%t) Service_Config_DLL::init() - ")
                    ACE_TEXT ("process_directive() failed for:\n")
                    ACE_TEXT ("\"%s\": %m\n"),
                    this->directive_[0]));


#if defined (ACE_HAS_THREADS)

      // Become an Active Object if more than one argument passed.
      // Two arguments indicate two "test objects" to be dynamically
      // loaded.
      return this->activate ();  // 执行activate才能调用svc函数。

#endif  /* ACE_HAS_THREADS */

    }
  else if (argc == 1)
    {
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("Service_Config_DLL::init () %@ - %s\n"),
                  this,
                  argv[0]));
    }
  else
   {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("(%P|%t) Incorrect number of arguments ")
                         ACE_TEXT ("(%d) passed to Service_Config_DLL::init ()"),
                         argc),
                        -1);
    }


  return 0;
}

int
Service_Config_DLL::fini (void)
{
  return 0;
}

int
Service_Config_DLL::svc (void)
{
  // spawn 方法创建线程,invoke_service_config 是线程函数。

  if (ACE_Thread_Manager::instance ()->spawn (invoke_service_config,
                                              this->directive_[1]) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("(%P|%t) Unable to spawn thread to ")
                       ACE_TEXT ("invoke Service Configurator.\n")),
                      -1);
  

  return 0;
}

// The same class (Service_Config_DLL) is used to implement each of the
// Service Objects whose service descriptors are defined below.

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_1,
                       ACE_TEXT ("Test_Object_1"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_2,
                       ACE_TEXT ("Test_Object_2"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_3,
                       ACE_TEXT ("Test_Object_3"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_4,
                       ACE_TEXT ("Test_Object_4"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_5,
                       ACE_TEXT ("Test_Object_5"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_6,
                       ACE_TEXT ("Test_Object_6"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Final_Object,
                       ACE_TEXT ("Final_Object"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_1_More,
                       ACE_TEXT ("Test_Object_1_More"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)

// -----------------------------------------------------------------

ACE_STATIC_SVC_DEFINE (Test_Object_2_More,
                       ACE_TEXT ("Test_Object_2_More"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (Service_Config_DLL),
                       ACE_Service_Type::DELETE_THIS
                       | ACE_Service_Type::DELETE_OBJ,
                       0)


// -----------------------------------------------------------------

// Same factory is used for all service descriptors defined above.
ACE_FACTORY_DEFINE (Service_Config_DLL, Service_Config_DLL)

/*
** Simple service which will refuse to load/initialize correctly.
** The main program should do:
**  1. Try to load this service (which should fail)
**  2. Try to look up this service and call its info() hook; if info()
**     can be called, the test has failed.
** Similarly, if fini() is called later, something is very wrong.
*/

/// Initializes object when dynamic linking occurs.
int
Refuses_Init::init (int, ACE_TCHAR *[])
{
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Refuses_Init::init - refusing to init\n")));
  return -1;
}

/// Terminates object when dynamic unlinking occurs.
int
Refuses_Init::fini (void)
{
  ACE_ERROR ((LM_ERROR,
              ACE_TEXT ("Refuses_Init::fini should not be called!\n")));
  return 0;
}

/// Returns information on a service object.
int
Refuses_Init::info (ACE_TCHAR **info_string, size_t length) const
{
  ACE_TCHAR const *msg =
    ACE_TEXT ("Refuses_Init service, shouldn't be here!\n");
  if (*info_string == 0)
    *info_string = ACE_OS::strdup (msg);
  else
    ACE_OS::strncpy (*info_string, msg, length);
  ACE_ERROR ((LM_ERROR,
              ACE_TEXT ("Refuses_Init::info() called - shouldn't be\n")));
  return ACE_OS::strlen (*info_string);
}

ACE_FACTORY_DEFINE (Service_Config_DLL, Refuses_Init)

 

2. 宿主程序的代码

Service_Config_Test.cpp 文件 (在\ACE-6.0.0\ACE_wrappers\tests目录下)

// -*- C++ -*-

//=============================================================================
/**
 *  @file    Service_Config_Test.cpp
 *
 *  $Id: Service_Config_Test.cpp 91673 2010-09-08 18:49:47Z johnnyw $
 *
 *  This is a simple test to make sure the ACE Service Configurator
 *  framework is working correctly.
 *
 *  @author David Levine <[email protected]>
 *  @author Ossama Othman <[email protected]>
 */
//=============================================================================

#include "test_config.h"
#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_errno.h"
#include "ace/OS_NS_Thread.h"
#include "ace/Log_Msg.h"
#include "ace/Object_Manager.h"
#include "ace/Service_Config.h"
#include "ace/Service_Object.h"
#include "ace/Service_Repository.h"
#include "ace/Service_Types.h"
#include "ace/Reactor.h"
#include "ace/Thread_Manager.h"
#include "ace/ARGV.h"

static const u_int VARIETIES = 3;

static u_int error = 0;

class MyRepository : public ACE_Service_Repository
{
public:
  array_type& array ()
  {
    return service_array_;
  }
};

/**
 * @class Test_Singleton
 *
 * @brief Test the Singleton
 *
 * This should be a template class, with singleton instantiations.
 * But to avoid having to deal with compilers that want template
 * declarations in separate files, it's just a plain class.  The
 * instance argument differentiates the "singleton" instances.  It
 * also demonstrates the use of the param arg to the cleanup ()
 * function.
 */
class Test_Singleton
{
public:
  static Test_Singleton *instance (u_short variety);
  ~Test_Singleton (void);

private:
  u_short variety_;
  static u_short current_;

  Test_Singleton (u_short variety);

  friend class misspelled_verbase_friend_declaration_to_avoid_compiler_warning_with_private_ctor;
};

u_short Test_Singleton::current_ = 0;

extern "C" void
test_singleton_cleanup (void *object, void *)
{
  // We can't reliably use ACE_Log_Msg in a cleanup hook.  Yet.
  /* ACE_DEBUG ((LM_DEBUG, "cleanup %d\n", (u_short) param)); */

  delete (Test_Singleton *) object;
}

Test_Singleton *
Test_Singleton::instance (u_short variety)
{
  static Test_Singleton *instances[VARIETIES] = { 0 };

  if (instances[variety] == 0)
    {
      ACE_NEW_RETURN (instances[variety],
                      Test_Singleton (variety),
                      0);
    }

  ACE_Object_Manager::at_exit (instances[variety],
                               test_singleton_cleanup,
                  reinterpret_cast<void *> (static_cast<size_t> (variety)),
                  "Test_Singleton");
  return instances[variety];
}

Test_Singleton::Test_Singleton (u_short variety)
  : variety_ (variety)
{
  if (variety_ != current_++)
    {
      ACE_DEBUG ((LM_ERROR,
                  ACE_TEXT ("ERROR: instance %u created out of order!\n"),
                 variety_));
      ++error;
    }
}

// We can't reliably use ACE_Log_Msg in a destructor that is called by
// ACE_Object_Manager.  Yet.

Test_Singleton::~Test_Singleton (void)
{
  /* ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test_Singleton %u dtor\n"), variety_)); */

  if (variety_ != --current_)
    {
      ACE_OS::fprintf (stderr,
                       ACE_TEXT ("ERROR: instance %u destroyed out of order!\n"),
                       variety_);
      /* ACE_DEBUG ((LM_ERROR, ACE_TEXT ("ERROR: instance %u destroyed out of order!\n"),
                 variety_)); */
      ++error;
    }
}

void
testFailedServiceInit (int, ACE_TCHAR *[])
{
  static const ACE_TCHAR *refuse_svc =
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
    ACE_TEXT ("dynamic Refuses_Svc Service_Object * ")
    ACE_TEXT ("  Service_Config_DLL:_make_Refuses_Init() \"\"")
#else
    ACE_TEXT ("<dynamic id=\"Refuses_Svc\" type=\"Service_Object\">")
    ACE_TEXT ("  <initializer init=\"_make_Refuses_Init\" path=\"Service_Config_DLL\" params=\"\"/>")
    ACE_TEXT ("</dynamic>")
#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
    ;

  int error_count = 0;
  if ((error_count = ACE_Service_Config::process_directive (refuse_svc)) != 1)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Failed init test should have returned 1; ")
                  ACE_TEXT ("returned %d instead\n"),
                  error_count));
    }

  // Try to find the service; it should not be there.
  ACE_Service_Type const *svcp = 0;
  if (-1 != ACE_Service_Repository::instance ()->find (ACE_TEXT ("Refuses_Svc"),
                                                       &svcp))
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Found service repo entry for Refuses_Svc\n")));
      ACE_Service_Type_Impl const *svc_impl = svcp->type ();
      ACE_TCHAR msg[1024];
      ACE_TCHAR *msgp = msg;
      if (svc_impl->info (&msgp, sizeof (msg) / sizeof (ACE_TCHAR)) > 0)
        ACE_ERROR ((LM_ERROR, ACE_TEXT ("Refuses_Svc said: %s\n"), msg));
    }
  else
    ACE_DEBUG ((LM_DEBUG,
                ACE_TEXT ("Repo reports no Refuses_Svc; correct.\n")));
}


void
testLoadingServiceConfFileAndProcessNo (int argc, ACE_TCHAR *argv[])
{
  ACE_ARGV new_argv;

#if defined (ACE_USES_WCHAR)
  // When using full Unicode support, use the version of the Service
  // Configurator file appropriate to the platform.
  // For example, Windows Unicode uses UTF-16.
  //
  //          iconv(1) found on Linux and Solaris, for example, can
  //          be used to convert between encodings.
  //
  //          Byte ordering is also an issue, so we should be
  //          generating this file on-the-fly from the UTF-8 encoded
  //          file by using functions like iconv(1) or iconv(3).
#  if defined (ACE_WIN32)
  const ACE_TCHAR svc_conf[] =
    ACE_TEXT ("Service_Config_Test.UTF-16")
    ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
#  else
  const ACE_TCHAR svc_conf[] =
    ACE_TEXT ("Service_Config_Test.WCHAR_T")
    ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
#  endif /* ACE_WIN32 */
#else
    // ASCII (UTF-8) encoded Service Configurator file.
  const ACE_TCHAR svc_conf[] =
    ACE_TEXT ("Service_Config_Test")
    ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
#endif  /* ACE_USES_WCHAR */

  // Process the Service Configurator directives in this test's Making
  // sure we have more than one option with an argument, to capture
  // any errors caused by "reshuffling" of the options.
  if (new_argv.add (argv) == -1
              || new_argv.add (ACE_TEXT ("-d")) == -1
              || new_argv.add (ACE_TEXT ("-k")) == -1
              || new_argv.add (ACE_TEXT ("xxx")) == -1
              || new_argv.add (ACE_TEXT ("-p")) == -1
              || new_argv.add (ACE_TEXT ("Service_Config_Test.pid")) == -1
              || new_argv.add (ACE_TEXT ("-f")) == -1
              || new_argv.add (svc_conf) == -1)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("line %l %p\n"),
                  ACE_TEXT ("new_argv.add")));
      ++error;
    }

  // We need this scope to make sure that the destructor for the
  // <ACE_Service_Config> gets called.
  ACE_Service_Config daemon;

  if (daemon.open (new_argv.argc (), new_argv.argv ()) == -1 &&
      errno != ENOENT)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("line %l %p\n"),
                  ACE_TEXT ("daemon.open")));
      ++error;
    }

  ACE_Time_Value tv (argc > 1 ? ACE_OS::atoi (argv[1]) : 2);

  if (ACE_Reactor::instance()->run_reactor_event_loop (tv) == -1)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("line %l %p\n"),
                  ACE_TEXT ("run_reactor_event_loop")));
    }

  // Wait for all threads to complete.
  ACE_Thread_Manager::instance ()->wait ();
}


void
testLoadingServiceConfFile (int argc, ACE_TCHAR *argv[])
{
  ACE_ARGV new_argv;

#if defined (ACE_USES_WCHAR)
  // When using full Unicode support, use the version of the Service
  // Configurator file appropriate to the platform.
  // For example, Windows Unicode uses UTF-16.
  //
  //          iconv(1) found on Linux and Solaris, for example, can
  //          be used to convert between encodings.
  //
  //          Byte ordering is also an issue, so we should be
  //          generating this file on-the-fly from the UTF-8 encoded
  //          file by using functions like iconv(1) or iconv(3).
#  if defined (ACE_WIN32)
  const ACE_TCHAR svc_conf[] =
    ACE_TEXT ("Service_Config_Test.UTF-16")
    ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
#  else
  const ACE_TCHAR svc_conf[] =
    ACE_TEXT ("Service_Config_Test.WCHAR_T")
    ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
#  endif /* ACE_WIN32 */
#else
    // ASCII (UTF-8) encoded Service Configurator file.
    // 确定配置文件名称:
  const ACE_TCHAR svc_conf[] =
    ACE_TEXT ("Service_Config_Test")
    ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
#endif  /* ACE_USES_WCHAR */

  // Process the Service Configurator directives in this test's
  // 把命令行参数加入到一个ACE参数对象中,便于后面分析,把配置文件作为参数也加入其中。
  if (new_argv.add (argv) == -1
              || new_argv.add (ACE_TEXT ("-f")) == -1
              || new_argv.add (svc_conf) == -1)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("line %l %p\n"),
                  ACE_TEXT ("new_argv.add")));
      ++error;
    }

  // We need this scope to make sure that the destructor for the
  // <ACE_Service_Config> gets called.
  ACE_Service_Config daemon;

  // open方法解析配置文件。

  if (daemon.open (new_argv.argc (), new_argv.argv ()) == -1)
    {
      if (errno == ENOENT)
        ACE_DEBUG ((LM_WARNING,
                    ACE_TEXT ("ACE_Service_Config::open: %p\n"),
                    svc_conf));
      else
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("ACE_Service_Config::open: %p\n"),
                    ACE_TEXT ("error")));
    }


  ACE_Time_Value tv (argc > 1 ? ACE_OS::atoi (argv[1]) : 2);

  if (ACE_Reactor::instance()->run_reactor_event_loop (tv) == -1)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("line %l %p\n"),
                  ACE_TEXT ("run_reactor_event_loop")));
    }

  // Wait for all threads to complete.
  // 等待进程内的其他线程退出。

  ACE_Thread_Manager::instance ()->wait ();
}


// Loading and unloading the ACE logger service should not smash singletons.
void
testUnloadingACELoggingStrategy (int, ACE_TCHAR *[])
{
  static const ACE_TCHAR *load_logger =
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
    ACE_TEXT ("dynamic Logger Service_Object * ")
    ACE_TEXT ("  ACE:_make_ACE_Logging_Strategy() \"\"")
#else
    ACE_TEXT ("<dynamic id=\"Logger\" type=\"Service_Object\">")
    ACE_TEXT ("  <initializer init=\"_make_ACE_Logging_Strategy\" ")
    ACE_TEXT ("    path=\"ACE\" params=\"\"/>")
    ACE_TEXT ("</dynamic>")
#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
    ;

  static const ACE_TCHAR *unload_logger =
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
    ACE_TEXT ("remove Logger")
#else
    ACE_TEXT ("<remove id=\"Logger\" />");
#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
    ;

  ACE_Reactor *r1 = ACE_Reactor::instance();

  // Ensure no errors are logged while searching for a valid ACE lib name;
  // these skew the scoreboard results.
  u_long mask = ACE_LOG_MSG->priority_mask (ACE_Log_Msg::PROCESS);
  ACE_LOG_MSG->priority_mask (mask & ~LM_ERROR, ACE_Log_Msg::PROCESS);
  ACE_DEBUG ((LM_DEBUG, "Was %x, now %x\n", mask, mask & ~LM_ERROR));
  int error_count = ACE_Service_Config::process_directive (load_logger);
  ACE_LOG_MSG->priority_mask (mask);
  if (error_count != 0)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Load ACE Logger should have returned 0; ")
                  ACE_TEXT ("returned %d instead\n"),
                  error_count));
    }
  ACE_Service_Config::process_directive (unload_logger);

  ACE_Reactor *r2 = ACE_Reactor::instance ();
  if (r1 != r2)
    ACE_ERROR ((LM_ERROR, ACE_TEXT ("Reactor before %@, after %@\n"), r1, r2));
}


// @brief The size of a repository is unlimited and can be exceeded
void
testLimits (int , ACE_TCHAR *[])
{
  static const ACE_TCHAR *svc_desc1 =
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
    ACE_TEXT ("dynamic Test_Object_1_More Service_Object * ")
    ACE_TEXT ("  Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_1_More\"")
#else
    ACE_TEXT ("<dynamic id=\"Test_Object_1_More\" type=\"Service_Object\">")
    ACE_TEXT ("  <initializer init=\"_make_Service_Config_DLL\" path=\"Service_Config_DLL\" params=\"Test_Object_1_More\"/>")
    ACE_TEXT ("</dynamic>")
#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
    ;

  static const ACE_TCHAR *svc_desc2 =
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
    ACE_TEXT ("dynamic Test_Object_2_More Service_Object * ")
    ACE_TEXT ("  Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_2_More\"")
#else
    ACE_TEXT ("<dynamic id=\"Test_Object_2_More\" type=\"Service_Object\">")
    ACE_TEXT ("  <initializer init=\"_make_Service_Config_DLL\" path=\"Service_Config_DLL\" params=\"Test_Object_2_More\"/>")
    ACE_TEXT ("</dynamic>")
#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
    ;

  u_int error0 = error;

  // Ensure enough room for one in a own, the repository can extend
  ACE_Service_Gestalt one (1, true);

  // Add two.
  // We cant simply rely on the fact that insertion fails, because it
  // is typical to have no easy way of getting detailed error
  // information from a parser.
  one.process_directive (svc_desc1);
  one.process_directive (svc_desc2);

  if (-1 == one.find (ACE_TEXT ("Test_Object_1_More"), 0, 0))
    {
      ++error;
      ACE_ERROR ((LM_ERROR, ACE_TEXT("Expected to have registered the first service\n")));
    }

  if (-1 == one.find (ACE_TEXT ("Test_Object_2_More"), 0, 0))
    {
      ++error;
      ACE_ERROR ((LM_ERROR, ACE_TEXT("Expected to have registered the second service\n")));
    }

  ACE_Service_Repository_Iterator sri (*one.current_service_repository (), 0);

  size_t index = 0;
  for (const ACE_Service_Type *sr;
       sri.next (sr) != 0;
       sri.advance ())
    {
      if (index == 0 && ACE_OS::strcmp (sr->name(), ACE_TEXT ("Test_Object_1_More")) != 0)
        {
          ++error;
          ACE_ERROR ((LM_ERROR, ACE_TEXT("Service 1 is wrong\n")));
        }
      if (index == 1 && ACE_OS::strcmp (sr->name(), ACE_TEXT ("Test_Object_2_More")) != 0)
        {
          ++error;
          ACE_ERROR ((LM_ERROR, ACE_TEXT("Service 2 is wrong\n")));
        }
      ++index;
    }

  // Test close
  one.current_service_repository ()->close();

  if (one.current_service_repository ()->current_size () != 0)
    {
      ++error;
      ACE_ERROR ((LM_ERROR, ACE_TEXT("Size of repository should be 0\n")));
    }

  if (error == error0)
    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Limits test completed successfully\n")));
  else
    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Limits test failed\n")));

}

void
testrepository (int, ACE_TCHAR *[])
{
  MyRepository repository;
  ACE_DLL handle;
  ACE_Service_Type s0 (ACE_TEXT ("0"), 0, handle, false);
  ACE_Service_Type s1 (ACE_TEXT ("1"), 0, handle, false);
  ACE_Service_Type s2 (ACE_TEXT ("2"), 0, handle, false);
  ACE_Service_Type s3 (ACE_TEXT ("3"), 0, handle, false);
  ACE_Service_Type* result = 0;
  repository.insert (&s0);
  if (repository.current_size () != 1)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Repository was wrong size %d\n"),
                  repository.current_size ()));
    }
  repository.insert (&s1);
  if (repository.current_size () != 2)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Repository was wrong size %d\n"),
                  repository.current_size ()));
    }
  repository.insert (&s2);
  if (repository.current_size () != 3)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Repository was wrong size %d\n"),
                  repository.current_size ()));
    }
  if (repository.remove (ACE_TEXT ("1"), &result) != 0)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Remove failed\n")));
    }
  if (repository.current_size () != 3)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Repository was wrong size %d\n"),
                  repository.current_size ()));
    }
  if (repository.array ()[1] != 0)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Element 1 not zero\n"),
                  repository.current_size ()));
    }
  repository.insert (&s3);
  if (repository.current_size () != 4)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Repository was wrong size %d\n"),
                  repository.current_size ()));
    }
  repository.remove (ACE_TEXT ("0"), &result);
  if (repository.remove (ACE_TEXT ("1"), &result) != -1)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Double remove didn't return -1\n")));
    }
  repository.remove (ACE_TEXT ("2"), &result);
  repository.remove (ACE_TEXT ("3"), &result);
  if (repository.current_size () != 4)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Repository was wrong size %d\n"),
                  repository.current_size ()));
    }
  repository.close ();
  if (repository.current_size () != 0)
    {
      ++error;
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Repository was wrong size %d\n"),
                  repository.current_size ()));
    }
}

// @brief ??
void
testOrderlyInstantiation (int , ACE_TCHAR *[])
{
  for (u_int i = 0; i < VARIETIES; ++i)
    {
      Test_Singleton *s = Test_Singleton::instance (i);

      if (s == 0)
        {
          ++error;
          ACE_ERROR ((LM_ERROR,
                      ACE_TEXT ("instance () allocate failed!\n")));
        }
    }
}

// This test verifies that services loaded by a normal ACE startup can be
// located from a thread spawned outside of ACE's control.
//
// To do this, we need a native thread entry and, thus, it needs special care
// for each platform type. Feel free to add more platforms as needed here and
// in main() where the test is called.
#if defined (ACE_HAS_WTHREADS) || defined (ACE_HAS_PTHREADS_STD)
#  if defined (ACE_HAS_WTHREADS)
extern "C" unsigned int __stdcall
#  else
extern "C" ACE_THR_FUNC_RETURN
#  endif
nonacethreadentry (void *args)
{
  ACE_Log_Msg::inherit_hook (0, *(ACE_OS_Log_Msg_Attributes *)args);

  if (ACE_Service_Config::instance()->find(ACE_TEXT("Test_Object_1_Thr")) != 0)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("In thr %t cannot find Test_Object_1_Thr ")
                  ACE_TEXT ("via ACE_Service_Config\n")));
      ++error;
    }
  else
    ACE_DEBUG ((LM_DEBUG,
                ACE_TEXT ("In thr %t, located Test_Object_1_Thr ")
                ACE_TEXT ("via ACE_Service_Config\n")));

  if (0 != ACE_Service_Repository::instance()->find
      (ACE_TEXT("Test_Object_1_Thr")))
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("In thr %t cannot find Test_Object_1_Thr ")
                  ACE_TEXT ("via ACE_Service_Repository\n")));
      ++error;
    }
  else
    ACE_DEBUG ((LM_DEBUG,
                ACE_TEXT ("In thr %t, located Test_Object_1_Thr ")
                ACE_TEXT ("via ACE_Service_Repository\n")));

  return 0;
}

void
testNonACEThread ()
{
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Beginning non-ACE thread lookup test\n")));

  static const ACE_TCHAR *svc_desc =
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
    ACE_TEXT ("dynamic Test_Object_1_Thr Service_Object * ")
    ACE_TEXT ("  Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_1_Thr\"")
#else
    ACE_TEXT ("<dynamic id=\"Test_Object_1_Thr\" type=\"Service_Object\">")
    ACE_TEXT ("  <initializer init=\"_make_Service_Config_DLL\" path=\"Service_Config_DLL\" params=\"Test_Object_1_Thr\"/>")
    ACE_TEXT ("</dynamic>")
#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
    ;

  static const ACE_TCHAR *svc_remove =
#if (ACE_USES_CLASSIC_SVC_CONF == 1)
    ACE_TEXT ("remove Test_Object_1_Thr")
#else
    ACE_TEXT ("<remove id=\"Test_Object_1_Thr\"/>")
    ACE_TEXT ("</remove>")
#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
    ;

  if (-1 == ACE_Service_Config::process_directive (svc_desc))
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("%p\n"),
                  ACE_TEXT ("Error loading service")));
      ++error;
      return;
    }

  // Allow the spawned thread to contribute to the logging output.
  ACE_OS_Log_Msg_Attributes log_msg_attrs;
  ACE_Log_Msg::init_hook (log_msg_attrs);

  u_int errors_before = error;

#if defined (ACE_HAS_WTHREADS) && !defined (ACE_HAS_WINCE)
  HANDLE thr_h = (HANDLE)_beginthreadex (0,
                                         0,
                                         &nonacethreadentry,
                                         &log_msg_attrs,
                                         0,
                                         0);
  if (thr_h == 0)
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("_beginthreadex")));
    }
  else
    {
      WaitForSingleObject (thr_h, INFINITE);
      CloseHandle (thr_h);
    }
#elif defined (ACE_HAS_PTHREADS_STD)
  pthread_t thr_id;
  int status = pthread_create (&thr_id, 0, nonacethreadentry, &log_msg_attrs);
  if (status != 0)
    {
      errno = status;
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("pthread_create")));
    }
  else
    {
      pthread_join (thr_id, 0);
    }
#endif

  if (error != errors_before)  // The test failed; see if we can still see it
    {
      if (0 != ACE_Service_Config::instance()->find
          (ACE_TEXT ("Test_Object_1_Thr")))
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("Main thr %t cannot find Test_Object_1_Thr\n")));
      else
        ACE_DEBUG ((LM_DEBUG,
                    ACE_TEXT ("Main thr %t DOES find Test_Object_1_Thr\n")));
    }

  if (-1 == ACE_Service_Config::process_directive (svc_remove))
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("%p\n"),
                  ACE_TEXT ("Error removing service")));
      ++error;
      return;
    }
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Non-ACE thread lookup test completed\n")));
}
#endif /* ACE_HAS_WTHREADS || ACE_HAS_PTHREADS_STD */


int
run_main (int argc, ACE_TCHAR *argv[])
{
  ACE_START_TEST (ACE_TEXT ("Service_Config_Test"));

 //[] testOrderlyInstantiation (argc, argv); // 先屏掉这句
 //[] testFailedServiceInit (argc, argv); // 先屏掉这句
  testLoadingServiceConfFile (argc, argv);  // 只留这句测试
 //[] testLoadingServiceConfFileAndProcessNo (argc, argv); // 先屏掉这句
 //[] testUnloadingACELoggingStrategy (argc, argv); // 先屏掉这句
 //[] testLimits (argc, argv); // 先屏掉这句
 //[] testrepository (argc, argv); // 先屏掉这句
#if defined (ACE_HAS_WTHREADS) || defined (ACE_HAS_PTHREADS_STD)
 //[] testNonACEThread(); // 先屏掉这句
#endif

  ACE_END_TEST;
  
  getchar(); // 加这句让窗口停留,便于查看输出内容。
  
  return error;
}


3. 配置文件

 Service_Config_Test.conf 文件 (在\ACE-6.0.0\ACE_wrappers\tests目录下)

# Dynamically loading each of the Service Objects below causes a
# number of threads to be spawned, each one invoking the Service
# Configurator (e.g. ACE_Service_Config::process_directive().  If the
# Service Configurator is thread safe and reentrant, then parsing of
# this `Service_Config_Test.conf' file should run to completion
# without error.
#
# Test_Object_1 will cause Test_Object_2 and Test_Object_3 to be
# dynamically loaded.  Dynamic loading of each of object will occur in
# a separate thread.
dynamic Test_Object_1 Service_Object * Service_Config_DLL:_make_Service_Config_DLL() "2 3"     // 引号内是参数

# Test_Object_4 will cause Test_Object_5 and Test_Object_6 to be
# dynamically loaded.  Dynamic loading of each of object will occur in
# a separate thread.
dynamic Test_Object_4 Service_Object * Service_Config_DLL:_make_Service_Config_DLL() "5 6"     // 引号内是参数

# Final_Object does nothing but print a completion message.
dynamic Final_Object Service_Object * Service_Config_DLL:_make_Service_Config_DLL() "FINAL"    // 引号内是参数


 

 

你可能感兴趣的:(ACE动态服务配置的实例代码分析)