Posts

Embed Third party dependency using bnd-maven-plugin

Image
This post explains the use of bnd-maven-plugin to embed third party dependency  Two main instructions of bnd-maven-plugin that serves the purpose are detailed below.  -conditionalpackage  pick packages from respective library and copy them in the bundle. Any dependencies of those copied packages will also be copied if they match the selectors. This means we need to explicitly list all the Java package names of desired dependency as part of this instruction (including its transitive dependencies) More about conditionalpackage instruction from official docs -  https://bnd.bndtools.org/instructions/conditionalpackage.html -includeresource  For including resource inline -includeresource: @artifactId-version.jar!/* For embedding as a jar with an entry in bundle class path -includeresource: artifactId-version.jar;lib:=true For several other possible combinations for including the resource, please check - https://bnd.bndtools.org/instructions/includeresource.html Wi...

Set OSGi Component properties dynamically using OCD - Use case with Sling ResourceChangeListener

Image
This post demonstrates the use of Object Class Definition(OCD) in setting the OSGi component properties. In general, per OSGi R6 annotations and above, we can set OSGi component properties via property attribute of @Component annotation (Static values) or Dynamically using @ ObjectClassDefinition together with  @ AttributeDefinition     (property amends in run time via Config Admin or /system/console/configMgr ) AttributeDefinition should be framed such that it evaluates to the property name correctly (underscores are converted to dots/period) Association of OCD with OSGi component happens via annotation named @Designate Example : Component properties like service.ranking  and in case of specific implementations like say WorkflowProcess , we set property named process.label  and for EventHandler, it is  EventConstants.EVENT_TOPIC  and examples add on in a similar fashion for any OSGi Component for that matter.   In order to illustrate this, ...

Prioritize Search Results based on Boost in Lucene Index

Image
This short post explains the use of boost property in Index definition to prioritize the search results.  In Lucene Index, we have a property named boost   of type Double   which will help assign weightage to desired properties (that are part of fulltext/contains query) Properties with high boost value will be displayed earlier in the search results. Recently we had a query in the Community related to this subject to prioritize search term in URL to be first in the search results than the one found in properties like title/description.  In AEM, URL/path to the resource is simply the node names.  Node names are declared as property within the indexRules using special case identifier as   :nodename   and  is already available OOTB in cqPageLucene(/oak:index/cqPageLucene) Prerequisite for fulltext/contains query : We should make sure that we have two other properties named nodeScopeIndex and analyzed set to true (Both are of type "Boolean")...

Embedding Third party dependency/OSGi bundle in AEM application hosted in AEMasCS

Image
This post illustrate the ways of embedding third party dependency in AEM maven project. Steps are mentioned considering the project structure to be followed for AEMasCS while the same can be followed for classic versions too.  Before we begin, I would like to explain the scenario of including a dependency in our AEM maven project.  When we would like to make use of an API that is not already available in our project, we look for that in maven-central repository and specify the dependency in main pom.xml and desired module's pom.xml file. (Lets say, AWS S3 Java SDK V2 dependency) Upon updating the project in the IDE, we would see our class files (making use of those APIs) are compiled/build successfully without any errors.  Now, in the context of AEM/OSGi environment, when the same package and hence the bundle is deployed to AEM instance, dependencies that we added new might not be resolved/available in the OSGi as a bundle. Something like the below This indicates that the...

Index on Functions | Coalesce function in JCR-SQL2

Image
 This post illustrates the index definition for function with sample use case using function named Coalesce in JCR-SQL2 query.  Recently, we had a query in forum related to Sorting columns/properties with different names - https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/how-to-sort-query-results-by-combining-multiple-fields-as-single/td-p/419215 ie. To sort based on language where the language value is stored against a different property name in each component say, lang/language/compLanguage. Sorting needs to be based on the consolidated values of each of these fields.  I came across this blog which explains the similar scenario and the solution is to use Coalesce function in JCR-SQL2 query.  I reproduced the same (as illustrated in the blog above) in my local and it works fine. I haven't tried index definition for Functions before and hence decided to use this example. Note : I suggest to read through the forum query and the blog before p...

AEMasCS REST API calls from POSTMAN or any external application

Image
This post details the steps to invoke REST API hosted in AEM as a Cloud Service (AEMasCS) instance from POSTMAN or any external application.  As we all know AEM is REST based Web application and contents of Repository can be accessed via GET call to respective path (Eg say,  ".json" extension or content path with ".html" extension) and  updates to Repository is possible via respective HTTP method type + API endpoint as exposed (Eg. Assets HTTP API Create Folder POST request) ,  provided we have Authentication and Authorization to the accessing endpoints.  Authentication is achieved using the credentials that we use to access our instance. Eg. In our local AEM author instance, we login using admin/admin or any username as created/available in the respective instance Authorization refers to the permissions to the path we are accessing  Eg: If we are to make GET request on /content/we-retail.html , we need to have read permission on this path. Given this...

