OSGi bundles with Sling-Initial-Content do not work properly on AEMaaCS

Update from 2023: This workaround is no longer required and can be removed. During the Cloud Manager deployment Sling-Initial-Content is extracted from the bundles automatically and deployed separately.

Overview

In wcm.io, all modules are shipped as OSGi bundle jar files. Most of them also have some application content to be deployed to /apps, contained as Sling-Initial-Content as part of the bundle (see Sling JCR Content Loader). This pattern is also applied when the wcm.io Maven Archetype for AEM is used and the parameter optionSlingInitialContentBundle is activated.

Bundles like this are working fine in AEMaaCS deployment. Their application content gets extract during the “Build Images” step of the cloud manager deployment pipeline and is then part of the read-only part of the content repository baked into the docker image. On first startup after deployment a “This builder is read-only” error message is logged, but this can be safely ignored.

at org.apache.jackrabbit.oak.spi.state.ReadOnlyBuilder.unsupported(ReadOnlyBuilder.java:44) [org.apache.jackrabbit.oak-store-spi:1.24.0] at org.apache.jackrabbit.oak.spi.state.ReadOnlyBuilder.setChildNode(ReadOnlyBuilder.java:200) [org.apache.jackrabbit.oak-store-spi:1.24.0] at org.apache.jackrabbit.oak.core.SecureNodeBuilder.setChildNode(SecureNodeBuilder.java:314) [org.apache.jackrabbit.oak-core:1.24.0] at org.apache.jackrabbit.oak.plugins.tree.impl.AbstractMutableTree.addChild(AbstractMutableTree.java:75) [org.apache.jackrabbit.oak-core:1.24.0] at org.apache.jackrabbit.oak.core.MutableTree.addChild(MutableTree.java:199) [org.apache.jackrabbit.oak-core:1.24.0] at org.apache.jackrabbit.oak.plugins.tree.TreeUtil.addChild(TreeUtil.java:253) [org.apache.jackrabbit.oak-security-spi:1.24.0] at org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate.addChild(NodeDelegate.java:690) [org.apache.jackrabbit.oak-jcr:1.24.0] at org.apache.jackrabbit.oak.jcr.session.NodeImpl$5.perform(NodeImpl.java:314) [org.apache.jackrabbit.oak-jcr:1.24.0] at org.apache.jackrabbit.oak.jcr.session.NodeImpl$5.perform(NodeImpl.java:280) [org.apache.jackrabbit.oak-jcr:1.24.0] at org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.perform(SessionDelegate.java:207) [org.apache.jackrabbit.oak-jcr:1.24.0] at org.apache.jackrabbit.oak.jcr.session.ItemImpl.perform(ItemImpl.java:112) [org.apache.jackrabbit.oak-jcr:1.24.0] at org.apache.jackrabbit.oak.jcr.session.NodeImpl.addNode(NodeImpl.java:280) [org.apache.jackrabbit.oak-jcr:1.24.0] at org.apache.sling.jcr.contentloader.internal.BundleContentLoader.getTargetNode(BundleContentLoader.java:606) [org.apache.sling.jcr.contentloader:2.3.0] at org.apache.sling.jcr.contentloader.internal.BundleContentLoader.installContent(BundleContentLoader.java:235) [org.apache.sling.jcr.contentloader:2.3.0] at org.apache.sling.jcr.contentloader.internal.BundleContentLoader.registerBundleInternal(BundleContentLoader.java:148) [org.apache.sling.jcr.contentloader:2.3.0] at org.apache.sling.jcr.contentloader.internal.BundleContentLoader.registerBundle(BundleContentLoader.java:95) [org.apache.sling.jcr.contentloader:2.3.0] at org.apache.sling.jcr.contentloader.internal.ContentLoaderService.activate(ContentLoaderService.java:244) [org.apache.sling.jcr.contentloader:2.3.0] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.apache.felix.scr.impl.inject.methods.BaseMethod.invokeMethod(BaseMethod.java:228) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.inject.methods.BaseMethod.access$500(BaseMethod.java:41) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.inject.methods.BaseMethod$Resolved.invoke(BaseMethod.java:664) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.inject.methods.BaseMethod.invoke(BaseMethod.java:510) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.inject.methods.ActivateMethod.invoke(ActivateMethod.java:317) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.inject.methods.ActivateMethod.invoke(ActivateMethod.java:307) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.SingleComponentManager.createImplementationObject(SingleComponentManager.java:340) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.SingleComponentManager.createComponent(SingleComponentManager.java:114) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:982) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.SingleComponentManager.getServiceInternal(SingleComponentManager.java:955) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:765) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.DependencyManager$SingleStaticCustomizer.addedService(DependencyManager.java:1045) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.DependencyManager$SingleStaticCustomizer.addedService(DependencyManager.java:999) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.ServiceTracker$Tracked.customizerAdded(ServiceTracker.java:1216) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.ServiceTracker$Tracked.customizerAdded(ServiceTracker.java:1137) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.ServiceTracker$AbstractTracked.trackAdding(ServiceTracker.java:944) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.ServiceTracker$AbstractTracked.track(ServiceTracker.java:880) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.manager.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:1168) [org.apache.felix.scr:2.1.16] at org.apache.felix.scr.impl.BundleComponentActivator$ListenerInfo.serviceChanged(BundleComponentActivator.java:125) [org.apache.felix.scr:2.1.16] at org.apache.felix.framework.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:990) at org.apache.felix.framework.EventDispatcher.fireEventImmediately(EventDispatcher.java:838) at org.apache.felix.framework.EventDispatcher.fireServiceEvent(EventDispatcher.java:545) at org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4833) at org.apache.felix.framework.Felix.registerService(Felix.java:3804) at org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:328) at org.apache.sling.jcr.base.AbstractSlingRepositoryManager.registerService(AbstractSlingRepositoryManager.java:218) [org.apache.sling.jcr.base:3.1.0] at org.apache.sling.jcr.base.AbstractSlingRepositoryManager.initializeAndRegisterRepositoryService(AbstractSlingRepositoryManager.java:541) [org.apache.sling.jcr.base:3.1.0] at org.apache.sling.jcr.base.AbstractSlingRepositoryManager.access$300(AbstractSlingRepositoryManager.java:92) [org.apache.sling.jcr.base:3.1.0] at org.apache.sling.jcr.base.AbstractSlingRepositoryManager$4.run(AbstractSlingRepositoryManager.java:496) [org.apache.sling.jcr.base:3.1.0]

