I have a java class where I need to have full control the time and place of instantiation - therefore I can't initialize it as blueprint bean.
In the same bundle as that class I have a bean that I export as an OSGi-service. I would need to get access to that very service instance from the previously explained non-blueprint class.
I can't just perform a service lookup as there are other services implementing the same interface aswell. Creating a second (internal) instance of the service class will not work either.
So, as a recap:
Before I used blueprint, I had the service implementation as classic singleton, enabling me to register the same instance as service in the activator class that I could later access from within the bundle. But with blueprint (as far as I know) making the service class a "classic" singleton is not possible because it would not be possible for blueprint to create the service instance
I can't perform a service lookup because there is more than one service registered implementing the service interface.
My current solution is to query all services implementing the interface and looping the list to find the one thats instance of the one class I want.
BundleContext ctx = FrameworkUtil.getBundle(getClass()).getBundleContext();
ServiceReference<?>[] refs = ctx.getServiceReferences(ServiceInterface.class.getName(), null);
ServiceImpl provider = null;
for (ServiceReference ref : refs) {
if (ctx.getService(ref) instanceof ServiceImpl) {
provider = (ServiceImpl) ctx.getService(ref);
}
}
But I do not really like the idea of that approach.
Is there any better way to solve that? Maybe some way to request a service instance direct from the blueprint container? I found the interface BlueprintContainer with a method to get instances by the ID they got - but again the only way to get an instance of the BlueprintContainer I found is to inject the instance in the class - where I hit the initial problem of the class not possible to be a blueprint bean again.
Just set a property when exporting the service. So you can filter for it. This way you can distinguish your service impl from the others.
I also propose to use a ServiceTracker for your service. So you do not have to handle the lookup for every call to the service. If you do not use a ServiceTracker make sure to unget the service after use.
Related
In Java EE, if I have an interface:
#Remote
public interface MetaService {
ServiceData get();
}
And I have, in an ear 2 implementations:
#Stateless
public class Service1MetaService implements Calculator {
#Override
public ServiceData get() {...}
}
#Stateless
public class Service2MetaService implements Calculator {
#Override
public ServiceData get() {...}
}
I can create a bean, where:
#Stateless
public class View {
#Inject
private Instance<MetaService> metaServices;
...
}
And in View, the field metaServices will have the 2 implementations of MetaService.
I'd like similar functionality with remote beans.
So let's say, I have the above interface and implementations, but the packaging is different.
In base.jar I have the MetaService interface. This is packaged will all the subsequent applications mentioned below.
In a.ear I have the Service1MetaService implementation, while in b.ear I have the Service2MetaService implementation and in c.war I have the View class, which would like to use these implementations.
But as you would expect, the injected Instance is empty (not null tho). Is there a way to find the remote bean references in my injected Instance instance, even though these implementations are in separate applications?
One important thing is that in the View class I don't know and don't care about the number of these implementations, nor the names of the applications they are deployed in. So there is no way for me to use specific JNDI strings to get these references.
P.S.: Should I try and use technologies like JMS instead? So that I call the method add on a JMS proxy, which sends out the requests and waits for answers from all the applications that implement said interface?
P.S.: To clarify, the reason I need this is actually so that I can get data of running services on my application server(s). I updated the example interface and implementations, so that it's more clear. Also, it would be nice, if I could get these metadata synchronously, so JMS is not neccessarily prefered, however I can probably make it work.
I managed to convince myself to move away from remote EJBs. Well, it was also thanks to #chrylis-onstrike- as well, however, I'll opt for using JMS for this purpose.
The reason is that I can broadcast a request for the different services I need data from on-demand, enabling me to check for new services going online, or services failing.
Thanks to everyone who spent time trying to help me out.
I am working on a project which uses OSGi which has below code
#Component(policy = ConfigurationPolicy.OPTIONAL, ds = true, immediate = true, metatype = false)
#Service(TestInterface.class)
public class TestInterface{
Here the code doesn't implement the interface in which the service is going to exposed. Also I have verified everywhere this is not referenced anywhere with #Reference.
Does it really need to make it as service instead of only component? In case if i want to use it in another Component i have to make it as a service by implementing interface.
Does OSGI really mandates the service to be exposed should implements interface?
An OSGi service can be registered under any type name not just interfaces. Interfaces are highly recommended since they nicely separate the implementation class from consumers of the service.
I am trying to create an EJB class using it's class type. My function gets this class type as parameter. This class has it's own dependencies and i want those dependencies to be created as well.
addToUploadQueue(Class<? extends ICallback> callbackClazz)
how can i create an ejb instance of this class?
Edit: i am uploading videos to youtube on a ManagedExecutorService thread.This is a generic module. i want this to run on every project. Http requests call my function, i create another thread and return immediately. When upload finishes i need to inform this callback function to update statusses of those videos on db (or do whatever they want).
Given the extra information that you have provided, it looks a little like you're trying to reinvent the Observer Pattern.
Fortunately, Java EE 6 and newer provides us with a CDI framework that implements this for us.
Adam Bien shows an example at JAVA EE 6 OBSERVER PATTERN / EVENTS WITH CDI (JSR-299/JSR-330) AND EJB 3.1.
you have to get a ejb instance using the lookup method, you can do something like that
addToUploadQueue(Class<? extends ICallback> callbackClazz) {
InitialContext ic = new InitialContext();
MyEjb myEjb = (MyEjb)ic.lookup("java:comp/env/ejb/" + callbackClazz.getName());
}
I'm currently converting a piece of code from plain Java code to OSGi Declarative Services.
Original plain Java code
new AggregateServiceImpl(
new ChildServiceImpl1(),
new ChildServiceImpl2(),
new ChildServiceImpl3()
);
The classes are declared as so:
class AggregateServiceImpl implements Service
class ChildServiceImpl1 implements Service
class ChildServiceImpl2 implements Service
class ChildServiceImpl3 implements Service
So all classes implement Service, but the Aggregate implementation is capable of deferring to child Services when called upon.
AggregateServiceImpl itself does not know of the other implementations' existence. Its constructor is originally declared as:
public class AggregateServiceImpl(Service... children)
Clarification: the interface name 'Service' is intended generically and is not meant to represent an OSGi DS or Service concept.
Converting to OSGi
First I move each implementation into its own bundle. Then I declare my components (service implementations). I happen to be using bnd, so I use service annotations. For example:
#Component
class ChildServiceImpl1 implements Service
In the client class, we can look up the Service using the low level OSGi API or use DS in that bundle to create the object for us.
Problem
What's the best way of looking up a 'Service'? I want the AggregateServiceImpl but I might receive one of the ChildServiceImpls.
Is it best to use a separate service type or add a property to one of the components (e.g. "isRootService") to use as a filter when looking up ServiceReferences?
The best way is to use service registration properties
#Component
#Service
#Property(name = "service.id", value = "<some service unique ID")
class ChildServiceImpl1 implements Service{...}
When you look for some specific services you can use service filter:
bc.getServiceReferences(Service.class.getName(), "(service.id=<some value>)");
or if you like to use it in DS component as service reference:
#Reference(target = "(service.id=<some value>)", cardinality = ...)
private Service service;
If the AggregateServiceImpl is the only Service being used by other bundles, then it should be the only one you register.
From the code you have currently shown, we cannot tell if the AggregateServiceImpl class has dependencies on Service or the actual implementations.
If it has dependencies directly on other implementations, not the Service interface (as you have currently described it) the aggregate bundle should create the other implementation classes it requires directly and then register the AggregateServiceImpl as a Service.
If the other implementations need to be used elsewhere as well, then you should use properties (as you suggested) so consumers can distinguish between them. In this case, you still cannot use DS to construct your aggregate, since it doesn't have a dependencies on Service
I have an EJB which I don't want anyone to be able to instantiate explicitly. So I have a static method for instantiating it( Factory method) this class is called EmailEJB. It has an interface called EmailService.
Now as I am using jsf, I have a managed bean called EmailMB.
My questions:
Why do I have access only to the interface and not to the bean itself?
How can I instantiate that EmailEJB in EmailMB ? I cannot have an static class inside interface and I cannot instantiate interface.
Thank you.
An EJB is instanciated and its lifecycle is managed by your container.
A Managed Bean is linked to JSF and supposed to contains values from your user.
The role of the EJB is to execute the business job (retrieve data from database, save, update, insert, call another EJB, etc...).
You extract informations from your managed bean and give them to a method of your EJB as parameters. The EJB will do the job and maybe give you some information back which can be stored in the managed bean to go back to the user.
The EJB will never be instanciated in a managed bean. You don't manage the EJB : it is managed by the application server.