Search code examples
javaserviceosgiosgi-bundle

Multiple OSGi services


I'm new to OSGi and trying to develop an application with OSGi. I have a OSGi service which has one interface and two implementations.

Interface: ExportService

Implementations: ExcelExportServiceImpl, PdfExportServiceImpl

ExportService is my interface and ExcelExportServiceImpl, PdfExportServiceImpl are the implementations of ExportService.

I want ExcelExportServiceImpl and PdfExportServiceImpl as two different services.

From my application bundle, if I want to use excel export, I should be able to call the ExcelExportServiceImpl service without involving PdfExportServiceImpl.

How to register two different services which has same interface?

@Override
public void start(BundleContext context) throws Exception {
        context.registerService(ExportService.class.getName(), new ExcelExportServiceImpl(), null);
        context.registerService(ExportService.class.getName(), new PdfExportServiceImpl(), null);
    }
}

For now, I came up with the above code in my activator and it doesn't seem to work since both the service has ExportService.class.getName() as the class name. How to achieve two different services in same bundle with one interface?

Update/Solution:

I changed the code as below in my service bundle's activator,

@Override
public void start(BundleContext context) throws Exception {
        Hashtable excelProperty = new Hashtable();
        excelProperty.put("type", "excel");
        excelServiceRegistration = context.registerService(ExportService.class.getName(), new ExcelExportServiceImpl(), excelProperty);
        Hashtable pdfProperty = new Hashtable();
        pdfProperty.put("type", "pdf");
        pdfServiceRegistration = context.registerService(ExportService.class.getName(), new PdfExportServiceImpl(), pdfProperty);
}

And in my application bundle, I added the below filter

public static void startBundle(BundleContext context) throws InvalidSyntaxException {
    String EXCEL_FILTER_STRING = "(&(" + Constants.OBJECTCLASS + "=com.stpl.excel.api.ExportService)" + "(type=excel))";
    String PDF_FILTER_STRING = "(&(" + Constants.OBJECTCLASS + "=com.stpl.excel.api.ExportService)" + "(type=pdf))";
    Filter excelFilter = context.createFilter(EXCEL_FILTER_STRING);
    Filter pdfFilter = context.createFilter(PDF_FILTER_STRING);
    ServiceTracker excelService = new ServiceTracker(context, excelFilter, null);
    ServiceTracker pdfService = new ServiceTracker(context, pdfFilter, null);
    excelService.open();
    pdfService.open();
}

Solution

  • The code above will register two different services with the same interface. This is correct.

    The problem is that a consumer that binds the service by interface will get one of these services and can not decide which is the correct one.

    One way to solve this is to add properties to each service registration. For example there could be a proerty type=pdf that you set on the pdf one.

    Then the client could bind the service by interface and an ldap filter like (type=pdf). It will then only match the pdf ExportService service.