Blogs

Sling Models with Sightly – Part IV (Key Annotations II)

 

In this post, I will explain some important questions related to OSGi Services and Sling Models. These questions had been asked by some of my blog readers on the basis of my last blog.

So the Problem Statement is-

According to them, they have one interface with multiple service implementations and want to choose any one of these service implementations according to their need. So their questions were-

1. How to choose the desired service implementation from these service implementations in another services or servlets?
2. How to choose the desired service implementation from these service implementations in Sling Model Class?

I have created a demo implementation according to their requirement and for doing that I have created an interface named as TestService with a dummy method named as test(). Here is the code-

package services;
public interface TestService {
    void test();
}

Now, I have created two dummy service implementations of this interface. Here is the code for the first implementation named as TestServiceFirstImpl.

@Service
@Component(enabled = true,immediate = true,metatype = true)
public class TestServiceFirstImpl implements TestService {
    public void test() {
        System.out.println("inside first");
    }
}

Here is the code for my second implementation named as TestServiceSecondImpl.

@Service
@Component(enabled = true,immediate = true,metatype = true)
public class TestServiceSecondImpl  implements TestService {
    public void test() {
        System.out.println("inside second");
    }
}

Answer for the first question-
It is a two-step process. These steps are explained below-

Step 1
Add a new property that have a unique value for each and every service implementation. This property could be anything you want to add. For example, I am using service.label property for these services and on the basis of this property I will choose from these implementations.

Here are my new definitions for TestServiceFirstImpl class.

@Service
@Component(enabled = true,immediate = true,metatype = true)
@Property(name = "service.label", value = "first")
public class TestServiceFirstImpl implements TestService {
    public void test() {
        System.out.println("inside first");
    }
}

Code For TestServiceSecondImpl class.

@Service
@Component(enabled = true,immediate = true,metatype = true)
@Property(name = "service.label", value = "second")
public class TestServiceSecondImpl  implements TestService {

    public void test() {
        System.out.println("inside second");
    }
}

Step:- 2

Use @Reference annotation in another servlet or in OSGi Service with an extra attribute named as “target”. Just redefine this line as shown below-

@SlingServlet(paths="/bin/testService",extensions = "html",generateComponent = false)
@Component(enabled = true,immediate = true)
public class TestServlet extends SlingSafeMethodsServlet {

    @Reference(target = "(service.label=second)")
    TestService testService;

    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)throws ServletException, IOException{
        testService.test();
        response.getWriter().print(" CHECK YOUR LOGS ");
    }
}

Try to run your code, you will get the desired output.

Q2. How to choose these services in Sling Model class?

In Sling Model class you can call an external service using two annotations. These are-
1. @OSGiService
2. @Inject with @Source annotation

If you are using @OSGiService annotation then you have an attribute “filter”, here add your condition and you will get the desired implementation as shown below-

@OSGiService(filter = "(service.label=first)")
TestService testService;

If you are using @Inject with @Source annotation then you need to add one more annotation @Filter. Here is the new code-

    @Inject @Source("osgi-services")
    @Filter("(service.label=second)")
    TestService testService1;

Now here my complete working code that will show you the use of both of these two approaches.

@Model(adaptables = Resource.class)
public class ServiceResolver {


    @OSGiService(filter = "(service.label=first)")
    TestService testService;

    @Inject @Source("osgi-services")
    @Filter("(service.label=second)")
    TestService testService1;

    @PostConstruct
    public void activate(){
        System.out.println("Inside Post Constructor Method");
        testService.test();
        testService1.test();
    }

    @Inject
    @Default(values = "Ankur Chauhan")
    private String firstName;

    public String getFirstName() {
        return firstName;
    }
}
Q3. How am I testing these annotations in Sling Model class?

I have created a dummy component and that component calls these Sling Model classes. Sightly code snippet is-

<div data-sly-use.serviceResolver="sling.models.ServiceResolver">
   ${serviceResolver.firstName}
</div>

For complete working code, I am sharing the Git repository link.
https://bitbucket.org/accunitysoft/accunity-blog-snippets

Happy Coding!

Share it:

Ankur Chauhan

December 21, 2016

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Comment

Related Posts