January 2, 2021
Estimated Post Reading Time ~

One Tool to Configure Them All: Sling RepoInit

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:
org.apache.sling.jcr.repoinit – 1.1.24
org.apache.sling.repoinit.parser – 1.6.2

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:

package com.company;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import org.osgi.framework.BundleContext;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Register the repoint scripts in the bundle's /repoinits context path.
*/
@Component(immediate = true)
public class RegisterRepoInits {

public static final String PID = "org.apache.sling.jcr.repoinit.RepositoryInitializer";
private static final Logger log = LoggerFactory.getLogger(RegisterRepoinits.class);

@Reference
private ConfigurationAdmin configAdmin;

private Configuration config;

/**
* Install the Sling RepoInit configuration based on the RepoInit scripts
* embedded in this bundle
*
* @param ctx the OSGi ComponentContext
* @throws IOException an exception occurs resolving the RepoInit scripts
*/
@Activate
@Modified
protected void activate(ComponentContext ctx) throws IOException {
log.info("activate");
BundleContext bundleContext = ctx.getBundleContext();

// Get or create the configuration if it does not already exist
config = configAdmin.getConfiguration(PID + "-company");

List<String> urls = new ArrayList<>();
// Find all of the RepoInit text files in ./src/main/resources/repoinits by
// enumerating the Bundle's entries
Enumeration<?> repoinits = bundleContext.getBundle().getEntryPaths("/repoinits");
while (repoinits.hasMoreElements()) {
Object repoinit = repoinits.nextElement();
log.info("Adding RepoInit: {}", repoinit);
// Resolve the Bundle URL for the Bundle Resource
URL repointUrl = bundleContext.getBundle().getResource(repoinit.toString());
urls.add(repointUrl.toString());
}

// Create and register an OSGi configuration with an Array of Bundle Resource
// URLs
@SuppressWarnings("java:S1149")
Dictionary<String,Object> properties = new Hashtable<>();
properties.put(ConfigurationAdmin.SERVICE_FACTORYPID, PID);
properties.put("references", urls.toArray(new String[urls.size()]));
properties.put("scripts", new String[] {});
config.update(properties);

log.info("RepoInit Registered");
}

/*
* Remove the config when the component is deactivated
*/
@Deactivate
protected void deactivate() throws IOException {
log.info("deactivate");
if (config != null) {
config.delete();
log.info("Repoinit De-registered");
}
}
}


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.

Source:
https://blogs.perficient.com/2020/06/17/one-tool-to-configure-them-all-sling-repoinit/


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.