Showing posts with label Debugging. Show all posts
Showing posts with label Debugging. Show all posts

March 30, 2021
Estimated Post Reading Time ~

Debug Your Client libs

AEM will concatenate your CSS/js files for you and roll them into a single file. This reduces your HTTP request load, but it makes debugging a little difficult. Fortunately, there's a way to turn that off temporarily...



By aem4beginner

March 22, 2021
Estimated Post Reading Time ~

How to Debug/ Troubleshoot Sling Context Aware Configuration AEM

If we are using Sling Context-Aware configurations in AEM and something went wrong it's difficult to debug/know from where these values or pulling. We know this in the AEM Web console.

After open AEM Web console click on the sling tab, you will find the "Context-Aware Configuration" option


After Navigate Context-Aware Configuration web console page you will see a form. You can enter the "Content Path" and "Config name" which you want to debug and click on resolve. if you are debugging a collection config check the checkbox "Resouce Collection"



Note: if "cq:conf" property set to your jcr:content node of page sometimes it will read configurations for the path. So keep an eye on "cq:conf" and "sling:configRef" properties.

To know how to develop with Sling context configurations refer to my post Sling Context Aware Configuration AEM 6.5 Examples.



By aem4beginner

January 2, 2021
Estimated Post Reading Time ~

How to disable the minification for client libraries in AEM?

Minification refers to the process of removing unnecessary or redundant data without affecting how the resource is processed by the browser — e.g. code comments and formatting, removing unused code, using shorter variable and function names, and so on.

Minification helps to reduce the size of the resources(JavaScript and CSS) and improves the performance of page loading.

Sometimes we may be required to disable the minification for specific Java script files may be due to the files are already minified or the issue with the minification process.

There are two options to disable the minification for Java Scripts and CSS in AEM

Disable through Adobe Granite HTML Library Manager — Disable the minification globally for JS and CSS, this will impact all the client libraries in the system(both default and custom)

Disable Minification for specific client libraries — Disable the minification for specific client library — JS/CSS, this will impact only the specific client library where this configuration is enabled.
Disable through Adobe Granite HTML Library Manager

Un-select minify option in Adobe Granite HTML Library Manager through ConfigMgr(http://localhost:4502/system/console/configMgr/com.adobe.granite.ui.clientlibs.impl.HtmlLibraryManagerImpl)


Please note this is a global configuration and it will impact all the client libraries, non of the client libraries will be minified now and this will impact the performance. This approach is not recommended as this will disable the minification for all the custom and default system-level client libraries.
Disable Minification for specific client libraries

Enable the minification in global configuration(Adobe Granite HTML Library Manager) — http://localhost:4502/system/console/configMgr/com.adobe.granite.ui.clientlibs.impl.HtmlLibraryManagerImpl and disable the minification for required client libraries in the client library level. This will only disable the minification for the specific client library.


To disable the minification for a specific client library add the below properties to the client library node.

To disable Java Script Minification — add jsProcessor String[] default:none, min:none


To disable CSS Minification — add cssProcessor String[] default:none, min:none


Disabling the minification at a global level is not recommended as this will impact the overall impact of the website performance, enable the configurations to required client libraries to disable the minification for JS/CSS.


By aem4beginner

December 31, 2020
Estimated Post Reading Time ~

Unit testing in AEM - Debugging issues in Test class

This post is for illustrating the possible errors/exception we get while writing Test class. Also highlights the possible ways of creating Test content and the ResourceResolverType available for creating AemContext (from io.wcm framework)

Test content:
  • The most important aspect of Unit Testing is creating Test content which in the AEM sense is to provide a means of the repository at the time of code build phase to test our Java code (written interacting with a repo)
  • For creating the same, we already saw that there are 3 possible APIs - Content Loader, Content Builder, and Resource Builder available.
  • Most often we use Content Loader making use of JSON file at classpath and loading it to dummy content path. Below are the sample snippet making use of the other two APIs.
Content Builder :
private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);
ContentBuilder contentBuilder = aemContext.create();
With this contentBuilder object, we can create page, asset, tag etc - Full list of methods available with ContentBuilder API is in doc.

Resource Builder:
private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);
ResourceBuilder rescBuilder= aemContext.build();
With this rescBuilder object, we can create resource with properties - Full list of methods available with ResourceBuilder API is in doc.

Resource Resolver Types (as available from io.wcm)
RESOURCERESOLVER_MOCK - new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
  • Mock for Resource Resolver / Factory
  • Access to all Sling API
  • No underlying JCR repository and hence the usage of JCR API is not possible.
    • (Example: Adapting to JCR objects will return null)
  • This type is very fast
  • Usage: If no JCR APIs are involved, we can make use of RESOURCERESOLVER_MOCK while creating AemContext.
JCR_MOCK - new AemContext(ResourceResolverType.JCR_MOCK);
  • JCR In-memory mock as an underlying repository.
  • Support most of the JCR features with an exception of extended features like Eventing, Search, Versioning, etc.
  • This is slow compared to RESOURCERESOLVER_MOCK
  • Usage: If both Sling API and JCR APIs are involved, make use of JCR_MOCK.
JCR_OAK - new AemContext(ResourceResolverType.JCR_OAK);
  • Uses a real JCR Jackrabbit Oak repository.
  • This is slow compared to JCR_MOCK
  • Usage: Common use case would be for logic involving JCR query, JCR Observation
Note: We can create AemContext without specifying ResourceResolverType as well - new AemContext()

Debugging/Troubleshooting:
Null pointer Exception:
  • Let's consider we are writing Test class for Sling Model and in Test class, we have created AemContext, mock content and instantiated the Sling model (via request or resource of aemContext)
  • In case if any of the APIs/objects used in the sling model in -> init method / in constructor injected scenario is not available to Test class, it will result in the Sling Model object being null.
  • If a null check is handled, it will result in the next possible scenario.
Example :
  • In the example below, the "currentPageObj" in the "init" method is an instance variable and is initialized in Injected Constructor.
  • If currentPage object in the constructor (to initialize the "currentPageObj") is not set to AemContext, then currentPage in the constructor is null while the Sling model is instantiated in Test class and hence null for currentPageObj in init method -> Ultimately Sling Model object will be null in Test class.
@Model(adaptables = { Resource.class,
SlingHttpServletRequest.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class SlingModelConstructor {

private Page currentPageObj;

public String getTitle() {
return title;
}

private String title;

/* Constructor Injection */
@Inject
public SlingModelConstructor(@ScriptVariable @Named("currentPage") Page currentPage) {
currentPageObj = currentPage;
}

@PostConstruct
protected void init() {
title = currentPageObj.getTitle();
}

}


In the Test class snippet below, we have used ContentBuilder to create a Page object and is set to AemContext and then Sling Model is instantiated via request from AemContext. In this way, the valid object is created and will be available to access its methods.

@ExtendWith({ AemContextExtension.class, MockitoExtension.class })
class SlingModelConstructorTest {

private SlingModelConstructor modelObj;

private Page page;

private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);

@BeforeEach
void setUp() throws Exception {
aemContext.addModelsForClasses(SlingModelConstructor.class);
ContentBuilder cntBuilder = aemContext.create();
page = cntBuilder.page("/content/learnings", "/conf/learnings/templates/content-temp", "Sample Page - Aug 2020");
/* Page is set to AemContext object */
aemContext.currentPage(page);
/* Sling Model Instantiation */
modelObj = aemContext.request().adaptTo(SlingModelConstructor.class);
}

@Test
void testGetTitle() {
String expectedTitle = "Sample Page - Aug 2020";
assertNotNull(modelObj);
String actualTitle = modelObj.getTitle();
assertEquals(expectedTitle, actualTitle);
}

}


Assertion Failed :
  • If the assertion conditions are not satisfied, then it will result in AssertionFailedError.
  • From the literal sense, we know if expected and actual are not the same, then it results in this sort of error.
  • Most often we get this in the below situation.
  • Example:
    • In the same example as above in a Test class -> assume Page object is not set to AemContext -> Sling Model object retrieved -> null check is handled while invoking its method - In this case, it is getTitle() method, it would result in AssertionFailed error. (Expected would be some String while the actual title we get is null)
@ExtendWith({ AemContextExtension.class, MockitoExtension.class })
class SlingModelConstructorTest {

private SlingModelConstructor modelObj;

private Page page;

private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);

@BeforeEach
void setUp() throws Exception {
aemContext.addModelsForClasses(SlingModelConstructor.class);
modelObj = aemContext.request().adaptTo(SlingModelConstructor.class); // No Page object set and model is directly instantiated
}

@Test
void testGetTitle() {
String expectedTitle = "Sample Page - Aug 2020";
String actualTitle = null ;
if(null != modelObj){ // modelObj will be null and this block won't execute
actualTitle = modelObj.getTitle();
}
assertEquals(expectedTitle, actualTitle); // actualTitle will be null and hence AssertionFailedError

}

}


