Reading, Creating, Building, and Installing AEM Packages through the Java API

Contents

Objective

After reading this Article, You should have an Understanding of –

  • Reading the existing package through JcrPackageManager.
  • Creating, building, and installing packages through a Java API.

Introduction

In AEM Development, we mostly come across the situation of having to deal with the AEM Package with Java Code. For example, you have to archive the content available in a folder daily and store it in cloud storage. In this case, you can create a package and send it to cloud storage through the Java API. Another case may be to read the package to get the content path. So we will cover all the approaches to creating, reading, installing, building, and uploading features of the package through the Java API.

Hence, without any further delay, let’s get started:

Dependency to use Package Manager API

Dependency in core pom.xml

				
					    <!-- https://mvnrepository.com/artifact/org.apache.jackrabbit.vault/org.apache.jackrabbit.vault -->
        <dependency>
            <groupId>org.apache.jackrabbit.vault</groupId>
            <artifactId>org.apache.jackrabbit.vault</artifactId>
            <version>3.2.8</version>
        </dependency>
				
			

Reading the package through JcrPackageManager

The JcrPackageManager API helps to get package names, group names, filter sets, and other required details. The below servlet shows the use of the package manager api for getting AEM package details programmatically. These details can be used to create new packages. So lets see the implementation code :

AEMPackageReading.java

				
					package com.adobe.learning.core.servlets;

import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
import org.apache.jackrabbit.vault.packaging.JcrPackage;
import org.apache.jackrabbit.vault.packaging.JcrPackageDefinition;
import org.apache.jackrabbit.vault.packaging.JcrPackageManager;
import org.apache.jackrabbit.vault.packaging.PackagingService;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.Session;
import javax.servlet.Servlet;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author Shiv
 * http://localhost:4502/bin/packageReading?packagePath=/etc/packages/my_packages/sample.zip
 */
@Component(service = Servlet.class, property = {Constants.SERVICE_DESCRIPTION + "= Package Reading",
        "sling.servlet.paths=" + "/bin/packageReading", "sling.servlet.methods=" + HttpConstants.METHOD_GET
})
public class AEMPackageReading extends SlingSafeMethodsServlet {

    private static final Logger logger = LoggerFactory.getLogger(AEMPackageReading.class);

    ResourceResolver resourceResolver;

    String packageName = StringUtils.EMPTY;
    List<String> filterPaths;
    String groupName = StringUtils.EMPTY;
    JsonObject jsonObject;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {

        // Getting package path from query parameter
        String packagePath = request.getParameter("packagePath");

        //Getting resource resolver and session
        resourceResolver = request.getResourceResolver();
        Session session = resourceResolver.adaptTo(Session.class);

        //Getting JcrPackageManager with the help of session
        JcrPackageManager jcrPackageManager = PackagingService.getPackageManager(session);

        //Getting the Node from Package
        Node packageNode = Objects.requireNonNull(resourceResolver.getResource(packagePath)).adaptTo(Node.class);
        assert packageNode != null;

        jsonObject = new JsonObject();

        //Get JcrPackage with the help of Package Node
        try (JcrPackage jcrNodePackage = jcrPackageManager.open(packageNode)) {
            assert jcrNodePackage != null;
            //Getting Package Definition
            JcrPackageDefinition jcrNodeDefinition = jcrNodePackage.getDefinition();
            assert jcrNodeDefinition != null;
            //Getting Package and Group Name
            packageName = jcrNodeDefinition.get("name");
            groupName = jcrNodeDefinition.get("group");
            jsonObject.addProperty("name", packageName);
            jsonObject.addProperty("group", groupName);

            //Getting Path Filter Set from Package definition using getMetaImf Method
            List<PathFilterSet> pathFilterSetList = Objects.requireNonNull(jcrNodeDefinition.getMetaInf().getFilter()).getFilterSets();
            filterPaths = new ArrayList<>();
            //Adding all the filter in array list
            for (PathFilterSet currentFilter : pathFilterSetList) {
                filterPaths.add(currentFilter.getRoot());
            }
            jsonObject.addProperty("filter", filterPaths.toString());

            response.getWriter().write("Package Details : \n");
            response.getWriter().write(jsonObject.toString());

        } catch (Exception e) {
            logger.error("Error in Package Reading {}", e.getMessage());
        }
    }
}

				
			

