Adobe Experience Manager | AEM/CQ | Apache Sling

Upgrade to the official OSGi Declarative Services (DS) Annotations from Apache Felix SCR annotations in Adobe Experience Manager (AEM).
By now you're pretty comfortable writing OSGi components and services using the Felix SCR annotations. However, with AEM 6.2 and greater comes support for the official OSGi Declarative Services annotations. This is exciting for two reasons. First, it's the official implementation; and second, it provides access to future improvements and specification advancements. The Felix Maven SCR plugin probably won't be providing much in the way of future enhancements. In fact, taken directly from the from the Apache Felix Maven SCR Plugin website:

"While the Apache Felix Maven SCR Plugin is a great tool for developing OSGi components using Declarative Services you should use the official annotations from the OSGi R6 specification. The development of the Apache Felix SCR Plugin is in maintenance mode."

The Apache Sling project and the Adobe Experience Manager product are both moving in this direction and it's suggested that you consider it for your project as well. The migration is fairly easy and both annotation styles will work side-by-side while you complete the switch-over.

If you want to skip directly to the examples, I've created a sample project with a service, servlet, filter, event handler and scheduler using the new annotation hosted on GitHub at: https://github.com/nateyolles/aem-osgi-annotation-demo.

Declarative Services

Remember that declarative services is a compile time process. In order for the DS annotations to be effective, they must be handled during the build process. The Apache Felix SCR annotations require the maven-scr-plugin while the OSGi DS annotations require the maven-bundle-plugin version 3.2.0 or greater.

With the maven-scr-plugin you may be used to finding the DS output under /target/classes/OSGI-INF and /target/classes/OSGI-INF/metatype. With the maven-bundle-plugin you will have to unzip the compiled artifact (the jar file) to find the DS output in its /OSG-INF directory.

Java Packages

Rather than using org.apache.felix.scr.annotations.*, you'll use org.osgi.service.component.annotations.* and org.osgi.service.metatype.annotations.*.

Dependencies

Rather than using the maven-scr-plugin, you need the maven-bundle-plugin version 3.2.0 or greater.

You also need the artifacts org.osgi.service.metatype.annotations and org.osgi.service.component.annotations (currently version 1.3.0) rather than org.osgi.core and org.osgi.compendium. See the provided sample project's POM file for more specifics.

Once you update your project's dependencies, you'll find that your IDE will inform you that the org.apache.felix.scr.annotations.* annotations are deprecated.

Service Configuration

The most noticeable difference between Felix SCR annotations and OSGi DS annotations is where service reference properties are defined. With Felix annotations everything is in the Properties and Property annotations either at the head of the class file or inline. OSGi DS annotations move the service reference properties to it's own class.

The annotations will move to their own class which declutters the component or service. For components with a large amount of options, you might find that you like an independent class, while a component with only one or two properties may be fine as a subclass.

You'll also immediately notice the Activate method becomes much cleaner as the need to use org.apache.sling.commons.osgi.PropertiesUtil to provide default values has been replaced.



Service Reference Properties

The AttributeDefinition method naming convention will immediately seem out of place. It's very Pythonic looking with its use of underscores. You don't need to write your method names that way, but the reason for doing so is that the underscores are converted to dots for display in the Felix console and your OSGi configs. For example, you're probably familiar with seeing properties defined as something like resource.resolver.searchpath. To achieve this in your configuration class, your method would be named resource_resolver_searchpath.

Provided is an example of how to create each individual property type with the newer OSGi annotations:





SlingServlet Annotation

The SlingServlet annotation is a special case - it's a convenience annotation and unfortunately it's not available anymore. However, the idea is that it will be available in the future as a custom annotation provided by Sling working in the OSGi DS framework when R7 is released. Your current SCR SlingServlet looks something like this (although without all the available properties set):



Instead, use a regular component annotation with service type Servlet.class. The service reference properties for paths, extensions, selectors, methods and resourceTypes are simple String properties. When setting array properties, set each entry on a new line. See the Apache Sling docs on Servlet Registration for the available service reference properties. When setting a non-String property value such as an Integer or Boolean, include the type such as service.ranking:Integer=100. Here's the OSGi version of that same servlet (again, you probably won't use all the available properties in your servlet):



Expanded Examples

