I have one java application which uses OSGI model :
I have two preexisting bundles :
com.mos
com.login
com.login has a implementation and registration of Authenticator service (own service for authentication).com.login as well as com.mos uses this authentication service.
Now I am writing one new bundle (com.new) and I have to add / modify Authenticator Service so I have written my own implementation of it.
Once I start my program / application, if my new bundle com.new runs after com.login then all bundles uses new Authenticator Service.But If com.new bundles runs before com.login then old Authenticator Service is available.
Is there any mechanism in OSGI where we give some priority something like which bundle should start first.
The OSGi bundle startlevels allow you to influence the start order for each bundle.
See the according javadocs http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/startlevel/package-summary.html
But I would not recommend to do that.
Start levels should usually not be used as a way to control service startup. In OSGi service start orders are not guaranteed and services may come and go at will.
Making your new bundle (com.new) depending on the specific implementation of your Authenticator service would do the trick and guarante the correct order.
In general, when you have multiple OSGi services available, you have two options to pick one:
Service Filter
Service Ranking
Service Filter can be used to filter out services based on service properties as described here or here.
Service Ranking published by the service makes them eligible to be picked up based on the service ranking. The one with highest service ranking will be picked up as described here or here.
According to the documentation of the BundleContext.getServiceReference() method:
If multiple such services exist, the service with the highest priority is selected. This priority is defined as the service reference with the highest ranking (as specified in its Constants.SERVICE_RANKING property) is returned.
If there is a tie in ranking, the service with the lowest service ID (as specified in its Constants.SERVICE_ID property); that is, the service that was registered first is returned.
Related
I'm attempting to use Declarative Services to create a service bundle that provides functionality to another bundle. However, I want my Service Provider bundle to not start until it is needed. Let me describe my conditions.
There are two bundles:
-com.example.serviceprovider
-com.example.serviceconsumer
The Service Provider bundle provides a services using Declarative Services as follows:
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" enabled="true" immediate="true" name="samplerunnable1">
<implementation class="com.example.serviceprovider.SampleRunnable"/>
<service>
<provide interface="java.lang.Runnable"/>
</service>
The Service Consumer references the provided services as follows:
<reference name="SampleRunnable"
interface="java.lang.Runnable"
bind="setRunnable"
unbind="unsetRunnable"
cardinality="1..n"
policy="dynamic"/>
When both of these bundles are "ACTIVE" on start up, the Service Consumer has no trouble communicating with the service declared by the Service Provider. The problem happens when I try and have the service provider start in a lazy fashion.
After the Service Provider is set to load lazy this is what I get in the OSGi console:
osgi> ss
"Framework is launched."
id State Bundle
15 STARTING com.example.serviceconsumer_1.0.0.X
16 RESOLVED com.example.serviceprovider_1.0.0.X
What I would expect to see, is that even though bundle 16 is only "RESOLVED" that it would have at least registered is service. But when I call the "bundle" command, it states "No registered services."
osgi> bundle 16
com.example.serviceprovider_1.0.0.X [17]
Id=17, Status=RESOLVED Data Root=C:\apache\apache-tomcat-.0.40\work\Catalina\localhost\examplesX\eclipse\configuration\org.eclipse.osgi\bundles\17\data
"No registered services."
No services in use.
No exported packages
Imported packages
org.osgi.framework; version="1.7.0"<org.eclipse.osgi_3.8.0.v20120529-1548 [0]>
No fragment bundles
Named class space
com.example.serivceprovider; bundle-version="1.0.0.X"[provided]
No required bundles
Maybe I've missed the fundamental concept of lazy loaded bundles and services registration. If a bundle is in a "RESOLVED" state, shouldn't it have all it's "wires" connected? (ie, has a classloader, resolved import and export dependencies and services registered.) If the Service Consumer tries to access the service shouldn't that bundle transition to the "ACTIVE" state? What piece am I missing here?
Bundles in the RESOLVED state cannot provide services, and they will be ignored by Declarative Services. You should in general start all bundles during launch time, even if you want lazy loading behaviour. The key is to make the activation of the bundles cheap (or free!), and only pay for initialization of components when they are required.
DS takes care of lazy activation by default already. There is nothing you need to enable or change for this to happen. Essentially DS publishes the service entry in the registry, but it does not actually instantiate your component (or even load its class) until some client tries to use the service.
Furthermore, because DS does not load the class until required, OSGi does not even need to create a ClassLoader for the bundle, so long as your bundle does not have a BundleActivator.
To reiterate, you should not seek to make your bundles stay in RESOLVED state. Such bundles can only export static code and resources, but they cannot "do" anything and they cannot participate in the service registry.
Declarative services were designed for this case. Starting a bundle means that's functionality should be available, it does not mean it actually uses resources. Only stop bundles when you don't want is function.
This question is a good example of trying to control too much. In a component oriented world programmers should use lazy initialisation as much as possible but they should never attempt to control the life cycle.
I have rather big set of services registered with registerService. For simplicity let's assume they are lookup by some property name. So pair of invocation is straightforward (I use pseudocode for property spec):
context.registerService(
IMyService.getClass().getName(), myServiceInst, {"name"="a"})
After that on client side:
context.getServiceReferences(IMyService.getClass().getName(), {"name"="a"})
For some reason I cannot register all possible combinations of name. Is it possible to intercept all OSGi queries so I could create services on the fly when they are queried?
I would like have basic solution that works on all layers of OSGi - it mean that code above and code with (for example) Declarative Service will work the same way.
Take a look at Service Hooks in the core specification. They allow you to find out who is waiting for what services. Notice that this might imply parsing the filter if you're interested in what properties they're waiting for.
I think you have a couple of options:
Option 1:
If you need only one Service object by client bundle (where the client bundle identifies the key-value pairs) consider using http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/ServiceFactory.html. I think the javadoc is pretty self explaining and you can find easily usage samples in google. In this case you have to implement ServiceFactory and you have to use that one in Declarative Services (please correct me if I have not used declarative services only blueprint)
Option 2:
Create your services with the help of ConfigAdmin. You create a configuration with your client bundle and your service provider bundle will catch that and export the necessary service. After the service is provided you can catch the new service registration with the client. You can find nice doc at http://felix.apache.org/site/apache-felix-config-admin.html. Well in case of this option you will be able to get more services by client bundles but I do not think you can use this with Declarative Services (You must catch the configuration changes programmatically).
Option 3:
Instead of registering IMyService register IMyServiceFactory as an OSGi service. that has a createService(name) function. In this case in the client bundles you have to take care of the lifecycles of your IMyService objects (if no more IMyService is used you can "unget" IMyServiceFactory).
I have an OSGi bundle (that is not owned by me - so I cannot change it!) that exposes (exports) a service EchoService, and I want to attach an aspect to methods of this service (so as to perform some pre/post processing around it). These are deployed on the Apache Felix container.
I've written my own OSGi bundle (that obviously imports the EchoService), and attaches Spring aspects to it using standard Spring AOP. However, looks like the aspects are not attached and my interceptor is not being invoked.
I suspect that this is because I'm trying to intercept a service that does not belong to my bundle (which seems reasonable). Is that correct? How can I overcome this?
Here's what my interceptor/aspect looks like:
#Before("serviceOperation()")
public void before(JoinPoint jp) {
logger.debug("Entering method: " + jp.toShortString());
}
#AfterReturning("serviceOperation()")
public void after(JoinPoint jp) {
logger.debug("Exiting method: " + jp.toShortString());
}
I'm not an AOP nor a Spring expert, but maybe I could give you some ideas. As far as I see Spring use standard J2SE dynamic proxies for AOP proxies. Hence your clients should use the proxy instead of the original EchoService object. This is also true when you're using CGLIB proxies because "the proxies are created by sub-classing the actual class".
If your client bundles asking for an EchoService you have to pass them the proxy somehow. For this inside an OSGi container you should also export an EchoService (proxy) and make sure that the clients use the proxied service/bundle, not the original. You can accomplish this by setting a different version number for the (proxied) package and set this version as an import requirement in your client bundles. (I suppose you can modify the clients of EchoService.) For services you can set a property when you're registering it and modify the clients to query only for services which have this property.
If you are not able to modify the client bundles another solution could be wrapping the original bundle as an internal jar in your bundle. You can call the wrapped bundle's activator from your activator and pass them a modified BundleContext. This BundleContext should catch the registering service calls and register the proxy object instead of the original EchoService. You can use simple delegate pattern since BundleContext, ServiceListener etc. are usually interfaces. I suppose it could work but it maybe has other challenges.
As a bit of background - I'm using JBoss 5.1, for web applications. The applications are vertically deployed so each feature ends up in a separate WAR file. It has a jar file for dao and business logic. This is fine so far however I need to deploy another app which doesn't have much logic in itself - its basically a view like say dashboard. The dashboard needs to aggregate data from different data providers(usually they are other apps/features). Right now the dashboard knows way too much about other features. So everytime a new feature is added this dashboard gets redeployed as well with relevant code additions.
It would be great if there is a common interface for this dashboard that few other features implement and whenever a new feature(WAR) is deployed the dashboard can dynamically get data from the new provider as well. Is this possible? If not what is the closest I can get to without manipulating classloaders for the apps? It would be good to know if first of all this is possible inside jboss.
Please let me know if you need more info.
There are a couple of ways to do what you're talking about, so I'll propose two types of solutions and I can give you more info about whichever fits your needs best.
A relatively quick solution is to use a portal server like GateIn. Your WARs could be displayed on the same page, but they'd be in seperate places and not integrated. You'd have to turn your WAR's into portlets and have an administrator add them to the portal's UI, but the portal would be able to scan and detect all available portlets.
A more flexible solution would be to have one of your classes for each deployment implement a common MBean interface. Your dashboard could then use JMX, specifically javax.management.MBeanServerConnection's queryMBeans method to obtain all MBeans (or a subset of MBeans belonging to a particular package, which you can specify as a query parameter). Then you can execute interface methods through javax.management.MBeanServerConnection's invoke method. To obtain the MBeanServerConnection with JBoss, call org.jboss.mx.util.MBeanServerLocator.locateJBoss().
Some additional detail as requested (Note, the following is JBoss-specific):
1) Turn your deployments into MBean's
For each of your JAR files, add a jboss-service.xml and *-xmbean.xml file to the META-INF directory (where * is a name of your choosing). Follow this example for those files.
Implement the MBean at whatever path you specified in the jboss-service.xml mbean element's code attribute (org.jboss.chap2.xmbean.JNDIMap in the example). Specify a consistent namespace and parameter for the jboss-service.xml mbean element's name attribute (chap2.xmbean:service= in the example). The operations and attributes you specify in the *-xmbean.xml file should map exacly to your interface.
2) Create the dashboard and in one of it's classes poll the services (this code hasn't been tested, but should provide a good outline)
//Get the connection
MBeanServerConnection connection = org.jboss.mx.util.MBeanServerLocator.locateJBoss();
//Query for MBeans in the chap2.xmbean namespace
Set<ObjectInstance> mbeans = connection.queryMBeans(null, new ObjectName("chap2.xmbean:service=*"));
//Loop over each MBean and invoke an interface method
for (ObjectInstance mbean : mbeans)
{
//Invoking 'put' method from example. If this were an info method, this would return the result of the MBean operation
connection .invoke(mbean.getObjectName(), "put", new Object[] {"TestKey", "TestValue"}, new String[] {Object.class.getName(), Object.class.getName()});
}
I am interested in using OSGI as a means of managing plugins for a project. That is there can be many implemenators of my interface, each appearing in its own / separate OSGI bundle with the implementation class exported...
Declarative Service should be the way to go.
You can declare your interface as a service
<service>
<provide interface="my.Interface"/>
<property name="foo" value="bar"
</service>
Each implementation of that interface can define Bundle activation and de-activation methods.
But what is really neat is their nature: if you are using the latest SCR (the "Service Component Runtime" which is an "extender bundle" implementing the new and improved OSGi R4.2 DS - Declarative Service - specification), your classes will not import anything from the OSGI model. They remain pure POJO.
Then define another service which depends on your first service:
<reference name="myInterfaceServiceName"
interface="my.Interface"
bind="myActivationMethod" unbind="myDeactivationMethod"
cardinality="0..n"/>
That service will detect and list all your concrete instances of your first service and deal with them as you intent to.
See the Eclipse Extensions and Declarative Services question for more details.
The presentation:
Component Oriented Development in OSGi with Declarative Services, Spring Dynamic Modules and Apache iPOJO, from EclipseCON2009, will provide you with a concrete example.
This can be done declaratively (like VonC) has detailed, or dynamically at runtime via the standard service registry.
Any implementer can simply register their implementations as a service and consumers can get them from the registry, which is pretty basic OSGi stuff. The services can also be registered with properties, so consumers can use these properties to distinguish between implementations when looking up the service.