CppMicroServices

C++ Micro Services: Example 2b - Alternative Dictionary Service Module
Example 2b - Alternative Dictionary Service Module

This example creates an alternative implementation of the dictionary service defined in Example 2. The source code for the module is identical except that instead of using English words, French words are used. The only other difference is that in this module we do not need to define the dictionary service interface again, since we can just link the definition from the module in Example 2. The main point of this example is to illustrate that multiple implementations of the same service may exist; this example will also be of use to us in Example 5.

In the following source code, the module uses its module context to register the dictionary service. We implement the dictionary service as an inner class of the module activator class, but we could have also put it in a separate file. The source code for our module is as follows in a file called dictionaryclient/Activator.cpp:

#include "IDictionaryService.h"
#include <usModuleActivator.h>
#include <usModuleContext.h>
#include <usGetModuleContext.h>
#include <usServiceProperties.h>
#include <set>
#include <algorithm>
#include <memory>
US_USE_NAMESPACE
/**
* This class implements a module activator that uses the module
* context to register a French language dictionary service
* with the C++ Micro Services registry during static initialization
* of the module. The dictionary service interface is
* defined in Example 2 (dictionaryservice) and is implemented by a
* nested class. This class is identical to the class in Example 2,
* except that the dictionary contains French words.
*/
class US_ABI_LOCAL Activator : public ModuleActivator
{
private:
/**
* A private inner class that implements a dictionary service;
* see DictionaryService for details of the service.
*/
class DictionaryImpl : public IDictionaryService
{
// The set of words contained in the dictionary.
std::set<std::string> m_dictionary;
public:
DictionaryImpl()
{
m_dictionary.insert("bienvenue");
m_dictionary.insert("au");
m_dictionary.insert("tutoriel");
m_dictionary.insert("micro");
m_dictionary.insert("services");
}
/**
* Implements DictionaryService.checkWord(). Determines
* if the passed in word is contained in the dictionary.
* @param word the word to be checked.
* @return true if the word is in the dictionary,
* false otherwise.
**/
bool CheckWord(const std::string& word)
{
std::string lword(word);
std::transform(lword.begin(), lword.end(), lword.begin(), ::tolower);
return m_dictionary.find(lword) != m_dictionary.end();
}
};
std::auto_ptr<DictionaryImpl> m_dictionaryService;
public:
/**
* Implements ModuleActivator::Load(). Registers an
* instance of a dictionary service using the module context;
* attaches properties to the service that can be queried
* when performing a service look-up.
* @param context the context for the module.
*/
void Load(ModuleContext* context)
{
m_dictionaryService.reset(new DictionaryImpl);
props["Language"] = std::string("French");
context->RegisterService<IDictionaryService>(m_dictionaryService.get(), props);
}
/**
* Implements ModuleActivator::Unload(). Does nothing since
* the C++ Micro Services library will automatically unregister any registered services.
* @param context the context for the module.
*/
void Unload(ModuleContext* /*context*/)
{
// NOTE: The service is automatically unregistered
}
};
US_EXPORT_MODULE_ACTIVATOR(frenchdictionary, Activator)

For an introduction how to compile our source code, see Example 1 - Service Event Listener. Because we use the IDictionaryService definition from Example 2, we also need to make sure that the proper include paths and linker dependencies are set:

set(_srcs Activator.cpp)
NAME "French Dictionary"
LIBRARY_NAME "frenchdictionary")
set(frenchdictionary_DEPENDS dictionaryservice)
CreateExample(frenchdictionary ${_srcs})

After running the CppMicroServicesExampleDriver program we should make sure that the module from Example 1 is active. We can use the s shell command to get a list of all modules, their state, and their module identifier number. If the Example 1 module is not active, we should load the module using the load command and the module's identifier number or name that is displayed by the s command. Now we can load our dictionary service module by typing the l frenchdictionary command:

CppMicroServices-build> bin/CppMicroServicesExampleDriver
> s
Id | Name                 | Status
-----------------------------------
 - | dictionaryservice    | -
 - | eventlistener        | -
 - | frenchdictionary     | -
 1 | CppMicroServices     | LOADED
> l eventlistener
Starting to listen for service events.
> l frenchdictionary
Ex1: Service of type IDictionaryService/1.0 registered.
Ex1: Service of type IDictionaryService/1.0 registered.
> s
Id | Name                 | Status
-----------------------------------
 1 | CppMicroServices     | LOADED
 2 | Event Listener       | LOADED
 3 | Dictionary Service   | LOADED
 4 | French Dictionary    | LOADED
>

To unload the module, use the u <id> command. If the module from Example 1 is still active, then we should see it print out the details of the service event it receives when our new module registers its dictionary service. Using the CppMicroServicesExampleDriver commands u and l we can unload and load it at will, respectively. Each time we load and unload our dictionary service module, we should see the details of the associated service event printed from the module from Example 1. In Example 3, we will create a client for our dictionary service. To exit CppMicroServicesExampleDriver, we use the q command.

Note
Because our french dictionary module has a link dependency on the dictionary service module from Example 2, this module is automatically loaded by the operating system loader. Unloading it will only succeed if there are no other dependent modules like our french dictionary module currently loaded.

Next: Example 3 - Dictionary Client Module

Previous: Example 2 - Dictionary Service Module