Class TenantScopedCache<C>
- Type Parameters:
C- the type of per-tenant component cached
- All Implemented Interfaces:
MultiTenantAwareComponent,DescribableComponent
As a MultiTenantAwareComponent it follows the tenant provider: registerTenant(TenantDescriptor) and
registerAndStartTenant(TenantDescriptor) return a Registration whose cancellation evicts the
tenant's cached component, so a re-added tenant rebuilds a fresh one.
Eviction only drops this cache's reference to the component. That suits a component whose lifecycle is owned
elsewhere, such as one bound to a connection the connection manager closes. A component that has to be released on
eviction needs that release wired in, which DefaultTenantComponentProvider does to destroy the instances it
hands to message handlers. Such a release runs exactly once per component, whether its registration was cancelled,
superseded, or replaced while the component was being created.
Only a registered tenant gets a component. Requesting the component of a tenant that was never registered, or whose
registration was cancelled, is rejected with a TenantNotResolvedException. A removed tenant would otherwise
get a fresh component that nothing evicts again, since the registration that would have evicted it is already
cancelled, and for a backend-bound component that means holding a connection to a context that was just dropped.
Components are cached per registration rather than per tenant, so one created concurrently with the removal of its tenant is discarded instead of outliving that registration.
Component creation runs inside the cache update. The factory must therefore not register or unregister tenants on, nor request components from, this cache on the creating thread.
- Since:
- 5.3.0
- Author:
- Jakob Hatzl, Laura Devriendt
-
Constructor Summary
ConstructorsConstructorDescriptionTenantScopedCache(Function<TenantDescriptor, C> componentFactory, String owner) Constructs aTenantScopedCachebuilding its components with the givencomponentFactory, dropping its reference to a component on eviction without releasing it any further.TenantScopedCache(Function<TenantDescriptor, C> componentFactory, BiConsumer<TenantDescriptor, C> onEviction, String owner) Constructs aTenantScopedCachebuilding its components with the givencomponentFactoryand handing every component it evicts to the givenonEviction. -
Method Summary
Modifier and TypeMethodDescriptioncomponentFor(TenantDescriptor tenant) Returns the component of the giventenant, creating and caching it on first access.voiddescribeTo(ComponentDescriptor descriptor) Describe the properties ofthis DescribableComponentwith the givendescriptor.registerAndStartTenant(TenantDescriptor tenantDescriptor) Behaves identically toregisterTenant(TenantDescriptor): components are created lazily on first use, so there is nothing to start eagerly.registerTenant(TenantDescriptor tenantDescriptor) Registers the giventenantDescriptoras a known tenant with this multi-tenant aware component.tenants()Returns the tenants currently registered withthiscache, whether their component was built yet or not.
-
Constructor Details
-
TenantScopedCache
Constructs aTenantScopedCachebuilding its components with the givencomponentFactory, dropping its reference to a component on eviction without releasing it any further.- Parameters:
componentFactory- the factory building a tenant's component, invoked once per tenant on first accessowner- howthiscache names its owner in theTenantNotResolvedExceptionraised for a tenant that is not registered, so the component that rejected the tenant can be told from the others caching per tenant in the same call- Throws:
NullPointerException- if any of the given arguments isnull
-
TenantScopedCache
public TenantScopedCache(Function<TenantDescriptor, C> componentFactory, BiConsumer<TenantDescriptor, C> onEviction, String owner) Constructs aTenantScopedCachebuilding its components with the givencomponentFactoryand handing every component it evicts to the givenonEviction.- Parameters:
componentFactory- the factory building a tenant's component, invoked once per tenant on first accessonEviction- invoked with a tenant and the component evicted for it, exactly once per evicted component, so its owner can release itowner- howthiscache names its owner in theTenantNotResolvedExceptionraised for a tenant that is not registered- Throws:
NullPointerException- if any of the given arguments isnull
-
-
Method Details
-
componentFor
Returns the component of the giventenant, creating and caching it on first access.- Parameters:
tenant- the tenant to return the component for- Returns:
- the tenant's cached component
- Throws:
TenantNotResolvedException- if the giventenantis not registered
-
registerTenant
Description copied from interface:MultiTenantAwareComponentRegisters the giventenantDescriptoras a known tenant with this multi-tenant aware component.The caller must retain the returned
Registrationand cancel it when the tenant is removed, since releasing the component's per-tenant resources rides on that cancellation.- Specified by:
registerTenantin interfaceMultiTenantAwareComponent- Parameters:
tenantDescriptor- TheTenantDescriptorto register with this component.- Returns:
- A
Registrationused to deregister the giventenantDescriptor.
-
registerAndStartTenant
Behaves identically toregisterTenant(TenantDescriptor): components are created lazily on first use, so there is nothing to start eagerly.- Specified by:
registerAndStartTenantin interfaceMultiTenantAwareComponent- Parameters:
tenantDescriptor- the tenant to register withthiscache- Returns:
- a registration whose cancellation evicts the tenant's component
-
tenants
Returns the tenants currently registered withthiscache, whether their component was built yet or not.- Returns:
- the tenants currently registered with
thiscache
-
describeTo
Description copied from interface:DescribableComponentDescribe the properties ofthis DescribableComponentwith the givendescriptor.Components should call the appropriate
describePropertymethods on the descriptor to register their properties. The descriptor is responsible for determining how these properties are formatted and structured in the final output.Best Practices: As a general rule, all relevant fields of a
DescribableComponentimplementation should be described in this method. However, developers have discretion to include only the fields that make sense in the context. Not every field may be meaningful for description purposes, especially internal implementation details. Furthermore, components might want to expose different information based on their current state. The final decision on what properties to include lies with the person implementing thedescribeTomethod, who should focus on providing information that is useful for understanding the component's configuration and state.Example implementation:
public void describeTo(ComponentDescriptor descriptor) { descriptor.describeProperty("name", this.name); descriptor.describeProperty("enabled", this.enabled); descriptor.describeProperty("configuration", this.configuration); // A nested component descriptor.describeProperty("handlers", this.eventHandlers); // A collection }- Specified by:
describeToin interfaceDescribableComponent- Parameters:
descriptor- The component descriptor to describethis DescribableComponentn its properties in.
-