Mocking the right resource:
  • If we are to create a mock resource JSON for performing tests, we need to understand which line of code to be tested and the respective resource can be retrieved from the actual content (from repo/CRXDE) using selector - "tidy.-1.json" on the respective resource.
  • By the term "respective resource",
    • It means node/resource of type cq:Page if we are to test page related functionality.
    • It means node/resource of type nt:unstructured/component node under the content path if we are to test component related logic via ValueMap.
Others:
  • Apart from the above, if any of the code statements making use of a specific API is not available within the method under test, then it will throw its respective exception according to the API used.
  • There are cases where certain methods or properties are not available with Testing APIs themselves. One such case which was raised in the Community forum recently, jcr:created property is not accessible
Conclusion:
  • The first immediate reach is AemContext from io.wcm framework, if anything is not accessible within that, explore Mocking related frameworks and its methods -> provide dummy implementation per the code statements.
  • With the understanding of the flow of how to test class works + making use of available Testing/Mocking APIs + method under test + functionality it executes + control flow when a specific line is executed, we will be able to write test class with ease and debug in case of any issues in test class execution.


By aem4beginner

December 28, 2020
Estimated Post Reading Time ~

Basic Steps to Debug an Error in AEM

There are times when something is not working as expected from the AEM Server; relax, you are fine. The error can be quickly identified through debugging on the server with a series of steps. Once the error has been identified you can attempt to solve the error efficiently. In this article, I will share with you the basic steps I take to quickly debug an error in AEM; following the order (in steps) will help you optimize and identify the problem quickly.

Common issues you may be experiencing can be:
  • Replication is not replicating properly.
  • The rendered page is missing a component.
  • The rendered page is blank.
  • Servlet is not registered.
  • etc…


1. Analyse Browser’s Console
When there’s an issue, be sure to take a look at the browser’s console log as the first action to take. The console log can show you errors that may help you pinpoint the error immediately, before looking at server logs.

The errors might be a third-party JavaScript library or from an external RESTFUl micro-service that is not related to AEM at all…

2. Analyse error.log
If the Browser’s console log has no relevant information, we can go ahead to review the error.log; this file can be found from ./crx-quickstart/logs/error.log.

The error.log catches exceptions that are output into the log file. Typically the logs in this file can help you quickly pinpoint the error. Whether the error will be from a bundle by your organization, a bundle from the AEM product, or even a missing configuration, the logs will expose this information.

