Hello Everyone,
While working on a project last week, I went through a very interesting use case and so many learnings while solving that. This blog is shared with you about that learning process I have been through.
Problem Statement: I was working on an integration tool with AEM, in which we are having many servlets registered with paths . Few of the servlets are being called by a third party and few are for internal calls.
All the servlets start with a specific prefix. Let’s suppose: /bin/aem-integration/events, /bin/aem-integration/tasks etc. So the prefix for all the servlets is "/bin/aem-integration" and it was as a constant in the code.
But while using that tool, a client requested to provide them the flexibility to define the prefix as per their requirement. So that, while they made calls from any external system to AEM, they could make their own choice of prefix or may be a very environment specific prefix like for dev it will be /bin/aem-integration/dev/tasks but for stage it will be /bin/aem-integration/stage/tasks. The requirement looks easier but while implementing, it was quite challenging.
How I approach this problem:
So if I mention the above problem precisely, it is registering the servlets based on dynamic paths.
How can we do that?
Let’s suppose I have a servlet "RunModeServlet" using SlingSettings as a Reference and I want to register this servlet dynamically. So how to do that.
1.First I create a service "ServletRegistration" having an OSGI Configuration asking for Endpoint Prefix Configuration, because every service is a component, so on the activate method of the component we need to register all the servlets dynamically and unregister and re-register with new values, if the author makes any change in configuration.
Now if you are creating reference of a component via new RunModeServlet() and if in the RunModeServlet is using any @Reference annotation, all the services injections will be null. To solve this, pass the service reference via the constructor to the servlet like shown in the code.
Note: In this case in the ServletRegistration class need to have all the service injections using @Reference annotation and need to pass to the servlets via the constructor new RunModeServlet(slingSettings).
2. In the RunModeServlet, we remove all the annotations and get the services via the constructor in place of @Reference annotation.
1. Use this on the component/servlet you want to create programmatically:
2. Then in another component/service (ServletRegistration) you can get the ComponentFactory:
3. Create an instance from it and register the servlet like this.
Note: The way we have registered a servlet, you can register any service, filter or any authenticationHandler dynamically.
I hope you find it interesting and useful.
Thanks and Happy sharing.
Always appreciable to learn something new with your blog. Thanks
ReplyDeleteExcellent post, thanks
ReplyDeleteVery interesting use case. Thanks for sharing!
ReplyDeleteexcellent posts...!!!city siege
ReplyDelete