Sling Context-Aware configuration (part 7): A conclusion

This the part 7 of my small series on Sling Context-Aware configuration, and probably the final posting of it. Time for a conclusion.

CAC adresses a need I often see in projects: having configuration which is neither OSGI config nor “real”content, but something in between. Something a super-author is supposed to work with, which can be changed on runtime without the need to have admin privileges. And it solves these requirements quite well.

The design is elegant and extensible, the API easy to use (of course the documentation could be improved, but that’s probably something which every opensource project could benefit from. And the fact, that there is the wcm.io toolbox which adds even more functionality is absolutely great; thanks Stefan and team!

The only problem I see is AEM itself. The fact that you need to add a thirdparty software to write the configuration in a way that it can be integrated into the workflow is something one can question. I would expect that AEM offers this capability out of the box. And when we are it, I would hope that the use of CAC within the product itself will increase over time.

But besides that, it’s an overall cool thing. Finally a good way to get rid of these homegrown administration frameworks. Enjoy Sling Context Aware Configuration!

Sling Context-Aware configuration (part 6): replicate CA-Config

In the last blog posts we solely focused on the authoring case, where an author edits content and config. But I haven’t discussed yet how this CA-Config gets to the publish. As such config can be changed on the fly by authors, we cannot rely on deployment processes, but it has to fit into regular processes triggered and monitored by regular users.

And to make this happen, we will use an out-of-the-box functionality of AEM, replication. Replication is limited from an UI perspective to assets and pages, and we don’t want to change that for config.
That means, that we have to wrap all config into a cq:Page to make that work. Unfortunately Sling does not know anything about AEM pages and their structure (the page node and the jcr:content node), thus writing the configuration into an AEM page is not possible (since AEM 6.3 reading from pages is supported).

Fortunately the wcm.io toolbox can help us here as well. With the optional “PagePersistenceStrategy” ) you can read and write the configuration in the jcr:content node of the page. The code for is part of the “caconfig.extension” package and should be deployed into AEM, and then a OSGI configuration for io.wcm.caconfig.extensions.persistence.impl.PagePersistenceStrategy needs to be set (enabled=true).

(I udated my github project on ca-config and added all relevant pieces, you just need to enable the configuration for this service in the ui.apps module; I left it turned off so it does not break the functionality I outlined in earlier posts).

But how does this help us here? The problem are the references to the configuration; when you activate a page by default AEM wants to activate also all referenced pages and assets of the page which are not yet activated. But if a reference to a simple node is not considered and never listed.
But this does only work for directly referenced pages. If change a page, and its parent holds the sling:configRef node, the simple ReferenceSearch functionality of AEM does not help. But for this there is a custom ReferenceSearchProvider by wcm.io, which is turned on by default.

Now you have a chance to edit your configuration on author and then activate it afterwards. It’s still a bit clumsy, but at least mangeable as part of an authoring workflow.

And then I discovered a small feature, which has been recently added to the wcm.io Configuration Editor (version 1.3.0). The editor has now a “Publish this page” button, which claims to activate the configuration and all referenced CA Configurations. But unfortunately, it’s not working properly yet. But when it’s fixed, it can help a lot.

Why you need to start EnsureOakIndex manually

Struggling with new index definitions is one of the most … annoying actions I do in AEM development. Because dropping indexing definitions with contentpackages directly into /oak:index is always a bit problematic (you need to have set the property “reindex=true” in your package, and what happens if you deploy the same package twice? Reindexing starts again, although nothing has changed), I greatly improved the EnsureOakIndex functionality in ACS AEM Commons a while back. I needed a reliable and automated way to add indexes to a huge number of AEM instances. It works quite well and is able to handle our indexing modification requirements.

Today I got the “complaint” from one of my colleagues, that they always need to restart the bundle to start this feature. Well, there’s a good reason for it. And I already had to explain a few times, so I thought it’s a good idea to post it here.

A production deployment is typically time-critical. That means it should complete within a certain amount of time (typically within 1hour or so). If you add an index to the system and the reindexing for this new index is enforced immediately at deployment time, it can have a massive impact on the deployment itself and the time needed for it.That’s mostly because of the impact of reindexing on the overall system performance; and depending on the index and the repository size this can take from seconds to days.  That means that the immediate start of reindexing has a good chance to break your schedule. Therefor the indexes are not applied automatically. But you can always trigger it via JMX (search for “Ensure Oak Index”) to start the process of applying the changed index definitions.

But I understand, that this makes the handling of new indexes much more cumbersome for some people. If you interested in a (configurable) feature to apply new index definitions immediately, drop me a comment here or (better) raise a feature request on ACS AEM Commons Github page. Let’s see if we can make it happen 🙂

 

 

