Recently I was working on an AEMaaCS migration. I was dealing with tons of deprecated Java APIs. One was org.apache.sling.engine.SlingSettingsService. I went straight into the commit history for the Sling Engine project. And I fished out a reference to SLING-1460. It looked simple enough. Switch to the new interface.
So I began switching to the new interface, org.apache.sling.settings.SlingSettingsService. But my IDE was still screaming deprecation! I checked the source code on GitHub. It was not marked as deprecated. And if you are referencing the AEM 6.5 API, everything is fine!
I was referencing the AEM SDK. So I went to its JavaDoc. It says:
⚠️ AEM as a Cloud Service does not support run modes or file system access at runtime.
And it got deprecated on October 5th, 2020. Since the project on GitHub had no such change, I resorted to a Google search with the only clues I had. "SlingSettingsService 2020-10-05". I read through some of the results. And I stumbled on issue #528 from the AEM Project Archetype. So even though the SlingSettingsService makes sense on-prem, it does not on cloud!
No Custom Run Modes on AEMaaCS
In the weeks leading up to the start of the project, I had run the Best Practices Analyzer. And I had made a note of the URC errors. So now it made sense that this API would get deprecated on the cloud service, but not on 6.5.
In fact, I have known that checking run modes at runtime was a bad practice. I learned this a few years ago when I read a blog post by Carsten Ziegeler: The Truth about AEM Run Modes. You'll notice his name comes up in the archetype issue #528.
Lets go through some of the common scenarios you may find in which checking run modes gets done at runtime. And how to change your code so that it doesn't.
The Ubiquitous If/Else
The thing I see the most is "if on author, do this. Otherwise do that". For example one thing that comes to mind is default values shown to content author in a Sling model. For example
The intention is obvious. If a component property has not been set, prompt the author to enter one. Removing the check on the run mode can get done several ways.
The second thing that comes to mind is to do it in HTL. And check the WCM mode instead of the run mode
And finally another option would be to switch to the WCM mode check in Java
The other thing I see a lot of are OSGi components that behave in a different way on author vs publish. If they have a reference to the user's Sling request, the WCM mode might be an option. But this is not always the case. Some notorious examples are Sling jobs, event handlers and resource change listeners.
Imagine an event handler that updates a search index every time a page gets activated. It makes sense that it would run on the author service only. This is the type of thing I see
By default the component will remain inactive. And to activate it on author, create an OSGi configuration file in the config.author run mode. Even if you don't have any properties, an empty JSON object will work.
OSGi Bundles & Content Packages
I am going to use the example above, and take it to the next level. Istead of activating OSGi components on a run mode, lets activate an entire bundle.
Lets say I have a core set of OSGi components for a specific feature. For example servlets, event handlers and services that deal with search indexing. And they only run on the author service. So lets create a new bundle called mysite.search.
And like the core bundle, I embed it into the all content package
Notice the .publish run mode suffix. This will cause the JCR Installer to skip the bundle if it does not match the current run mode.
And this is not limited to bundles. It can ge entire content pacakges. For example, the Groovy Console. This tool is usually deployed on author service only. As with the bundle, append .author on the embed target
Up until now we have been dealing with the system run modes which are author and publish. These are constant on both cloud and on-prem. But what about custom environment run modes? For example dev, qa, stage, prod. Or any number of variations we may have come up with to suit our needs?
Unfortunately, AEMaaCS supports an exact set of run modes which are rde, dev, stage or prod. So what are you going to do if you need a qa or uat? Or a second development environment. One that used to develop and test an upgrade to the backend systems.
You might want to take a look at cloud manager environment variables. Lets use this example. We have a development environment. This is where our develop branch gets deployed every time a PR gets merged. At the same time, we have a second team developing and testing a back-end system upgrade. So if we are on-prem, we could have the dev and devupgrade environment run modes. But on cloud, if we spin up two development environments, they will have the same dev run mode.
Here is a sample servlet that integrates with a back-end search API
And this is its OSGi R7 declarative configuration
We can create this OSGi JSON config file. And save in the config.dev folder which is the run mode used by development environments.
Here we are using the environment-specific and secret value placeholders. These are set in the environment configuration dialog. And now the service can operate in one or more development type environments. For example, search.service.url will be
With access to the SlingSettingsService, developers have fallen into a bad practices. In this case, checking the run mode at runtime. Now Adobe is trying to enforce best practices.
I can't come up with every possible scenario you may encounter. Here I have outlined the tools that will help you get rid of custom run modes. And align with the set supported by AEMaaCS. Use the WCM mode to detect if you are on author. Use the configuration policy to activate OSGi components in specific run modes. Leverage the run mode support of the JCR installer. And use the cloud manager environment variables.