AEM 6.5 LTS Integration

AEM 6.5 LTS can mount Oak Chain content into its own repository. The content appears at /oak-chain, read-only, next to /content, /apps and /libs, and it is read live from a validator. Sling, CRXDE and the JCR API see ordinary nodes. Binaries stream from the validator.

This is the supported Oak Chain path for AEM 6.5 LTS: one add-on bundle and an opt-in tool, applied with one restart. No Oak bundle is changed. AEM 6.5 LTS SP3 ships Apache Oak 2.4.0 byte for byte, and the bundle builds against exactly those artifacts.

Status

Demonstrated on AEM 6.5 LTS SP3 (6.6.3.20260819, Apache Oak 2.4.0, Java 21) against a three-validator cluster in mock mode on one host. Two complete opt-in and opt-out rounds passed every step: 591 of 591 bundles active, exactly one composite registration per boot, no ERROR lines, writes under the mount rejected, global writes working, and the original configuration restored byte for byte. Booting with the validator down, attaching when it came up, an outage after attach, and streaming an external binary were each checked live.

Validator garbage collection under a live mount was also run, against a three-validator trunk cluster with short GC intervals. The validator AEM mounts ran two full compactions and released the deleted binaries. Every segment AEM had read for the deleted content was physically reclaimed and answered 404, while 639 reads of current content through AEM all returned the right content and bytes. AEM's own Revision Clean Up then compacted its repository with the mount attached.

Not yet run: publish instances, other LTS service packs, chain-backed mode, several hosts, and sustained load.

Support boundary

Adobe does not support a composite node store on AEM 6.5 LTS with TarMK. This is Oak Chain's opt-in path, built on Apache Oak's own composite store. Opting in means accepting that boundary for the instance; opting out restores the original configuration exactly.

How It Works

aem-integration

AEM's repository runs on Oak's CompositeNodeStore with two parts:

The bundle registers exactly one OSGi service: a NodeStoreProvider with role=composite-mount-oak-chain. In AEM 6.5 LTS the only components that bind that interface filter by role, so it cannot rebind or restart any other store. The Segment Tar classes the mount needs are embedded privately, which keeps every import within what the AEM 6.5 LTS API controller allows.

Data Table
Behavior
What happens
Validator down at boot
AEM starts normally; /oak-chain does not exist yet
Validator comes up
The mount attaches within one refresh interval (default 5 s), with no restart
New commits on the validator
The mount follows the validator's journal head on the same interval
Write under /oak-chain
Rejected by Oak's read-only builder; the rest of the repository is unaffected
Validator outage after attach
Cached nodes stay readable; uncached segments and binaries fail until it returns; AEM keeps running
Validator garbage collection
The mount moves to the compacted head on its next refresh; current reads are unaffected

Requirements

Data Table
Item
Requirement
AEM
AEM 6.5 LTS (quickstart 6.6.x), author. Verified on SP3.
Storage
TarMK (crx3tar). MongoMK, standby or secondary instances, and custom segment stores are refused.
Instance state
Started at least once, so its repository and OSGi configuration exist
Java
The JVM AEM already runs on (17 or 21). The opt-in tool runs on the same JVM.
Validator
Reachable over HTTP from the AEM host; store format version 1 or 2. An unreachable validator is a warning, not a blocker.
Build
Maven 3.9+ and JDK 17+ to build the bundle from source (no binary release yet)

Opt In

Build the bundle. The jar is both the OSGi bundle and the opt-in tool.

git clone https://github.com/somarc/oak-chain-connector.git
cd oak-chain-connector
mvn -f mount/pom.xml install
JAR=$(ls mount/target/oak-chain-connector.mount-*.jar)

Then run four commands against the AEM home, the directory that contains crx-quickstart:

AEM=/opt/aem/author
VALIDATOR=http://validator.example.internal:8090

# 1. Checks only; safe while AEM runs
java -jar $JAR preflight $AEM --validator $VALIDATOR

# 2. Stop AEM, then apply. It refuses unless AEM is stopped.
java -jar $JAR enable $AEM --validator $VALIDATOR

# 3. Start AEM as usual, then confirm the opted-in state
OAKCHAIN_AEM_AUTH=admin:password java -jar $JAR verify $AEM --aem-url http://localhost:4502

# 4. Any time: what is applied, and whether anything drifted
java -jar $JAR status $AEM

If the validator requires a token, put it in an environment variable and pass the variable's name with --token-env. Tokens and passwords never go on the command line. Other options: --mount-path (default /oak-chain), --refresh in seconds (default 5).

What preflight checks

Preflight changes nothing and exits non-zero on any failure. It checks the AEM build and that AEM is stopped, using the TarMK repository lock. It confirms TarMK storage, that no other composite, mount or TAR-persistence configuration exists, and that oak-store-composite and Oak's TarPersistenceService are installed. It resolves every Import-Package of the bundle against this instance's own bundle cache, checks the AEM 6.5 LTS API controller rules, and probes the validator's manifest, journal head and head segment.

What Enable Changes

Enable writes nine files and touches nothing under repository/. Every managed file carries an oakchain.optin marker. Its SHA-256 is recorded in crx-quickstart/oak-chain-opt-in/state.properties, and any file it replaces is first copied to oak-chain-opt-in/backup/.

