So far we have not had any way to configure our system other than directly modifying code, which generally is not an elegant way.
The Eclipse Dataspace Connector exposes configuration through its ConfigurationExtension
interface. That is a "
special" extension in that sense that it gets loaded at a very early stage. There is also a default implementation
named FsConfigurationExtension.java
which uses a standard Java properties file to store configuration entries.
In the previous steps we had not included that in the JAR file, so we need to add
the :extensions:common:configuration:configuration-filesystem
module to the dependency list:
dependencies {
// ...
implementation(project(":extensions:common:configuration:configuration-filesystem"))
// ...
}
We compile and run the application with:
./gradlew clean samples:03-configuration:build
java -jar samples/03-configuration/build/libs/filsystem-config-connector.jar
you will notice an additional log line stating that the "configuration file does not exist":
INFO 2021-09-07T08:26:08.282159 Configuration file does not exist: dataspaceconnector-configuration.properties. Ignoring.
By default, the FsConfigurationExtension
expects there to be a properties file
named dataspaceconnector-configuration.properties
located in the current directory. The name (and path) of the config
file is configurable using the edc.fs.config
property, so we can customize this to our liking.
First, create a properties file in a location of your convenience,
e.g. /etc/eclipse/dataspaceconnector/config.properties
.
mkdir -p /etc/eclipse/dataspaceconnector
touch /etc/eclipse/dataspaceconnector/config.properties
Second, lets reconfigure the Jetty Web Server to listen to port 9191
instead of the default 8181
. Open
the config.properties
with a text editor of your choice and add the following line:
web.http.port=9191
An example file can be found here. Clean, rebuild and run the connector again, but this time passing the path to the config file:
java -Dedc.fs.config=/etc/eclipse/dataspaceconnector/config.properties -jar samples/03-configuration/build/libs/filsystem-config-connector.jar
Observing the log output we now see that the connector's REST API is exposed on port 9191
instead:
INFO 2022-04-27T14:09:10.547662345 HTTP context 'default' listening on port 9191 <-- this is the relevant line
DEBUG 2022-04-27T14:09:10.589738491 Port mappings: {alias='default', port=9191, path='/api'}
INFO 2022-04-27T14:09:10.589846121 Started Jetty Service
Let's say we want to have a configurable log prefix in our health REST endpoint. The way to do this involves two steps:
- add the config value to the
config.properties
file - access and read the config value from code
Simply add a new line with an arbitrary key to your config.properties
:
edc.samples.03.logprefix=MyLogPrefix
The ServiceExtensionContext
exposes a method getSettings(String, String)
to read settings (i.e. config values)'.
Modify the code from the HealthEndpointExtension.java
as shown below (use the one from the samples/03-configuration
of course):
public class HealthEndpointExtension implements ServiceExtension {
@Inject
WebService webService;
private static final String LOG_PREFIX_SETTING = "edc.samples.03.logprefix"; // this constant is new
@Override
public void initialize(ServiceExtensionContext context) {
var logPrefix = context.getSetting(LOG_PREFIX_SETTING, "health"); //this line is new
webService.registerResource(new HealthApiController(context.getMonitor(), logPrefix));
}
}
Next, we must modify the constructor signature of the HealthApiController
class and store the logPrefix
as variable:
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Path("/")
public class HealthApiController {
private final Monitor monitor;
private final String logPrefix;
public HealthApiController(Monitor monitor, String logPrefix) {
this.monitor = monitor;
this.logPrefix = logPrefix;
}
@GET
@Path("health")
public String checkHealth() {
monitor.info(String.format("%s :: Received a health request", logPrefix));
return "{\"response\":\"I'm alive!\"}";
}
}
There are a few things worth mentioning here:
- things like configuration value names should be implemented as constants, e.g.
LOG_PREFIX_SETTING
and should have a consistent and hierarchical naming scheme - if a config value is not present, we should either specify a default value (i.e.
"health"
) or throw anEdcException
- configuration values should be handled in the
*Extension
class, as it's job is to set up the extension and its required business logic (e.g. the controller). The extension itself should not contain any business logic - it's better to pass the config value directly into the business logic than passing the
entire
ServiceExtensionContext
, using configuration objects when there are more than one
Part of most connectors will be the management api defined in the
:extensions:control-plane:api:management-api
module. Therefore, we need to add the following
module to the dependency list in our build.gradle.kts
:
dependencies {
// ...
implementation(project(":extensions:control-plane:api:management-api"))
// ...
}
As described in the README.md of the api-configuration module, the management api should be exposed on a separate jetty context. Therefore, it is necessary to provide the following configuration to the connector:
Note: The ports could be chosen arbitrarily. In this example, they are aligned to the already existing
web.http.port
setting described above.
web.http.port=9191
web.http.path=/api
web.http.management.port=9192
web.http.management.path=/api/v1/management
Caution: If you do not provide this configuration, it leads to the problem that the authentication mechanism is also applied to EVERY request in the default context of Jetty, which includes the IDS communication between two connectors.