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..!!

Ankur Chauhan
Tech Lead

Sling Models with Sightly Part – V (Key Annotations – III)

In this post, I will answer some of the queries asked by my blog readers. This blog will also help you in getting knowledge of How you access cq:defined Object in Sling Model classes?
Before answering these question, I want to make sure that you guys are using latest Sling Model dependency and AEM version 6.x. So let’s start-

Q1. How will I get properties object in Sling Model Class?

I think there is no need to get this properties object as you can directly inject the resource properties ( already described in my previous blog) but if you still want to do that then, you have to make two changes.

First use adaptable as SlingHttpServletRequest.class as shown below-

@Model(adaptables = {SlingHttpServletRequest.class})

Then you can directly inject properties as shown below-

@Inject
private ValueMap properties;
Q2. During the build time, I am getting a Maven build error as shown below-
 Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project blog-bundle: Compilation failure: Compilation failure:
[ERROR] /D:/accunity/blog/bundle/src/main/java/sling/models/CQDefinedObjectImplModel.java:[3,34] package com.day.cq.commons.inherit does not exist
[ERROR] /D:/accunity/blog/bundle/src/main/java/sling/models/CQDefinedObjectImplModel.java:[31,13] cannot find symbol
[ERROR] symbol:   class InheritanceValueMap
[ERROR] location: class sling.models.CQDefinedObjectImplModel
[ERROR] /D:/accunity/blog/bundle/src/main/java/sling/models/CQDefinedObjectImplModel.java:[39,33] cannot access com.day.cq.commons.LabeledResource
[ERROR] class file for com.day.cq.commons.LabeledResource not found
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :blog-bundle
How to resolve this issue?

For resolving this issue,  you need to add one more maven dependency into your project the dependency name is
cqcommens and it’s Maven dependency is-

<dependency>
   <groupId>com.day.cq</groupId>
   <artifactId>cq-commons</artifactId>
   <version>5.5.0</version>
   <scope>provided</scope>
</dependency>
Q3. How will I get inherited page properties object in Sling Model class?

For getting this object in your Sling Model class, you need to inject a field as shown below-

@Inject
private InheritanceValueMap pageProperties;

With SlingHttpServletRequest.class as an adaptable value.

Q4. Can I use Resouce.class as well as slingHttpServletRequest.class as adaptable in the same class?

Yes, you can do that. Here is the syntax-

@Model(adaptables = {SlingHttpServletRequest.class,Resource.class})
Q5. How will I get page object in Sling Model class?

For getting this object in your Sling Model class, you need to inject a field as shown below-

@Inject
private Page resourcePage;

With SlingHttpServletRequest.class as an adaptable value.

Q6. Do you have any working Sling model class example that implements all these properties?

Yes, here it is-

@Model(adaptables = {SlingHttpServletRequest.class,Resource.class})
public class CQDefinedObjectImplModel {

    private Logger logger = LoggerFactory.getLogger(CQDefinedObjectImplModel.class);

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

    private String value;

    @Inject
    private Page resourcePage;

    @Inject
    private InheritanceValueMap pageProperties;

    @Inject
    private ValueMap properties;

    @PostConstruct
    public void activate() {

        logger.info(resourcePage.getPath()+" ================= ");
        String[] cloudServices = pageProperties.getInherited("cq:cloudserviceconfigs",new String[0]);
        logger.info(cloudServices.length + " = lenght of array");
        for (String x : cloudServices) {
            logger.info("Configuration is = " + x);
        }
        firstName = properties.get("firstName","");
        logger.info(firstName);
    }

    public String getValue() {
        return "Hi! "+firstName;
    }
}
Q7. 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-

Happy Coding..!!

Ankur Chauhan
Tech Lead

Sling Models with Sightly Part – III (Key Annotations – I)

Sling Models with Sightly Part III

The title of this blog is “Key Annotations – I” because In this post, I will explain two important annotations related to Sling Models and continue explaining other annotations in my coming posts. So for explaining two annotations, I have selected following two questions for this post.

1). How to include OSGI Services in Sling Model?
2). What is the use of @ResoucePath annotation?

I am assuming that you are using the latest versions of Sling Model APIs that I described in my previous blog.
For Answering first question, I have created an OSGi Service that have a dummy method as follows-

@Component(immediate = true,enabled = true,metatype = false)
@Service (DemoService.class)
public class DemoService {

    private Logger logger = LoggerFactory.getLogger(DemoService.class);

    public void dummyMethod(){
        logger.info("Inside Dummy Method, its working fine. ");
    }
}
Now, You can include OSGi Services in your Sling Models using two annotations, these are-

1. @OSGiService Annotations
2. @Inject Annotation

Here is the Sling Model class, that shows how to use these annotations?

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

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

    @Inject @Source("osgi-services")
    DemoService demoService;

    @OSGiService
    DemoService demoServiceX;

    @PostConstruct
    public void activate(){
        demoService.dummyMethod();
        demoServiceX.dummyMethod();
    }

    public String getFirstName() {
        return firstName;
    }
}

When you call this Model class then you will see that both of these two annotations working in the same manner.

Q1. What is the use of @ResoucePath annotations?

@ResoucePath annotation is a very handy annotation provide by Sling and using this annotation, you can convert a path into its resource object without writing any code. Let’s suppose you have a predefined path (e.g. /content/geometrixx/en) of the resource and want to convert that path into resource object then you can use @ResourcePath annotation.

Q2. How to use @ResoucePath annotation?

Here the code snippet that shows you the use of this annotation-

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

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

    @Inject @ResourcePath(path = "/content/geometrixx/en")
    Resource tempRes;

    @PostConstruct
    public void activate(){
        System.out.println( tempRes + " = Resource Path");
    }

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

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

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

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

Happy Coding..!!

Ankur Chauhan
Tech Lead