How to wait to another bundle? - java

I am developing an OSGi application which is composed by several bundles. All of them depend on the EventAdmin one. However, one specific plug-in has to start up a scheduled task as soon as the bundled is started (i.e. in the start method of the activator). The problem is that the event admin service is not still registered and I should wait for the deployment of this. I would not like to do this through the config properties file, therefore, is there any operation to do this without the properties file of Felix?
Thanks a lot in advance

There is no start ordering in OSGi ... get over it ... Though there are mechanisms to influence the initial start ordering, the problem is that any bundle can stop at any time. So the ONLY solution is to actually handle your dependency on Event Admin.
With Declarative Services (DS), this is actually very little work. Also, please forget bundle activators, they are bundle singletons and are thus a bad idea. So in DS you would do the following (using the annotations):
#Component(immediate=true)
public class MyTask extends Thread {
EventAdmin ea;
public void run() {
while ( !isInterrupted()) {
// do something
ea.postEvent(...);
}
}
#Activate void activate() { this.start();}
#Deactivate void deactivate() { this.interrupt(); }
#Reference void setEventAdmin(EventAdmin ea) { this.ea = ea;}
}
There are rare cases you should not use DS and are stuck with Bundle-Activators, but they are rare and should become rarer. If you're stuck with such a really bad case, then you can also create a service tracker in the Bundle Activator start method and track Event Admin services. Once you get one, you create a thread to run your code. When the service disappears you interrupt the thread. However, this is a much more complex solution.
There are also other service dependency manager but I strongly recommend Declarative Services with their annotations.

I have used iPOJO for this. It is designed to be used in felix & karaf. This library understands the lifecycle and dependencies of components and you will be notified via #Validate and #Invalidate methods when a components dependencies are available or one or more goes away.
It also support #Bind and #Unbind when an implementation of a service (an interface) appears or disappears. This make subscriptions much simpler.
You have a listener to a service and this component #Provides an interface to be called. The central event register will then be called on its #Bind method when such a component appears and #Unbind when it goes away for any reason.
I suspect iPOJO should do all the dependency management and binding you need.

Related

Java - Scheduling tasks in Jboss & without EJB

My java web application that uses spring for dependency injection is packaged in an EAR and is deployed in Jboss 7, but has no EJB. The application is installed on two load balancing machines. I need to schedule a method to run daily, but that method can't run at the same time on both instances.
I tried to use Spring's Scheduling annotations, but the problem is that, as there is load balancing, the scheduled method runs twice (once in each cluster).
What is the best way to do this in Jboss 7? Can someone help me ?
The method to be scheduled looks like the one below.
public synchronized void processor() {
LOGGER.info("start");
//processing logic
LOGGER.info("the end");
}
Thanks a lot!!!
Well, considering the requirements: two or more apps and they need to be synchronized, you need either #Singleton or #Stateless EJB, described here.
Invoking it via the timer service, then it needs to be an EJB with #Timer on some method and if you use #Scheduled or such on a method, then it will invoke that method
On this case a Singleton is recommended, otherwise, you might end up with multiple instances of the same timer running.
Example
#Example
private void init()
{
ScheduleExpression Expression = new ScheduleExpression();
#This means twice per hour {0,2,4, ... 22} ~ since it ends on 23h:
expression.second(0).minute(0).hour(*/2).month(*).dayOfWeek(*);
stopTimer();
Timer timer = service.createCalendarTimer(exp);
}
Any other suggestion seems to add too much complexity.

OSGI: do declarative services become available after bundle start

