Example 2b - Alternative Dictionary Service BundleΒΆ

This example creates an alternative implementation of the dictionary service defined in Example 2. The source code for the bundle is identical except that:

  • Instead of using English words, it uses French words.
  • We do not need to define the dictionary service interface again, as we can just link the definition from the bundle 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 bundle uses its bundle context to register the dictionary service. We implement the dictionary service as an inner class of the bundle activator class, but we could have also put it in a separate file. The source code for our bundle is as follows in a file called dictionaryclient/Activator.cpp:

#include "IDictionaryService.h"

#include "cppmicroservices/BundleActivator.h"
#include "cppmicroservices/BundleContext.h"
#include "cppmicroservices/ServiceProperties.h"

#include <algorithm>
#include <memory>
#include <set>

using namespace cppmicroservices;

namespace {

/**
 * This class implements a bundle activator that uses the bundle
 * context to register a French language dictionary service
 * with the C++ Micro Services registry during static initialization
 * of the bundle. 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 BundleActivator
{

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();
    }
  };

public:
  /**
   * Implements BundleActivator::Start(). Registers an
   * instance of a dictionary service using the bundle context;
   * attaches properties to the service that can be queried
   * when performing a service look-up.
   * @param context the context for the bundle.
   */
  void Start(BundleContext context)
  {
    std::shared_ptr<DictionaryImpl> dictionaryService =
      std::make_shared<DictionaryImpl>();
    ServiceProperties props;
    props["Language"] = std::string("French");
    context.RegisterService<IDictionaryService>(dictionaryService, props);
  }

  /**
   * Implements BundleActivator::Stop(). Does nothing since
   * the C++ Micro Services library will automatically unregister any registered services.
   * @param context the context for the bundle.
   */
  void Stop(BundleContext /*context*/)
  {
    // NOTE: The service is automatically unregistered
  }
};
}

CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator)

We must create a manifest.json file that contains the meta-data for our bundle; the manifest file contains the following:

{
  "bundle.symbolic_name" : "frenchdictionary",
  "bundle.activator" : true
}

For a refresher on 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)

set(frenchdictionary_DEPENDS dictionaryservice)
CreateTutorial(frenchdictionary ${_srcs})

After running the usTutorialDriver program, we should make sure that the bundle from Example 1 is active. We can use the status shell command to get a list of all bundles, their state, and their bundle identifier number. If the Example 1 bundle is not active, we should start the bundle using the start command and the bundle’s identifier number or name that is displayed by the status command. Now we can start our dictionary service bundle by typing the start frenchdictionary command:

CppMicroServices-build> bin/usTutorialDriver
> status
Id | Symbolic Name        | State
-----------------------------------
 0 | system_bundle        | ACTIVE
 1 | eventlistener        | INSTALLED
 2 | dictionaryservice    | INSTALLED
 3 | frenchdictionary     | INSTALLED
 4 | dictionaryclient     | INSTALLED
 5 | dictionaryclient2    | INSTALLED
 6 | dictionaryclient3    | INSTALLED
 7 | spellcheckservice    | INSTALLED
 8 | spellcheckclient     | INSTALLED
> start eventlistener
Starting to listen for service events.
> start frenchdictionary
Ex1: Service of type IDictionaryService registered.
> status
Id | Symbolic Name        | State
-----------------------------------
 0 | system_bundle        | ACTIVE
 1 | eventlistener        | ACTIVE
 2 | dictionaryservice    | INSTALLED
 3 | frenchdictionary     | ACTIVE
 4 | dictionaryclient     | INSTALLED
 5 | dictionaryclient2    | INSTALLED
 6 | dictionaryclient3    | INSTALLED
 7 | spellcheckservice    | INSTALLED
 8 | spellcheckclient     | INSTALLED
>

To stop the bundle, use the stop 3 command. If the bundle from Example 1 is still active, then we should see it print out the details of the service event it receives when our new bundle registers its dictionary service. Using the usTutorialDriver commands stop and start we can stop and start it at will, respectively. Each time we start and stop our dictionary service bundle, we should see the details of the associated service event printed from the bundle from Example 1. In Example 3, we will create a client for our dictionary service. To exit usTutorialDriver, we use the shutdown command.

Note

Because our French dictionary bundle has a link dependency on the dictionary service bundle from Example 2, this bundle’s shared library is automatically loaded by the operating system’s dynamic loader. However, its status remains INSTALLED until it is explicitly started.