The Context-Aware Configuration Editor
You might be looking to create your own custom context-aware configurations. Or you might be dealing with existing ones like those for the WCM core components. Either way, they are not very author friendly. An admin has to create and replicate content nodes under /conf/mysite.
Luckily, the wcm.io CA Config Editor allows content authors to help themselves. It is open source and well documented. Yet, I found the initial setup instructions a little hard to follow. In this blog I aim to streamline the process to help you get up and running. And explain a few things along the way.
Create An Annotation Class
The archetype project configures the bnd-maven-plugin to use the ConfigurationClassScannerPlugin. This will generate the Sling-ContextAware-Configuration-Classes header in your bundle. It will contain a list of all the annotation classes.
Test the Annotation Class
The archetype project sets up the wcm.io mocking framework. Setting up a unit test is simple. The goal of a unit test is to ensure that the context aware config resource gets mapped to the annotation class. Here is the unit test. I will point out the key points.
First, the test sets up the AEM context with the ContextPlugins.CACONFIG plugin. It is important because it adds all the services needed to read and write configurations.
The test also sets up some sample content. /content/mysite has the property sling:configRef. This is for the DefaultContextPathStrategy. It is one of the services added by the plugin.
Testing With The New Path Strategy
It is important to test your code. It is reasonable to assume that when you are using third-party software, they have done the same. So you need not test theirs. But if you want to avoid having to manage the sling:configRef property, use a path strategy.
The only difference form the first unit test is that I no longer set the sling:configRef property. And I register the absolute path strategy using a static helper. This static helper only allows you to set the levels. If you want to set the other settings, take a look at the source code. And don't use this helper. If you do want to use this helper you will need to add this dependency.
Install The Extensions
Try to resolve the annotation class using the Context-Aware console in Felix. For example, set the context path as /content/mysite/us/en. It will try to find one under /conf/mysite.
The archetype project will create a content path at /conf/mysite/sling:configs. And it sets the sling:configRef on /content/mysite/jcr:content to point to this path. The default path strategy will use this property. The problem is that it is a very flat structure. ALL configurations for the site will get stored there. You can change the value of sling:configRef at different levels. But this will become impractical as the number of sites, countries and languages grow.
Then embed it with the filevault-package-maven-plugin.
Enable the absolute parents strategy by adding an OSGi JSON config file named io.wcm.caconfig.extensions.contextpath.impl.AbsoluteParentContextPathStrategy~mysite.cfg.json. Its OSGi declarative config already has defaults for its other properties.
Testing the resolution in the Felix console now yields a new set of configuration paths. These track the content hierarchy, using levels 2 & 3. The country and language levels.
The extension package installs a few other things, including two persistence strategy services. I will cover these in the next sections.
Install The Editor
So far you have created a configuration annotation class. You have created a content node under /conf/mysite. And the configurations get resolved based on the site structure. Creating, updating and replicating that config content is an administrative task. The wcm.io Context-Configuration Editor fills in this gap.
Install the editor package by adding the dependency in all/pom.xml file. The same embed statement from before should embed it.
Once installed, you will find that the application at /apps/wcm-io/caconfig/editor. There you will find a static template under templates/editor. Copy this template to your own application i.e. /apps/mysite/templates/editor.
It would look like this. Make sure you do NOT set the allowedTemplates property.
Instead you will add /apps/mysite/templates/.* to the list of allowed templates to your site root.
You should be able to create an instance of an editor page at any level within your sites content tree. You will see that the editor page will save the configuration content to /conf/mysite. When you click the Publish button on the editor, the editor page gets published. But not the actual config content. We need to change the way the content gets persisted so that it get detected and published.
Don't forget to disable the editor on the publish instance. To do this, create an OSGi config named io.wcm.caconfig.editor.impl.EditorConfig.cfg.json. Save it in the config.publish folder.
Enable Page Persistence
You know how AEM prompts you to publish the related content every time you publish a page? That lookup gets done by reference providers. And there are a lot of them. Use this filter in the service console: (objectClass=com.adobe.granite.references.ReferenceProvider).
Among those you will find the one installed by the extensions package. You can find its source code here. That service gets enabled by default. But it requires that configurations get persisted as AEM pages.
You will need to enable one of the two persistence strategies available. The AEM Page strategy. Create an OSGi config named io.wcm.caconfig.extensions.persistence.impl.PagePersistenceStrategy.cfg.json. Save it in the config.author folder.
Now when you create a config in the editor, it will be persist it as an AEM page. The references will get detected when you click on the Publish button on the editor page.
When I first learned of context-aware configuration some 5 years ago, I did not see the benefits. At the time, static templates and custom page components were the norm. And editable templates were still a novelty.
If I needed to associate content to configuration, I would stick it in the page properties. And use an InheritanceValueMap to traverse the path up the tree. Or use a Sling model injector like the Hierarchical Page Property Injector.
Custom page components and static templates are becoming a thing of the past. Replaced by editable templates, content policies and context-aware configuration.
The one missing feature for context-aware has been authoring. The wcm.io editor fills this gap. It empowers content authors to update and publish context-aware configurations. And it decouples the content from the configuration. Something you could never achieve with page properties.