Expand my Community achievements bar.

SOLVED

How do I specify an implementation using @OSGiService

Avatar

Level 2

I have two implementations of an interface. Both are OSGi

public interface MenuService {

//...

}

and

@Component(

    immediate = true,

    service = MenuService.class,

    name = "menuServiceImpl1"

)

public interface MenuServiceImpl1 implements MenuService {

//...

}

and

@Component(

    immediate = true,

    service = MenuService.class,

    name = "menuServiceImpl2"

)

public interface MenuServiceImpl2 implements MenuService {

}

I can inject an implementation using OSGiService like so:

@OSGiService

private MenuService menuService;

But I always get MenuServiceImpl1 and never MenuServiceImpl2

I've tried using @Named like so:

@Named("menuServiceImpl2")

@OSGiService

private MenuService menuService;

but no luck.

Can anyone let me know how I can do this?

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

Hi,

 

When working with services and service references I see exactly 2 usecases:

 

* You get one service reference and you don't care which implementation. You don't want to pin it to a certain service implementation because the service interface gives you the assurance about the implementation to work. If you have 2 services implementing the same interface and you want always to get the first or second service implementation, then your design is flawed. You should use different service interfaces then.

* You want to get a list of service interfaces and then iterate through all of them in order to achieve your goal. Or you do a manual filtering based on some methods of the service interface. You can get this list already sorted according to the service ranking. But in all cases you expect that there are multiple implementations around for this interface and you are ready to deal with it.

 

For your case I would definitly use different service interfaces (and it might be only a marker interface) to reliably achieve this. Of course you can pin a reference to a specific implemntation, but that's not what I would recommend especially if you have full control over the service interfaces, implementations and the classes using them.

 

Jörg

 

ps: See also this thread: https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/aem-multiple-implementatio...

View solution in original post

10 Replies

Avatar

Level 10

Hi,

Please check the HELPX article link shared by Scott.

Adobe Experience Manager Help | Managing multiple instances of the same Adobe Experience Manager OSG...

Here you can manage multiple instances of Same AEM OSGi service.

Thanks,

Ratna Kumar.

Avatar

Level 2

Maybe I'm misunderstanding your reply but I don't think it answers my question. I don't have two instances of the same Java implementation. I have two different implementations. Your example uses MailServiceImpl but with two different labels allowing independent configuration. Useful, but not what I need. I have something like PopMailServiceImpl and ImapMailServiceImpl.

Avatar

Level 2

One more point is that I'd like to do this purely in code without touching the OSGi console.

Avatar

Correct answer by
Employee Advisor

Hi,

 

When working with services and service references I see exactly 2 usecases:

 

* You get one service reference and you don't care which implementation. You don't want to pin it to a certain service implementation because the service interface gives you the assurance about the implementation to work. If you have 2 services implementing the same interface and you want always to get the first or second service implementation, then your design is flawed. You should use different service interfaces then.

* You want to get a list of service interfaces and then iterate through all of them in order to achieve your goal. Or you do a manual filtering based on some methods of the service interface. You can get this list already sorted according to the service ranking. But in all cases you expect that there are multiple implementations around for this interface and you are ready to deal with it.

 

For your case I would definitly use different service interfaces (and it might be only a marker interface) to reliably achieve this. Of course you can pin a reference to a specific implemntation, but that's not what I would recommend especially if you have full control over the service interfaces, implementations and the classes using them.

 

Jörg

 

ps: See also this thread: https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/aem-multiple-implementatio...

Avatar

Community Advisor

I agree with Jorg.

If you have different service implementation go for different interface.

because name attribute in component annotation is used to defines PID not to point to implement class

name
Defines the Component name also used as the PID for the Configuration Admin Service

In Sling Model you use @Named annotation

If the field or method name doesn't exactly match the property name, @Named can be used:

E.g.

@Model(adaptables=Resource.class) public class MyModel { @Inject @Named("secondPropertyName") private String otherName; }

If you still want to do that, please go through with below:

https://techrevel.blog/tag/multiple-service-implementation/



Arun Patidar

Avatar

Level 2

Two interfaces is apparently the best use case in AEM. Unfortunately it is very cumbersome. Coming from a Java background, this is very annoying. AEM really ought to implement the standard Java interfaces (@Inject and @Named). How do I file a change request?

Avatar

Employee Advisor

I don't think that this is cumbersome, but rather straight forward :-)

As all the references are handled by the OSGI container (Apache Felix), I would recommend you to discuss that topic with the OSGI alliance.  But I am quite sure, that this discussion happened already a few times there (Spring is around for years, as well as OSGI), so maybe you start with searching the mail archives first.

Jörg

And of course you can specify a certain implementation of an interface with OSGI

@Reference (target="(component.name=name.of.the.component.as.specified.in.their.component.properties)")

MySuperService service

(https://osgi.org/specification/osgi.cmpn/7.0.0/service.component.html , chapter 112.3.10 "Target selection", check the references)

Avatar

Level 2

Your answer is a cop out.

You don't think it's cumbersome. I think it's cumbersome. I think most Java devs who are new to AEM would think it's cumbersome.

Yes, Apache Experience Manager uses OSGi but it also has its own annotations. Apache could make things easier but it clearly doesn't think this is a priority. That's fine. Companies have priorities, but don't say that they couldn't do it.

Avatar

Employee Advisor

I don't think that AEM has it's own annotations when it comes to OSGI references. It uses both SCR (Apache Felix) and OSGI annotations (IIRC starting with R6) and the idea is to move to the OSGI annotations over time.

If you are interested in discussing this with actual Adobe engineers (I am not!), I would suggest to switch over to one the Apache mailing lists. I am very sure that they are open for proposals to switch to more widely used and well-known annotations.

Avatar

Level 1

Hi,

Was looking for similar query and found this, hope any new reader finds it useful:

N.B: Its always recommended to use single interface for single service implementation.

// incase of injecting the service inside a sling model
@OSGIService (filter="(component.name=menuServiceImpl2)")
MenuService menuService;

// incase of injecting the service inside any other backend module like services/servlets
@Reference (target="(component.name=menuServiceImpl2)")
MenuService menuService;

 The reason why in your case its always taking the first service and not the second is because during the bundle activation the first service is getting a service ID that is lower than second service ID, so if you always want to trigger the menuServiceImpl2:

@component(...)
@ServiceRanking(1000)
public class menuServiceImpl2 implements MenuService {
}

@Component(...)
@ServiceRanking(1001)
public class menuServiceImpl2 implements MenuService {
}

 The higher Service ranking will have higher priority (unlike the service id where lower is higher priority)

 

Hope this helps!