The core paradigm for the Java Content Repository (JCR), the repository for Adobe Experience Manager (AEM) is Everything is Content. This principal drives the flexibility which made AEM a market-leading solution. It does, however, come with a downside, managing the initial repository state is challenging since the repository state is a combination of the content, code and configuration for an AEM application.
Managing this initial state is important for developers and administrators to be able to stand up local instances, standing up new environments and keeping environments in sync.
Multiple teams have build parts of a solution to this problem, including:
- Netcentric Access Control Tool
- ACS AEM Commons Ensure Service User
- ACS AEM Commons Authorizable Packager
- Apache Sling Service User Web Console
- AEM Content Packages
Recently though, another solution has come to the fore for configuring the initial repository state.
Apache Sling RepoInit
Apache Sling RepoInit has been a feature of Apache Sling since 2016, but historically has been used for base repository initialization as a part of slingstart / launchpad starter, not for project-level repository initialization.
Version 1.1.6+ of Sling JCR RepoInit includes the ability for registering configurations with RepoInit scripts or references. This brings Apache Sling Repoint out from just being a base repository initializer to enable use by project teams.
With Sling Repoint, we have a consolidated grammar to:
- Create groups
- Assign permissions
- Create paths
- Set properties
- Assign group membership
- Create OSGi configurations
- Create service users
Enabling RepoInit in AEM
Note: this is based on AEM 6.5.5, newer service packs and AEM Cloud Service may have different dependency versions.
AEM includes a fairly old version of Sling RepoInit, in order to leverage the full power of Sling RepoInit, you need to upgrade to the following dependencies for AEM 6.5.5:
Configuring RepositoryInitializer
We can configure RepoInit scripts to be executed by registering a configuration of the org.apache.sling.jcr.repoinit.impl.RepositoryInitializer
Service Factory, however there is a challenge with how this service resolves the references. Each reference is expected to be in the form of a URL and OSGi supports exposing bundles as URLs, however when Apache Felix resolves the URL of a bundle in the URLHandlersBundleStreamHandler, it expects the URL host to be the UUID of the bundle, not a stable ID such as the Bundle’s Symbolic Name.
Note: as per Oliver Lietz’s comment I would recommend following the PAX URL Classpath method rather than the approach below.
I have opened a ticket to get this resolved, but until that’s complete and Generally Available, the best option is to create an OSGi Component to resolve the Bundle URL and initialize the configurations when the bundle starts.
Below is a sample implementation showing how this could be done, showing how to support multiple RepoInit files in a single bundle:
Now that you have Sling RepoInit setup and working, you can create any number of RepoInit scripts in the ./src/main/resources/repoinits folder and on bundle installation they’ll be live reloaded.
With the RepoInit scripts, you can set up your repository completely with commands like:
# Create paths create path /content/my-site(cq:Page) # Create a group create group my-site-admin set ACL for my-site-admin allow crx:replicate, jcr:lockManagement, jcr:versionManagement, rep:write on /content/my-site end # Add group members add my-site-admin to group administrators # And More!
Apache Sling RepoInit is the consolidated way to initialize a repository for any Apache Sling-based system including AEM 6.5, AEM as a Cloud Service and Apache Sling CMS. With RepoInit, you can be assured that your solution will work on both the current version of AEM as well as AEM as a Cloud Service.
You don’t have to write any code, you can use the field scripts and put your script in there (which works best if you deploy the script).
Agreed Jörg, you can do this without any additional code, however, specifying via the script attribute isn’t ideal as you have to inline the RepoInit statements into OSGi configuration which is hard to read / understand.
While implementing repoinit there are only two scenarios when these scripts gets executed, given if one does not have access to either crx/de or felix console.(for the case of CI/CD using Jenkins or cloud deployment)
1. If config related to repoinit with scripts in it is not existing, then doing a mvn deployment using ci/cd for first time will add ACL or create group based on whatever is written in script. However it is not adding or updating any ACL in subsequent deployment. (it works only if we manually remove repoinit config from crx/de before next deployment or save script by opening it again in crx/de or felix).
2. If we are restarting the application, then all scripts gets executed and permission gets added. ( effectively after each deployment we need to bounce the application to execute repoinit script)
Because of this limitation, if there is a requirement to update the script with different set of ACL for existing group or user then those permission will not get updated unless we bounce the instance or some one with access to crx/de or admin console goes and manually triggers those config. In both the case admin is required.
Any suggestion on how to overcome this problem.
I am trying to create groups but dont know why groups are not created via script
Hi Dan,
I am trying to use the following syntax raw:classpath://some-repoinit-file.txt as mentioned in the documentation but I get a java.lang.IllegalStateException: Unknown protocol: raw.
Any idea why? Also what is the link to the ticket you have submitted so that I can follow?
Assuming it works, will the init file get executed everytime the bundle containing it is deployed or only once?
Thanks,
There is no need to write any code, just use Pax URL Classpath (an OSGi URL handler) to reference (configurations and) repoinit statements.
Since version 2.6.3 Pax URL Classpath is an uber jar and therefore you only have to deploy the pax-url-classpath bundle to make it work.
See also SLING-5930 “Provide repoinit statements as bundle resource” (2016!), SLING-9944 “Bundle configurations and reference via classpath protocol” and https://github.com/apache/sling-org-apache-sling-karaf-configs/commit/a0d41eb84d4d32f88dcf2edfcdbbebf67055030a – plain repoinit statements are much more readable and easier to (re)use.
The proper syntax for factory configs is classpath:[//BundleSymbolicName/]filename.