Skip to content

Instantly share code, notes, and snippets.

@stoerr
Last active March 11, 2021 08:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stoerr/a54c58b4b05770c6a7ee39654ea84305 to your computer and use it in GitHub Desktop.
Save stoerr/a54c58b4b05770c6a7ee39654ea84305 to your computer and use it in GitHub Desktop.
Servlet to download a resource subtree from AEM as a content-package
/**
* This is a servlet that enables to download a package of a JCR subtree without
* having to create a package in the package manager. The package is
* created on the fly, and not saved to disk / the repository, so this is
* better suited to large content trees, but valuable also for quickly downloading
* a page.
*
* CAUTION: not suitable for production, only for internal testing systems!
*
* Usage with curl e.g.
* curl -s -S -o tmp.zip -u admin:admin http://localhost:6502/apps/net/stoerr/hpsx/getpackage.html/{path to download}
*
* Example Creates a package of this tool:
* http://localhost:6502/apps/net/stoerr/hpsx/getpackage.html/apps/net/stoerr/hpsx
*
* Fragment of a bash script to download a path from another AEM system and install it locally on AEM:
* path=$1
* TMPFIL=`mktemp -u`.zip
* trap "{ rm -f $TMPFIL; }" EXIT
* PKG=$(basename $TMPFIL)
* curl -S -o $TMPFIL -u ${OTHER_USER}:${OTHER_PWD} http://${OTHERIP}:4502/apps/netcentric/hpsx/getpackage.html${path}?packageName=$PKG
* curl -u admin:admin -F file=@"$TMPFIL" -F name="tmp $path" -F force=true -F install=true http://localhost:6502/crx/packmgr/service.jsp
* curl -u admin:admin -F cmd=delete http://localhost:6502/crx/packmgr/service/.json/etc/packages/my_packages/${PKG%%.zip}-1.zip
*/
package apps.net.stoerr.hpsx.getpackage;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
import org.apache.jackrabbit.vault.packaging.*;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import java.io.IOException;
public class getpackage extends SlingSafeMethodsServlet {
String PARAM_PACKAGENAME = "packageName";
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
throws ServletException, IOException {
RequestPathInfo pathInfo = request.getRequestPathInfo();
String resourcePath = pathInfo.getSuffix();
ResourceResolver resolver = request.getResourceResolver();
Resource resource = resolver.getResource(resourcePath);
if (resource == null) {
throw new IllegalArgumentException("Not found: " + resourcePath);
}
if (!resource.getPath().matches("/.*/.*/.*")) {
throw new IllegalArgumentException("Path too short - package would probably be too large");
}
if (!"admin".equals(request.getResourceResolver().getUserID())) {
throw new IllegalArgumentException("For security reasons only allowed for admin");
}
resourcePath = resource.getPath();
String packageName = "tmp-" + resourcePath.replaceAll("[^a-zA-Z0-9_-]+", "_");
if (StringUtils.isNotBlank(request.getParameter(PARAM_PACKAGENAME))) {
packageName = request.getParameter(PARAM_PACKAGENAME);
}
response.setContentType("application/zip");
response.addHeader("Content-Disposition", "attachment; filename=" +
packageName + ".zip");
BundleContext bundleContext = FrameworkUtil.getBundle(Packaging.class).getBundleContext();
ServiceReference packagingRef = bundleContext.getServiceReference(Packaging.class.getName());
Packaging packaging = (Packaging) bundleContext.getService(packagingRef);
try {
writePackage(resource, packageName, request, packaging, response.getOutputStream());
} catch (RepositoryException | PackageException e) {
throw new ServletException(e);
} finally {
bundleContext.ungetService(packagingRef);
resolver.revert();
}
}
private void writePackage(Resource resource, String packageName, SlingHttpServletRequest request, Packaging packaging, ServletOutputStream outputStream) throws IOException, RepositoryException, PackageException {
JcrPackageManager pkgmgr = packaging.getPackageManager(request.getResourceResolver().adaptTo(Session.class));
JcrPackage jcrPackage = pkgmgr.create("my_packages", packageName, "1");
try {
JcrPackageDefinition pkgdef = jcrPackage.getDefinition();
DefaultWorkspaceFilter workspaceFilter = new DefaultWorkspaceFilter();
workspaceFilter.add(new PathFilterSet(resource.getPath()));
pkgdef.setFilter(workspaceFilter, false);
pkgmgr.assemble(pkgdef, null, outputStream);
} finally {
try {
pkgmgr.remove(jcrPackage);
} catch (Exception e) {
// ignore
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment