How to register a nano service

Service, van Gogh

Registration of the nano service

Before you can use nano services, they should be registered. This can be done manually by the operator of the service, or automatically in a ServiceStarter.

You should have read these tutorials beforehand:
Package initialization
How to start a simple target

Registration manually

Nano services are always bound to a namespace. In most cases, this is the SYSTEM namespace. So we need the nano service registry of the namespace. Preferably we register the nano service in the StartTarget handler (see How to start a simple target).

In the service starter:

public void getDependencies(@NotNull final IServiceDependencyList aDependencyList)
{
    aDependencyList.add(INamespaceRegistry.class);
}

In the target:

private boolean asyncStartTarget(@NotNull final CEnvelope aEnvelope,
                                 @NotNull final CRecord aRecord) throws CException
{
    final INamespaceRegistry namespaceRegistry = mDependencies.getNamespaceRegistry();
    final INamespace namespace = namespaceRegistry.getNamespace(CWellKnownNID.SYSTEM);
    assert namespace != null;
    final INanoServiceRegistry nanoServiceRegistry = namespace.getNanoServiceRegistry();
    nanoServiceRegistry.addNanoService(CRecordNotifyRemoteNodeAdded.ID,
                                       "Notification: A remote node has been added");

    aEnvelope.setResultSuccess();
    return true;
}

Okay, that's way too much work.
Instead of getting the NamespaceRegistry, we should get the nano service registry right away. For this we need a filter.

In the service starter:

public void getDependencies(@NotNull final IServiceDependencyList aDependencyList)
{
    aDependencyList.add(INanoServiceRegistry.class,
                        "nid=SYSTEM");
}

In the target:

private boolean asyncStartTarget(@NotNull final CEnvelope aEnvelope,
                                 @NotNull final CRecord aRecord) throws CException
{
    final INanoServiceRegistry nanoServiceRegistry = mDependencies.getNanoServiceRegistry();
    nanoServiceRegistry.addNanoService(CRecordNotifyRemoteNodeAdded.ID,
                                       "Notification: A remote node has been added");
    aEnvelope.setResultSuccess();
    return true;
}

That's much better. If we need an observer, we can register the service and the observer with one method call.

private boolean asyncStartTarget(@NotNull final CEnvelope aEnvelope,
                                 @NotNull final CRecord aRecord) throws CException
{
    final INanoServiceRegistry nanoServiceRegistry = mDependencies.getNanoServiceRegistry();
    nanoServiceRegistry.addNanoServiceAndObserver(CRecordNotifyRemoteNodeAdded.ID,
                                                  "Notification: A remote node has been added",
                                                  getAddress());
    aEnvelope.setResultSuccess();
    return true;
}

There are other variants of registration. Here the generated class is used as argument. This has the advantage that the name or description of the nano service does not have to be specified, since it is already present in the class.

private boolean asyncStartTarget(@NotNull final CEnvelope aEnvelope,
                                 @NotNull final CRecord aRecord) throws CException
{
    final INanoServiceRegistry nanoServiceRegistry = mDependencies.getNanoServiceRegistry();
    nanoServiceRegistry.addNanoServiceAndObserver(CRecordNotifyRemoteNodeAdded.class,
                                                  getAddress(),
                                                  true);
    aEnvelope.setResultSuccess();
    return true;
}

Registration of nano services in service starter

The pure registration of nano services is best done in service starter1140. Here some records of the Job module are registered and deregistered. The work is done by another service, the RecordRegistryHelper. It takes the data it needs for registration from the record classes. Nano services are registered with the specified namespaces. Furthermore, the names of the records are registered with the NameDb, since their ID is often an unreadable UUID. This makes reading LOG files much more pleasant.

public class CPackageImplJobRecords implements IServiceStarter
{
    @Override
    public void getDependencies(@NotNull final IServiceDependencyList aDependencyList)
    {
        aDependencyList.add(IRecordRegistryHelper.class);
    }

    @Override
    public void start(@NotNull final IServiceRegistry aServiceRegistry) throws Exception
    {
        final IRecordRegistryHelper helper = aServiceRegistry.getService(IRecordRegistryHelper.class);
        if (helper != null)
        {
            helper.registerRecord(CRecordAddJob.class);
            helper.registerRecord(CRecordAddThread.class);
            helper.registerRecord(CRecordJobFinished.class);
            helper.registerRecord(CRecordRemoveJob.class);
        }
    }

    @Override
    public void stop(@NotNull final IServiceRegistry aServiceRegistry) throws Exception
    {
        final IRecordRegistryHelper helper = aServiceRegistry.getService(IRecordRegistryHelper.class);
        if (helper != null)
        {
            helper.deregisterRecord(CRecordAddJob.class);
            helper.deregisterRecord(CRecordAddThread.class);
            helper.deregisterRecord(CRecordJobFinished.class);
            helper.deregisterRecord(CRecordRemoveJob.class);
        }
    }
}

For this to work, some information is needed in the record definitions.

{
  "id": "aaee82f5-17a1-4925-a0a5-02c1260cb25b",
  "name": "CLI_REMOVE_HANDLER",
  "isService": "true",
  "namespaces": "SYSTEM",
  "description": "Remove a Command Handler.",
  "slots": [
    {
      "key": "1",
      "name": "COMMAND",
      "direction": "REQUEST",
      "mandatory": "true",
      "type": "STRING",
      "description": "The command."
    }
  ]
}

nyssr.net - Innovative Distributed System