May 3, 2020
Estimated Post Reading Time ~

Restricting an AEM component to a certain number of instances per page.

An unusual requirement came up for a client project: Restricting the number of instances of a component on a page. Typically, the restriction is “only one” but it’s possible that there could be circumstances where the maximum number of items is 2 or 3. We want to have a robust solution.

Options:
1. Extensive hacking of the front-end UI code to check for a component on the page already and then either remove it from the sidekick or prevent the drag and drop behavior.

2. Solving the problem on the back-end by checking the node structure.

In either case, there needs to be additional business rules. For instance, if we already have one of a component on a page, should we prevent a new one being added or should adding a new copy of a component remove the old. Essentially, what is the priority of these components?

The option I feel is best is to go the option of #2 and using servlet filters. Our solution will consist of a few steps.
  1. Add a cq:editConfig node to the component with the listeners set to “REFRESH_PAGE”.
  2. Create a servlet filter for that component at the REQUEST scope. For performance reasons, you want this filter to only perform its logic in the author's runmode. If you want to restrict multiple components, I found it easier to create a filter service for each component. This will allow you to use OSGI properties to administer the number of instances of each component type by creating an OSGI property such as “num.instances”.
  3. Use @Reference to get a ResourceResolverFactory and examine the current resource or parent page to check the number of instances of a component (use the property of sling:resourceType to check). If more than the desired instances are found, use the appropriate business rules to remove the excessive number.
  4. Continue the request.
In cases like this, I STRONGLY recommend adding a component in edit mode that displays author notifications and adding an appropriate notification to the request (use a request attribute convention like a request attribute of “project.author.notifications” containing a List<String>of all appropriate notifications).

Another approach you could take is to register an EventListener. This can work BUT an event listener is usually registered on a specific path. This makes more sense if the components in question are only enabled on a specific sub-section of your site. Otherwise, you will be triggering tons of events as every edit, node update, etc, will trigger your listener. Also, because EventListeners are asynchronous you have to really watch for race conditions and ensure all your code is thread-safe.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.