Software re-use, component based design, extensibility, compatibility: these four problems can be addressed through the effective use of XOE services.
There are three different, but related, processes with regards to XOE services: defining a service, implementing a service, and using a service. During the life of your software project you may use any one or more of these processes.
Defining a service consists of defining a functionality name and writing a Java interface that specifies the abstract functionality of the service. A TV service, for example, might have the functionality type "television" and have the following methods defined:
// true=on, false=off boolean getPower (); void setPower (boolean isOn); // channel > 0 int getChannel (); void setChannel (int channel); // 0 < volume < 100 int getVolume (); void setVolume (int volume);
It's also important to make sure your service interface extends the org.xoe.core.services.IService interface. The Service subsystem uses this interface to ask a specific implementation of a service for more information about itself.
Functionality and interface do not map one-to-one. Different service implementations may provide the same functionality but using different interfaces. It's also possible to have two implementations of the same interface that provide different functionalities.
When defining a service, it is also possible to define various 'features' that can be used to describe the specific functionality of a specific implementation of the service. For example, two different implementations of the TV service might have the following characteristics:
Service Provider 1 Functionality: "television" Interface: org.xoe.tv.ITelevision Features: Cable=false Color=false HDTV=false SizeInInches=10 ManufactureDate=1976 Service Provider 2 Functionality: "television" Interface: org.xoe.tv.ITelevision, org.xoe.tv.IPictureInPicture Features: Cable=true Color=true HDTV=true SizeInInches=72 ManufactureDate=2001
Notice that the second TV supports another interface as well, IPictureInPicture. Although the developer could have just used a new ITVWithPictureInPicture that had all the functions of both, and not implemented ITelevision, defining an additive interface is better. This allows older software that only knows about ITelevision to still be able to use the newer implementation, but enables newer software to take advantage of the latest and greatest features.
In order for other software to use or implement your service, it must have access to the interface. This means you must package the interface and make the package available. If you know that it will only be used by one package it may make sense to ship the interface along with the client-package. Otherwise the interface should be shipped in its own package.
An implementation of a service consists of a Java class that implements the Java interface. Because the defined service interface extends IService, it is also necessary to implement the functions defined in IService. These methods are used to ask the service what functionality it provides, what interfaces it wishes to 'announce', and what features it supports. The IService interface also has an init function that is used to initialize and configure the service.
Once you have written the Java class, you must register your service. Registering the service consists of adding a file called services.xml to the package containing the service. In this file you list the class name of the service you want registered and an optional configuration file that should be passed to it during initialization.
When your package is installed, each class listed in services.xml will be instantiated, initialized, and registered. If any of these steps fail for any service the package installation is considered failed.
Remember that your package must have access to the definition of the service interface. This means you must depend on the package that contains the interface class file.
In order to use a service, you must locate a specific implementation and then access it using the defined interface. If your package absolutely depends on the availability of a service to run properly (or to be installed) you can specify that dependency in your package description (see the reference appendixes Core Installers and Provisos, and Dependencies).
Locating a service is simple. You specify the functionality, interface, and features you need in a service, and receive references to all matching providers. Pick the one(s) you want, cast them to the chosen interface, and that's it.
Remember that if the interface is defined in a separate package, you must specify a dependency on that package.
See the chapter Service Registration and Location for code examples.