Extension Model
1. Extension basics
Three things are needed to register an extension module with the EDC runtime:
- a class that implements
ServiceExtension
- a provider-configuration file
- adding the module to your runtime’s build file. EDC uses Gradle, so your runtime build file should contain
runtimeOnly(project(":module:path:of:your:extension"))
Extensions should not contain business logic or application code. Their main job is to
- read and handle configuration
- instantiate and register services with the service context (read more here)
- allocate and free resources, for example scheduled tasks
2. Autodoc and Metamodel Annotations
EDC can automatically generate documentation about its extensions, about the settings used therein and about its extension points. This feature is available as Gradle task:
./gardlew autodoc
Upon execution, this task generates a JSON file located at build/edc.json
, which contains structural information about
the extension, for example:
Autodoc output in edc.json
[
{
"categories": [],
"extensions": [
{
"categories": [],
"provides": [
{
"service": "org.eclipse.edc.web.spi.WebService"
},
{
"service": "org.eclipse.edc.web.spi.validation.InterceptorFunctionRegistry"
}
],
"references": [
{
"service": "org.eclipse.edc.web.spi.WebServer",
"required": true
},
{
"service": "org.eclipse.edc.spi.types.TypeManager",
"required": true
}
],
"configuration": [
{
"key": "edc.web.rest.cors.methods",
"required": false,
"type": "string",
"description": "",
"defaultValue": "",
"deprecated": false
}
// other settings
],
"name": "JerseyExtension",
"type": "extension",
"overview": null,
"className": "org.eclipse.edc.web.jersey.JerseyExtension"
}
],
"extensionPoints": [],
"modulePath": "org.eclipse.edc:jersey-core",
"version": "0.8.2-SNAPSHOT",
"name": null
}
]
To achieve this, the EDC Runtime Metamodel defines several annotations. These are not required for compilation, but they should be added to the appropriate classes and fields with proper attributes to enable good documentation. For detailed information please read this chapter.
Note that @Provider
, @Inject
, @Provides
and @Requires
are used by Autodoc to resolve the dependency graph for
documentation, but they are also used by the runtime to resolve service dependencies. Read more about that
here.
3. Configuration and best practices
One important task of extensions is to read and handle configuration. For this, the ServiceExtensionContext
interface
provides the getConfig()
group of methods.
Configuration values can be optional, i.e. they have a default value, or they can be mandatory, i.e. no default
value. Attempting to resolve a mandatory configuration value that was not specified will raise an EdcException
.
EDC’s configuration API can resolve configuration from three places, in this order:
- from a
ConfigurationExtension
: this is a special extension class that provides aConfig
object. EDC ships with a file-system based config extension. - from environment variables:
edc.someconfig.someval
would map toEDC_SOMECONFIG_SOMEVAL
- from Java
Properties
: can be passed in through CLI arguments, e.g.-Dedc.someconfig.someval=...
Best practices when handling configuration:
- resolve early, fail fast: configuration values should be resolved and validated as early as possible in the
extension’s
initialize()
method. - don’t pass the context: it is a code smell if the
ServiceExtensionContext
is passed into a service to resolve config - annotate: every setting should have a
@Setting
annotation - no magic defaults: default values should be declard as constants in the extension class and documented in the
@Setting
annotation. - no secrets: configuration is the wrong place to store secrets
- naming convention: every config value should start with
edc.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.