AEM Service With Multiple Implementation
AEM services are modular components in the AEM framework that encapsulate specific functionality, promoting a highly modular and extensible architecture. They allow multiple implementations, enabling developers to create tailored solutions for different use cases, user roles, devices, or locations. This customization enhances the user experience and increases customer engagement on AEM-based platforms.
AEM services offer various use case examples, such as an Email Delivery Service for sending transactional emails with multiple implementations, allowing the platform to choose the most suitable email delivery provider. Another use case is the Personalization Service, which enables a retail website to offer personalized product recommendations by experimenting with different algorithms based on user preferences and behavior. These examples showcase how AEM’s modularity and flexibility enhance functionality and user experience.
Prerequisites:
- Ensure you have an OSGi container or framework set up to deploy and manage your OSGi components and services
- Your project should be configured with Maven to handle dependencies and build your OSGi bundles.
- Make sure you have the necessary dependencies to use OSGi Declarative Services (DS) annotations(R8 in my case) in your project.
Why Multiple Implementations?
- Modular Components: AEM services act as modular components, organizing business logic effectively.
- Extensibility: Multiple implementations allow addressing specific use cases and adapting to diverse requirements.
- Customization: Businesses can customize services for personalized user experiences.
- Data-Driven Decisions: A/B testing with different implementations helps make informed decisions.
- Scalability & Maintenance: Modular architecture enhances scalability and simplifies maintenance.
Accessing a specific service
Let’s say we have multiple implementations of a service, and we want to call a particular implementation of the service dynamically. So, let’s look at an example where we will be making a servlet and trying to access the specific implementation by the search parameter.
- I have created a SearchImageService, which is basically an interface that provides functionality related to searching for images.
- Then, we implemented this service with two concrete classes, SearchDogImageServiceImpl and SearchFoxImageServiceImpl, each responsible for fetching random images of dogs and foxes, respectively.
- The SearchImageServlet uses these service implementations based on user input to fetch and display the appropriate images. This structure allows for modular and extensible image retrieval.
Codebase:
Here, you will find the full code for the service implementation and other required changes; Please go through the conversation for more details regarding the implementation.
To access a specific service, we use @Reference annotation, which is an annotation in Java that is used to inject OSGi service references into a component. The @Reference annotation is used to define a reference to a service.
So, in my servlet, you can see the Reference annotation somewhat like this.
@Reference( service = SearchImageService.class, cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, bind = "bindService", unbind = "unbindService" )
Now let us understand one by one what the parameters mean here in layman’s terms.
let’s imagine you’re a construction manager and the @Reference annotation is like a request for tools and workers. Here’s how it translates:
- @Reference = This annotation is used to define a reference to a service. This is like you saying, “I need some tools and workers for a job.”
- service = SearchImageService.class: This is the class or interface of the service that you want to reference. This is specifying the type of worker you need. It’s like saying, “I need workers who can use a hammer.”
- cardinality = ReferenceCardinality.MULTIPLE: This defines how many instances of the service the component requires. This is like saying, “I might need more than one worker.” It means your construction project can use multiple workers who know how to use a hammer.
- policy = This defines when the service will be bound. It can be STATIC (the service is bound before the component is activated and unbound after it is deactivated) or DYNAMIC (the service can be bound or unbound at any time). ReferencePolicy.DYNAMIC This is like saying, “Workers can come and go as they please.” It means that workers can join or leave the project at any time.
- bind = This is the name of the method that will be called when a service is bound to the component.“bindService“: This is like saying, “When a worker comes to help, they should start by doing the ‘bindService’ task.” It specifies the task to be performed when a worker joins the project.
- unbind = This is the name of the method that will be called when a service is unbound from the component. “unbindService“: This is like saying, “When a worker finishes their shift, they should finish by doing the ‘unbindService’ task.” It specifies the task to be performed when a worker leaves the project.
So in layman’s terms, this line of code is like putting up a sign at a construction site that says, “Help Wanted: Looking for one or more workers who know how to use a hammer. You can come and go as you please. When you start, do bindService When you finish, do unbindService” And then your construction project waits for workers to come and help out as needed.
In my case I’m referencing a service of type SearchImageService.class, allowing for multiple instances (MULTIPLE), with a dynamic binding policy (DYNAMIC). The methods for binding and unbinding are “bindService” and “unbindService” respectively.
Conclusion
Multiple implementations of a service offer flexibility in software design. They allow for different strategies to accomplish the same task, optimizing for various scenarios. This promotes modularity and loose coupling, as components interact with the service interface without knowing the underlying implementation details. This makes the system more maintainable and scalable.
References
https://mvnrepository.com/artifact/org.osgi/osgi.annotation/8.0.0
https://experienceleague.adobe.com/docs/experience-manager-learn/cloud-service/underlying-technology/introduction-osgi.html?lang=en
https://mvnrepository.com/artifact/org.osgi/osgi.annotation/8.0.0
Access multiple implementation of an OSGi service from a Sling servlet dynamically