What is it ?

The Lucy back-end (ILcyLucyEnv) provides a mechanism for sharing objects between different parts of Lucy without creating a hard dependency between those parts. This mechanism is called the service mechanism.

You can see it as a giant bag: you can put objects in the bag with ILcyLucyEnv.addService(Object), and remove them from the bag with ILcyLucyEnv.removeService(Object). It is also possible to request from the bag all objects that extend or implement a certain class or interface.

An example use case of why it is important to have such a mechanism involves the Lucy map add-on: the map add-on has an action to load data on the map, which needs to support a lot of data formats. Loading data on the map requires model decoders and layer factories. You can make those model decoders and layer factories available as services. By letting the loading action delegate to the model decoder and layer factory services, the action can support all data formats. You can add support for an extra data format without changing any action code, by adding new model decoders and layer factories to the services.

In this scenario, the data format add-ons are the suppliers of the services, and the open action of the map add-on a consumer of those services.

See ILcyLucyEnv.getServices(Class) for more information, and for an overview of all types of objects which are available as service.

Summary: the service mechanism allows add-ons to register objects with a central registry, which can be queried and used by other add-ons. Doing so prevents hard dependencies between the different add-ons.

Example use case of the service mechanism

An example use case of the service mechanism is an action that creates an ILcdGXYLayer for an ILcdModel. The action needs to find an ILcdGXYLayerFactory that accepts the ILcdModel and can create an ILcdGXYLayer for it.

Typically, the available ILcdGXYLayerFactory instances are not created in the action, but in separate ALcyAddOn instances.

There are two options that let the action use those ILcdGXYLayerFactory instances: either the add-ons set the factory instances on the action, or there is a mechanism that allows the action to find those ILcdGXYLayerFactory instances.

The first option would introduce a hard dependency between the different add-ons and the action. Each add-on that adds support for a new data format needs to register its factory with that action. If a new action is introduced that also needs those factories, each format add-on needs to be adjusted to register its factory with that new action as well. This is not very scalable, and would make adding new functionality to Lucy very hard.

However, if those add-ons register their ILcdGXYLayerFactory instances as service objects with the backend, as demonstrated by Program: Register an object as a service with the back-end, the action can request them from the back-end later on, thereby preventing the dependency. See Program: Retrieve the registered service objects from the back-end for an illustration.

Program: Register an object as a service with the back-end
  ILcyLucyEnv aLucyEnv;
  ILcdGXYLayerFactory aLayerFactory;
  aLucyEnv.addService(aLayerFactory); //register the factory
Program: Retrieve the registered service objects from the back-end
  ILcyLucyEnv aLucyEnv;
  //retrieve all registered ILcdGXYLayerFactory instances
  List<ILcdGXYLayerFactory> factories = aLucyEnv.getServices(ILcdGXYLayerFactory.class);

The Javadoc of the ILcyLucyEnv.addService(Object, int) includes a list of all objects that are registered by default.