External configuration model

OpenHub framework extends Spring Boot externalized configuration model (version 1.4.3.RELEASE) - bold items represent custom extension in OpenHub framework:

  1. Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
  2. @TestPropertySource annotations on your tests.
  3. @SpringBootTest#properties annotation attribute on your tests.
  4. Command line arguments.
  5. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)
  6. ServletConfig init parameters.
  7. ServletContext init parameters.
  8. JNDI attributes from java:comp/env.
  9. Java System properties (System.getProperties()).
  10. OS environment variables.
  11. A RandomValuePropertySource that only has properties in random.*.
  12. Project specific configuration file "openhub.properties"
  13. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
  14. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
  15. Application properties outside of your packaged jar (application.properties and YAML variants).
  16. Application properties packaged inside your jar (application.properties and YAML variants).
  17. @PropertySource annotations on your @Configuration classes.
  18. Default properties (specified using SpringApplication.setDefaultProperties).
  19. Default properties from database

Project specific configuration file

There is specific properties file openhub.properties that overrides all other property files. 

Use this file if you need to set specific project configuration and override default values.

It's not possible to define spring.profiles.active property in openhub.properties file. But there are another ways how to tell Spring which profiles should be active.

Default properties from database

Storing properties

Properties are stored in the table configuration in DB. See Data model for more details about columns of this table.

New properties are inserted via SQL scripts as defined in application*.properties files:

# populate using data.sql
spring.datasource.initialize=false
# a data (DML) script resource reference
spring.datasource.data=classpath:/db/db_data-h2.sql,classpath:/db/db_data.sql,classpath:/db/db_init-configuration-h2.sql,classpath:/db/db_init-configuration.sql

Use db_init-configuration.sql or db_init-configuration-h2.sql if you need to add specific features (here H2 features).

Example from db_init-configuration.sql:

--
-- core.throttling
--

-- true for disabling throttling at all
INSERT INTO configuration (code, category_code, current_value, default_value, data_type, mandatory, validation)
    VALUES('ohf.throttling.disable', 'core.throttling', 'false', 'false', 'BOOLEAN', true, null);

Getting properties

Properties defined in database have the lowest priority in Spring Boot externalized configuration model. Therefore these properties represent default values.

All property names are defined in org.openhubframework.openhub.api.configuration.CoreProps

Database properties are necessary for OpenHub configuration running in the Cluster.

If you need to have one place for adding/administrating a configuration parameter common for all cluster nodes then database has to be used. Furthermore you can change parameter values on the fly (if implementation that use specific parameter can get current value anytime the parameter is used).

Use @ConfigurableValue and ConfigurationItem for defining wrapper for getting (up-to-date) parameter values:

@ConfigurableValue(key = "ohf.asynch.countPartlyFailsBeforeFailed")
private ConfigurationItem<Integer> countPartlyFailsBeforeFailed;

@ConfigurableValue(key = "ohf.server.localhostUri")
private ConfigurationItem<String> localhostUri;

ConfigurationItem offers simple API for getting final parameter value:

  • getValue()
  • getValue(defaultValue)

@Value vs @ConfigurableValue:

  • it's preferable to use @ConfigurableValue because it has two underlying advantages:
    • everytime you call getValue() you get up-to-date value (@Value is processed only once during post-processing phase). If you have configuration parameter in database then you can change behavior on the fly.
    • full use of Spring Boot externalized configuration model because properties are getting via Enviroment interface.

Note: Configuration values are cached by Cache, see Hazelcast and "config_params" data structure. In other words you should clear the cache to get new value when you change it.

There can be null/empty parameter value (that is optional) and it can be problem to convert null/empty value to target data type. For example:

@ConfigurableValue(key = "ohf.asynch.externalCall.skipUriPattern")
private ConfigurationItem<Pattern> skipOperationUriList;

If parameter ohf.asynch.externalCall.skipUriPattern is empty then it ends with the following expcetion: java.lang.IllegalArgumentException: Cannot convert value [] from source type [String] to target type [Pattern]

In these scenarious is better to use String as target data type and compile Pattern by yourselve.

@ConfigurableValue(key = "ohf.asynch.externalCall.skipUriPattern")
private ConfigurationItem<String> skipOperationUriList;

Implementation

Implementation classes are in the package org.openhubframework.openhub.core.configuration:

  • DbPropertySource - database property source
  • DbExternalPropertiesAutoConfiguration - adds DbPropertySource
  • DbConfigurationParam - entity represents one configuration parameter in database
  • Conversion to target data type uses Spring conversion model via org.springframework.core.convert.ConversionService


There is application-test-default.properties file in core module that contains default values for unit tests.

Why? If OpenHub runs in production mode then default values are taken from database but not all unit tests are using database. Therefore default values in the file are useful.