The question is simple, but I can't find answer - Can I state that all declarative services in bundle A become available after bundle A start? For example,
bundle=context.installBundle("file:bundleA-1.0.0.jar");
bundle.start();
//In this point are declarative services of bundle A 100% available?
P.S. I use apache felix, but I think it must be defined in Specs but not in implementation.
EDIT:
I assume that DS runtime is running, config is present and all mandatory references are present.
The answer to your question is a very simple: NO. There are NO guarantees about availability in OSGi ever based on neither timing nor ordering. The only guarantees are specified in the service events.
It is one of the greatest causes of complexity to make timing/ordering assumptions in your code because they are always violated in the most obscure way.
DS makes it trivial to write code that correctly reacts to the service dependencies as they come and go. Making sure that you get those guarantees associated with services is incredibly complex and you destroy all that value if you start to make assumptions that something should be available after you call a method.
In your example, just rely on a service that you need. If that service is available, then you are sure all initialization is done.
If you stick to service dependencies life in OSGi is fairly easy and very robust.
UPDATED with example after questions
One the non-OSGi side:
systemBundleContext = ... create framework
systemBundleContext.registerService(
BundleActivator.class,
new BundleActivator() {
public void start(BundleContext c) {
// start non-OSGi code
}
public void stop(BundleContext c) {
// stop non-OSGi code
}
},
null );
DS Component:
#Component
public class Initiator {
#Reference
BundleActivator ba;
#Referenc
MyService myService;
#Activate void activate(BundleContext context) throws Exception {
ba.start(context);
}
#Deactivate void deactivate(BundleContext context) throws Exception {
ba.stop(context);
}
}
You can not assume that all DS Components are available as services after bundle start. The first thing is that the DS runtime must also be running. Then DS components by default are lazily activated. This means they are active only when some other bundle requires such a service and last but not least components only are activated once all their mandatory references are present.
Well ... and before I forget it it you can also define that a component is only activated if a config is present for it.

What would cause the #Activate method to not be invoked for Apache Felix?

I have an Apache Felix component who's definition looks like this:
...
#Component(immediate=true)
#Service
public class myClass implements myClassInterface {
...
#Activate
public void activate(final Map<String, Object> properties) {
//Do activation stuff
}
...
}
From reading the Apache Felix documentation on the #Component and #Activate annotations (http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html#component) I understand that the immediate=true attribute for the #Component is "activated immediately". My problem is that my activate method never seems to be invoked. I have my debugger on from the moment I build my project until the moment I request the service myClass using OSGi, but the activate method never seems to be invoked.
So, my question has a few layers:
1. Telling me that immediate=true attribute causes the component to be "activated immediately" doesn't give me enough information. Does this mean that the component is activated immediately after the project is built, immediately after an instance of myClass is created, or immediately after the service myClass is requested by the OSGi bundle?
2. Is there anything that might cause my activate method to not be invoked in spite of my usage of immediate=true? If so, what can I do to correct the issue?
Thanks in advance for your help. Please let me know if I need to provide additional information.
Immediate=false means the component is only activated once it is requested by another component. Immediate=true means it is activated once all its mandatory references are present.
So if your component is not activated then maybe a service it needs is not present. You can look into the status of the components by using the scr commands in the gogo shell.
Another thing is to define what interface to publish the service with. I am not sure about the felix SCR annotations but with DS annotations you need to set #Component(service=myClass.class) if the class does not implement any interface.
Btw. You should switch to the standard DS annotations. See http://enroute.osgi.org/doc/217-ds.html. The felix ones are deprecated now.

Getting a specific implementation from Felix