View more examples in the demonstration project on GitHub: https://github.com/nateyolles/aem-osgi-annotation-demo.

Further Reading

Carsten Ziegeler's blog posts: ( @cziegeler):
Feike Visser's blog post ( @heervisscher):
Adobe Marketing Cloud:
Sync Crypto Keys across AEM 6.3 instances
In order to read data on one instance that was secured on another, you need to sync the Crypto keys across all of your instances. Prior to AEM 6.3, you would package up /etc/key and share it between your author and publish servers (See: How to Use Crypto support in Adobe CQ / AEM). However, in AEM 6.3 the Crypto keys were moved out of the JCR to make them more secure in case someone gains access to your CRXDE. Side note, ensure the public can't access CRXDE by going through the AEM 6.3 Security Checklist.

In order to sync the Crypto keys between servers in AEM 6.3:

  1. Find the bundle Id for com.adobe.granite.crypto.file, for example, 21. You can navigate to /system/console/bundles/com.adobe.granite.crypto.file to see the Id.
  2. Navigate to /crx-quickstart/launchpad/felix/bundle<Id>/data in the file system.
  3. Copy the two files: hmac and master from the source instance to the target instances.
  4. Restart the target com.adobe.granite.crypto bundle or the entire AEM instance.
There is a way to make AEM 6.3 read the Crypto keys from the JCR like you're currently familiar with, however, this is not recommended if you can avoid it. Start AEM 6.3 with the -Dcom.adobe.granite.crypto.file.disable=true flag. Note that this must happen on the first startup of the instance. The instance will not change behavior once AEM has been started with or without the flag.
Use custom Granite render conditions to determine if Touch UI components should display in AEM.
Granite render conditions can be used to determine whether a component should be rendered or not. From the Render Condition documentation, a "typical example would be to render a submit button based on whether the current user has a privilege to create or modify a resource." Render conditions can be used to help guide the author by dynamically customizing forms based on known information.

Download the sample project on GitHub at https://github.com/nateyolles/aem-granite-rendercondition-demo which includes various examples of utilizing the built-in render conditions as well as examples on how to create your own custom render conditions, how to pass in data to those render conditions and how to evaluate Expression Language with your custom render conditions.

Screenshot of an AEM admin form using Granite render conditions
There are many examples of render conditions throughout AEM and an easy way to start exploring is to query for the most basic render conditions from within CRXDE Lite using something like  /jcr:root//*[@sling:resourceType='granite/ui/components/foundation/renderconditions/simple']. You can find the standard render conditions such as  simpleandornot and  privilege under  /libs/granite/ui/components/foundation/renderconditions. There are a few custom render conditions under  /libs/cq/gui/components/projects/admin/renderconditions which you can explore, as well as  /libs/cq/gui/components/renderconditions/islocked/libs/wcm/msm/components/touch-ui/renderconditions/isblueprint and  /libs/wcm/msm/components/touch-ui/renderconditions/islivecopy. There is another great example of a custom render condition in the  ACS AEM Commons project which displays components based on the current path.

To utilize this server-side display logic, simply create a node under your Granite widget named granite:rendercondition, set the sling:resourceType to the render condition component such as granite/ui/components/foundation/renderconditions/simple and populate the required properties such as expression. For example, the following textfield will only render when the query string parameter biz equals baz.



Granite render conditions take advantage of JSP Expression Language or EL for short. As such, you have access to param, paramValues, header, headerValues, cookie, requestPathInfo, state and tenant. You also have access to a powerful, yet simple and straight-forward syntax to evaluate logic in Expression Language. Furthermore, Granite provides extra convenience with a few provided EL Functions. For example:



See the Granite UI Documentation on Expression Language for more information regarding available variables and functions. Note that EL expressions can be used outside of render conditions as well. For example, you'll find them granite/ui/components/foundation/hyperlink components to pass data forward, such as:



The simple render conditions are quick and readily available for most basic expressions. However, if you need custom logic, you can write your own render condition. A render condition is simply a JSP component. Within your custom logic you will get the granite:rendercondition resource, retrieve its relevant properties via the resource's Config and set a true or false  SimpleRenderCondition as a request attribute. To evaluate EL expressions, use the ExpressionHelper by way of the ExpressionResolver service, which is powered by the Apache Commons EL interpreter. The combination of a custom render condition and EL expressions is very powerful.



