Search code examples
javaosgiaemsling

Is there a way to access SlingRepository in a POJO?


Is there a way to access SlingRepository in a POJO that is not managed by OSGI?

For example, we might have a POJO named Site:

public class Site {

    private String domainName;

    public String getDomainName() { return domainName; }

    public void setDomainName(String domainName) { this.domainName = domainName; }

    public void validate() throws Exception {
        SlingRepository repo = ...;
        // validation logic dependent on repo
    }
}

That is used like this:

Site site = new Site();
site.validate();



Update (re. Tomek's answer)

The reason why I cannot use @Reference or the current request's ResourceResolver is because I am trying to implement a JSR-303 (aka Bean validation) validator.

In our Sling app, we have a bunch of servlets that receive JSON payloads from the browser. Then we convert them to pojos:

Person p = new Gson().fromJson(json, Person.class)
validate(p); // Validate p using Bean Validation

Person is a simple POJO annotated with JSR-303 annotations:

public class Person {

    @NotNull
    private String name;

    @UniqueProperty(
      name = "email", 
      path = "/content/myapp", 
      nodeType = "cq:PageContent"
    )
    private String email;

}

In short, my goal is to implement the @UniqueProperty validation. In the example above, if a node of type cq:PageContent under /content/myapp exists that has an email property with the same value as this model, the validation fails.

The validator class itself will look like this:

public class UniquePropertyValidator implements ConstraintValidator<UniqueProperty, String {

    @Override
    public void initialize(UniqueProperty constraintAnnotation) {
        ...
    }

    @Override
    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
        // need to execute a JCR query here
    }
}

UniquePropertyValidator will be instantiated by the JSR-303 implementation (e.g. Hibernate Validator) as needed, and there's no way it can access the current request's resource resolver, hence why I was looking for a way to access the SlingRepository.


Solution

  • In general you should not retrieve external resources from a pojo. Simply add a contructor or setter where you inject the SlingRepository at the position where you do the new. This has the advantage that your pojo is independent of OSGi and can be used in different environments. Also unit testing is easier with this approach.

    Site site = new Site(slingRepository);
    

    Of course this just moves the problem to the class that creates the instance. I guess at some point you start at an activator where you have access to the BundleContext and can lookup the service.

    In the rare cases where you really want to lookup a service directly use

    FrameworkUtil.getBundle(this.getClass()).getBundleContext(); 
    

    From there you can lookup the service.