I've spent a long time on learning OSGi, but I still feel as though a crucial piece of the puzzle is missing.
This is my use case:
I am using JAX-RS (Grizzly) to create a REST API. I have an interface that has many various implementations. My solution should be able to add new implementations at any time.
Based on some form of input, I have to get a hold of one these specific instances. For example, lets say I register two interface implementations with Felix Interface A and Interface B. A user should be able to ask for Implementation B
By using the command line we get from running felix.jar(Apache Felix Gogo ) I have been able to install and start my own bundles. The problem I now face is how I from one of my controllers is supposed to retrieve any of these implementation.
Here is the code for the activator of one of my implementations.
public class MyClassActivator implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
System.out.println("Starting ImplementationA");
Hashtable<String, String> props = new Hashtable<>();
props.put("Identifier", "ImplementationA");
context.registerService(MyInterface.class.getName(), new MyClassA(), props);
}
#Override
public void stop(BundleContext context) throws Exception {
System.out.println("Stopping ImplementationA");
}
private class ImplementationA implements MyInterface {
/*my implementation*/
}
}
From one of my JAX-RS classes, I want to, somehow, do this:
MyInterface myclassA = getBundle("ImplementationA");
The String ImplementationA is the same string I placed in the props map.
What I have tried so far is
BundleContext bc = FrameworkUtil.getBundle(MyInterface.class).getBundleContext();
This however just returns null, it doesn't seem to actually be "talking" to my felix instance.
So my questions are how do I get an interface from Felix? And is what I want to do even possible with OSGi?
Your question is confusing since you mix terms for services and bundles. A bundle is an installable unit which contains code. That code can register and consume services. Services are object which, typically, implement some interface which is shared between the bundle providing the service and the bundles consuming the services.
So the first order of business is to make sure the service interface's package is exported by some bundle and imported by all the bundles which plan to participate in providing and consuming the service. This is necessary to ensure type safety. That is, the consuming bundles can safely cast the service object to the expected type of the service.
Once that is done, as you observer, there can be multiple providers of a service. When a provider registers a service, they can specify some metadata about the service in the form of key/value properties. Your example shows this in the Identifier property. When a consumer looks up a service, a filter string can be specified which can specify information to be checked against a service' metadata to select from among multiple provided services.
public class MyServiceConsumer implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
System.out.println("Looking for ImplementationA");
ServiceReference<MyInterface>[] refs =
context.getServiceReferences(MyInterface.class, "(Identifier=ImplementationA)");
MyInterface service = context.getService(refs[0]);
}
}
The above is terrible code; don't actually use it. It does not handle there being no service when the consumer bundle is activated (refs == null), nor does is it prepared for the service to go away. I strongly recommend you use OSGi Declarative Services when writing bundles. It makes service use and dealing with the dynamic super simple.
#Component
public class MyServiceConsumer {
MyInterface service;
#Reference(target="(Identifier=ImplementationA)")
private void bindService(MyInterface s) {
service = s;
}
#Activate
private activate() {
// do work
}
#Deactivate
private deactivate() {
// do work
}
}
This is a component which will only be instantiated when a matching service is present. It will be called at bindService to inject the service instance, the activate will be called to enable to component to do it work. If the injected service goes away, the component will be called at deactivate and then discarded. If later another matching service comes along, a new instance of the component will be activated.
See http://enroute.osgi.org/ for a tutorial on OSGi app dev.

How to detect application type in Java code

Imagine we have a java package. This package can be used anywhere. However, there are some codes in this package which are context dependant. For instance, if the application which uses this package is a web app we need to perform some tasks by calling a function while performing other tasks if the application was a console application by calling the very same function.
Here is my question:
Is there any way in java that within the code we can detect if the application was run as a web app or a console?
I appreciate any help :)
As a real world example, the ways we load properties files are different for web and console applications.
For web applications we probably use this.getClass().getClassLoader().getResourceAsStream(url) and for console apps we use new FileInputStream(physical path).
It might be better to set a build property somewhere rather then trying to detect your application type, because I don't think there is a reliable way to do that.
Moreover you shouldn't try to detect application type because your view layer (either web, desktop or console) should be easily interchangeable according to modern architectural principles.
In response to your last comment.
As user384706 said DI is the correct choice here IMO.
I will give an example with spring.
In both your console and web app parts you can have:
public class WebOrConsoleServiceImpl {
private PropertyProvider propertyProvider = new NullPropertyProvider();
// and
public void setPropertyProvider(PropertyProvider impl) {
this.propertyProvider = impl;
}
// and in your service logic
public void logic() {
final Properties props = propertyProvider.loadProperties();
// do stuff
}
}
Where your loadProperties() method would be overriden for different implementations of your PropertyProvider.
And in your spring context you can have:
<bean id="consolePropertyProvider" class="com.company.ConsolePropertyProvider"/>
<bean id="myConsoleService" class="com.company.MyConsoleService">
<property name="propertyProvider" ref="consolePropertyProvider" />
</bean>
And the same pair of bean definitions for your WebService and WebPropertyProvider.
Just use dependency injection
Just place all the appropriate parameters to configure your library via setters and let the container or application configure it accordingly using DI.
So you will not need any checks which IMHO is a bad approach
The J2EE way. If your package is used in a web application then, I am assuming that you are in a J2EE container then, you can add a Reference in the naming at deploy time. You can also register an MDB that can listen to the changes to this reference and modify behavior of your code at runtime. Sweet right?
Other standard way in which you can pass the context of the caller is through a parametrized Factory or through properties.
One non-standard way - for fun is to get the stack trace and look for who the caller is or look for j2ee context etc.

Categories