Creating, building, and installing packages through a Java API

When you work with back-up creation or archiving of assets or pages weekly or monthly, the first thought that comes into your mind is to create a package programmatically and schedule the package creation weekly. Here you will see a servlet showing how we can create a package with a custom name, group name, and filters. You can also build and install it using Java Code. So let’s see the implementation code:

AEMPackageCreation.java

				
					package com.adobe.learning.core.servlets;

import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener;
import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
import org.apache.jackrabbit.vault.fs.io.ImportOptions;
import org.apache.jackrabbit.vault.packaging.JcrPackage;
import org.apache.jackrabbit.vault.packaging.JcrPackageDefinition;
import org.apache.jackrabbit.vault.packaging.JcrPackageManager;
import org.apache.jackrabbit.vault.packaging.PackagingService;
import org.apache.jackrabbit.vault.util.DefaultProgressListener;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Session;
import javax.servlet.Servlet;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Shiv
 * http://localhost:4502/bin/packageCreation?packageName=sample&groupName=my_packages
 */
@Component(service = Servlet.class, property = {Constants.SERVICE_DESCRIPTION + "= Package Creation",
        "sling.servlet.paths=" + "/bin/packageCreation", "sling.servlet.methods=" + HttpConstants.METHOD_GET
})
public class AEMPackageCreation extends SlingSafeMethodsServlet {

    private static final Logger logger = LoggerFactory.getLogger(AEMPackageCreation.class);

    ResourceResolver resourceResolver;

    String packageName = StringUtils.EMPTY;
    private List<String> filterPaths;
    String groupName = StringUtils.EMPTY;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {

        // Getting package name & group name from query parameter
        packageName = request.getParameter("packageName");
        groupName = request.getParameter("groupName");

        //Setting up the filter pages for package
        filterPaths = new ArrayList<>();
        filterPaths.add("/content/learning/us/en/samplePage");
        filterPaths.add("/content/learning/us/en/learningPage");


        //Getting resource resolver and session
        resourceResolver = request.getResourceResolver();
        Session session = resourceResolver.adaptTo(Session.class);

        //Getting JcrPackageManager with the help of session
        JcrPackageManager jcrPackageManager = PackagingService.getPackageManager(session);

        //Creating JcrPackage with the help of name and group
        try (JcrPackage jcrPackage = jcrPackageManager.create(groupName, packageName)) {
            //Getting JcrPackageDefinition
            JcrPackageDefinition definition = jcrPackage.getDefinition();
            //Getting DefaultWorkspaceFilter and setting up filter
            DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
            /*filterPaths is the package filters*/
            for (String filterPath : filterPaths) {
                PathFilterSet pathFilterSet = new PathFilterSet();
                pathFilterSet.setRoot(filterPath);
                filter.add(pathFilterSet);
            }

            //if autoSave is false then we have to explicitly save the session.
            assert definition != null;
            definition.setFilter(filter, true);

            //This method will build the package.
            ProgressTrackerListener listener = new DefaultProgressListener();
            jcrPackageManager.assemble(jcrPackage, listener);

            //Method to install the Package and Specify the import configurations
            ImportOptions importOption = new ImportOptions();
            jcrPackage.install(importOption);

            response.getWriter().write("Package created successfully !!!");

        } catch (Exception e) {
            logger.error("Error in Package Creation {}", e.getMessage());
        }
    }
}

				
			

Conclusion

  • So in this post, we tried to cover most of the operations in the AEM Package through the Java API. I hope you enjoyed this post. If you find it useful, leave us a comment. I would love to hear your thoughts and suggestions to make it better. Also, you can connect with me on LinkedIn.

12 Comments

  1. Hi ,
    Is it possible to translate the path when we create this package? Meaning /content/dam/abc should be written as “/content/dam/bcd” when the package gets created?

  2. Great post. May I know how would we create this package in one AEM instance (say author) and install it in another (say publish)?

Leave a Reply

Your email address will not be published. Required fields are marked *