IServiceCreator factories to create Service instances at first usage

The IServiceCreator Interface provides the capability to the ServiceContainer to create service instances „on the fly“ - at the first request and not at session startup through registering services manually (using the AddService method) or services.xml files using the ServiceLoader. The IServiceCreator service serves as an optional factory for new instances of the requested service types.

The IServiceCreator functionality is similar to the .NET Framework’s ServiceCreatorCallback delegate:

https://msdn.microsoft.com/en-us/library/system.componentmodel.design.servicecreatorcallback(v=vs.110).aspx

However, as the ABL does not support delegates, we have implemented this through an Interface.

An IServiceCreator instance must be registered (AddService method, ServiceLoader class) in the Service Container under the type(s) that it can create instances of when needed. The IServiceCreator instance does not need to implement the interface of the service types that it can create instances of.

When the service type is requested for the first time through the Service Container GetService () method, the Service Container will call into the CreateInstance method of the factory instance passing the requested service type as an input parameter. The IServiceCreator instance is expected to return an instance of the requested type to the Service Container.

The Service Container will then register the created new service instance automatically as the service instance. So that when the service type is requested the next time, the then existing instance (created by the IServiceCreator instance at the first request) is reused and passed to the caller.

When the IServiceCreator instance was used to create all service types it was registered for, the Service Container will no longer hold a reference to that type and it’s expected that the IServiceCreator instance will be removed from session memory by the garbage collector.

Registering the IServiceCreator implementation

The Service Container can use a single or multiple IServiceCreator instances. IServiceCreator implementations need to be registered in the Service Container for the type (typically an interface implemented by services) that they should act as a factory for.

This example demonstrates how a single factory (implementing the IServiceCreator interface) can be registered as a factory for two service interfaces:

The sample code uses OpenEdge 11.6 syntax (single line comments). The GET-CLASS function is available from OpenEdge 11.4 on. Earlier OpenEdge releases require the usage of the Progress.Lang.Class:GetClass() method.

DEFINE VARIABLE oFactory AS ServiceFactory NO-UNDO .

/* ***************************  Main Block  *************************** */

oFactory = NEW ServiceFactory() .

// Register Factory for type ITypeA and ITypeB
FrameworkSettings:ServiceContainer:AddService(GET-CLASS (ITypeA), oFactory) .
FrameworkSettings:ServiceContainer:AddService(GET-CLASS (ITypeB), oFactory) .

It is also possible to register a single IServiceCreator instance as the factory for multiple service types using a services.xml file:

<?xml version="1.0"?>
<ttServiceLoader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ttServiceLoaderRow>
    <Order>1</Order>
    <ServiceTypeName>Test.ServiceCreator.ITypeA,Test.ServiceCreator.ITypeB</ServiceTypeName>
    <ServiceClassName>Test.ServiceCreator.ServiceFactory</ServiceClassName>
  </ttServiceLoaderRow>       
</ttServiceLoader>

Implementing the IServiceCreator Interface

The IServiceCreator implementation must contain a single method CreateInstance which receives the type of service to be created as an input parameter. That way the same instance can serve as a factory for multiple types. Below is a very simple example using a CASE statement. More dynamic implementations are possible.

CLASS Test.ServiceCreator.ServiceFactory

    IMPLEMENTS IServiceCreator:
    /*------------------------------------------------------------------------------
        Purpose: Creates a service instance
        Notes:   Factory method for services referenced by the provided service type
                 (typically an interface)
        @param poType The service type to create an instance of
        @return The created service instance
    ------------------------------------------------------------------------------*/
    METHOD PUBLIC Progress.Lang.Object CreateInstance (poType AS Progress.Lang.Class):

        CASE poType:
            WHEN GET-CLASS (ITypeA) THEN
                RETURN NEW TypeAImpl () .
            WHEN GET-CLASS (ITypeB) THEN
                RETURN NEW TypeBImpl () .
        END CASE .

    END METHOD.

END CLASS.