3. Analyse <custom>.log
When the error.log does not show you the relevant information you can take a look at your custom log files that exist in ./crx-quickstart/logs/*. The custom log files will be able to help you pinpoint your error.


By aem4beginner

October 13, 2020
Estimated Post Reading Time ~

Debugging Adobe IO Actions in VS Code


Todays lets understand how we can debug the Adobe IO actions using VS code and openwhisk.

1. Install wskdebug
npm install -g @adobe/wskdebug

2. Setup the Docker locally. You can download it from https://docs.docker.com/docker-for-windows/install/ and once restart your system after installation.

3. Now we need create the Adobe IO’s image locally to execute out actions. Use below command to create your local image in docker:

wskdebug --inspect-brk=11932 <ACTION NAME> <FULL PATH TO THE SOURCE FILE> -l

Now lets setup our VS Code to access this image and start our debugging:
1. Open VS Code.
2. Go to debug section on left.
3. Click on create launch.json (Selecting Node.js preview)
4. Now add the below configuration to the created launch .json file.

"configurations": [
{
    "type": "node",
    "request": "launch",
    "name": "wskdebug ",
    "runtimeExecutable": "wskdebug",
    "args": [ "", "${workspaceFolder}/", "-l" ],
    "localRoot": "${workspaceFolder}",
    "remoteRoot": "/code",
    "outputCapture": "std"
}
]


Now we are done creating the debugger for our IO actions locally. Just start your debugger locally and once you see below message then start your execution of code and check for logs.

Ready, waiting for activations! Use CTRL+C to exit

Reference: https://code.visualstudio.com/docs/editor/debugging#_launch-configurations


By aem4beginner

September 22, 2020
Estimated Post Reading Time ~

ClientLibs debugger [?debugClientLibs=true] in AEM

Today in this tutorial we are going to discuss how and what we can achieve using the debugClientLibs parameter in AEM.

What is debugClientLibs? What is the use of debugClientLibs?
AEM provides tools for debugging and debugClinetLibs is one of them. Using this we can see all the embedded client library files. By default, client libraries embed all your code in a single file when it delivered to the browser. So when you want to see all the embedded files in separate at runtime append "?debugClinetLibs=true" in URL (this is something like passing a parameter with URL). Then you will see response return all of the individual script files that ClientLibs embed inside each clientLibs file.

e.g. URL: https://localhost:4502/content/jorvee/home.html?debugClientLibs=true

Benefits of using debugClientLibs:
  • You can detach your embedded script at runtime.
  • Helps you to identify and fix the JS/CSS issues.
Ref: 



By aem4beginner

How to start AEM in debug mode?

There are multiple approaches to start or tune AEM instance in debug mode. we will cover a few of them in this tutorial.
  1. We could start AEM using the command prompt by using the below command line.
  2.  java -jar aem63-author-p4502.jar -debug <port#>
  3. Another way to start tune AEM instance in debug mode is we could update the start.bat file and start AEM by clicking on the start.bat file in the crx-quickstart folder. To do so we have to do the following.
  • First we need to update the start file; go to \crx-quickstart\bin\start.bat and append this command "-debug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=<port#>" with line 25, default JVM options.
  • Save the file
  •  Now double click on the start.bat file to start your AEM instance.
    After changes, your start.bat file will look like the following.
    @echo off
    :: This script configures the start information for this server.
    ::
    :: The following variables may be used to override the defaults.
    :: For one-time overrides the variable can be set as part of the command-line; e.g.,
    ::
    ::     SET CQ_PORT=1234 & ./start.bat
    ::
    setlocal

    ::* TCP port used for stop and status scripts
    if not defined CQ_PORT set CQ_PORT=4502

    ::* hostname of the interface that this server should listen to
    :: if not defined CQ_HOST set CQ_HOST=

    ::* runmode(s)
    ::* will not be used if repository is already present
    if not defined CQ_RUNMODE set CQ_RUNMODE=author

    ::* name of the jarfile
    :: if not defined CQ_JARFILE set CQ_JARFILE=

    ::* default JVM options
    if not defined CQ_JVM_OPTS set CQ_JVM_OPTS=-Xmx2048m -XX:MaxPermSize=512M -Djava.awt.headless=true -debug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=30303

    ::* ------------------------------------------------------------------------------
    ::* authentication
    ::* ------------------------------------------------------------------------------
    ::* when using oak (crx3) authentication must be configured using the
    ::* Apache Felix JAAS Configuration Factory service via the Web Console
    ::* see http://jackrabbit.apache.org/oak/docs/security/authentication/externalloginmodule.html

    ::* use jaas.config (legacy: only used for crx2 persistence)
    :: if not defined CQ_USE_JAAS set CQ_USE_JAAS=true

    ::* config for jaas (legacy: only used for crx2 persistence)
    if not defined CQ_JAAS_CONFIG set CQ_JAAS_CONFIG=etc\jaas.config

    ::* ------------------------------------------------------------------------------
    ::* persistence mode
    ::* ------------------------------------------------------------------------------
    ::* the persistence mode can not be switched for an existing repository
    set CQ_RUNMODE=%CQ_RUNMODE%,crx3,crx3tar
    :: set CQ_RUNMODE=%CQ_RUNMODE%,crx3,crx3mongo

    ::* settings for mongo db
    :: if not defined CQ_MONGO_HOST set CQ_MONGO_HOST=127.0.0.1
    :: if not defined CQ_MONGO_PORT set CQ_MONGO_PORT=27017
    :: if not defined CQ_MONGO_DB   set CQ_MONGO_DB=aem6

    ::* ------------------------------------------------------------------------------
    ::* do not configure below this point
    ::* ------------------------------------------------------------------------------

    chdir /D %~dp0
    cd ..
    if exist conf\controlport del conf\controlport
    if not defined CQ_JARFILE     for %%X in (app\*.jar) do set CQ_JARFILE=%%X
    for %%* in (.) do set CurrDirName=%%~n*
    cd ..

    set START_OPTS=start -c %CurrDirName% -i launchpad
    if defined CQ_PORT            set START_OPTS=%START_OPTS% -p %CQ_PORT%
    if defined CQ_RUNMODE         set CQ_JVM_OPTS=%CQ_JVM_OPTS% -Dsling.run.modes=%CQ_RUNMODE%
    if defined CQ_HOST            set CQ_JVM_OPTS=%CQ_JVM_OPTS% -Dorg.apache.felix.http.host=%CQ_HOST%
    if defined CQ_HOST            set START_OPTS=%START_OPTS% -a %CQ_HOST%
    if defined CQ_MONGO_HOST      set START_OPTS=%START_OPTS% -Doak.mongo.host=%CQ_MONGO_HOST%
    if defined CQ_MONGO_PORT      set START_OPTS=%START_OPTS% -Doak.mongo.port=%CQ_MONGO_PORT%
    if defined CQ_MONGO_DB        set START_OPTS=%START_OPTS% -Doak.mongo.db=%CQ_MONGO_DB%
    if defined CQ_USE_JAAS        set CQ_JVM_OPTS=%CQ_JVM_OPTS% -Djava.security.auth.login.config=%CQ_JAAS_CONFIG%
    set START_OPTS=%START_OPTS% -Dsling.properties=conf/sling.properties

    if exist newTaskList.txt del newTaskList.txt
    if exist oldTaskList.txt del oldTaskList.txt
    tasklist /FI "IMAGENAME eq java.exe" /NH > oldTaskList.txt
    start "CQ" cmd.exe /C java %CQ_JVM_OPTS% -jar %CurrDirName%\%CQ_JARFILE% %START_OPTS%

    :: removing the delay until CQ-4202186 is solved
    :: timeout /T 1 /NOBREAK >nul

    tasklist /FI "IMAGENAME eq java.exe" /NH > newTaskList.txt
    java -cp %~dp0 GetProcessID oldTaskList.txt newTaskList.txt java.exe > %CurrDirName%\conf\cq.pid
    if exist newTaskList.txt del newTaskList.txt
    if exist oldTaskList.txt del oldTaskList.txt

    Once you have done with the above changes and started your AE in debug mode then you have to configure debugger in your IDE (Eclipse or IntelliJ). To configure the debugger with your local AEM instance please follow this article. Remote debugger in eclipse


    By aem4beginner

    Configure and start remote debugger in Eclipse

    Set the remote debugger configuration in Eclipse, to debug the running application code and identify the code issues.

    Step 1: Open the Debug perspective from the toolbar. if you don't see the debug perspective option in your toolbar, then open the perspective from this path in Eclipse. 
    Windows >> Perspective >> Open perspective >> Others >> Debug  
    1. Click on the perspective drop-down option very next to the bug symbol.
    2. Select the option Debug configuration

    Debug Configuration in Eclipse

    Step 2: Debug Configuration will open a new window(below is the screenshot).
    1. Click on the Remote Java Application option from the left side rail.
    2. Click on the New Launch configuration(new configuration) button. As shown in the screenshot below.

    Remote Java Application setup

    Step 3: Once you click on the new configuration button, a configuration setup option will appear right side on the same window. Switch to the connect tab, if you are not on the connect tab by default.
    1. In the Name section, please provide a valid name.
    2. In the Connection Properties section specify the host and port on which your application is running. 
      e.g. 
      Host: localhost
      Port: 30303 (default AEM debug mode port)
    3. Project: Select the core folder of your project.
    4. Connection type: Keep it as Standard.

    Debugger remote connection setup

    Step 4: Now switch to the source tab, next to connect and configure your Java project. Below is the screenshot.
    1. Switch to source tab
    2. Click on Add option
    3. Select Java Project option
    4. Hit Ok button
    5. Select your project 
    6. Hit Ok button
    7. After successful selection, your project gets added to the source section.  

    Debug project setup in Eclipse

    You have successfully set up the debugger with your remote application. Now run or tune your application in debug mode and start the debugger in Eclipse from a debug perspective to listen to the request from your application server to Eclipse.


    By aem4beginner

    May 22, 2020
    Estimated Post Reading Time ~

    CQ5 debug bundles using eclipse won't halt

    I created a bundle that I already uploaded, but I would like to debug it. I started the server with debug mode: java -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n -XX:MaxPermSize=256m -Xmx1024M -jar AEM_6.0_Quickstart.jar, and then I set to the project that packaged into the bundle its remote debugging configuration, but when I set the breakpoints in the project, it won't halt where it needs to when the lines are executed.

    I looked where am I go wrong, but I see that this is how everybody doing it, and it works for them.

    Best How To:
    Below are some steps that can be helpful. Use that command line to start your CQ instance.java -jar cq5-author-4502.jar -fork -forkargs -- -Xdebug -Xrunjdwp:transport=dt_socket,address=59865,suspend=n,server=y -Xmx1520m -XX:MaxPermSize=512m -XX:-UseSplitVerifier

    I have a simple title component in which I am calling some service method. And applied some breakpoints in service. I have multi-module eclipse project practice. Setup eclipse debug configurations as shown below :



    Inside source adds project's module as shown below :



    Click on the debug button and refresh the cq page. You will see below image:

    Open the Eclipse in debug perspective you can see your variables over there and the page still loading as you not complete the method execution.


    By aem4beginner

    May 21, 2020
    Estimated Post Reading Time ~

    Debug/Info Logging for a Particular Java Class in Adobe CQ 5

    In Adobe CQ5, it sometimes becomes necessary to make a particular package or class spit out DEBUG level log entries in order to troubleshoot problems.

    1) From the error.log, determine the class that you want to bump up logging on. I.e. let’s say you’ve got system logging turned up to Warn and you want to see the INFO level progress of your datastore Garbage Collection (com.day.crx.persistence.tar.utils.DataStoreGarbageCollector)

    2) Add an INFO logger configuration for that class.

    In the OSGi configuration console at /system/console/configMgr, search for “Apache Sling Logger Configuration” and click the plus sign to its right. The class name should be in the field labeled “Logger”. See the example below.


    By aem4beginner

    May 15, 2020
    Estimated Post Reading Time ~

    Debugging AEM

    Debugging AEM: A Primer
    Follow along with my quest to solve a bug with the DAM Update Asset workflow
    One of the hardest things for me when starting with AEM was learning how to break problems down to figure out the root cause. There are so many moving parts in AEM, and most of them were either unfamiliar territory (Sling, Felix, the JCR) or are unique to AEM itself (things like Granite, Coral, the workflow engine, etc.) So, when I recently was forced to debug a problem that occurs in AEM out-of-the-box, I decided to write a detailed article laying some of the techniques I use to debug AEM when it isn’t doing what I think it should. 

    On the other hand, if you’re someone who is finding that their “DAM Update Asset” workflow disappears from the “Timeline” view, and you’d like to skip to the end, jump directly to “Restoring the DAM Update Asset Workflow”.

    Introducing the Problem
    For the past few AEM releases, every few months my end-users would re-open the same internal support ticket. “‘DAM Update Asset’ Workflow is unavailable in the siderail.”

    We have a fairly large implementation of AEM Assets, disconnected from any AEM Sites instance, with a number of users who work in AEM every day but aren’t exactly…well, they’re graphics people. They refer to me as their “propeller-head”, so I think I’ll refer to them as my “Luddites”.

    One of the operations they need to do on a fairly regular basis is to perform the “DAM Update Asset” workflow on 20-30 assets at a time. To do this, they often use the “Timeline” rail in the Assets view:


    So you can perhaps imagine the consternation when, every few days, that workflow just completely disappears from the rail.

    Even more frustrating, it would happen between releases, when we were pretty sure no one should be changing anything. At first we suspected it was a permissions issue, but as we dug deeper we found that even the built-in “admin” user couldn’t see the desired workflow in this select list. So began a hunt for what may be the most subtle bug I’ve ever found in AEM.

    How does that rail work, anyway?
    As I began to dig into the problem, I decided the first task was to see what builds that siderail, and specifically the dropdown list of Workflow Models that we are allowed to select from. Of course, AEM is all built on top of a series of HTTP Requests, so the first thing I did was open my Chrome DevTools panel and load the page.

    …238 requests. OK, this is going to take some time.
    My first assumption was that there would be a .json request for the list of Workflow models, so I tried using the “filter” box to just show requests containing .json, but after 30 minutes or so of going through the JSON responses, I realized this assumption was flawed. Nothing I could find led to the list of workflows.

    Taking a different tack, I cleared the DevTools and reloaded the page, this time instructing Chrome to capture screenshots as the page loaded. I had a strong hunch that whatever it was would be loaded before the Workflow Selector UI was visible, so this led me to focus in on the requests made sometime between 2.24 seconds into the request and 2.39 seconds; a much smaller body of requests to work with.


    Here, I have filtered the DevTools requests for those items which came in between approximately 2.1 and 2.3 seconds:


    I got excited seeing those timeline.js entries, but upon further inspection these turned out to simply be the code that defines some of rendering of that side rail, but it didn’t include any of the actual content. When none of the others panned out either, I moved back to that moment between 2.0s and 2.2s, where you can see the long green bar.


    From my previous dive into the JSON requests, I already know datasource.data.json and assetdetails.assetnavigation.json weren’t the culprits, so I zeroed in on that timeline.html request, and found the data I was looking for!


    Now we have a path we can use to dig into the CRX: /mnt/overlay/dam/gui/content/assetdetails/jcr:content/rails/timeline/items/timeline.html. My first guess when looking for anything that lives behind /mnt/overlay is always to start with /libs - because that’s the OOTB configuration for how AEM itself decodes these. So let’s take a peek in the CRX DeLite at /libs/dam/gui/content/assetdetails/jcr:content/rails/timeline/items/timeline. Stick with me for a bit longer, because crawling around the dependency tree of built-in components can feel more than a little tedious.
    /libs/dam/gui/content/assetdetails/jcr:content/rails/timeline/items/timeline is a Granite Include (granite/ui/components/coral/foundation/include) referencing the path /mnt/overlay/dam/gui/coral/content/commons/sidepanels/timeline. Again, we replace /mnt/overlay with /libs, and find that /libs/dam/gui/coral/content/commons/sidepanels/timeline has a sling:resourceType of cq/gui/components/coral/common/admin/timeline; again, we know we need to resolve that, most likely under /libs. At first blush, it feels like the trail may have gone a bit cold on us here because that path has a ton of structure:


    But ultimately I’m looking for some datasources, and it didn’t take very many expansions of childnodes to find /libs/cq/gui/components/coral/common/admin/timeline/events/workflow/datasources, which has a very useful JSP nested under it at /libs/cq/gui/components/coral/common/admin/timeline/events/workflow/datasources/models/models.jsp. I wish I could link to a GitHub Gist of the code behind this, marking up the lines of code that are the most interesting, but there’s a big, scary header at the top of the file: 

    <%-- ADOBE CONFIDENTIAL Copyright 2015 Adobe Systems Incorporated All Rights Reserved. NOTICE: All information contained herein is, and remains the property of Adobe Systems Incorporated and its suppliers, if any. The intellectual and technical concepts contained herein are proprietary to Adobe Systems Incorporated and its suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior written permission is obtained from Adobe Systems Incorporated. --%>

    Anyway, if you’ve got a copy of AEM, you can open it yourself and follow along as I explain at a higher level what’s going on in this JSP.

    As the path suggests, this JSP generates the list of workflows for the “Timeline” siderail; it uses a ComponentHandler to look for a property named “workflowtags”, parses that as CSV data, and then it looks for workflows that have cq:tags attributes on them that exist in that CSV data. So we need to find where AEM is reading that “workflowtags” property from, in order to determine why the “DAM Update Asset” workflow isn’t visible here.

    After hunting around manually for a while, I returned to our timeline.html rendered content to look for more clues, and saw an identifier that seemed like it might pretty useful for digging further: cq-common-admin-timeline-toolbar-actions-workflow-select 



    I took this value to the “Search” box on the main page of CRX DeLite, and one of the first hits it led me to was /libs/dam/gui/coral/content/commons/sidepanels/timeline/items/toolbar/items/workflows/items/form/items/model


    So, we have found that only things with the cq:tag “workflow:dam” will appear in the Timeline siderail. Venturing out to /var/workflow/models/dam/update_asset/metaData, we can see it has actually two tags:


    Well, that didn’t seem to help at ALL! It should be included in our Timelines siderail, based on all this logic. It was at this point that I spun up a new version of AEM 6.5, installed SP1, and to confirm that I wasn’t losing my mind, added a logger to the shouldBeIncluded method found in the aforementioned models.jsp file. Watching my logs, I could see that the workflow came through just fine, so I cloned our production AEM Assets instance and added the same logger, and found to my amazement that the “DAM Update Asset” workflow was missing the “dam” tag!

    A diversion on cq:tags
    cq:tags have, more than once, been a source of frustration in an AEM implementation. For example, if you create a bunch of content, and tag it up, and then export a package to load that content onto another server, you might be frustrated to discover many of your tags have gone missing.
    I really feel this is an under-documented area of AEM, as I could only find one single line that explained the behavior, buried in the middle of a page about “programmatically working with tags”:

    The TagManager ensures that tags entered as values on the cq:tags string array property are not duplicated, it removes TagIDs pointing to non-existing tags and updates TagIDs for moved or merged tags.

    Even more, interestingly, these are not direct cq:tag properties, but rather a sort of hybrid use of tags, with enforcement enabled by the model.jsp file. With the repository restructuring, I knew that cq:tags moved from /etc/tags to /content/cq:tags (not the most intuitive of the moves in the repository restructuring, I would really have expected those to be part of the new /conf tree, but ), and that there was a special “Backwards Compatibility” mode where even in 6.4 instances if AEM saw an /etc/tags tree it would continue to persist new cq:tag nodes there, rather than in the preferred location.

    Returning back to our hunt for the missing model, we are expecting this model to have the requisite “dam” tag, but our logger has shown us that something is off. At this point, I went into the new /conf tree and found that the workflow had been modified


    HA! Old some-user-who-should-know-better has modified the workflow, and you can see RIGHT THERE - the modified the cq:tags, so that now only Workflow:WCM is part of this workflow. After hours of hunting around in AEM to find the root cause, I had my smoking gun!

    I proceeded to some-user-who-should-know-better’s desk and read them the riot act about changing things in Prod where they had no business being. They insisted they had not touched the tags, they had only marked the workflow as non-transient; because we have an internal utility that queries our AEM Assets implementation for in-progress workflows to show them on a dashboard, we need the workflow history to be persisted in the tree. Trying to calm my raging emotions, I allowed for how perhaps they had ACCIDENTALLY removed the tag, not realizing they’d done it. They seemed really confident this wasn’t the case, so we took a little trip to the office of some-user-who-should-know-better’s boss to find a mediator for the discussion.

    To demonstrate what I believed to have happened, I sat at the computer of some-user-who-should-know-better’s boss and went to my newly created AEM 6.5 SP1 instance, navigated to the “DAM Update Asset” workflow as I explained my theory of the crime.
    “So when you load this page here,” I explained, “you’ll see there are two tags on the…”. I stopped, mid-sentence. There was only ONE TAG on the workflow - “Workflow: WCM”.

    “Well, ” I vamped. “You can see how easy it is to accidentally remove the tags, as I appear to have done the same myself. Now, we can just go into the Tag Manager here and add that critical Workflow:DAM tag back onto this workflow…”
    Again, stunned silence. There WAS NO TAG for Workflow:Dam. It simply wasn’t there!

    Restoring the DAM Update Asset Workflow
    I backed my way out of the conversation and headed back to my desk, wondering when I had deleted that so-critical tag. I nuked my AEM 6.5 SP1 instance and created a new one, navigate to the same workflow. There it was again: the Workflow:DAM tag was missing, and this was a BRAND NEW instance of AEM. I opened the tag browser and found the tag was missing, and it all finally came together. 

    At this point, I have checked every release between 6.2.0.0 and 6.5.1.0, and I cannot find this Workflow:DAM tag in ANY of these versions OOTB.


    Because of the original nodes in /var/workflows use a normal string property named ‘tags’ rather than actually using truly a cq:tag the property, this tag being missing doesn’t actually get caught until someone tries to edit one of these workflows; when saving those edits, the new version of the workflow gets saved under /conf and the property is converted to a real cq:tag the property, at which point AEM deletes the Workflow:DAM tag, because the tag doesn’t ACTUALLY exist in an OOTB instance of AEM.

    The simple resolution, until Adobe fixes this, is to manually create the Workflow:DAM tag in your cq:tags list; or, you can install this package via your Package Manager, which will create the tag for you.

    Source: https://aemhq.com/posts/debugging-aem-primer/


    By aem4beginner

    Debugging Adobe Dynamic Tag Management (DTM)

    Debugging Adobe Dynamic Tag Management, as with everything in the (marketing) technology world, means there will be a point where debugging is a must.

    Adobe Analytics is a powerful tool to analyse almost anything that can be tracked on a website. Unfortunately, any additional, customised code and feature increases the risk of introducing bugs as well.

    Setting up the debugging environment
    We already briefly discussed the advantages of DTM and how to include it into a digital marketing platform in a prior article on our blog. Once DTM is set up and all the necessary rules that help tracking the right data are defined, the fun begins: Seeing them in action. When testing if everything works the way it should two things need to be considered:
    The rule is firing successfully
    The variables are mapped correctly

    In order to properly manage to monitor this you need a packet analyser (or network analyser). Don't get intimidated though, you have one installed already, and you love to watch youtube with it.

    Yes, your browser most surely has a packet analyser already built in. It's normally the "network" tab of the “web console” or “developer tools” of your preferred browser. The name changes from one browser to another, but you should be able to find it in the browser's options. Also, there are some add-ons and plug-ins that can also do the same thing.

    For simplicity, I'll stick with Google Chrome's console (which you can bring up by hitting F12 on a PC, or ⌥⌘j on a Mac), and the Adobe Marketing Cloud Debugger plugin. Follow the instructions on Adobe's website to set everything up correctly.

    Enough with the tools, let's start debugging
    To make things a bit more visual let's think of an example: you set a “Page Load Rule” with a condition to fire for all pages that contain the word “marketing” in the URL. Now, you load the specific page and want to know if your rule fired or not. You have a couple of ways of knowing this:

    First approach to see if a rule fired:
    Set at least one variable in the “Adobe Analytics” section of the DTM rule; for example the Page Name. Now go to the Chrome's console, and in the “network” tab, look for a request to the Adobe Analytics servers. Pro tip: all request to Adobe Analytics have “/ss/” in the URL, so you can filter these out with the search function.


    Setting the Page Name Variable in DTM


    Filtering out Adobe Analytics requests in Google Developer Tools
    The image above shows that the rule fired successfully. Now, you can click on the result, see the contents of it, and confirm that the pageName came through as you set it.

    For better usability you can use the "Adobe Marketing Cloud Debugger". It shows the content of the requests in a better and easier to read way. This is how our request looks like on the debugger tool:


    Using the Adobe Marketing Debugger Tool to see if a rule is fired
    By looking at the request on the debugger, you can easily confirm that your variables are mapped correctly, too. In this case we are only setting page name, but of course here you can also check your evars, props, events and other system or configuration variables.

    If you want to use DTM for any tool other than Adobe Analytics, you can still check if the rule fired successfully using the method we described above. But to control if the variables were mapped correctly and a more in depth analysis you should get some advice on how to debug that specific tool that you are using.

    The quick check to see if a rule is fired:
    Another very simple hack to see if a rule is fired or not is using Javascript. You can add a short script to your DTM rule that will inform you once a rule is fired. Simply go to the “Javascript / Third Party Tags” section of the DTM rule and add a very simple new script: console.log(“Marketing Page Rule Fired”);


    Adding JavaScript to a DTM rule
    Adding the right script to display notifications in the browser console

    “Console logs” are vastly used for debugging code. All they do is to display anything you want in your browser console. In this case we only want it to display the text “Marketing Page Rule Fired” as soon as the rule is triggered. If the rule fires, you will see something like below on your console:


    Seeing the page rule fired in the browser's console

    Making Adobe DTM work
    Now you know how to debug your rules and confirm that your variables are mapped correctly. As mentioned above, the same thing can be achieved with several other tools, like the Firefox's console, firebug + omnibug, Httpfox, or other browsers' consoles.

    Source: https://www.netcentric.biz/insights/2015/09/debugging-adobe-dynamic-tag-management--dtm-.html


    By aem4beginner

    Debugging AEM Web Stacks Properly

    With web stacks getting larger and more complex, the need for debugging is more present then ever. Performance issues are especially painful to debug, and require much time and attention until a root cause analysis is completely performed. It is sometimes difficult to understand how to debug a problem or where to start when working on AEM Web Stacks.

    A common topic in AEM setup is that there are performance issues or bugs, and someone needs to find the root cause. In many cases the DevOps team or systems engineer tends to have the broadest understanding of the whole web stack, and in the end starts a first analysis.

    Usually one can categorise the different types of issues into two specific categories:
    1. Performance, something is running slow, the request isn't answered properly or similar
    2. Some bug, something isn't working as expected, a header is present but should not be
    In an AEM stack there are multiple layers involved:
    • CDN
    • Loadbalancer
    • Apache
    • mod_dispatcher / varnish
    • AEM
    For debugging such a large stack, it is possible to start on one end or the other. In most cases with AEM, it is good to start at AEM level and then work your way out because in many cases a bug, for example with a request , may be already at AEM level OR in fact it lets you know right away it is not at the AEM level.

    Below is a high level representation of a valid approach which can be applied to debug such a complex web stack for performance or bug type scenarios.

    Performance
    For performance issues, one can use various tools to first get an overview of where exactly the performance issue is coming from:
    1. Leverage the rlog.jar to identify slow running requests.
    2. Use the graphing tool from Jörg Hoh to visualize them.
    3. A good start is also to use your browser development tools. In some cases, this can lead to a quick pointer in the direction.
    Additionally it makes sense to look at performance data from the instance itself and not AEM only. For this, nmon is simple but very effective.

    Use nmon logs + nmon visualizer to visualise performance issues on the server
    1. Gather all the logs (error, request, nmon etc.)
    2. Create threaddumps before you restart AEM every 5 seconds 10 pieces
    3. Create the rlog jar output
    4. Visualize the logs
    5. Pinpoint a specific time when the issue occurred.
    6. Try to correlate slow running requests to some potential issues seen in nmon
    7. If you can't, the chances are high that the issue is in AEM. This will give you a good guess if it is an AEM issue or possibly some other problem impacting AEM
    8. A first step is to find the request and look in the error.log to see if there is any stacktrace possibly popping up in relation to the long-running request
    9. If it is an AEM issue, thread dumps are a must-have.
    To analyze thread dumps you can use fastThread or Online Java Thread Dump Analyzer

    At this point when looking at thread dumps it is good to involve the solutions architect or a senior developer to further analyze them if you are missing the detailed knowledge.

    Additionally, many projects have profilers at hand. For example, AppDynamics. Use it! Look at the general metrics, look for correlations and look at the garbage collections or other JVM metrics to try to identify a possible request and or job.


    Bugs
    Begin finding bugs by reproducing the problem. Start by getting exact input if you can. Try re-producing the problem in your test environment with as little data as possible. Ask about all the conditions present when the problem occurred (for example, other users, batch jobs, etc.)

    In some cases, you may need to debug some requests. The first stop is the browser dev tools. Here, ensure you are able to extract the specific request you need. You can alter it with a cache killer to see if it is an issue with the cache.



    Debugging bugs with proper domains
    In other cases, use DNS spoofing to setup local/etc/hosts entries set to a specific IP to simulate a public DNS record, but test directly against an AEM for example. Alternatively, a local proxy can help or tunnelling yourself to the server if direct access is not possible.

    Work your way back from the CDN down to AEM to debug those issues. Either way, it is doable.

    Debugging headers
    Adobe has the so called proxy.jar which is very helpful in these cases. This can be used to debug headers as it logs out the complete request output.

    Problems after deployment
    Generally use health checks to check if an instance is in a good state after deployment. Additionally, you might want to check the following things manually:
    Are all packages installed and in installed state
    Are all bundles present
    Are all bundles that should be present, in the right version
    Ensure the cache was flushed or invalidated

    Comparing bundles
    Additionally, you can use OOB OSGI Sanity Check to check the bundles or OOB OSGI Sanity Check Between Environments to compare the bundles between two instances.

    Conclusion
    The approach to finding the root causes of performance issues or bugs should always be an analytical one. This can save much time and allows for achieving faster results. Don't spend too much time in areas you are not sure about. Instead, involve a solutions architect or developer especially if the issue seems to be coming from within AEM. Robelle has published a very interesting article on their site on how to debug such issues. It is a recommended read even if not all points are fully applicable. The article elaborates on the clear analytical approach needed to solve performance issues and bugs quickly.



    By aem4beginner

    May 13, 2020
    Estimated Post Reading Time ~

    Debugging Client Libraries

    With different methods of categories and embeds to include multiple client libraries it can be cumbersome to troubleshoot. AEM exposes several tools to help with this. One of the most important tools is Rebuild Client Libraries which will force AEM to re-compile any LESS files and generate the CSS.

    Dump Libs - Lists all of the client libraries registered in the AEM instance.
    http://localhost:4502/libs/granite/ui/content/dumplibs.html

    Test Output - allows a user to see the expected HTML output of clientlib includes based on category.
    http://localhost:4502/libs/granite/ui/content/dumplibs.test.html

    Libraries Dependencies validation - highlights any dependencies or embedded categories that cannot be found.
    http://localhost:4502/libs/granite/ui/content/dumplibs.validate.html

    Rebuild Client Libraries - allows a user to force AEM to rebuild all of the client libraries or invalidate the cache of client libraries. This tool is particularly effective when developing with LESS as this can force AEM to re-compile the generated CSS. In general it is more effective to Invalidate Caches and then perform a page refresh versus rebuilding all of the libraries.

    http://localhost:4502/libs/granite/ui/content/dumplibs.rebuild.html


    By aem4beginner

    May 12, 2020
    Estimated Post Reading Time ~

    Debugging in AEM on Remote

    To access the complete flow of a CQ running on a remote server, First We need to start our CQ instance in debug mode.

    Step 1: Add the Remote Debugging JVM Parameter

    1. To use remote debugging, you must start CQ5 with this JVM parameter:
      -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
    You can add the parameter by doing the following;
    1. Start your server like this: crx-quickstart/bin/start -d --debug-port 8000. The -d parameter adds the jvm parameter to the CQ5 java process.
    2. Add it to your crx-quickstart/bin/start script CQ_JVM_OPTS environment variable (so your server always starts in debug mode).
    3. Include it as a parameter when starting CQ5 with java -jar directly. For example, java -Xmx512m -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n -jar cq-author-4502.jar
    Another Version of the command is :
    java -jar cq5-author-4502.jar -fork -forkargs -- -Xdebug -Xrunjdwp:transport=dt_socket,address=59865,suspend=n,server=y -Xmx1520m -XX:MaxPermSize=512m -XX:-UseSplitVerifier
    Notes
    • If necessary, you can change the port defined under “…,address=8000,…” from 8000 to something that works better in your environment.
    • Starting CQ 5.5, using the last solution, when Quickstart forks a new process it does not start the JVM with the debug options. You can prevent forking by specifying the -nofork command line option.
    • Te start script is located under crx-quickstart/server for CQ versions < 5.5

    Step 2: Start a remote debugging session

    To start a remote debugging session from Eclipse, do the following:
    1. Open Eclipse.
    2. Choose Run > Debug Configurations.
    3. Right-click Remote Java Applications and select New.
    4. Select your CQ5 project under Project.
    5. Type in the port from the “address” configuration of the jvm parameter defined above. In the example, it is port 8000 (and the host name of the machine you are connecting to, most likely localhost)
    6. To start a debugging session, double-click your new configuration in the Debug Configurations screen after saving it.
    Applies to:  CQ 5.x and Adobe Experience Manager 6.x
    Troubleshooting :
    1. While starting the AEM instance, make sure JVM has enough heap size for running CQ server, otherwise it will fork the JVM and parameters will not be passed to the forked jvm. Use -fork -forkargs – option to ensure that the command line parameters gets passed to the jvm.
    2. If you are using java 7 , make sure to specify the -XX:-UseSplitVerifier parameter to avoid the unwanted strict verification errors while debugging the bundle.


    By aem4beginner

    Decompiling and Debugging AEM

    A disassembled embedded computer
    If you know where to look you can step through pretty much every line of code that runs on an AEM instance. This article contains details on where to look and how to look there.
    Figuring out how stuff works is hard. When you’re working on AEM customizations, sometimes you need to know how something works at a level that is much deeper than the information provided by the documentation from your peers or even the source code itself. In this article I offer multiple multiple strategies to get to that deeper level. With this you can observe your code from multiple angles as it executes and determine exactly why certain behaviors are occurring.

    Tailing the logs

    Before we begin getting our hands dirty, a quick recommendation: When I’m developing AEM code I am always tailing the error logs for my active instances on a screen that is visible while I work. With this you can often catch exceptions as they occur by the unique indentation they have. You can see if an infinite loop has been created when the logs ramp up speed unexpectedly. With experience you can catch other issues too.
    Again I recommend tailing the error logs at all times during development. For most instances the logs are in crx-quickstart/logs with error.log being the most important. Note that all of the loggers open a new file each day. If you happen to be tailing when this happens, most apps will not correctly make the switch to the new file. You will need to halt the tail and restart it.
    For my setup I run 3 monitors – one with my browser, one with my IDE, and one with iTerm2. On iTerm2 I’m running tmux with a pane to run builds and git commands, and one pane each for the error.logs of the running AEM instances I have. I use less +F rather than tail so that I can ^c to halt the follow and go back to lines that have passed by. I start everything (including the AEM instances!) using a tmuxp profile each day (I recommend turning your computer off completely at the end of the day). You may find another setup that works for you.

    Tracing a Response to its Servlet

    If you are checking behavior for which you do not already have a stack trace, the first thing you need to do is find the handler for that behavior. In AEM the quickest and easiest way to do that for most behaviors is to know your Sling resolution basics. Adobe’s documentation has a great cheat sheet. There is a great deal of more detailed information in the Sling documentation.
    Tracking down the correct jsp, HTL template, or other Servlet manually can still be a lot of work. Luckily the OSGi console offers a special utility that can take a request path and tell you what is responding. That is located at /system/console/servletresolver. Note that if you are looking at a page the responding script will almost always be /libs/cq/Page/Page.jsp. That script generally just rewrites the request to use the underlying jcr:content node to respond. So to short cut this change /content/page/path.html to /content/page/path/_jcr_content.html when using this form. However in most cases you can pass the direct path to a component to get narrower results, such as /content/page/path/_jcr_content/header.html.
    Another important thing to know when tracing a response back to its servlet is the various locations where the request can be rewritten. I recommend bypassing the Dispatcher when performing work like this, but it is important to know that the Dispatcher is one source of rewrites. There are several others within AEM (nodes in the jcr, an OSGi config, and request filters off the top of my head). Luckily you can test the majority of these using another page in the OSGi console – /system/console/jcrresolver. For the purposes of debugging, you will want to use the “Resolve” button (which tests rewrites for incoming requests) rather than the “Map” button (which tests rewrites of links on outgoing content.

    Getting Java Source Code

    When debugging, the first thing you need is the source code. You can get pretty much all the source for AEM through decompiling. However before we get to decompiling I recommend that you check to see if the source is already up online. Many of the modules used in AEM are open source and their code is on GitHub, or another accessible repo.
    Note: If you can’t find the source but you’re using IntelliJ, you may be able to get some direct decompilation during debugging without finding the OSGi bundle. I still recommend knowing where everything is and how to do this in case IntelliJ fails.
    For the code that you can’t find online, you can grab the OSGi bundle for it and decompile it. In many cases you can find a specific class by searching for it, or its interface on the OSGi console’s Package Dependencies page at /system/console/depfinder. However sometimes this doesn’t work. I recommend skipping that step and doing a ^f on /system/console/status-Bundles instead.
    Once you know the OSGi bundle that contains your target class, grab that OSGi bundle’s bundle number. The bundle number actually corresponds to the bundle’s storage folder on your file system. On most systems the bundle with that number will be located at crx-quickstart/launchpad/felix/bundle<discovered bundle id>. Your jar will be under a folder named version#.# (pick the highest version number) and named bundle.jar. Copy it to second location before moving on. I recommend renaming the copy after the jar name listed in the bundle location field on /system/console/bundles.
    Note that some bundles are also in the jcr. The bundle location will then list jcrinstall:/apps… for these bundles you can also download them directly via that path.
    Once you have your appropriately named jar, you can decompile it directly. For this I recommend using JD-GUI. Note that JD-GUI is getting a little old. So it does some funny stuff when decompiling more functional Java. It will attempt to decompile classes to Java even if they were originally written in Groovy.
    JD-GUI can save the decompiled source code as a zip file that IDEs can use for debugging. To do this go to the File menu and then select “Save All Sources”.

    Debugging Java (and Groovy) Source Code

    Enabling Debug Mode on an AEM Instance

    Before you start adding breakpoints and running tests you will need to restart your AEM instance in debug mode. To do this you will need to modify the start script and then start your instance using the commandline instead of by double-clicking the jar.
    To do this open the start script in your favorite text editor. On most instances the start script is at crx-quickstart/bin/start. Then paste in the following content just above the comment that says “do not configure below this point”. In AEM 6.4 this is around line 88.
    if [ "$1" = "--debug" ]; then
    CQ_JVM_OPTS="${CQ_JVM_OPTS} -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=30303,suspend=n"
    fi
    Note: if you are using Windows for development then there is a similar change you can make to start.bat but I’m unfamiliar with that setup. These instructions are for OS X but should work on any unix based system with Bash available.
    From now on, you should use the following command to start your instance when you want debug mode enabled:
    crx-quickstart/bin/start --debug
    Note that this assumes you are currently in the same folder as the jar. I actually have a custom alias command that I run that uses the start script’s absolute path.
    A couple of caveats here:
    • The port in the lines you add to your start script must be unique and not in use. I recommend switching this to 40404 for the publish instance.
    • The start script no longer is correctly updated on initial build if your instance is a publish instance. You will need to ensure that the CQ_RUNMODE is set to publish for that. To do that you can find the setting toward the top of the start script. In AEM 6.4 it is at line 24.
    • The start script also no longer contains an updated port. So if you are using a custom port number or you are on a publish instance you will need to update the CQ_PORT variable as appropriate. In AEM 6.5 it is at line 13.

    Attaching a Debugger and Setting Breakpoints

    The big 3 Java IDEs all have built in debuggers that should work for debugging AEM. I recommend using either Netbeans or IntelliJ. In both cases you want to connect to a remote running JVM. Provide the port that you added in the start script (30303 by default) and keep localhost as the host if you are working locally. Once you connect your IDE to your running instance, you can set breakpoints by clicking to the far left of a line or by using your IDE’s debug configs to add method or class level breakpoints.
    If you need to use decompiled source from JD-GUI then add it to your debug sources using your IDE’s debug settings.
    Once breakpoints are set, run the corresponding behavior that you are testing and wait for your IDE to pause execution. Depending on what you are testing your browser may get stuck loading. As you debug on a regular basis you will get better at creating more targeted breakpoints and come up with a debugging style that works for you.
    A couple of caveats here:
    • Do not run a build while your debugger is attached. Detach the debugger, run the build, and reattach it again to repeat your test. An attached debugger may prevent the build from completing or cause other issues.
    • In some cases in IntelliJ the debugger will trip a breakpoint but the IDE won’t catch it. If execution pauses but the IDE isn’t working you can try pausing the debugger manually using its pause button and then hit play again to resume.
    • In some cases your debugger will not detach properly. If this occurs you may see halted execution or other weird behavior. Try reattaching to fix this. Otherwise you may need to restart your instance. This is pretty rare.
    • In some cases an AEM instance will not shut down properly after a debugger has been used. To stop it you will need to find it’s process id from the commandline and manually kill it. There are easy instructions for that in the Odds and Ends section below.

    Debugging AEM JSP and HTL (Sightly) Servlets

    When debugging sometimes I’ve come across a particularly complex JSP or HTL template. It is not possible to set breakpoints on these as-is. So it can be difficult to figure out what is going on. Fortunately these files actually get transformed into Java that is then used as Servlets for the execution of requests. AEM offers a way to retrieve the generated Java source! To do this, go to /system/console/fsclassloader in the OSGi console and click view. You can then hit download below Java in the table at the top. From there you can debug this source like any other Java source!
    Note: If you are trying to retrieve the source for a jsp or htl template in this way, make sure that you’ve actually run a page that requires that template on this server, otherwise it will not appear in the list.

    Decompiling and Debugging the MVN Build

    Occasionally I’ve been working on custom build changes for our AEM projects. Most projects use Maven which also happens to be a Java based tool. Maven offers the ability to debug its execution just like AEM. To do this, use mvndebug instead of mvn as your build command in your terminal. Execution will pause until a debugger is attached. You should set breakpoints in the Maven plugin code before attaching and then attach your debugger. By default the debug port will be 8000 (with localhost as the domain). Once your debugger is attached, execution will continue until the first breakpoint is hit. From there you can debug normally.
    When looking for plugin source code, note that almost all of this is open source. Try to look around online for the actual source. If you can’t find it, you can also find the jar in your .m2 folder (usually under ~ on most systems) and decompile it.

    De-Minifying and Debugging AEM JS

    When working with JavaScript it can be difficult to follow the code due to optimizations like minification, which consolidate the code by shortening variable names and removing whitespace. AEM has a built in feature that does this which can be disabled during debugging. If your js file ends in .min.js but is not stored in the JCR like that, then it is likely that this setting is on. To disable it, go to /system/console/configMgr and find the Adobe Granite HTML Library Manager. Uncheck the Minify checkbox. You may also want to check the Debug checkbox, which will stop clientlib concatenation and keep the js files separated. That way you can more easily track down the exact source file that contains the code you need to modify.
    All of the major browsers offer a developer console that you can use. The quick and dirty way to open it is to right click on something and choose inspect element. There are also other menus and key commands that you can learn. Once you have it open there are a lot of different items that I find very useful.
    The biggest feature is the sources tab (name varies). This allows you to explore all of the js that is running on the page. You can set breakpoints and step through the code line by line just like with Java debugging. The network tab allows you to see requests and many details about them as they happen. Finally the console tab allows you to run individual lines of JavaScript and see logged errors as they come in. There are a lot of other useful features as well. So look around and try everything!
    If you can’t disable minification for any reason, there is another option. Most of the major browser dev tools offer a “prettify” option that will take a minified js file and add basic indentation to make it more readable. Often this is also the easiest way to set meaningful breakpoints on a one line minified js file.
    Another nifty feature that you may want to take advantage of are DOM event breakpoints. These are only available in Chrome right now as far as I know, but they allow you to break execution whenever code makes a change to the DOM. This can be useful if you don’t know what JavaScript is causing an element to transform.
    Note that the developer consoles also have tabs where you can manipulate the css which can be vital in tracking down visual defects.

    Debugging Groovy Console Scripts

    Our company offers an open source solution called the AEM Groovy Console which allows administrators to write quick Groovy scripts that run against the live AEM instance. With it you can do things like gather reports, find and replace for a specific property, or even build an entire site from scratch. The scripts are written in a browser window and submitted to the backend for processing. It took some digging to figure out how to add breakpoints to these scripts so that I can debug them while they are running.
    I found the secret by debugging the console itself using the techniques above. You can see the method that actually runs the script at com.icfolson.aem.groovy.console.impl.DefaultGroovyConsoleService.runScript(). Once you know that, you can step through and check the class name of the script variable.
    With the classname, in this case it is almost always Script1.groovy (fully qualified – no package), you can trick your IDE into using the source of your script to back that class. In IntelliJ and Netbeans, just putting the script in a file named Script1.groovy in the default class path was enough (for most AEM projects this would be in /<name of project>/<name of project>-core/src/main/java/Script1.groovy). From there you can set a breakpoint on that file and it will trigger for the same line as the Groovy Console script executes. Hooray debugging!

    Odds and Ends – Misc Good Stuff

    Here’s a few quick notes on other things I think you should know when decompiling and debugging AEM.

    Killing your instance

    If your instance becomes stuck or won’t respond, you may need to manually kill it and restart it. To do this I recommend the commandline utility lsof. AEM connects to it’s main port and also connects to the specified debug port when debugging. So you can quickly find the process by searching for programs that are connected to those ports.
    I run the following to find the author port listeners
    lsof -i :4502
    I also check
    lsof -i :30303
    in case the instance is partially shut down and only connected to the debug port. The results of this should give you a process id that you can then kill with the following:
    kill -kill <process id>
    Note that if you are doing this it probably means that the -kill is necessary (force quit) but you can try the command without it for graceful shutdown if you want.

    Grabbing /libs

    A quick bit of advice that came to me from Mark Daugherty: package up /libs using the package manager and unzip it locally to peruse that source code. I’ve always explored this in /crx/de/index.jsp but this gives you access to unix commandline tools and other programs. You can search with grep. Plus if you do this with multiple versions, you can even use diff utilities to see exactly what’s changed between versions!

    Documentation

    One important part of debugging is knowing what each piece is supposed to do. Documentation, especially JavaDoc is a huge help here. So you should keep track of where all of your documentation is! For instance Sightly Spec is at https://github.com/adobe/htl-spec/blob/master/SPECIFICATION.md, and the AEM 6.4 JavaDoc is currently at https://helpx.adobe.com/experience-manager/6-4/sites/developing/using/reference-materials/javadoc/index.html

    Never forget to look up the stack

    In the debugger and in log stack traces, we often focus down on the currently running function or method, but you can gain a lot of insight by looking up the stack. All of the major debuggers offer a pane where you can see the method chain that called the method you are currently in. Take a look in there and you can get an idea of where your input values came from.

    Conclusion

    I hope that this article has provided you with some new strategies for working with your code in AEM. Programming AEM features can be complicated and time consuming, but, if you can trace through execution, you can get there a lot faster. If there’s one thing I hope you remember from this article, it’s that there are many different avenues available for gaining information about your code. So you should keep digging until you find what you need.
    I had originally intended for this article to include step by step instructions for each debugging task. Unfortunately I’ve simply run out of time to put those instructions together. I hope that this article can help you get 90% of the way there anyway. If you get stuck, poke around and try things, you might even find an improvement on my process!
    “Take chances, make mistakes, and get messy!” – The Magic School Bus

    References

    While working in AEM I found a large number of articles and posts that helped me arrive at the processes above. Unfortunately many of those have since been lost. In some cases I derived the methods above directly and later found an article describing them. The references I do have noted are the following:


    By aem4beginner