javasingletonosgidaoapache-karaf

Karaf, get an object instance from a deployed Kar, but prone error because the Kar could be not deployed


Context:

I have a Karaf instance running and by bad design, someone decided to include an Hibernate entity into the Jar files loaded by a Kar, now, that Kar knows the objectDao I need in my karaf runtime, and also, the Kar zip has the @entity notation inside of its classes.

So the table is not created until you load that Kar, but I need to make use of the objectDao class inside that Kar in my Karaf instance and be prone to errors to know if the Kar is not loaded yet.

My question:

How could I retrieve an object instance that knows the objectDao from the Kar (jar file) that will be loaded later.

My personal thoughts:

I was thinking on create a Singleton class inside the source code of the Kar file (that knows the objectDao I need), then retrieving the object by calling the getInstance() method by reflection, but I read in some forums that reflection and Singletons can be prone error and dangerous.

Code example:

On the karaf instance running:

public class myHandler (){

public void saveInfo(String info){

saveInfoIntoDatabase(info);

}

private void saveInfoIntoDatabase(String info){

Object objectProvided;

/*
Solution I want to implement
~ this converts the objectProvided
~ into the object that is equal
~ to the instance created on the Kar by loading later
*/

objectProvided.saveIntoBadDesignedDao(info);

}
}

On the KAR that can be deployed:

public class InfoSaver{

ObjectDao objectDao; // The instance is being provided by the bean/service/reference features of OSGI
//this means that we have to provide the object created on the OSGI blueprint

public void saveIntoBadDesignedDao(String info){

objectDao.methodThatPersistData(info);

}
}

There is already a piece of code that does this job, and is a ServiceTracker from OSGI, the Kar file has a dependency on one interface from the Karaf modules, but, it uses a Publish-suscribe design patter. The method that calls the objectDao on the kar file, is private, and either by making accessible with a public method (which is HORRIBLE TO DO) it is giving an OSGI error.


Solution

  • #Found out a solution.

    Apparently it is possible to track your services (objects) with a class provided by the OSGI framework

    https://docs.osgi.org/javadoc/r6/core/org/osgi/util/tracker/ServiceTracker.html

    By this it is possible to get references from the different services running in your OSGI environment, like in karaf, by providing the bundleContext

    So in any deployed .kar (Bunch of deployable .jars but with metadata for the runtime deployer like karaf) it is possible to get the instances of your services in those, as long as you provide the interface implemented in those services.

    Basically in 3 steps:

    private ServiceTracker tracker = null;
    
    tracker = new ServiceTracker( 
    bundleContext, 
    ITheClassUWannaTrack.class.getName(), 
    null );
    
    tracker.open();
    
    Object[] objectServices = tracker.getServices();
    
     for ( Object obj : objectServices )
          {
            ITheClassUWannaTrack classTracked = (ITheClassUWannaTrack) obj;
            ITheClassUWannaTrack.helloWorld();
          }
    
    

    And the service in your blueprint could be something like this>

    <bean id="objectService"
          class="com.fictioncompany.coolpackage.TheClassUWannaTrack"
          init-method="init">
        <property name="bundleContext" ref="blueprintBundleContext" />
    </bean>
    

    With this it is exposed, so the service tracker can get the class implemented in the .kar after deplyment

    #In your .KAR

    /NOTE THAT YOU HAVE TO CREATE THE BLUEPRINT BEAN/SERVICE FOR THIS SO THE SERVICE TRACKER ACTUALLY CAN GET IT AND GET THE REFERENCE LATER/

    
    public class TheClassUWannaTrackInKar implements ITheClassUWannaTrack{
    
    @override
    public void helloWorld(){
    
    }
    
    }
    

    With this, all the Hello Worlds will be executed in the for loop taking the object service references if you have beans implemented in the common interface and exposed in their corresponding bundle blueprint, you can call objects "From the future"