AWS Service in AEM

Image
 This post details the steps to make use of AWS service in web application developed using AEM. For incorporating any third party services/APIs in AEM, we have two direct possible routes - Via  Java SDK (as available in Maven Central) and via  Javascript SDK . Choice between the two depends on the availability, functional requirement and existing project set up.  With respect to AWS services, we have both SDK available and in this post, I am using AWS JAVA SDK V2.  Note  : The intention of this post is to demonstrate the ways to make use of AWS service in AEM projects and not to illustrate about the AWS service itself.  Prerequisites: AWS IAM user with Programmatic access type and with permissions to desired service set via Groups in IAM Access Key and Secret key pertaining to the user as created above. Reference :   https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html Approach: Include SDK in code base. Set up the acquired Se...

Create/build and install OSGi bundle of third party APIs/dependency using maven plugins

Image
This post details the steps to create and deploy OSGI bundle out of third party API/dependency using relevant plugins in simple maven project. We would have been in situation where OSGi bundle created out of third party jar is added/available in our instance and our project code base using the third party bundle being in active state. However at the time of execution, ClassNotFound or NoClassDefFound error pops up. This is the case when the dependencies of our desired third party API is not included/available when it is added as an OSGi bundle. We can overcome this by creating the bundle using maven-bundle-plugin which has option to include direct (desired third party dependency - highlighted in red in below screenshot -  * -  to include all the dependency entry in the pom.xml file or  artifactId name if we would like to mention explicitly  Note : There are several other possible options documented for <Embed-Dependency> in official plugin page (Mentioned the...

Customization in AEM Asset Quick Publish Action

Image
This post is about a requirement raised in Experience League Community forum related to Custom implementation on Asset Publish.   Project has custom field named "Effective date". If an asset is selected to publish before an Effective date, pop up should be triggered with option to either "Cancel" or "Continue to Publish" Requirement of this sort involving customizations on top of an OOB functionality can be approached as follows Locate the OOB files related to the functionality Custom code readiness Understanding the existing logic Incorporating our custom logic by overlaying the OOB files. Testing all possible use cases related to custom functionality without hindering any other related  OOB flow.  Locate the OOB files: As part of locating the OOB files, first step is to trigger a "Quick Publish" on an Asset and observe the flow. While observing the flow for this purpose, we need to have Developer tools on -> Network Tab with "Preserve L...

Unit testing in AEM - Debugging issues in Test class

Image
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 : Most important aspect of Unit Testing is creating Test content which in AEM sense is to provide a means of repository at the time of code build phase to test our Java code (written interacting with 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 class path and loading it to dummy content path. Below are the sample snippet making use of 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...

Unit Testing Hands on - For Sling Servlet

Image
This post is about creating Unit Test class for Sling Servlet, another commonly used Java class as part of an AEM application.  In Sling servlets, we have  SlingSafeMethodsServlet - read only servlet supporting GET  (doGet) SlingAllMethodsServlet - Supports POST, PUT and DELETE (doPost/doPut/doDelete) In either case, we have request and response objects using which desired code logic is written in Servlet.  For Unit testing, we have Mock sling request and sling response from Sling Mocks ( org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest  and org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse respectively) Writing unit test for Servlet involves the following Instantiate Servlet to be tested. Get mock request and response from AemContext Prepare the mock request object (per the code logic before calling doGet/doPost) Call doGet/doPost method of Servlet to be tested Assert the Servlet response (per the code logic) Inst...

Unit Testing Hands on - For WCMUsePojo

Image
This post illustrate the unit test for WCMUsePojo , Java class for backend logic as part of  AEM Component development. Quick Recap about WCMUsePojo :   WCMUsePojo initializes the objects associated with Bindings (Eg: WCMBindings/SlingBindings) via its init(Bindings) method which in turn calls activate() method for post initialization tasks. This init(Bindings bindings) method gets called if the POJO is instantiated in HTL via data-sly-use attribute. Bindings(javax.script.Bindings)  extends  Map(java.util.Map)  and hence it is basically a map object where  key  (type String) is the global variable and  value  is the respective object.  Once when the bindings are initialized, we are able to make use of the global variables which is available to us via methods like  getCurrentPage(), getProperties() etc. Example : When we call getCurrentPage() to get page object, below happens behind the scene  (considering the above flow) get...