OSGI: do declarative services become available after bundle start - java

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.

Related

Get the real object from CDI Proxy

I looked for a clean CDI solution and not a WELD dependent one but so far nothing...
I need to test if every element of a list of objects that I get with #Inject #Any MyInterface beans is a proxy, and when true I need to get the real object to do introspection and get all the properties of the object.
My WELD implementation:
MyInterface interf = obj;
if (isProxy(interf )) {
interf = (Config) ((TargetInstanceProxy)interf ).getTargetInstance();
}
where isProxy is so defined (CDI solution?):
public boolean isProxy(Object obj) {
try{
return Class.forName("org.jboss.weld.bean.proxy.ProxyObject").isInstance(obj);
} catch (Exception e) {
LOGGER.error("Unable to check if object is proxy", e);
}
return false;
}
Any suggestions /Indications. In the official documentation I found no mention of introspection (here)
And then I would like to get all the properties of the bean with something like this:
Arrays.stream(interf.getClass().getDeclaredFields()).forEach(
field -> extractStuff(...)
);
We use Wildfly and WELD but don't want to bind us to an implementation of CDI.
Thanks in advance!
EDIT:
The question is, more precisely: Do you know a clean CDI solution that WELD is already implementing with TargetInstanceProxy? Not if I need to go back to school or if I understand what I'm writing.. Thanks for taking time to help!
CDI is intentionally hiding (or rather not exposing) the internals as they should be unimportant to end user when programming against interface.Furthermore messing with this can cause weird errors as you should always be invoking methods via proxy, not the actual instance.
So the short answer is - no, there is no pure CDI way to do this.
(At least not an intended one.)
However, seeing that you are using Weld already, there are other ways. Weld comes with pretty much any EE server excepting TomEE, so depending on Weld API should be pretty safe.
Now why am I saying this - in Weld 3.x (WildFly 12+), the API was extended to contain WeldConstruct and WeldClientProxy which are interfaces implemented by either Weld sublasses (interceptors/decorators) and/or client proxies - see javadocs of those classes for more information.
So if you must do this, then you could add a dependency on Weld API as such:
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-api</artifactId>
<version>x.y.z</version>
</dependency>
And then, in your code, you can check if injected object is a proxy by doing:
#Inject
Foo foo;
public void doSomething() {
if (foo instanceof WeldClientProxy) {
// foo is a proxy
} else {
// not a proxy
}
}
If you want to obtain actual instances, WeldClientProxy allows you to obtain Metadata from which you can the retrieve the underlying contextual instance. That's the closest I can get you to what you are after.
One common option is to:
get the Bean of the instance you want to unwrap
get its scope (bean.getScope())
from the bean manager (injectable) get the Context associated to the scope
do a context.get(bean) to get the unwrapped instance if available in CDI context (there are some cases you can't get it at all).

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.

Transparently managing per-request transactions in Java-EE

I'm developing a JEE application where each request done to "facade" beans should run a single transaction.
Basicly, in each method, I could do it like this:
#Override
public void updateSalaries(float factor)
{
initializeTransaction();
// Actual business code...
commitTransaction();
}
Where ùpdateSalaries()is a method invoked by the client, and whereinitializeTransaction()andcommitTransaction()` respectively take care of getting/starting/committing/rolling back (if necessary) the transaction.
Unfortunately, the transaction management should be more transparent: something developers should not care about when writing business methods.
Therefore, some way to "decorate" these business methods would be nice, but I can't think of a possible way to do that.
Another possible solution I thought of would be to handle it in a central DataAccessBean class, where I would start the transaction on #PostConstruct and commit it on #PreDestroy:
#Stateless
public class DataAccessBean implements IDataAccessBean
{
#PostConstruct
public void initializeTransaction() { /* ... */ }
#PreDestroy
public void endTransaction() { /* ... */ }
#Override
public <T implements Serializable> T getObjectById(
Class<T> objectType, Object key) { /* ... */ }
#Override
public void saveObject(Serializable object) { /* ... */ }
}
I'm not sure though, if I can rely on that mechanism. An important question would also be, what type of bean I'd need: I doubt a stateful bean would be suitable as the transaction is per-request and not per-session. Maybe a stateless bean would be a good option, but AFAIK a stateless bean might not be destroyed when a request completes (if it resides in a stateless bean pool).
Two little constraints:
The solution should not depend on a particular non-standard framework or JEE-server
The solution should be compatible with JEE 6 and JEE 7
Thanks for the suggestions.
What you need is addressed by Java Transaction API (JTA). From the JEE6 Tutorial (Part VIII - Chapter 42):
The Java Transaction API (JTA) allows applications to access transactions in amanner that is
independent of speciic implementations. JTA speciies standard Java interfaces between a
transactionmanager and the parties involved in a distributed transaction system: the
transactional application, the Java EE server, and themanager that controls access to the shared
resources afected by the transactions.
You want to use the Container-Managed Transaction. In this strategy you just need decorate the beans/methods with the appropriate transaction attribute i.e.:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void myMethod() {
...
}
The design of your service layer must carefully address the transaction life cycle in case your have services of services (nested service calls).

How to wait to another bundle?

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.

Use #EJB as injection annotation in Weld

I have an application which is part JavaEE (the server side) part JavaSE (the client side). As I want that client to be well architectured, I use Weld in it to inject various components. Some of these components should be server-side #EJB.
What I plan to do is to extend Weld architecture to provide the "component" allowing Weld to perform JNDI lookup to load instances of EJBs when client tries to reference them. But how do I do that ?
In other worrds, I want to have
on the client side
public class ClientCode {
public #Inject #EJB MyEJBInterface;
}
on the server-side
#Stateless
public class MyEJB implements MyEJBInterface {
}
With Weld "implicitely" performing the JNDI lookup when ClientCode objects are created. How can I do that ?
Basically, doing so requires write a so-called portable CDI extension.
But, as it is quite long and requires a few tweaks, let me explain it further.
Portable extension
Like weld doc explains, first step is to create a class that implements the Extension tagging interface, in which one will write code corresponding to interesting CDI events. In that precise case, the most interesting event is, to my mind, AfterBeanDiscovery. Indeed, this event occurs after all "local" beans have been found by CDI impl.
So, writing extension is, more opr less, writing a handler for that event :
public void loadJndiBeansFromServer(
#Observes AfterBeanDiscovery beanDiscovery, BeanManager beanManager)
throws NamingException, ClassNotFoundException, IOException {
// Due to my inability to navigate in server JNDI naming (a weird issue in Glassfish naming)
// This props maps interface class to JNDI name for its server-side
Properties interfacesToNames = extractInterfacesToNames();
// JNDI properties
Properties jndiProperties = new Properties();
Context context = new InitialContext();
for (Entry<?, ?> entry : interfacesToNames.entrySet()) {
String interfaceName = entry.getKey().toString();
Class<?> interfaceClass = Class.forName(interfaceName);
String jndiName = entry.getValue().toString();
Bean<?> jndiBean = createJndIBeanFor(beanManager, interfaceClass, jndiName, jndiProperties);
beanDiscovery.addBean(jndiBean);
}
}
Creating the bean is not a trivial operation : it requires transforming "basic" Java reflection objects into more advanced weld ones (well, in my case)
private <Type> Bean<Type> createJndIBeanFor(BeanManager beanManager, Class<Type> interfaceClass,
String jndiName, Properties p) {
AnnotatedType<Type> annotatedType = beanManager
.createAnnotatedType(interfaceClass);
// Creating injection target in a classical way will fail, as interfaceClass is the interface of an EJB
JndiBean<Type> beanToAdd = new JndiBean<Type>(interfaceClass, jndiName, p);
return beanToAdd;
}
Finally, one has to write the JndiBean class. But before, a small travel in annotations realm is required.
Defining the used annotation
At first, I used the #EJB one. A bad idea : Weld uses qualifier annotation method calls result to build hashcode of bean ! So, I created my very own #JndiClient annotation, which holds no methods, neither constants, in order for it to be as simple as possible.
Constructing a JNDI client bean
Two notions merge here.
On one side, the Bean interface seems (to me) to define what the bean is.
On the other side, the InjectionTarget defines, to a certain extend, the lifecycle of that very bean.
From the literature I was able to find, those two interfaces implementations often share at least some of their state. So I've decided to impelment them using a unique class : the JndiBean !
In that bean, most of the methods are left empty (or to a default value) excepted
Bean#getTypes, which must return the EJB remote interface and all extended #Remote interfaces (as methods from these interfaces can be called through this interface)
Bean#getQualifiers which returns a Set containing only one element : an AnnotationLiteral corresponding to #JndiClient interface.
Contextual#create (you forgot Bean extended Contextual, didn't you ?) which performs the lookup :
#Override
public T create(CreationalContext<T> arg0) {
// Some classloading confusion occurs here in my case, but I guess they're of no interest to you
try {
Hashtable contextProps = new Hashtable();
contextProps.putAll(jndiProperties);
Context context = new InitialContext(contextProps);
Object serverSide = context.lookup(jndiName);
return interfaceClass.cast(serverSide);
} catch (NamingException e) {
// An unchecked exception to go through weld and break the world appart
throw new LookupFailed(e);
}
}
And that's all
Usage ?
Well, now, in my glassfish java client code, I can write things such as
private #Inject #JndiClient MyRemoteEJB instance;
And it works without any problems
A future ?
Well, for now, user credentials are not managed, but I guess it could be totally possible using the C of CDI : Contexts ... oh no ! Not contexts : scopes !
Section 3.5 of the CDI spec should help out. You may want to use some of the properties on the EJB annotation as well. Also, (probably don't need to tell you this) make sure you have JNDI set up correctly on the client to reference the server, and pack any of the needed interfaces into your client jar.

Categories