The custom render condition is used the same way the default render conditions are utilized, simply update the sling:resourceType to the path of your custom render condition component and populate your defined resource properties.



When you download the sample project at https://github.com/nateyolles/aem-granite-rendercondition-demo, you'll notice that the most straight-forward condition is the simple render condition and that you can combine conditions by nesting and, or and not conditions. This snippet from the demo project reveals a variety of ways to dynamically render Touch UI components including cookies, headers, query string parameters, selectors, suffixes, JCR privileges and custom render conditions.



You'll notice in the provided sample project that I created a custom Touch UI admin page to help demonstrate the various ways of using the Expression Language to interact with the URL. (If you're interested in how to do that, see Chris Millar's post on How to create an AEM 6.2 Admin Console for Touch UI.) Take note that render conditions work with any Granite widget, however, in specific scenarios, certain challenges exist when trying to use render conditions with component dialogs in your typical Touch UI editing of pages. Remember that an AJAX call is made to open the dialog and the EL expressions are evaluated on that AJAX request, not the request for the page which is in fact /editor.html. Therefore, the path, suffix, selectors and query string parameters are independent of what you see in your browser's address bar when using a normal component dialog in the editor.
Create custom HTML output for AEM clientlibs and Sightly to take advantage of HTML5 and enhance site performance.
AEM clientlibs are extremely powerful. They allow you to produce client-side JavaScript and CSS libraries while controlling minification, concatenation, and dependency management. However, out-of-the-box, they don't allow you to customize the HTML output. While optimizing your website for speed, you may want to use the defer, async, and/or onload attributes on your script elements. Likewise, while managing your cross-origin resource sharing (CORS) HTTP requests, you may want to utilize the crossorigin attribute on your script and/or link elements for JavaScript and CSS.


Using clientlibs in AEM with Sightly is demonstrated in the AEM documentation Using Client-Side Libraries, as well as Feike Visser's ( @heervisscher) Sightly intro part 5: FAQ.



When we follow the data-sly-use block's expression value in our AEM instance, we find three files that work together with the HtmlLibraryManager to provide the final clientlib output. clientlib.html contains named Sightly template blocks ( js, css, all), which in turn set the proper Sightly expression option for mode and call the named Sightly templates in graniteClientLib.html. graniteClientLib.html then sets the proper Sightly expression options and delegates the more complex logic to a Java-Use API POJO. ClientLibUseObject.java then utilizes the HtmlLibraryManager in order to write out the final HTML markup.

All files associated with Sightly clientlibs are viewable in your AEM instance under the /libs/granite/sightly/templates node. To make any alterations, we simply copy all three files out of /libs into /apps, update the files, and update our Sightly components to point to the new clientlib component (usually headlibs.html or similar partial in the page component).



In our case, we want to alter the HTML markup by adding additional attributes to the script and link elements. In order to do that, we first add additional Sightly expression options to all the Sightly templates. In this example, I'm using loading, onload, and crossorigin options.



Once the new Sightly expression options are set, the Java-Use POJO is updated to obtain those options from the provided bindings. AEM hands the responsibility of printing the final HTML markup to the HtmlLibraryManager's writeIncludes, writeCssInclude and writeJsInclude methods. However, since we want custom markup, we need to do that ourselves in the POJO.



I've written a demonstration AEM project as well provided the code which can easily be installed into a single folder for use in your project. There is also an AEM package available for easy install. View the AEM Clientlib Async project on GitHub.
Use com.adobe.granite.confmgr.ConfMgr in AEM to set multi-tenant, ACL protected, inheritance supplied configurations.
As of AEM 6.1 you may have noticed the new /conf node at the root level along with /content, /etc, /apps and /libs. Over time the /etc folder's responsibility has expanded and configurations have been moved in an effort to clean it up a little. Whereas prior to 6.1 you would have stored site configurations in /etc, it's now recommended that you store those configurations under /conf. Along with the new node structure Adobe has provided a valuable, yet simple, utility to help manage these new site configurations in com.adobe.granite.confmgr.ConfMgr and com.adobe.granite.confmgr.Conf.

Read the Adobe provided documentation for  Conf and ConfMgr.