Sling Context-Aware configuration (part 5): thoughts on a production layout

In the past blog posts of this series I outlined some of the capabilities of the Sling Context-Aware configuration. I was focussing on the demo aspect of it, and ignored aspects of it which are relevant when we talk about the use of it in an production environment.

(Note: There is not too much experience using Sling CA Config in wider production use. In this blog post I discuss these based on my experience with the product I gained in many projects; and I assume that it will work. If you have different experience with, I am interested to hear from them!)

For example I placed the configuration editor in /content/ca-config/en/configuration-page, while the configuration itself was located somewhere in /conf. Also the WCM.io editor can only edit the configuration for the context it is located in; that means, that your editor at /content/ca-config/configuration-page cannot modify the configuration applicable to the content context /content/ca-config/en, but you have to have a dedicated configuration editor located in that context.

Let’s stick with /conf in this blog post . Every code and every user which needs to consume configuration has to have read access to /conf; and to make inheritance working, you have to have read access to the configuration you are inheriting from as well. Generally spoken, you need to provide read access to a large part of /conf to all users. Which is typically not a problem.

But if you want to prevent access to certain parts of /conf but still be able to use them as part of Context Aware Configuration you have to trick a bit.
Imagine the case, that you want to store password data for certain backend system in CA-Config. You want to make them read- and writable only to the group which administers this backend access, but not for other users. But nevertheless all users should be able to use this backend service.

In that case the best way is to hide the access to the backend system in an OSGI service which utilizes a service-user to access these CA-Config resource in /conf. Whenever an user access this backend system, he will utilize this service and its service-user to read the configuration, and therefor this region of /conf can be locked down.

In the next blog post I want to show you another aspect of “making CA-Config production ready”: Publishing configuration.

Sling Context-Aware Configuration (part 4) — using inheritance

Till now this series of blog posts has only worked with configuration which has been explicitly set. But when working in hierarchical systems (like the AEM content tree) it’s often useful when you can inherit things from a parent container/concept. That means, that a specific setting on a node has effect on a complete subtree below that node instead of just the single node.

And of course Inheritance works with CA-Config as well. For easier demonstration I updated the demo content at https://github.com/joerghoh/cqdump/tree/master/ca-config-example in a way, that we can edit the configuration at 3 different locations:

  • /contnet/ca-config/configuration.html
  • /content/ca-config/en/configuration.html
  • /content/ca-config/fr/configuration.html

We always use the WCM.io configuration editor I introduced in the last post.

For demo purposes I also created a new configuration “de.joerghoh.cqdump.caconfig.inheritance.InheritanceDemoConfig” (code). Be aware that the configuration editor only works when the Pojo classes for the configuration are properly annotated.

Ok, let’s get started.

Open the configuration at /contnet/ca-config/configuration.html, hit the “add” button at the top and select the “Configuration to demo the inheritance” configuration. Then change the value of the “aProperty” configuration, check the “enable property inheritance” box and press “Save”.

caconfig-inheritance-globallevel

You have created a configuration which should be inherited down to the other levels. Specifically we should be able to see it at /content/ca-config/en/configuration.html. So let’s check it.

caconfig-inheritance-locallevel

On a repository level only the property “sling:configPropertyInherit” has been added to /conf/ca-config/content/sling:configs/de.joerghoh.cqdump.caconfig.inheritance.InheritanceDemoConfig.

caconfig-inheritance-crxdeview

It is that simple to allow configuration inheritance. And there are many usecases where this can be useful.

If you look back, we can build this functionality also the InheritanceValueMap. But right now we only scratched the surface of the CA-Config functionality. But before we dig deeper into it, I will discuss some aspects of Sling CA-Config for production usecases.

Sling Context-Aware configuration (part 3): using a UI

In the last post I gave you a small tour how you can create your context-aware configuration. And you always used CRXDE Lite to do changes on your configuration. Which is ok for testing and during development, but as this configuration is made to be changed (otherwise we might have put it into OSGI, do you remember?), we need to provide a better way to do it. Something suited also for less-technical users.