Data Table
Configuration
Purpose
SegmentNodeStoreService
The original primary store is kept but made inert. Your settings are preserved and backed up. An install-folder copy outranks the quickstart default so it is never re-applied.
TarPersistenceService
Opens the existing repository/segmentstore in place
SegmentNodeStoreFactory~oakchain-global
The composite's global store over that persistence. Copies the primary's tuning; keeps observation and Sling discovery working.
MountInfoProviderService
Declares the read-only mount path
CompositeNodeStoreService
Assembles the repository. Package Manager reads its enabled=false flag.
RevisionCleanupTask~main
AEM's Revision Clean Up task, edited in place with role=composite-global. Without it, daily maintenance finds no revision GC and never compacts the repository.
OakChainMountProvider
Validator URL and refresh interval; the optional token is written to a file only the owner can read
install/15/oak-chain-connector.mount.jar
The bundle

Run enable again with new options to change the validator URL or refresh interval. It updates in place and keeps the original backups.

Verify

verify checks the current boot only. It confirms that AEM is up and every bundle is active, the mount bundle is active, and the mount path is served. It also confirms exactly one composite registration, which means the repository did not restart, that the mount connected, that there are no resolution errors, and that Revision Clean Up targets the global store. With --write-probe it also confirms that a write under the mount is rejected while a global write and delete succeed.

verify http://localhost:4502 (opted in)
  PASS  AEM up                             login page HTTP 200
  PASS  Bundles                            591 total, 591 active, 0 resolved, 0 installed
  PASS  Mount bundle                       com.oakchain.connector.mount Active
  PASS  Mounted path                       /oak-chain HTTP 200
  PASS  Composite registrations this boot  1 (no repository restart)
  PASS  Mount connected this boot          connected to validator
  PASS  Bundle resolution                  no resolution errors
  PASS  ERROR lines this boot              0
  PASS  Revision Clean Up role             role=composite-global (daily maintenance compacts the global store)
RESULT: OK

If the validator was not reachable at boot, Mounted path reports a warning rather than a failure: the mount attaches as soon as the validator answers.

Opt Out

# Stop AEM, then:
java -jar $JAR disable $AEM
# Start AEM, then confirm the original state:
OAKCHAIN_AEM_AUTH=admin:password java -jar $JAR verify $AEM --expect vanilla

Disable restores every replaced file byte for byte and removes everything else enable wrote. On the next start AEM's installer uninstalls the bundle, and the original SegmentNodeStoreService opens the same segmentstore again. If a managed file was edited after enable, disable stops and lists it; --force restores the originals anyway.

Operating Notes

What restarts the repository

AEM binds its node store with static, greedy OSGi references, so some changes restart the whole repository. The opt-in avoids all of them in normal operation. Plan these for a maintenance window:

Validator garbage collection

Validators run segment and binary GC by default. The mount follows the validator's journal, so it moves to the compacted head on its next refresh, and reads of current content are unaffected.

A reader that holds one revision for a long time, such as a JCR session that never refreshes or a backed-up observation queue, is safe for one full GC cycle, because validators keep two generations. After that its uncached segments can be gone. When that happens is not fixed: Oak rewrites a segment file only when that saves at least a quarter of it, so deleted content can stay on disk for many cycles. A binary the validator has released answers 404, and reading it through AEM fails.

AEM maintenance

AEM's Revision Clean Up finds the revision GC to run by role. After opt-in the repository's store has the role composite-global, so enable sets that role on the task, and verify checks it. If your code base configures RevisionCleanupTask itself, add role=composite-global there, or daily maintenance stops compacting. Data Store Garbage Collection needs nothing.

Service packs

Opt out, apply the service pack, then run preflight and enable again. Preflight catches import ranges or API controller rules that changed with the new Oak line before AEM restarts.

Security

Limits

Data Table
Limit
Detail
Chain changes reach JCR observation late
Oak's composite dispatches changes only on AEM's own commits, so a chain change arrives with the next one, batched. Listeners and workflow launchers that match /oak-chain will see it. For timely chain events, use the validator's event stream.
No query indexing of /oak-chain
Read by path. Oak's indexes do not cover the mount.
One validator per instance
Validators agree on content, not on file layout, so the mount follows a single validator. Switching validators is a reconfiguration and a repository restart.
Long-held revisions
A reader that keeps one revision across two validator GC cycles can lose uncached segments. Request-scoped reads are not affected.
Read-only
AEM reads chain content. Writing to the chain is outside this path.
Author, AEM 6.5 LTS only
Publish instances have not been run. AEM as a Cloud Service and AEM 6.5 (non-LTS) are not supported.

Troubleshooting

Data Table
Symptom
Cause and fix
enable: AEM is running
The TarMK repository lock is held. Stop AEM and run enable again.
preflight: Bundle wiring fails
The instance exports a different Oak line or restricts a package. Rebuild the bundle for that line, or stay opted out.
/oak-chain returns 404 after start
The validator was not reachable. Check VALIDATOR/manifest from the AEM host; the mount attaches on its own once it answers.
verify: composite registrations is not 1
Something restarted the repository during boot, usually another bundle registering a node store or persistence service.
verify: Revision Clean Up role fails
A code-base config of RevisionCleanupTask overrides the one enable wrote. Add role=composite-global to it.
disable lists drifted files
A managed file was edited after enable. Review the change, then run disable --force to restore the originals.

Next Steps