In my application, using services by themselves is pretty useless. You always need some external configuration information for a service to be usable.
Components coupled with ConfigurationAdmin makes sense, since then for each configuration I create, a component instance will be created. This is just perfect for my use-case.
Now, the question arises, what if I'd like to use a component from an other bundle programmatically? Does this make sense?
I know I could export the component as a service yet again, and consume that from other beans, but let's say I have a servlet, where the user can create the configurations, and for each configured instance there are a list of actions; when he clicks the actions, I'd need to find the appropriate component, and execute the action on it.
What'd be the best way to implement this functionality on top of OSGi?
"Using a component from another bundle programatically" sounds exactly like OSGi Services to me.
This method retrieves the osgi service (iso having the osgi container wire the dependencies):
public class ServiceLocator {
public static <T extends Object> T getService(final Class<T> clazz) {
final BundleContext bundleContext = FrameworkUtil.getBundle(clazz).getBundleContext();
// OSGI uses the order of registration if multiple services are found
final ServiceReference<T> ref = bundleContext.getServiceReference(clazz);
return bundleContext.getService(ref);
}
}
I used this when introducing DS in existing project which does not use DS everywhere. Not all components in the project were instantiated as osgi DS components. Anywhere I need to access a DS Component in classes instantiated by any other means I used this method...
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 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 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.
I am trying to use the picoContainer in my project.
I know very little about it but want to give it a shot.
As I understand, I have to create a picoContainer and registercomponents with it.
I did this
public static PicoContainer getPicoContainer(){
final MutablePicoContainer pico = new DefaultPicoContainer();
pico.registerComponentImplementation(X.class);
pico.registerComponentImplementation(A.class);
pico.registerComponentImplementation(C.class);
pico.registerComponentImplementation(V.class);
pico.registerComponentImplementation(T.class);
pico.registerComponentImplementation(D.class);
return pico;
}
Now my problem is that for any component to get the other component, it needs a handle on pico.
To access any component it needs to do this
A juicer = pico.getComponent(A.class);
So, in the constructor for each of them, I need to pass in the pico object? I can easily replace this with a factory. What's the point then? I'm sure i'm missing something here.
Would appreciate any help.
Common pattern is to have somewhere a factory for the main container.
For stand-alone app it probably will be "public static void main()" entry point, for web app it will be front controller servlet or filter or context listener (pico has support class for listener case).
So at the entry point you configure the container in a way you mentioned above "public static PicoContainer getPicoContainer()" then you need to pass control to an entry point in the container. The nice way is to have at least one container's component to implement lifecycle interface (http://picocontainer.codehaus.org/lifecycle.html) then you start() the container and have everything wired up.
In normal case you should never access the container itself beside entry configuration and such things as special factories or transaction demarcation etc.
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