I want to create a timer EJB3 when a stateless bean is created in the pool.
But if I use #PostConstruct I get the exception:
java.lang.IllegalStateException: [EJB:010193]Illegal call to EJBContext method. The bean is in "null" state. It cannot perform 'getting the Timer Service' action(s). Refer to the EJB specification for more details.
If container calls #PostConstruct, the bean ins't null. So, why I get this exception?
CLASS
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Override
public void test() {
}
}
INTERFACE
#Local
public interface TesteLocal {
void test();
}
SERVLET
public class TestServlet extends HttpServlet {
#EJB
private TestLocal test;
protected void doGet(....) throws .... {
test.test();
}
}
DETAILS
I'm using weblogic server 11g.
You can NOT use a #PostConstruct to create a timer in a stateless bean EJB 3. See this blog How to use EJB 3 timer in a weblogic 10 cluster environment for the explanation. Even the blog was talking about weblogic, but the explanation should apply to other app servers also.
Container will not allow for timerService in method annotated with #PostConstruct of Stateless Session Bean. If you want to use timerService in method annotated with #PostConstruct the go for Singleton session bean(#Singleton).
I'm not 100% sure but I think that the bean class must implement javax.ejb.TimedObject or have a method annotated with #Timeout to use EJB timers. Example:
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Timeout
#TransactionAttribute(value=REQUIRES_NEW)
public void timeoutCallback(Timer timer) {
...
}
}
Does WebLogic still complain with the above code?
PS: In any case, the error you currently get is very poorly reported, you should probably open a case.
Related
I have a Bean, which creates an instance of an object, which i need to inject into other beans. Everything works fine, i can print a property of the injected object in the #PostConstruct method, but if i try to call a method from that injected object inside the #OnOpen method of a ServerEndpoint it gives me a NullPointerException.
Here is my ServerEndpoint
#Named
#ApplicationScoped
#ServerEndpoint(value = "/websocket")
public class BeanThree {
private String message = "test";
#Inject private User user;
#PostConstruct
public void init() { System.out.println(user.getUserName()); } <-- displayed in the console correctly
public String getMessage() { return this.message; }
#OnOpen
public void onOpen(Session session) {
System.out.println("onOpen");
System.out.println(user.getUserName()); <-- causes NullPointerException
}
}
Is it possible to fix this?
Edit1:
Im using cdi 1.2, jetty 9.1, jsf 2.2, java-ee7 and websockets from java-ee7
The problem is that BeanThree is declared both a CDI bean and an endpoint at the same time.
It has to be split into two different beans:
#ServerEndpoint("/endpoint")
public class BeanThree {
#Inject
ApplicationScopedBean bean;
#OnOpen
public String onOpen(Session s) { System.out.println(bean); }
#OnMessage
public String onMessage(String message) { System.out.println(bean); }
}
#ApplicationScoped
public class ApplicationScopedBean { ... }
But there's another issue.
CDI / Websocket integration is very limited: out of the box you can inject #ApplicationScoped and probably #Dependent beans only.
From your snippet it seems you intend to use #SessionScoped User bean withing a Websocket session. That's not going to work because Websocket and HTTP sessions differ.
You'll have to manage Websocket sessions and session-bound data by yourself. Here's an example.
One way to do this is to allow CDI to instantiate it as a CDI bean.
Then subclasses the following classes: ServerEndpointConfig.Configurator
#ServerEndpoint(..., configurator=MyCustomConfigurator.class)
#SessionScoped
#Named("myMessageHandler")
public class MyMessageHandler{
#Inject
private MyInjectable instance;
...
}
public class MyCustomConfigurator extends ServerEndpointConfig.Configurator{
public <T extends Object> getEndpointInstance(Class<T> endpointClass) throws InstantiationException{
//do cdi lookup for endpoint using the simple name.
}
To have a reference to the cdi BeanManager, have a look at this thread:
http://dominikdorn.com/2010/04/cdi-weld-manual-bean-lookup/
In your case, you dont have a reference to FacesContext, so use the ServletContext
What could be the possible usage of having a reference of applicationContext within a bean ?
It used to be useful to have a handle to an ApplicationContext or ConfigurableApplicationContext when writing infrastructure code. For example, if you wanted to write a service locator that should find all beans implementing an interface, you could
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void addFooServices() {
for (... : this.applicationContext.getBeansOfType(FooService.class)) {
// do something with each
}
These kinds of uses are diminishing, since you can now (3.2, if not earlier) just inject
#Autowired
private List<FooService> fooServices;
But it can still be useful to have your hands on the container at times, e.g. to trigger a container refresh from JMX, or some other hackery.
Will tell you one of our usage experience. We used the application context to get the collection of beans implementing a particular interface:
public class MyBean implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
Collection<IMyInterface> implementors = context.getBeansOfType(IMyInterface.class).values();
}
}
I have a web project using Resteasy (which in turn uses Weld) and is deployed to Tomcat 7.0.22 (I put the specific version here in case this issue is particular to this version).
I have a ServletContextListener that looks like this:
#WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
// create a logger here
#Inject
HealthCheck healthCheck;
#Override
public void contextInitialized(ServletContextEvent event) {
if (healthCheck == null) {
log.error("healthCheck is null");
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
After deploying to Tomcat, healthCheck is null was logged, and I also noticed this line in the log:
<2013-11-13 13:27:40,191> <pack> INFO pool-2-thread-1 org.jboss.weld.environment.tomcat7.Tomcat7Container - Tomcat 7 detected, CDI injection will be available in Servlets and Filters. Injection into Listeners is not supported
Question 1: why is CDI injection not available in Listeners?
I looked into this answer, and it says Load on startup via #Startup. There is currently no equivalent to this in CDI.
Question 2: is the issue described in Question 1 a consequence of this?
Question 3: I am using org.jboss.weld.servlet:weld-servlet:1.2.0.Beta1. Is there any update on startup support in later versions?
Related Questions I Looked
startup class in Weld
Here is a workaround I discovered that can inject CDI beans when an application starts.
The requirement of the problem can be summarized as:
inject a CDI bean when the application starts
do something with the bean
Solution outline line:
Create a WebListener that calls BeanManager.fireEvent(new SomeDummyEvent())
Create an ApplicationScoped bean that responds to SomeDummyEvent and injects the CDI bean
Example code:
#WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
private static final Logger LOG = Logger.getLogger(ApplicationInitialisationListener.class);
#Override
public void contextInitialized(ServletContextEvent event) {
BeanManager beanManager = lookUpBeanManager();
if (beanManager != null) {
beanManager.fireEvent(new SomeDummyEvent());
LOG.info("beanManager fired SomeDummyEvent.");
} else {
LOG.error("beanManager is null. Cannot fire startup event.");
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
public BeanManager lookUpBeanManager() {
try {
// See reference below about how I came up with this
InitialContext iniCtx = new InitialContext();
BeanManager result = (BeanManager) iniCtx.lookup("java:comp/env/BeanManager");
return result;
} catch (NamingException e) {
LOG.error("Could not construct BeanManager.", e);
return null;
}
}
public static class SomeDummyEvent implements Serializable {
}
}
#ApplicationScoped
public class InitializationResourceBean {
private static final Logger LOG = Logger.getLogger(InitializationResourceBean.class);
#Inject
HealthCheck healthCheck;
public void listen(#Observes ApplicationInitialisationListener.SomeDummyEvent event) {
}
#PostConstruct
public void init() {
// Do something with healthCheck
}
#PreDestroy
public void destroy() {
// Do some other thing with healthCheck
}
}
References:
http://struberg.wordpress.com/tag/cdi/
From: http://docs.jboss.org/weld/reference/latest-master/en-US/html/environments.html#_tomcat
"Tomcat 7 and 8 are supported. Context activation/deactivation and dependency injection into Servlets and Filters works out of the box. Injection into Servlet listeners works on Tomcat 7.0.50 and newer."
So perhaps you can upgrade your Tomcat?
Now, all this is much easy to do with deltaspike servlet module
#ApplicationScoped
public class InitializationResourceBean {
#Inject
HealthCheck healthCheck;
public void onCreate(#Observes #Initialized ServletContext context) {
//Do initialisation stuff here.
if(HealthCheck != null) {
;
}
}
public void onDestroy(#Observes #Destroyed ServletContext context) {
System.out.println("Destroyed ServletContext: " + context.getServletContextName());
}
}
http://deltaspike.apache.org/documentation/servlet.html
I have some ear application which I need to rewrite to spring. War contains one class which run EJB:
/**
* The ear initialization.
*/
public final class Startup extends HttpServlet {
private static final long serialVersionUID = 6465240550145652729L;
#EJB(name="MyStartupBean")
private MyBeanLocal bean;
#Override
public void init(final ServletConfig servletConfiguration) throws ServletException {
bean.start();
}
#Override
public void destroy() {
bean.stop();
}
}
EJB contains some quart scheduler which run job every 30s
I really try to find some example of ear spring application with EJB but with no succes. How should I rewrite it into spring ?
Spring supports #EJB (not widely known but it does). So basically you can simply port your class to spring by removing the extends HttpServlet, add a #Component annotation, simplify the init method and add #PostConstruct and add #PreDestroy to the destroy method.
#Component
public final class Startup {
private static final long serialVersionUID = 6465240550145652729L;
#EJB(name="MyStartupBean")
private MyBeanLocal bean;
#PostConstruct
public void init() {
bean.start();
}
#PreDestroy
public void destroy() {
bean.stop();
}
}
Something like that would be the result. Now either declare this bean in xml
<bean class="Startup" />
Or use component scanning to detect/pickup this bean.
But as mentioned I would probably ditch the EJB altogether and use spring to bootstrap Quartz instead.
I'm trying to set up a very simple implementation of weld in java SE.
I have the extension class:
public class MyExtension implements Extension {
void beforeBeanDiscovery(#Observes BeforeBeanDiscovery bbd) {
System.out.println("Starting scan...");
}
<T> void processAnnotatedType(#Observes ProcessAnnotatedType<T> annotatedType, BeanManager beanManager) {
System.out.println("Scanning type: " + annotatedType.getAnnotatedType().getJavaClass().getName());
}
void afterBeanDiscovery(#Observes AfterBeanDiscovery abd) {
System.out.println("Finished the scanning process");
}
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
new Test();
}
}
I then have a simple class that I want to inject:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
}
And lastly the class I want to inject it in:
public class Test {
#Inject
private SimpleClass simple;
#PostConstruct
public void initialize() {
simple.doSomething();
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
The resulting output is:
80 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.10 (Final)
272 [main] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of #Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Starting scan...
Scanning type: test.Test
Scanning type: test.SimpleClass
Scanning type: test.MyExtension
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PostActivate' not found, interception based on it is not enabled
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PrePassivate' not found, interception based on it is not enabled
Finished the scanning process
Starting application
I would expect the simple class to be injected when Test() is constructed and the postconstruct method to be called which should output the expected text.
What exactly am I doing wrong?
There's two issues with your code:
Problem 1:
CDI does not manage beans created with new. For the most part you need to #Inject a bean in order for its life cycle to be managed by the container
Problem 2:
For the most part, you cannot inject bean instances into observers of container events. That's because the events are firing as the container is being initialized, aka before it can actually begin managing object life cycles.
You could hook the container initializer observer directly into your Test class. Something like this:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
#PostConstruct
public void initialize() {
System.out.println("Starting");
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
public class Test {
#Inject
private SimpleClass simple;
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
simple.doSomething();
}
}
What you're doing wrong is calling new Test(). This constructs a new instance of Test, but in the back of CDI. For CDI to inject your Test instance, CDI has to create it itself.
See the documentation for how to boostrap Weld in a Java SE environment.
Create a utils class with #ApplicationScoped. This class can produce objects of every type. In your case this is just like this:
#Produces
static SimpleClass generateSimpleClass(){
return new SimpleClass();
}
Otherwise, if simpleclass for you is going to be a unique class in the application, set its class as #ApplicationScoped. Problem is that weld does not know that the class belongs to the container if there is neither annotation nor producer