The open source components of Adobe Experience Manager (AEM) have excellent documentation. And yet, sometimes you may find yourself wanting to go a bit deeper. A huge benefit of using open source software is the fact that anyone can access the code to read it, review it, and (hopefully, one day) contribute back. So why not clone the source, hook up a debugger, and step through the code to see whatâs really happening behind the scenes?
As a case study for this post, letâs say youâve noticed a strange request in your production siteâs logs, and want to figure out how Sling is interpreting it.
-> GET ///bin///querybuilder.json.css/style.css?path=/content/we-retail&p.limit=100&p.hits=full HTTP/1.1
For starters, I canât recommend Reading the Docsâas a general approach applicable to most tech problemsâhighly enough. Sling has some great docs on its engine which can be found here: The Sling Engine. Of particular relevance to this post is the URL decomposition page which includes a table of helpful examples.
As a next step, Iâd leverage AEMâs built-in tools such as the Sling Servlet Resolver page in the Web Console. The exact purpose of this page is, âto check which servlet is responsible for rendering a responseâ. And it is usually quite accurate. For instance, entering the request path above results in the following:
The resource given by path â///bin///querybuilderâ does not exist. Therefore no resource type could be determined!
Itâs true that there is no resource at this path. But, this request is returning JSON data, so there must be something that is handling it.
If the docs arenât helping and the Sling Servlet Resolver isnât matching what youâre seeing in practice, you may need to go a bit deeper.
Get the source
To begin, clone the Sling Engine source code to your machine. It can be found here: github.com/apache/sling-org-apache-sling-engine
git clone git@github.com:apache/sling-org-apache-sling-engine.git
Check out the tag which is relevant to the version of AEM you are running. You can determine the version you need by looking in the System Console for Apache Sling Engine Implementation (org.apache.sling.engine)
: localhost:4503/system/console/bundles
In my case (AEM 6.5.5), Sling version 2.7.2
is being used. The names of all the tags are listed on the GitHub releases page:
git checkout org.apache.sling.engine-2.7.2
Open the source code using an IDE or code editor of your choice. You can debug Java code with a full-fledged IDE like IntelliJ or Eclipse, or opt for a lighter-weight option with the excellent Visual Studio Code editor. Just make sure you install the Language Support for Java and Debugger for Java extensions if you opt to use VS Code.
With that, you now have an exact copy of the Sling Engine source which is handling requests in your AEM instance.
Enable debug
mode
In order to connect a debugger to the Java virtual machine (JVM) which is running AEM, you will need to set the agentlib:jdwp
JVM arg as part of the command you use to start AEM. You can update the start script in crx-quickstart/bin/
to include this arg, or otherwise modify the command you use to run AEM:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:40404
Note that you cannot hook up a debugger to an AEM instance which was started by double-clicking the .jar file.
Make note of the address port above: 40404
. You will need this port later on when configuring your IDE.
Start AEM with this new arg in place, and you should see a log entry printed to the console indicating that it is listening:
Listening for transport dt_socket at address: 40404
Connect your IDE
This article covers the use of IntelliJ and Visual Studio Code. Other IDEs which support Java will have similar steps.
IntelliJ
Open the Sling Engine project source code with IntelliJ. On my Mac, I do so via File > Open, and then I select the folder which contains the top level pom.xml.
From the menu bar, select Run > Edit ConfigurationsâŠ:
From the left hand pane in the dialog which appears, expand Templates. Locate the Remote entry, and select it. From the top right of the dialog, click the âCreate Configurationâ text to create a new config from the Remote template.
Give it a name, such as âSling Engine debugâ. Ensure Debugger Mode is set to âAttach to remote JVMâ, Host is set to localhost
and port is the port number you set in your JVM args above (40404
in my case):
Click âOKâ to save your debug configuration.
With your new configuration selected in the âBuild/Runâ dropdown, click the bug icon to start a debugging session.
With any luck, you should see the following message in the debugger:
Excellent! Youâre now ready to set breakpoints and step through the code. You can skip the VS Code section below.
Visual Studio Code
Ensure you have the âLanguage Support for Java(TM) by Red Hatâ and âDebugger for Javaâ extensions installed.
Open the Sling Engine project source with VS Code. This can be done via the File > Open dialog, or by running code .
from a terminal where the current working directory is the Sling Engine source.
Open a Java file to âactivateâ the extension. I picked SlingRequestProcessorImpl.java
.
Select the Run tab, then click âcreate a launch.json fileâ.
In launch.json, change the value of request
from âlaunchâ to âattachâ. Replace mainClass
with hostName
and port
properties. As an example, refer to my configuration:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Debug Sling Engine",
"request": "attach",
"hostName": "localhost",
"port": 40404
}
]
}
Save launch.json.
Still in the Run tab, click the Play button in the dropdown containing a list of run configs:
You may be prompted to run the Java language server in Standard mode. I said âYesâ:
Barring any errors, you are now ready to debug!
Set a breakpoint
In your IDE/editor of choice, open SlingRequestProcessorImpl.java
(any Java file works, but this one is a good place to start). In the file margin next to the line number, click to set a breakpoint on that line.
Not sure where to start? Try setting a breakpoint on line 143
, just after the calls to requestData.initResource(..)
and requestData.initServlet(..)
.
Make a request to the AEM instance that you have your debug session connected to. Since I have connected to my publish instance, the following cURL command will do:
curl http://localhost:4503/content/we-retail/us/en.html
The response should not return right away. Instead, it should hang while your editor/IDE gives you a chance to inspect the state of the code at which you set the breakpoint. In IntelliJ, you should see a screen similar to this:
Using VS Code:
This post wonât attempt to describe everything you can do with a debugger connected (thereâs a lot!), but for staters I would recommend checking out the Variables pane. For example, try expanding resource
to see itâs fields including path
and resourceType
. By inspecting these fields you can see exactly how Sling has interpreted the current request.
URL decomposition of a tricky request
With our debugger environment configured and a breakpoint set, try issuing a request modeled after the âstrange requestâ from the beginning of this post to see how itâs interpreted:
curl http://localhost:4503///bin///querybuilder.json.css/style.css?path=/content/we-retail&p.limit=100&p.hits=full
While the ///bin///querybuilder.json.css
part of the request looks invalid, it is indeed being interpreted as a request to the QueryBuilderJsonServlet
, which explains the response weâre seeing!
Want to go deeper? Dig into requestData.currentContentData
to see how the URL has been broken down into itâs components, or step through requestData.initResource(..)
and requestData.initServlet(..)
to see how the URL is decomposed and the resource or servlet is determined.
Try other requests to compare, such as one to a path which does not exist:
curl http://localhost:4503/no/resource/here.html
Summary
This post has shown how you can set up your own local Sling debug environment without ever actually compiling the source or decompiling a bundle. I hope this helps build your understanding of the Sling Engine, and comes in handy when analyzing the URL decomposition and interpretation of complex requests.