[ 
https://issues.apache.org/jira/browse/OPENNLP-1966?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Richard Zowalla updated OPENNLP-1966:
-------------------------------------
    Description: 

OpenNLP loads extensions in two ways today. {{ExtensionLoader}} instantiates 
classes by name from model manifests, XML descriptors, training parameters and 
CLI arguments, guarded by a package allow-list (OPENNLP-1820). Service 
interfaces added in 3.0, such as {{TextEmbedder}} (OPENNLP-1937), need 
discovery without a class name. Both needs are covered by one SPI.

This epic adds {{Provider<T>}}, {{Providers}} and {{ProviderSpec}} to 
opennlp-api and moves the {{ExtensionLoader}} call sites to them, one group of 
service interfaces per ticket. The resolution rules follow CDI:

||CDI||OpenNLP||
|bean type|SPI sub-interface per service interface, for example 
{{TextEmbedderProvider extends Provider<TextEmbedder>}}, registered in 
{{META-INF/services}}|
|qualifiers|{{supports(ProviderSpec)}}|
|{{@Named}}|{{name()}}, used by descriptors, manifests and the CLI|
|{{@Alternative}} + {{@Priority}}|{{priority()}}, larger wins|
|{{@Vetoed}}|{{isAvailable()}} for a provider that vetoes itself, plus the 
configuration key {{opennlp.provider.<SPI FQN>.disabled}} for vetoing one from 
outside|
|{{Instance<T>.get()}} / iterating {{Instance<T>}}|{{Providers.select(spec)}} / 
{{Providers.supporting(spec)}}|
|unsatisfied / ambiguous resolution|{{UnsatisfiedProviderException}} / 
{{AmbiguousProviderException}}|
|{{@Dependent}}|{{create(spec)}} returns an instance owned by the caller|
|{{openwebbeans.properties}} keyed by SPI name, ordered by 
{{configuration.ordinal}}|{{META-INF/opennlp/providers.properties}} keyed by 
SPI FQN and ordered the same way, overridden by system properties, or a source 
the application passes to {{Providers.of(spi, loader, configuration)}}|
|{{DefaultLoaderService}} failing the deployment on a {{ServiceLoader}} error|a 
broken provider is skipped with a warning, an unreadable service file fails the 
lookup|

h3. Constraints for every ticket
* Thread-safe. {{Providers}} is immutable after {{of()}}; providers are 
stateless and thread-safe.
* Application server compatible. No static caches of providers or class 
loaders; the thread context class loader is used, falling back to the SPI's 
class loader.
* Native image friendly (OPENNLP-1954). Providers have a public no-arg 
constructor, lookup uses no reflection, availability is checked at call time.
* Existing models and descriptors keep loading. The class name path stays as a 
fallback until the last ticket decides on its deprecation.
* Adding a jar to the class path stays a code-trust decision, so an operator 
can restrict which provider classes may be used at all ({{opennlp.provider.<SPI 
FQN>.allowed}}), and a provider that is not allowed or is disabled by class 
name is never instantiated.

h3. Releases
{{Provider}}, {{Providers}} and {{ProviderSpec}} ship in 3.0.0 together with 
OPENNLP-1937, so the types are frozen from that release on. The follow-ups 
target 3.1.0 and must get by with additions: a new SPI sub-interface per 
service interface, and for nested feature generators an own {{create}} overload 
on that sub-interface.

h3. Tickets, in merge order
||Ticket||Release||Scope||
|OPENNLP-1972|3.0.0|{{Provider}}, {{Providers}}, {{ProviderSpec}}, resolution 
exceptions, {{DocumentAnnotatorProvider}} with the stemmer as first provider|
|OPENNLP-1937|3.0.0|{{TextEmbedder}} and {{TextEmbedderProvider}}, ONNX 
provider in opennlp-dl|
|OPENNLP-1967|3.1.0|{{ExtensionLoader}} bridge and trainer providers|
|OPENNLP-1968|3.1.0|Feature generator providers and {{name}} in XML descriptors|
|OPENNLP-1969|3.1.0|Data indexers, sequence codecs, string interners, doccat 
feature generators, entity linkers|
|OPENNLP-1970|3.1.0|Tool factories and artifact serializers referenced from 
model manifests|
|OPENNLP-1971|3.1.0|CLI format factories|


  was:

OpenNLP loads extensions in two ways today. {{ExtensionLoader}} instantiates 
classes by name from model manifests, XML descriptors, training parameters and 
CLI arguments, guarded by a package allow-list (OPENNLP-1820). Service 
interfaces added in 3.0, such as {{TextEmbedder}} (OPENNLP-1937), need 
discovery without a class name. Both needs are covered by one SPI.

This epic adds {{Provider<T>}}, {{Providers}} and {{ProviderSpec}} to 
opennlp-api and moves the {{ExtensionLoader}} call sites to them, one group of 
service interfaces per ticket. The resolution rules follow CDI:

||CDI||OpenNLP||
|bean type|SPI sub-interface per service interface, for example 
{{TextEmbedderProvider extends Provider<TextEmbedder>}}, registered in 
{{META-INF/services}}|
|qualifiers|{{supports(ProviderSpec)}}|
|{{@Named}}|{{name()}}, used by descriptors, manifests and the CLI|
|{{@Alternative}} + {{@Priority}}|{{priority()}}, larger wins|
|{{@Vetoed}}|{{isAvailable()}} for a provider that vetoes itself, plus the 
configuration key {{opennlp.provider.<SPI FQN>.disabled}} for vetoing one from 
outside|
|{{Instance<T>.get()}} / iterating {{Instance<T>}}|{{Providers.select(spec)}} / 
{{Providers.supporting(spec)}}|
|unsatisfied / ambiguous resolution|{{UnsatisfiedProviderException}} / 
{{AmbiguousProviderException}}|
|{{@Dependent}}|{{create(spec)}} returns an instance owned by the caller|
|{{openwebbeans.properties}} keyed by SPI name, ordered by 
{{configuration.ordinal}}|{{META-INF/opennlp/providers.properties}} keyed by 
SPI FQN and ordered the same way, overridden by system properties, or a source 
the application passes to {{Providers.of(spi, loader, configuration)}}|
|{{DefaultLoaderService}} failing the deployment on a {{ServiceLoader}} error|a 
broken provider is skipped with a warning, an unreadable service file fails the 
lookup|

h3. Constraints for every ticket
* Thread-safe. {{Providers}} is immutable after {{of()}}; providers are 
stateless and thread-safe.
* Application server compatible. No static caches of providers or class 
loaders; the thread context class loader is used, falling back to the SPI's 
class loader.
* Native image friendly (OPENNLP-1954). Providers have a public no-arg 
constructor, lookup uses no reflection, availability is checked at call time.
* Existing models and descriptors keep loading. The class name path stays as a 
fallback until the last ticket decides on its deprecation.
* Adding a jar to the class path stays a code-trust decision, so an operator 
can restrict which provider classes may be used at all ({{opennlp.provider.<SPI 
FQN>.allowed}}), and a provider that is not allowed or is disabled by class 
name is never instantiated.

h3. Tickets, in merge order
||Ticket||Scope||
|OPENNLP-1972|{{Provider}}, {{Providers}}, {{ProviderSpec}}, resolution 
exceptions, {{DocumentAnnotatorProvider}} with the stemmer as first provider|
|OPENNLP-1937|{{TextEmbedder}} and {{TextEmbedderProvider}}, ONNX provider in 
opennlp-dl|
|OPENNLP-1967|{{ExtensionLoader}} bridge and trainer providers|
|OPENNLP-1968|Feature generator providers and {{name}} in XML descriptors|
|OPENNLP-1969|Data indexers, sequence codecs, string interners, doccat feature 
generators, entity linkers|
|OPENNLP-1970|Tool factories and artifact serializers referenced from model 
manifests|
|OPENNLP-1971|CLI format factories|



> Resolve OpenNLP extensions through a generic provider SPI
> ---------------------------------------------------------
>
>                 Key: OPENNLP-1966
>                 URL: https://issues.apache.org/jira/browse/OPENNLP-1966
>             Project: OpenNLP
>          Issue Type: Epic
>            Reporter: Richard Zowalla
>            Assignee: Richard Zowalla
>            Priority: Major
>              Labels: graalvm, spi
>
> OpenNLP loads extensions in two ways today. {{ExtensionLoader}} instantiates 
> classes by name from model manifests, XML descriptors, training parameters 
> and CLI arguments, guarded by a package allow-list (OPENNLP-1820). Service 
> interfaces added in 3.0, such as {{TextEmbedder}} (OPENNLP-1937), need 
> discovery without a class name. Both needs are covered by one SPI.
> This epic adds {{Provider<T>}}, {{Providers}} and {{ProviderSpec}} to 
> opennlp-api and moves the {{ExtensionLoader}} call sites to them, one group 
> of service interfaces per ticket. The resolution rules follow CDI:
> ||CDI||OpenNLP||
> |bean type|SPI sub-interface per service interface, for example 
> {{TextEmbedderProvider extends Provider<TextEmbedder>}}, registered in 
> {{META-INF/services}}|
> |qualifiers|{{supports(ProviderSpec)}}|
> |{{@Named}}|{{name()}}, used by descriptors, manifests and the CLI|
> |{{@Alternative}} + {{@Priority}}|{{priority()}}, larger wins|
> |{{@Vetoed}}|{{isAvailable()}} for a provider that vetoes itself, plus the 
> configuration key {{opennlp.provider.<SPI FQN>.disabled}} for vetoing one 
> from outside|
> |{{Instance<T>.get()}} / iterating {{Instance<T>}}|{{Providers.select(spec)}} 
> / {{Providers.supporting(spec)}}|
> |unsatisfied / ambiguous resolution|{{UnsatisfiedProviderException}} / 
> {{AmbiguousProviderException}}|
> |{{@Dependent}}|{{create(spec)}} returns an instance owned by the caller|
> |{{openwebbeans.properties}} keyed by SPI name, ordered by 
> {{configuration.ordinal}}|{{META-INF/opennlp/providers.properties}} keyed by 
> SPI FQN and ordered the same way, overridden by system properties, or a 
> source the application passes to {{Providers.of(spi, loader, configuration)}}|
> |{{DefaultLoaderService}} failing the deployment on a {{ServiceLoader}} 
> error|a broken provider is skipped with a warning, an unreadable service file 
> fails the lookup|
> h3. Constraints for every ticket
> * Thread-safe. {{Providers}} is immutable after {{of()}}; providers are 
> stateless and thread-safe.
> * Application server compatible. No static caches of providers or class 
> loaders; the thread context class loader is used, falling back to the SPI's 
> class loader.
> * Native image friendly (OPENNLP-1954). Providers have a public no-arg 
> constructor, lookup uses no reflection, availability is checked at call time.
> * Existing models and descriptors keep loading. The class name path stays as 
> a fallback until the last ticket decides on its deprecation.
> * Adding a jar to the class path stays a code-trust decision, so an operator 
> can restrict which provider classes may be used at all 
> ({{opennlp.provider.<SPI FQN>.allowed}}), and a provider that is not allowed 
> or is disabled by class name is never instantiated.
> h3. Releases
> {{Provider}}, {{Providers}} and {{ProviderSpec}} ship in 3.0.0 together with 
> OPENNLP-1937, so the types are frozen from that release on. The follow-ups 
> target 3.1.0 and must get by with additions: a new SPI sub-interface per 
> service interface, and for nested feature generators an own {{create}} 
> overload on that sub-interface.
> h3. Tickets, in merge order
> ||Ticket||Release||Scope||
> |OPENNLP-1972|3.0.0|{{Provider}}, {{Providers}}, {{ProviderSpec}}, resolution 
> exceptions, {{DocumentAnnotatorProvider}} with the stemmer as first provider|
> |OPENNLP-1937|3.0.0|{{TextEmbedder}} and {{TextEmbedderProvider}}, ONNX 
> provider in opennlp-dl|
> |OPENNLP-1967|3.1.0|{{ExtensionLoader}} bridge and trainer providers|
> |OPENNLP-1968|3.1.0|Feature generator providers and {{name}} in XML 
> descriptors|
> |OPENNLP-1969|3.1.0|Data indexers, sequence codecs, string interners, doccat 
> feature generators, entity linkers|
> |OPENNLP-1970|3.1.0|Tool factories and artifact serializers referenced from 
> model manifests|
> |OPENNLP-1971|3.1.0|CLI format factories|



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to