Having this error message is not nice, also the AEM Anaylser Maven Plugin is complaining about bundles using Sling-Initial-Content. A long-term solution is discussed in the Sling Mailing List and SLING-10243 as probable long-term solution. For the time being we have to live with the current situation.

Problem

However, since March 2021 AEM client libraries that are contained as Sling-Initial-Content and that registered to built-in client library categories that allow to hook into AEM page editor and edit dialogs like cq.authoring.dialog , cq.authoring.editor.hook fail to work after deployment (see WTOOL-72).

The problem is that those client libraries are pre-generated during the “Build Images” step, and this ignores the client library additions contained in the Sling-Initial-Content parts of OSGi bundles. As a result, certain wcm.io features cease to work, e.g. the custom link plugin for RTE, the custom file upload widget for Media Handler.

The following wcm.io Modules are affected:

Solution

Until a long-term solution like SLING-10243 is in place (which would fix the problem automatically) you can apply a workaround and deploy the content-part of the OSGi bundles separately as content package. To make this easy, recent releases of wcm.io modules additionally provide a content package containing the Sling-Initial-Content file accessible via a classifier.

Example:

1. Define additional dependency for content package with “content” classifier

<dependency> <groupId>io.wcm</groupId> <artifactId>io.wcm.handler.link</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>io.wcm</groupId> <artifactId>io.wcm.handler.link</artifactId> <classifier>content</classifier> <type>zip</type> <version>1.6.2</version> </dependency>

2. Include this package content package in your deployment, e.g. if you are using CONGA add this dependency to the config-definition POM:

<dependency> <groupId>io.wcm</groupId> <artifactId>io.wcm.handler.link</artifactId> <classifier>content</classifier> <type>zip</type> <scope>compile</scope> </dependency>

3. And add in the CONGA role:

Repeat this for all affected wcm.io modules.

Apply solution to your own project

If you want to apply the same solution of splitting up an OSGi bundle with Sling-Initial-Content to your own project, you can make use of the Sling-Initial-Content Transformation Maven Plugin.

Declare this in your project’s parent POM, and it is applied to all bundles in the project:

This plugin produces two additional files and attaches them with classifiers to the artifact:

  • bundle: OSGi bundle without the Sling-Initial-Content

  • content: Content packages with the Sling-Initial-Content transformed to FileVault

The original JAR files the project produces remains untouched, so it still contains the Sling-Initial-Content.

It is possible to use the JAR files with the bundle classifier as alternative to the original JAR file and consequently deploying bundle and application content separately to get rid of the “This builder is read-only” error message mentioned above. But this is at least for the wcm.io modules not feasible, as we have to keep the original JAR files including the Sling-Initial-Content intact for backward compatibility, also for on-premises installations of AEM using AEM 6.5 and older which do not require these extra steps. The bundles have compile dependencies to each other, so you always get a mixture of bundles with and without bundle classifier and probably duplicates bundles if you do not manually exclude all dependencies.

Hopefully, all this is only a temporary workaround.