Controlling CDI Startup inside EJB 3.1
Asked Answered
P

3

6

I'm new in here and also new to the CDI world, and the first task I got in my job was to find out a way to controlled CDI uploading.

We are using both EJB 3.1 and CDI 1.0, and because they are controlled by different containers, we can control when and in what order the EJB Managed Beans will be up by using @Startup and @Singleton annotations.

But the @Inject CDI bean I have declared in my class is coming as null since the CDI Container hasn't started yet.

I have been trying for several days now to look up for solutions and the one I found here did not worked (still came as null).

We are using Java EE 6 and running the application on WebSphere Application Server 8.

Please, if you could help me find a way to control CDI uploading inside and regardless of the EJB?

here is a sample code of it:

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
public class BaseStartupLoader{


/**
 * Default constructor. 
 */
@Inject @MyStartup
BaseStartUp myStartup;

private static Logger m_logger = LoggerFactory.getLogger(BaseStartupLoader.class);
public BaseStartupLoader() {

}

@PostConstruct
public void init(){

    String applicationName = null;

    try {

            applicationName = myStartup.getClass().getName();
            myStartup.load();

    } catch (IllegalAccessException e) {
        m_logger.error("Faild to load data into preload system. "+e);               
    } catch (InstantiationException e) {
        m_logger.error("Faild to load data into preload system. "+e);               
    } catch (ClassNotFoundException e) {
        m_logger.error("Faild to load data into preload system - Class "+ applicationName + "Not found. "+e);               
    }
  }
}

Here is the BaseStartup Interface:

public interface BaseStartUp {
public void load() throws IllegalAccessException, InstantiationException, ClassNotFoundException;
}  

The Qualifier and Implementation:

@Retention(RetentionPolicy.RUNTIME)
@Target ({ElementType.PARAMETER, ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Qualifier 
@Dependent
public @interface MyStartup {   
}


@MyStartup
public class MyStartUpLoader implements BaseStartUp {

    @Inject
    SomeConfigLoader config;

    @Override
    public void load() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
    conifg.init();      
}   
}
Pendley answered 24/12, 2012 at 8:36 Comment(4)
Could you add some sample code how you do it?Florilegium
I've edit the question with Code Samples.Pendley
Just wondering, but what has 'controlled uploading' to do with the rest of the question?Mochun
I'm trying to contorl the starting point of the CDI. I used the word upload to describe the starting point of the container in the time that the server is comming up.Pendley
P
5

After much research I found some help from the guys in IBM, since we are working with WebSphere Application Server I can just add a JVM Property called:

"com.ibm.ws.cdi.immediate.ejb.start" = true

to the WAS in the Admin console, and he will make sure that once I will get to the EJB @PostConstruct method in the @Startup bean I created the CDI Container will already be up and running and already injected.

It Works!!

Here is the link to the Problem and Solution in IBM site:

http://www-01.ibm.com/support/docview.wss?uid=swg1PM62774

Pendley answered 14/1, 2013 at 15:7 Comment(1)
Note this changes something with the classloader which causes the JPA provider to change from Eclipse Link to OpenJPA (found under WebSphere 8.5.5.4),Frenchpolish
C
3

Maybe double check that CDI is in fact enabled in all places of the application where it needs to be. Try adding this code to BaseStartupLoader as an experiment:

@Singleton
@Startup
public class BaseStartupLoader {

    @Inject @MyStartup
    BaseStartUp myStartup;

    @Inject
    private InjectionTest test;


    public static class InjectionTest {}
}

If the test variable comes up null in the @PostConstruct, then CDI is likely not enabled in the jar where BaseStartupLoader is declared.

If say, for example, BaseStartupLoader is declared in a jar called orange.jar and MyStartUpLoader is declared in a jar called yellow.jar, then both these files must exist:

  • orange.jar!/META-INF/beans.xml
  • yellow.jar!/META-INF/beans.xml

If CDI is properly enabled in both jars via a META-INF/beans.xml, then this is a bug in the container. All @Inject points are required to be completed (for CDI-enabled jars), prior to @PostConstruct being called. This is true regardless of if @Startup is used and one of the beans happens to be an EJB.

Callipash answered 25/12, 2012 at 0:11 Comment(2)
The static inner class injection is a neat trick! Thanks for sharing this tip.Mochun
Thank you for the quick response, I've done you're test and indeed the variable came up as null in the @PostConstruct, further more the jars files exist in the META-INF/beans.xml, but the real problem is that the CDI Container has not initialized while the EBJ Container is already up, I found out one solution on web - to use start-on-load Servlet to Force start the CDI Container prior to the EJB. but this solution is not good for us (we don't whant WAR files in the BackEnd. If anyone has any other idea I'm open to sugestions...Pendley
A
0

Take a look at DeltaSpike. There's a CDI Control module that should do what you're looking for now. I believe Java EE 7 should fix this as well.

Acculturate answered 25/12, 2012 at 19:41 Comment(1)
You're not mistaken, I found out that this issue will be solved in CDI 1.1 Release, but still I was very suprised to see that there is no active solution (except the Servlet load-on-startup one).Pendley

© 2022 - 2024 — McMap. All rights reserved.