Steffen Seifert (of the Adobe partner Pro!Vision) started the project wcm.io and contributed there a lot of interesting stuff and extensions for AEM. And they also developed an editor for CA-Config (http://wcm.io/caconfig/editor/index.html).

Ok, so let’s use it. The integration is very simple:

  • Add the dependency to the io.wcm.caconfig.editor.page package and add it as subpackage to your ui.apps package.
  • Add a static template which uses “wcm-io/caconfig/editor/components/page/editor” as resourceType.
  • And use this template.

(I added these steps to my github example code at https://github.com/joerghoh/cqdump/tree/master/ca-config-example).

When you open this page at /content/ca-config/en/configuration.html, you see all available configurations for this bucket and when you click on the configuration you can edit it (including saving back to the correct location in the repository).

 

 

 

 

Cases like “the user does not have the permission to write this configuration” are also handled gracefully.

So the WCM.io configuration editor gives you a nice way to let users edit configuration without using CRXDE Light.

In the next blog post I want to introduce configuration inheritance which can help you to reduce the amount of configuration work.

Sling Context-Aware configuration (part 2)

Update (April 30th, 2018): I changed the name of the configuration item to align with with future development. Next to this change I also added a few bugfixes in the git repo.

In the last 2 blog (1,2) posts I talked about why a more content-oriented and content-centric way to store configuration is useful. And I also described 2 scenarios in which CA-Config can actually be used. Now I want to demonstrate how Sling Context-Aware Configuration can actually be used.

Let’s take the example from last blog post: For the approval workflow we want to configure the approval group externally via Sling CA-Config, so it can be configured per subtree/page. I use AEM 6.3 here, but it should work with 6.2 as well.

In the next steps I will guide you through the steps required to implement these steps. For reference the complete project is available at https://github.com/joerghoh/cqdump/tree/master/ca-config-example.

  • Create a structure in /conf where you would like to store your configuration. In my example the content lives in /content/ca-config with the subites “en” and “fr”, and for /conf I choose /conf/ca-config/content/.
  • Create a property “sling:configRef” with the value “/conf/ca-config/content” at /content/ca-config/jcr:content/. This links your content to the configuration.

In the CA-Config lingua you created a configuration bucket at /conf/ca-config/content, which is referenced by /content/ca-config.

caconfig-configRefs

And that’s it. Now every lookup through Sling CA-Config will lookup there.

Now let’s create some code which is using such a configuration. I created a DynamicParticipant WorkflowStep named “CaConfigParticipantStepChooser“, which assigns the workflow to a group defined by CA-Config. As you can see there a POJO class “CaConfigParticipantStepChooserConfig” is used to store the config read from CA-Config.

caconfig-wfstep

When you run this code, it will try to lookup the config property “approverGroup” (which is derived from the field name in CaConfigurationParticipantStepChooserConfig), but it returns the default value “admin”, as we haven’t provided any configuration value yet.

Now let’s assume that this workflow step, if it is executed on content below /content/ca-config, should assign the workflow to the group “content-authors“. Create a folder “/conf/ca-config/content/sling:configs” and add a node with the name “de.joerghoh.cqdump.caconfig.workflow.CaConfigParticipantStepChooserConfig“; add the property “approverGroup” and set it to the value “content-authors“.

caconfig-configsetting

To validate this setting there is a small tool in the OSGI webconsole.

  • Goto localhost:4502/system/console/slingcaconfig (in the navigation it’s “Sling” => “Context-Aware Configuration”)
  • enter “/content/ca-config” as content path
  • Enter “de.joerghoh.cqdump.caconfig.workflow.CaConfigParticipantStepChooserConfig” as “Other config name”.
  • And press “OK”.

 

It will display that that for this configuration name a property “approverGroup” with the value “content-authors” can be resolved. Which is exactly what we want.

When you test the workflow now, the workflow will be assigned correctly to the “content-authors” group.

To demonstrate the flexibility of context-aware configuration, let’s create a new folder /conf/ca-config/content/fr/sling:configs, add a node “de.joerghoh.cqdump.caconfig.workflow.CaConfigParticipantStepChooserConfig” and add a property “approverGroup” with the value “contributors“. Additionally add the property”sling:configRef” with the value “/conf/ca-config/content/fr” to the /content/ca-config/fr page. When you start the workflow now on /content/ca-config/fr the workflow will be assigned to the contributors group. And of course this also works for every page below /content/ca-config/fr.

(An important remark here: The paths are choosen arbitrarily. Especially in /conf you are very flexible, and the structure there does not necessarily need to match the structure below /content. I just choose the same structure for a better understanding of this example, and for convenience reason I recommend you to do the same.)

Congratulations, you are now able to use Sling Context-Aware Configuration! You can now freely package /content to move it to another stage, and the per-stage approver groups do not need to be re-adjusted.

But to be honest, this is a very simple way, and it has some drawbacks:

  • You need to use CRXDE to maintain the properties in /conf.
  • The need to create sling:configRef nodes for all buckets.

Let’s try to address these topics another time, in the next blog post.