I have created a demo project and hosted it on GitHub at https://github.com/nateyolles/aem-slash-conf.

As an example, let's host a multi-tenant AEM instance with three projects and one subproject: Aviato, Pied Piper, Hooli and subproject Hooli XYZ.

/content/aviato
/content/piedpiper
/content/hooli
/content/hooli/hoolixyz

Add a cq:conf property of type String at the root of every project page and point it to the site's corresponding configuration path. A global configuration will be used if a cq:conf property is not specified as is the case for Aviato in this example.

/content/piedpiper/jcr:content/@cq:conf = "/conf/tentants/piedpiper"
/content/hooli/jcr:content/@cq:conf = "/conf/tentants/hooli"
/content/hooli/hoolixyz/jcr:content/@cq:conf = "/conf/tentants/hooli/hoolixyz"

Conf respects relative paths as it pertains to the cq:conf property. Therefore, the following settings could also be used:

/content/hooli/jcr:content/@cq:conf = "/conf/tentants/hooli"
/content/hooli/hoolixyz/jcr:content/@cq:conf = "hoolixyz"

The tree structure of /conf should closely resemble /content. The configuration nodes should be of type cq:Page with the configuration properties on the jcr:content sub-nodes. All configurations start below the path specified in cq:conf with the addition of /settings.

/conf/global/settings/socialmedia/facebook/jcr:content/@enabled = false
/conf/tenants/piedpiper/settings/socialmedia/facebook/jcr:content/@enabled = true
/conf/tenants/hooli/settings/socialmedia/facebook/jcr:content/@enabled = true
/conf/tenants/hooli/hoolixyz/settings/socialmedia/facebook/jcr:content/@enabled = true

/conf/global is special as it provides an ultimate fallback in the Conf inheritance mechanism. It this example Aviato does not have its own config, so it would use the global configs. /conf/tenants is not dictated by AEM, but is a convention worth following to help prevent namespace collision in multi-tenant scenarios.

Configs can live under /conf, /apps and /libs with the same apps-then-libs type resolution that you are already familiar with. The resolution order can be set in the Felix console com.adobe.granite.confmgr.impl.ConfMgrImpl configuration: http://localhost:4502/system/console/configMgr/com.adobe.granite.confmgr.impl.ConfMgrImpl.

Use a Conf object to get a site configuration. The Conf object is usually obtained by adapted a Resource or Page using Apache Sling's adaptTo() method. Once you have the site's Conf object, you can get any number of predefined ValueMaps and properties. Notice that the ValueMaps cannot be modified – they are read-only. Properties are retrieved from the ValueMap in the familiar way of passing in either a default value or the class type.

The Conf object you retrieve is based on the path of the resource. So if have a Sling Model or WCMUsePojo and you adapt the current page, you will get a different Conf than if you adapt the current resource.



As you can see, the ConfMgr is a fairly lightweight and transparent helper. Everything is in the JCR, so configurations can be accessed through normal channels such as a Resource Resolver. However, there are three main benefits to using com.adobe.granite.confmgr.Conf.

The most obvious advantage is the built in inheritance management. For instance, the site for Hooli might have ten configurations. If the subproject Hooli XYZ overwrites only one of those configurations, it will use the other nine provided by Hooli. If the Conf object is looking for a config that doesn't exist in the subproject or project, it will look under /global. Conf inherits and overwrites at the node level, not the property level.

Conf handles null values for you. If the configuration, ValueMap or individual properties are null, you can continue without null checks and you won't get a Null Pointer Exception.

Conf respects ACLs and multi-tenant privacy. If you setup your ACLs correctly, a shared component between two tenants will still only be able to access the configurations of the current tenant. Conf does not allow relative paths that try to move up the tree and into another tenant (i.e. "../../differentSite/foo/bar").

ConMgr can be used as a service.



When used as a service, a Resource Resolver can be passed in which allows the use of Sling Service Accounts, thereby respecting ACLs on the configurations.



All inherited configurations can be obtained by using the Conf#getList() method, which returns a List of ValueMaps. Configurations can also be chosen explicitly by using a Resource Resolver to get the specific resource.



View a complete example at https://github.com/nateyolles/aem-slash-conf.

Thanks to Alex Klimetschek ( @alexkli) for sharing his knowledge of /conf of which much of this blog post is based on.