To be Reviewed By: August 20th, 2020

Authors: Patrick Johnson

Status: Draft | Discussion | Active | Dropped | Superseded

Superseded by: N/A

Related: ClassLoader Isolation

Problem

For the purposes of this document, a Geode component is any class/feature that, when created/started, adds to or changes the behavior of Geode, such as Cache, Region, or LuceneIndex. Currently, Geode components can be created and shutdown directly using things like CacheFactory in the case of Cache or RegionFactory in the case of Region. After the completion of the work proposed by the ClassLoader Isolation RFC, the majority of Geode's sub-projects will be loaded as isolated modules. In this case, a module is a collection of one or more jar files that are loaded at runtime using a different ClassLoader than the rest of the system. Modules can access classes and resources from the system ClassLoader and other modules upon which they explicitly depend, but cannot be directly accessed from outside the module system; accessing classes from a module requires service loading. The below graphic shows the division between the system and the module ClassLoaders.

system-module-separation

Let's use Cache as an example; Cache is located in geode-core, which is loaded as a module, as shown above, and is inaccessible from the system ClassLoader. In order to access classes from modules, they must implement an interface that is accessible from the system ClassLoader, so they can be service-loaded. While Cache is an interface, it requires several other classes from geode-core making it difficult to decouple and move to a separate sub-project. This is the case for more components than just Cache and impacts more modules than just geode-core. Without an external interface to use to load the implementation from the relevant module, we have no way of creating or managing components.

Anti-Goals

This document is intended to solve the problem of creating, managing, and destroying Geode components within the module framework and is not concerned with...

  • The implementation of modules within Geode
  • Adding, removing, or modifying the behavior of any Geode components

Solution

The proposed solution is the creation of a ComponentManagementService interface. The interface will live in a sub-project accessible from the system ClassLoader, allowing it to be used for service loading. There will be an implementation of ComponentManagementService for each type of component (Cache, Region, LuceneIndex, etc.), that will reside in the same module as the component. The implementation will be able to access classes from inside the module system, such as CacheFactory and Cache, allowing it to create, manage, and destroy its associated component. Different types of components will be identified using a ComponentIdentifier class, which will primarily consist of a name (e.g. "Cache"). The ComponentManagementService interface will have the following methods:

  • createComponent - creates a component given a name and arguments
  • destroyComponent - destroys a component given a name and some arguments
  • getComponent - returns the created component given its name
  • canCreateComponent - takes a ComponentIdentifier and determines whether or not the ComponentManagementService can create that type of component

The logic of creating a component using ComponentManagementService will be handled by the ManagementService proposed by the ClassLoader Isolation RFC. The basic flow for creating a component using ComponentManagementService will be as follows:

  1. Start with a ComponentIdentifier representing the type of component to be created.
  2. Load all implementation of ComponentManagementService from the module system.
  3. Ask each implementation if it can create the type represented by the ComponentIdentifier until you find one that can.
  4. Ask the found ComponentManagementService to create the component.
  5. Store the ComponentManagementService to be used later for accessing or destroying the component.

The ComponentManagementService should be responsible for holding on to instances of the components it creates so they can later be accessed or destroyed by name.

Use Cases

Scenario 1: A ComponentManagementService is asked if it can create a certain type of component (Cache, Region, etc.). The ComponentManagementService can create the given type.

Expected Behavior: The ComponentManagementService sees that the type name matches the type it creates and returns true.


Scenario 2: A ComponentManagementService is asked if it can create a certain type of component (Cache, Region, etc.). The ComponentManagementService can not create the given type.

Expected Behavior: The ComponentManagementService sees that the type name does not match the type it creates and returns false.


Scenario 3: A ComponentManagementService is asked to create a component using some arguments.

Expected Behavior: The ComponentManagementService takes the arguments and uses them to create a component, which is then stored.


Scenario 4: A ComponentManagementService is asked to create a component that already exists.

Expected Behavior: The ComponentManagementService will not overwrite the existing component and will report failure.


Scenario 5: A ComponentManagementService is asked to create a component using some arguments, but is given an invalid set of arguments (missing required parameters, wrong order, wrong types, etc.).

Expected Behavior: The ComponentManagementService will report that it failed to create the component.


Scenario 6: A ComponentManagementService is asked to destroy a component that has been created, given some arguments.

Expected Behavior: The component will be destroyed.


Scenario 7: A ComponentManagementService is asked to destroy a component that has been created, but is given an invalid set of arguments (missing required parameters, wrong order, wrong types, etc.).

Expected Behavior: The ComponentManagementService will report that it failed to destroy the component.


Scenario 8: A ComponentmanagementService is asked to destroy a component that has not been created or has already been destroyed.

Expected Behavior: Since no component instance exists, nothing will be destroyed and the ComponentManagementService will report failure.


Scenario 9: A ComponentmanagementService is asked to return a component that has been created.

Expected Behavior: The matching component instance is returned.


Scenario 10: A ComponentmanagementService is asked to return a component that has not been created or has already been destroyed.

Expected Behavior: Since no matching component instance can be found, the ComponentManagementService reports failure.

Changes and Additions to Public Interfaces

Addition of ComponentManagementService and ComponentIdentifier. No changes to existing pubic interfaces.

Public API Additions

Performance Impact

No anticipated performance impact.

Backwards Compatibility and Upgrade Path

No backward compatibility impact.

Prior Art

An alternative to this solution is to refactor every component to have an interface that only depends on other interfaces and pull all of the interfaces out of their current sub-projects into a sub-project, that will be accessible from the system ClasLoader, specifically for interfaces used for service loading.

FAQ

Answers to questions you’ve commonly been asked after requesting comments for this proposal.

Errata

What are minor adjustments that had to be made to the proposal since it was approved?


  • No labels