Medical Imaging Interaction Toolkit  2023.12.00
Medical Imaging Interaction Toolkit
Example 3 - Dictionary Client Module

This example creates a module that is a client of the dictionary service implemented in Example 2. In the following source code, our module uses its module context to query for a dictionary service. Our client module uses the first dictionary service it finds and if none are found it simply prints a message saying so and stops. Using a service is the same as using any C++ class. The source code for our module is as follows in a file called dictionaryclient2/Activator.cpp:

#include "IDictionaryService.h"
namespace {
class US_ABI_LOCAL Activator : public ModuleActivator
{
public:
void Load(ModuleContext *context)
{
// Query for all service references matching any language.
std::vector<ServiceReference<IDictionaryService> > refs =
context->GetServiceReferences<IDictionaryService>("(Language=*)");
if (!refs.empty())
{
std::cout << "Enter a blank line to exit." << std::endl;
// Loop endlessly until the user enters a blank line
while (std::cin)
{
// Ask the user to enter a word.
std::cout << "Enter word: ";
std::string word;
std::getline(std::cin, word);
// If the user entered a blank line, then
// exit the loop.
if (word.empty())
{
break;
}
// First, get a dictionary service and then check
// if the word is correct.
IDictionaryService* dictionary = context->GetService<IDictionaryService>(refs.front());
if ( dictionary->CheckWord( word ) )
{
std::cout << "Correct." << std::endl;
}
else
{
std::cout << "Incorrect." << std::endl;
}
// Unget the dictionary service.
context->UngetService(refs.front());
}
}
else
{
std::cout << "Couldn't find any dictionary service..." << std::endl;
}
}
void Unload(ModuleContext* /*context*/)
{
// NOTE: The service is automatically released.
}
};
}

Note that we do not need to unget or release the service in the Unload() method, because the C++ Micro Services library will automatically do so for us.

Since we are using the IDictionaryService interface defined in Example 1, we must link our module to the dictionaryservice module:

set(_srcs Activator.cpp)
usFunctionGenerateModuleInit(_srcs)
set(dictionaryclient_DEPENDS dictionaryservice)
CreateExample(dictionaryclient ${_srcs})

After running the usCoreExamplesDriver executable, and loading the event listener module, we can use the l dictionaryclient command to load our dictionary client module:

CppMicroServices-debug> bin/usCoreExamplesDriver
> l eventlistener
Starting to listen for service events.
> l dictionaryclient
Ex1: Service of type IDictionaryService/1.0 registered.
Enter a blank line to exit.
Enter word:

The above command loads the module and its dependencies (the dictionaryservice module) in a single step. When we load the module, it will use the main thread to prompt us for words. Enter one word at a time to check the words and enter a blank line to stop checking words. To reload the module, we must use the s command to get the module identifier number for the module and first use the u <id> command to unload the module, then the l <id> command to re-load it. To test the dictionary service, enter any of the words in the dictionary (e.g., "welcome", "to", "the", "micro", "services", "tutorial") or any word not in the dictionary.

This example client is simple enough and, in fact, is too simple. What would happen if the dictionary service were to unregister suddenly? Our client would abort with a segmentation fault due to a null pointer access when trying to use the service object. This dynamic service availability issue is a central tenent of the service model. As a result, we must make our client more robust in dealing with such situations. In Example 4, we explore a slightly more complicated dictionary client that dynamically monitors service availability.

Next: Example 4 - Robust Dictionary Client Module

Previous: Example 2 - Dictionary Service Module

usModuleActivator.h
ModuleContext
Definition: usModuleContext.h:91
ModuleContext::GetService
void * GetService(const ServiceReferenceBase &reference)
US_USE_NAMESPACE
#define US_USE_NAMESPACE
Definition: usGlobalConfig.h:75
ModuleContext::UngetService
bool UngetService(const ServiceReferenceBase &reference)
US_ABI_LOCAL
#define US_ABI_LOCAL
Definition: usGlobalConfig.h:117
US_EXPORT_MODULE_ACTIVATOR
#define US_EXPORT_MODULE_ACTIVATOR(_activator_type)
Export a module activator class.
Definition: usModuleActivator.h:119
usModuleContext.h
ModuleContext::GetServiceReferences
std::vector< ServiceReferenceU > GetServiceReferences(const std::string &clazz, const std::string &filter=std::string())