The Blueprint for AEM Repository Organization: ‘ui.apps.structure’ Explained
Details of "ui.apps.structure”
in AEM Project
ui.apps.structure
in an Adobe Experience Manager (AEM) project is an important module that defines the structure of the AEM repository where code packages are deployed. Here are some details about it:
Definition:
ui.apps.structure
is an empty package within the AEM project that serves as a blueprint for the expected structure of the AEM repository.Purpose: This package doesn’t contain actual code or assets. Instead, it defines how the AEM repository should be organized to accommodate the code packages deployed in the project.
Safety: The package is used by the package validator to ensure that the structure of the AEM repository conforms to the project’s expectations. It helps ensure that code is deployed safely without conflicting with other components in the repository.
Composition: While it’s often empty, it can contain configurations, definitions, and structural details to guide the deployment of code.
Dependence: Other packages and code in the project rely on
ui.apps.structure
to determine the areas within the AEM repository that are "safe from conflicts." This ensures that deployments are deterministic and non-conflicting.Customization: The structure can be customized to suit the specific needs of the AEM project, but it should always be aligned with the project’s expectations and the safety requirements of the AEM platform.
This structural package is crucial for maintaining order and predictability within the AEM repository, allowing different parts of the project to coexist harmoniously and preventing unintended conflicts during deployment.
Problem Statement:
Suppose we have to develop widget (widget-x, widget-y) in project-x. e.g.
But there is a possibility that previously another vendor has developed some widgets also in this project. So if we just write filter rules like this
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/apps/project-x/clientlibs"/>
<filter root="/apps/project-x/components"/>
<filter root="/apps/project-x/widgets"/>
</workspaceFilter>
will not going to work. This will just replace the existing widgets package and install the new one. We can add “mode=merge” in the filter rules but this is not ideal because it’s possible that the new package primary type is not exactly same as the previous one.
NB: We are not willing to touch the existing one’s properties.
Solution:
So the ideal is to introduce a new module called “ui.apps.structure”.
POM File:
The pom.xml file will look like this.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ====================================================================== -->
<!-- P A R E N T P R O J E C T D E S C R I P T I O N -->
<!-- ====================================================================== -->
<parent>
<groupId>com.adobe.aem.tutorial</groupId>
<artifactId>aem-tutorial</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!-- ====================================================================== -->
<!-- P R O J E C T D E S C R I P T I O N -->
<!-- ====================================================================== -->
<artifactId>aem-tutorial.ui.apps.structure</artifactId>
<packaging>content-package</packaging>
<name>AEM Tutorial - Repository Structure Package</name>
<description>
Empty package that defines the structure of the Adobe Experience Manager repository the Code packages in this project deploy into.
Any roots in the Code packages of this project should have their parent enumerated in the Filters list below.
</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<configuration>
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
<filters>
<!-- /apps root -->
<filter><root>/apps</root></filter>
<filter><root>/apps/project-x</root></filter>
<filter><root>/apps/project-x/widgets</root></filter>
<!-- Common overlay roots -->
<filter><root>/apps/sling</root></filter>
<filter><root>/apps/cq</root></filter>
<filter><root>/apps/dam</root></filter>
<filter><root>/apps/wcm</root></filter>
<filter><root>/apps/msm</root></filter>
<!-- Immutable context-aware configurations -->
<filter><root>/apps/settings</root></filter>
<!-- DAM folder root, will be created via repoinit -->
<filter><root>/content/dam/project-x</root></filter>
</filters>
</configuration>
</plugin>
</plugins>
</build>
</project>
Here we have declared that the root of widgets will be:
“<filter><root>/apps/project-x/widgets</root></filter>”
It will not touch anything till the “widgets” in the repository.
And then we need to update the filter in the ui.apps as well. The ui.apps filter will look like:
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/apps/project-x/clientlibs"/>
<filter root="/apps/project-x/components"/>
<filter root="/apps/project-x/widgets/widget-x"/>
<filter root="/apps/project-x/widgets/widget-y"/>
</workspaceFilter>
We need to update the filter rules for the widgets as
<filter root=”/apps/project-x/widgets/widget-x”/>
<filter root=”/apps/project-x/widgets/widget-y”/>
In this manner our project will not touch the existing package instead it will just install the widget-x and widget-y in the package. The existing things will remain as it is.
Module Adding:
If this module is not generated automatically we need to add this module manually.
Module adding process:
After adding this package under project we need to add this in the pom file as well so that it will work like a module.
Main POM: We need to add this in the main pom in the “<modules>” section as a “module”. e.g. “<module>ui.apps.structure</module>”
<modules>
<module>all</module>
<module>core</module>
<module>ui.frontend</module>
<module>ui.apps</module>
<module>ui.apps.structure</module>
<module>ui.config</module>
<module>ui.content</module>
<module>it.tests</module>
<module>dispatcher</module>
<module>ui.tests</module>
</modules>
UI.APPS POM: In the ui.apps pom we need to add this in two section.
- In the plugin section as repositoryStructurePackage
<!-- ====================================================================== -->
<!-- V A U L T P A C K A G E P L U G I N S -->
<!-- ====================================================================== -->
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<configuration>
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
<group>com.adobe.aem.tutorial</group>
<name>aem-tutorial.ui.apps</name>
<packageType>application</packageType>
<repositoryStructurePackages>
<repositoryStructurePackage>
<groupId>com.adobe.aem.tutorial</groupId>
<artifactId>aem-tutorial.ui.apps.structure</artifactId>
</repositoryStructurePackage>
</repositoryStructurePackages>
<dependencies>
<dependency>
<groupId>com.adobe.cq</groupId>
<artifactId>core.wcm.components.content</artifactId>
</dependency>
<dependency>
<groupId>com.adobe.cq</groupId>
<artifactId>core.wcm.components.config</artifactId>
</dependency>
</dependencies>
</configuration>
</plugin>
- In the dependency section as a dependency
<dependency>
<groupId>com.adobe.aem.tutorial</groupId>
<artifactId>aem-tutorial.ui.apps.structure</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
UI.Config POM: If we have ui.config module then we need to add here as well. Here we also need to add the module in two sections.
- In the plugin section as repositoryStructurePackage
<build>
<sourceDirectory>src/main/content/jcr_root</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<configuration>
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
<packageType>container</packageType>
<showImportPackageReport>false</showImportPackageReport>
<repositoryStructurePackages>
<repositoryStructurePackage>
<groupId>com.adobe.aem.tutorial</groupId>
<artifactId>aem-tutorial.ui.apps.structure</artifactId>
</repositoryStructurePackage>
</repositoryStructurePackages>
</configuration>
</plugin>
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- In the dependency section as a dependency
<dependencies>
<dependency>
<groupId>com.adobe.aem.tutorial</groupId>
<artifactId>aem-tutorial.ui.apps.structure</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
</dependencies>
After successfully adding the module in the project now we can take advantages of this module.
This illustration is just for a demonstration purpose. We may face a very big challenges like this then we can achieve the expectations easily. Like we need to introduce some custom Tools where we need to overlay the nodes from /libs to /app, in this case we can take benefits from this module.
I hope you discovered this article to be both captivating and enlightening. Don’t hesitate to share it with your friends to help expand the reach of this valuable information.
Also it will be very appreciable if you share your thoughts on it.
If for any doubts or anything you can reach me through LinkedIn: https://www.linkedin.com/in/chowdhury-asif/
Thanks a lot for your time.