Every application needs to read env specific or tuneable config parameters.
The only way to do this is OSGi configs.
Finding an end to end example of creating config variables (not via UI on a specific instance, but in code in git so it can be deployed to other envs), is difficult.
There seem to be two types of post on the subject:
those going into the JAVA code on creating OSGi services, requiring creating, understanding and debugging hundreds, if not thousands, of lines of java code to read a hand full of variables. The problem with this approach is there is no way to set the variables before hand, and setup env specific values in git which can be deployed. e.g. this post: https://aem.redquark.org/2018/10/day-12-creating-your-custom-osgi.html
But not which files (and paths) any of these are actually done in, and how an application (e.g a servlet, or a page) might read these values.
I have not yet found a way to set a config value anywhere, and read it, other than the complex route of writing a dedicated OSGi service in Java, which is a lot of work, can only be used by a single "service" java class (not several classes or globally), an doesn't have a way to do distribute env specific vars via code (only can set them manually after deployment to a specific env)
I am missing the tutorial which brings all this together.
What I understand from your question (and your other thread) is that you are missing the link between the OSGI service and its according configuration (residing inside the OSGI context) on the one hand and the configuration files/nodes in the repository on the other hand. Correct?
I’m not aware of a tutorial on this (maybe I’ll take this as a motivation to write one ;-), but I’ll try to outline the concept:
On the one hand you have the OSGI service that needs to be configured. You define certain properties and annotate them accordingly. There are already a couple of links and examples in this thread and it sounds like you already went through them. This part is self-contained. As soon as you have your service up and running, you can configure it through the web console UI and your service can use the configured values. A simple service does not need that much boilerplate, a functioning skeleton can be done with < 100 lines of Java code. (I will refer to an example below.)
The second part is about providing configurations to the service without using the web console.
The first level of abstraction here is that you can create a specific node within AEMs CRX repository (jcr:primaryType should be set to “sling:OsgiConfig”). Usually, you place such a node below /apps/yourproject/config/ (for global configurations). Propagation to the OSGI context will be handled automatically for you based on the node name: it should start with the OSGI service’s PID (so basically the class name, e. g. “com.day.cq.commons.impl.ExternalizerImpl” for one of AEMs OOTB services).
This is where run modes and environment specifics come into play. The name of the folder can be mapped to the run mode of your instance. So if you place a certain config in the “/apps/yourproject/config” folder, it will always be applied. If you place it into a folder named “config.author” it will only be applied if the instance has the “author” run mode. And so on. Please note: you will always deploy _all_ the configurations and folders to all you environments, but the once with irrelevant run modes will just not be applied and not be propagated to the OSGI context. They stay inactive in your CRX repository.
You can now add your configuration nodes to your AEM Maven project and deploy them through the regular process. They will be stored in the repository and propagated to the OSGI context.
If you need examples for the above, you may want to check the AEM Maven Archetype . It will generate a full AEM Maven project structure for you that already contains some basic examples. You will find a very simple scheduler service skeleton in the “schedulers” package of the “core” module that is configurable through the OSGI context (although it’s just the implementation of the Runnable interface; so to be fair: for a full custom service that can not be based on an existing interface you will need some more code to implement your own one). There is a dedicated Maven module (“config”) that holds all configurations for the generated project. It also comes with a couple of example configs, e .g. the project-specific logger configs.
Hopefully, my explanations combined with the examples make the mechanism a bit clearer to you.