Tag: Filtering service references

Apache Felix – Filtering service references

Via an earlier blog Apache Felix – Multiple implementation of Service, we had dicussed:

  1. How to create multiple implementation of a Service
  2. Get references of the registered service implementations as a List.

Here we would be discussing, on how to filter the references and get ONLY pre-defined specific implementation

Scenario:

Consider an online course website. A lecturer can publish his content by submitting a course bundle comprising of html pages, videos and assessment questions.

The lecturer had his/her course live for an year & is appreciated by many curious students. The lecturer now wishes to update the assessment questionnaire, to challenge students to dig deeper.

He/She now submit the latest questionnaire to the onlint course portal for updates.

At this point, the course website needs to assure, that only the “Assessment Import” service implementation is called amogst all available Import implementation (Page, Videos and Assessment)

Implementation details:

Specific service references can be fetched by utilizing the “target” attribute of @Reference annotation. It would comprise of 2 simple steps

Step 1: Add property to identify each implementation

You can add any custom property to uniquely identify the service. For example, in the below sample code, I have added “type” property to uniquely identify my each implementation of CourseImport Service

Page Import Implementation
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import blog.techrevel.service.CourseImport;

@Component(name = "Import HTML Pages")
@Service
@Properties({ @Property(name = "type", value = "page")})
public class PageImport implements CourseImport {

    private static final Logger LOGGER = LoggerFactory.getLogger(PageImport.class);

    @Override
    public void importContent() {
       LOGGER.info("Business Logic to import HTML Pages");
    }

    @Override
    public boolean canProcess(String fileName) {
       return StringUtils.endsWith(fileName, ".html");
    }
}
Video Import Implementation
@Component(name="Import course videos")
@Service
@Properties({ @Property(name = "type", value = "video")})
public class VideoImport implements CourseImport{

 private static final Logger LOGGER = LoggerFactory.getLogger(VideoImport.class);

    @Override
    public void importContent() {
        LOGGER.info("Business Logic to import course videos");
    }

    @Override
    public boolean canProcess(String fileName) {
        return StringUtils.endsWith(fileName, ".mp4");
    }
}
Assessment Import Implementation
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import blog.techrevel.service.CourseImport;

@Component(name="Import assessment questions")
@Service
@Properties({ @Property(name = "type", value = "assessment")})
public class AssessmentImport implements CourseImport{

    private static final Logger LOGGER = LoggerFactory.getLogger(AssessmentImport.class);

    @Override
    public void importContent() {
        LOGGER.info("Business Logic to import assessment questions");
    }

    @Override
    public boolean canProcess(String fileName) {
       return StringUtils.equals(fileName, "assessment.xls");
    }
}

 

Step 2: Use target attribute of @Refernce annotation to filter implementation

The target attribute filters services based on a property available in their ComponentContext

Following sample code, filters only PageImport service by matching ‘page’ value against type property of each implementation.

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import blog.techrevel.service.CourseImport;
import blog.techrevel.service.CourseImportHandler;

@Component(immediate = true)
@Service
public class AssessmentUpdateHandler implements CourseImportHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(CourseImportHandler.class);

    @Reference(target="(type=page)")
    private CourseImport courseImport;

    @Override
    public void importContent() {
        courseImport.importContent();
    }
}

 

Using patterns for reference filtering

The target attribute of @Reference annotation also accepts regex (ldap) patterns. For example:

@Reference(target="(type=*age)")
@Reference(target="(|(type=p*)(type=generic))")

 

 

Advertisements