Via an earlier blog Apache Felix – Multiple implementation of Service, we had dicussed:
- How to create multiple implementation of a Service
- 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))")
Great blog Aanchal.
LikeLike