Inject EJB into startup singleton bean - java

In my application, I have the following startup bean:
#Startup
#Singleton
#DependsOn("RecordAcumulator")
public class StartupBean {
private static final Logger logger = Logger.getLogger(StartupBean.class);
#Inject
RecordAcumulator recordAcumulator;
/**
* Initializes the EJB system on the post construct event
*/
#PostConstruct
public void init() {
The record accumulator is an EJB that accesses the database. The startup is intended to preload database tables into the cache.
#Stateless
public class RecordAcumulator {
When this launches, I get
Caused by: com.ibm.ws.exception.RuntimeWarning: CNTR0200E: The StartupBean singleton session bean in the EJB.jar module depends on the RecordAcumulator enterprise bean in the EJB.jar, but the target is not a singleton session bean.
I have tried many variations of this and I can't seem to get the thing to inject. My log file indicates that the RecordAcumulator EJB was bound prior to the startup bean being loaded, so I can't figure out why I can't inject the EJB into my startup.
If I remove the #DependsOn I get this:
Caused by: javax.ejb.NoSuchEJBException: An error occurred during initialization of singleton session bean bla#EJB.jar#StartupBean, resulting in the discarding of the singleton instance.; nested exception is: javax.ejb.EJBException: The #Inject java.lang.reflect.Field.recordAcumulator reference of type com.foo.bar.accum.RecordAcumulator for the StartupBean component in the EJB.jar module of the bla application cannot be resolved.
Any ideas how to pull this off?
EDIT----------
I found this link:
Controlling CDI Startup inside EJB 3.1
But the issue with that is i'm using WAS 8.5.5.0, That issue was supposed to be resolved in 8.5.0.2

From what I can see:
Remove the #DependsOn
Make your EJB #Singleton
There can be complexities with singleton EJBs, as all the traffic going through your application will go through that one instance. In your case that may not be an issue.

Related

Context not active exception while injecting request scope bean in application scope class with Postconstruct method

when I tried to inject request scoped bean in application scope bean I got the following error.
Method threw 'org.jboss.weld.contexts.ContextNotActiveException' exception. Cannot evaluate com.example.flow.txn.TxnMessageProcessor$Proxy$_$$_WeldClientProxy.toString()
Code Reference:
#ApplicationScoped
public class TxnMessageObserver {
private static final Logger logger = LoggerFactory.getLogger(TxnMessageObserver.class);
#Inject
private TxnMessageProcessor processor;
//message is observed here
public void postConstruct(#Observes #Initialized(ApplicationScoped.class) Object o) {
logger.info("Subscribing to queue [{}] for msg.", queue);
consumer.subscribe(queue);
}
}
#RequestScoped
public class TxnMessageProcessor {
private static final Logger logger = LoggerFactory.getLogger(TxnMessageProcessor.class);
//all processing happens here
}
I need to process every message in request scope.
If the applicationscoped bean is constructed eagerly when the servlet context is initialized (like is the case here), there is no request context and hence no requestscoped bean.
Since it is completely unclear what you try to achieve (your code is not a minimal reproducible example, let me point you to
JEE6 #ApplicationScoped bean and concurrency
Why #Singleton over #ApplicationScoped in Producers?
(All found via this search)
Injecting a requestscoped bean is therefor dangerous and I strongly suggest to retrieve the required requestscoped bean in the specific methods or do it the other way around, inject the applicationscoped bean in the requestscoped one and call a method on it, passing in itself.
I do not know what exactly the problem cause is. But I can confirm that you can inject #ReqeustScoped beant into #ApplicationScoped. I do that in many applications with hundreds of classes and it worked out of the box.

Dependency injection through constructor does not work for EJB bean

My app is being deployed on to IBM WebSphere. I have a simple service and I'd like to know how dependency injection works in this case.
// stateless EJB
#Stateless
public class UserService {
private UserDAO userDAO;
// btw, UserDAO is stateless EJB as well
#Inject
public UserService(UserDAO userDAO) {
this.userDAO = userDAO;
}
// biz methods ...
}
It fails with the following error:
[ERROR ] CWWKZ0002E: An exception occurred while starting the
application my-app. The exception message was:
com.ibm.ws.container.service.state.StateChangeException:
com.ibm.ws.cdi.CDIException:
com.ibm.wsspi.injectionengine.InjectionException:
com.ibm.ejs.container.EJBConfigurationException: EJB class
com.demo.app.UserService must have a
public constructor that takes no parameters
I remember there was something in EJB spec that says: the class must have a public constructor that takes no parameters and it makes sense for me that the bean instance is first instantiated by the container and afterward dependency injection is done.
On the other hand, I've found this in WELD docs:
First, the container calls the bean constructor (the default
constructor or the one annotated #Inject), to obtain an instance of
the bean.
And I am confused a little bit, why my EJB cannot be instantiated.
How is the EJB instance being created and dependencies injected when we have constructor injection point?
Any ideas? :)
So what happens is that you do not meet the requirements for initializing EJB beans.
CDI spec has some limitations on constructors - either no-args or one with #Inject.
But there is also this chapter, which specifies that in EE, the set of rules is extended by what EJB session beans require.
And now we are getting into EJB spec which requires a no-arg constructor on a bean.
This should be in chapter Enterprise Bean Class where it states
The class must define a public constructor that takes no arguments.
Now, finally moving on to whether this should work - e.g. can you have an EJB bean using CDI constructor injection?
Well, let's have a look at CDI TCK, a set of tests that all implementation and containers have to pass in order to be able to claim they implement CDI.
There, we can see this bean and this test using it - so yea, this can work, but you need to have both constructors.
EJBs are registered as CDI beans. But first they have to meet the requirements of the EJB spec.
I guess it works just by providing the no-args constructor.
the creation of EJB session beans is done by EJB container but it can choose to use CDI to provide EE resource injection but EJB resolution is delegated to the container
https://docs.jboss.org/weld/reference/2.1.0.Final/en-US/html/ri-spi.html says:
Alternatively, the integrator may choose to use CDI to provide EE
resource injection. In this case, the EE_INJECT environment should be
used, and the integrator should implement the Section A.1.4, “EJB
services”, Section A.1.7, “Resource Services” and Section A.1.5, “JPA
services”.
....
Weld registers resource injection points with
EjbInjectionServices, JpaInjectionServices, ResourceInjectionServices
and JaxwsInjectionServices implementations upfront (at bootstrap).
This allows validation of resource injection points to be performed at
boot time rather than runtime
if you interested in how CDI and EJB are integrated. you can have a look at the code of weld-EJB module and weld-integration(glassfish code)

What is the correct way to scope spring-batch components in an annotation driven configuration?

I am building a an application around spring MVC that incorporates spring-batch, that dynamically manages the batch processes in a manner similar to what spring-batch-admin does. I am trying to use the spring-batch-admin as a foundation to understand what is happening, translating the context initializations into annotation driven configurations.
While the application is using annotation driven configuration as much as possible, the spring-batch jobs are externalized as XML files.
On startup, the AppInitializer fails after the ClasspathXmlApplicationContextsFactoryBean has been properly initialized, when it tries the refresh the context. I know that the bean has been correctly initialized because it attempts to load one of the jobs, and can't find step-scoped beans. (The process is not supposed to load and execute the job, it is only supposed to be able to find them at this point).
The jobs themselves work correctly under spring-batch-admin, so there is no issue with the jobs.
I am certain that I have simply misunderstood the contexts of the different pieces, and a resolution depends on getting the pieces into the right contexts. Can anyone point out what I missed?
Environment:
Java 1.8
Spring 4.1.6
Spring-batch 3.0.2
Pivotal TC Developer Edition v3.0
Thanks in advance
Log excerpt:
DEBUG DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#425cccc3: defining beans [org.springframework.batch.core.scope.JobScope#0,org.springframework.batch.core.scope.StepScope#0,org.springframework.beans.factory.config.CustomEditorConfigurer,org.springframework.batch.core.configuration.xml.CoreNamespacePostProcessor,batch_state_transition_comparator,step0002-fetch,step0003-archive-purge,org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean#0,archive-purge-mt]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory#51ae827
WARN AnnotationConfigWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'step0002-fetch': Cannot resolve reference to bean 'sourceSelectionReader' while setting bean property 'itemReader'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'sourceSelectionReader' is defined
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'sourceSelectionReader' is defined
at
...
sourceSelectionReader Bean
#Component("sourceSelectionReader")
#Scope(value = "step", proxyMode = ScopedProxyMode.DEFAULT)
public class SourceSelectionReaderImpl implements ItemReader<TreeModel>,
ApplicationContextAware, StepExecutionListener, SourceSelectionReader {
AppInitializer:
public class AppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
Logger logger = LoggerFactory.getLogger(this.getClass());
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(MyConfig.class);
rootContext.refresh();
// Manage the lifecycle of the root appcontext
container.addListener(new ContextLoaderListener(rootContext));
container.setInitParameter("defaultHtmlEscape", "true");
AnnotationConfigWebApplicationContext jobExecutionContext = new AnnotationConfigWebApplicationContext();
jobExecutionContext.setParent(rootContext);
jobExecutionContext.register(ExecutionContextConfig.class);
jobExecutionContext.refresh();
AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
mvcContext.register(ViewConfig.class);
mvcContext.setServletContext(container);
... (snip) ...
}
}
I believe you should use #Scope(value="step", proxyMode=ScopedProxyMode.TARGET_CLASS) or its shortcut #StepScope.
PICNIC error: I was using the wrong paradigm. With a deeper look, I found that the JobRegistry component I was trying to use was meant load and execute directly from the classpath. I have refactored using the DefaultBatchConfigurer, and moved on to the next problem.

Looking up SessionContext in JBoss 7.2

For various reasons I need to perform a manual lookup of SessionContext. In JBoss5, the solution
InitialContext initialContext = new InitialContext();
SessionContext sessionContext = (SessionContext) initialContext.lookup("java:comp/EJBContext");
has served med well, but from JBoss 7 I instead get a
javax.naming.NameNotFoundException: EJBContext -- service jboss.naming.context.java.global.EJBContext
Has something changed in how context is looked up in JBoss 7.2, or is my deployment lacking anything vital? For reference, standard injection works fine, this is the only lookup that fails. Or am I doing something terribly wrong (besides performing a manual lookup of SessionContext)?
According to specification of Java EJB (this one is for EJB 3.2. but nothing changed about EJBContext from previous one, EJB 3.x), you can inject EJBContext into your components either using annotation #Resource or manually via lookup (section 11.15):
The container must make a component’s EJBContext interface available either through injection
using the Resource annotation or in JNDI under the name java:comp/EJBContext
Standard way of looking up for EJB resource is via EJBContext.lookup method but there is also JNDI way which is the only possibilities if you don't have already EJBContext:
Context initCtx = new InitialContext();
EJBContext ejbCtx = (EJBContext) initCtx.lookup("java:comp/EJBContext");
This is exactly what you did, so what is wrong? There are two things, which one I'm not sure about. First, with manually lookup it's sometime needed to assign resource to component with annotation at class level:
#Resource(name = "EJBContext", type = javax.ejb.EJBContext)
public class MyComponent {
...
}
but I'm not sure is it needed for EJBContext as well, I guess not. The second thing, more important and critical - according to specification once again:
EJBContext objects accessed through the naming environment are only valid within the bean
instance that performed the lookup.
this one is section 11.15.1, and the next one, section 11.15.2:
The Container Provider is responsible for providing an appropriate EJBContext object to the refer-
encing component. The object returned must be of the appropriate specific type for the bean requesting
injection or performing the lookup—that is, the Container Provider must return an instance of the SessionContext interface to referencing session beans and an instance of the MessageDrivenCon-
text interface to message-driven beans.
Those both mean that injection and lookup for EJBContext are only valid in Enterprise Java Beans, so those which are annotated with #MessageDriven, #Stateful, #Singleton or #Stateless (or described as EJBs in deployment descriptor file, also as EJB 2.x Specification). Maybe your component isn't valid EJB and it's why lookup isn't working? This is only suggestion of course.
There's one more possibilities to get EJBContext (more correctly SessionContext). Your component should implements SessionBean interface which has setSessionContext(SessionContext sessionContext) method. This method should be invoked by EJB container every time when component is used (injected somewhere, invoked by client or timeout, especially when it's created) and inside this method you should assign sessionContext parameter to bean's field.

How should be EJB Stateless Session Bean correctly injected into the web module?

Being completely new to Java EE (but not to Java itself) I'm trying to build a very simple "Enterprise Application" with Hibernate as JPA provider and JSF as the actual UI framework. For this purposes I'm using the NetBeans 7 with GlassFish 3.1.
{ApplicationName}-ejb:
I've accomplished to generate entity classes from database and local sesssion beans for these entities. Beans.xml is in place.
#Stateless
public class QuestFacade extends AbstractFacade<Quest> implements QuestFacadeLocal {
// some methods here as well as EntityManager injection ...
}
{ApplicationName}-war:
I've created a simple POJO as a backing bean for the JSF page. I've annotated it with javax.inject.#Named and javax.enterprise.context.#SessionScoped. This backing bean is now accessible from the JSF page as well as being injected when the actual page is accessed. Beans.xml is in place as well.
#Named
#SessionScoped
public class QuestBean implements Serializable {
#EJB
protected QuestFacade questFacade;
// several methods delegating lookups to the questFacade ...
}
Having this deployed and page accessed, I'm, however, getting an error from GlassFish that the QuestFacade cannot be looked up by the JNDI.
The stacktrace is quite long but the initial cause could be enough:
Caused by: javax.naming.NamingException: Lookup failed for 'model.session.QuestFacade#model.session.QuestFacade' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: model.session.QuestFacade#model.session.QuestFacade not found]
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.sun.ejb.EjbNamingReferenceManagerImpl.resolveEjbReference(EjbNamingReferenceManagerImpl.java:173)
... 74 more
Caused by: javax.naming.NameNotFoundException: model.session.QuestFacade#model.session.QuestFacade not found
at com.sun.enterprise.naming.impl.TransientContext.doLookup(TransientContext.java:248)
at com.sun.enterprise.naming.impl.TransientContext.lookup(TransientContext.java:215)
at com.sun.enterprise.naming.impl.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:77)
at com.sun.enterprise.naming.impl.LocalSerialContextProviderImpl.lookup(LocalSerialContextProviderImpl.java:119)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:505)
... 78 more
I understand that I'm persuading GlassFish to inject an EJB from a different module within the same application. Should the #Remote interface be used instead? I've also tried to explicitely specify the name for both #Stateless and #EJB annotation but without any success.
I believe that I'm doing something fundamentaly wrong, but I cannot find out what.
Any suggestion or would be greatly appreciated!
I believe that I'm doing something fundamentaly wrong, but I cannot find out what.
What you're doing wrong is that if you implement a business interface (either #Local or #Remote), then you must declare the variable where injection takes place as having the type of that interface, not of the actual bean class.
So in your case:
#Named
#SessionScoped
public class QuestBean implements Serializable {
#EJB
protected QuestFacadeLocal questFacade;
// several methods delegating lookups to the questFacade ...
}
However, a business interface is not required in EJB when you're doing local (in-jvm) communication. As you discovered, if you don't specify a business interface at all for your EJB, you can inject the bean class itself. This is because you then automatically get the so-called no-interface view.
If you want, you can optionally declare that you want BOTH the local view and the no-interface view. In that way, you can inject your bean class in places whether either the bean type itself is declared or its business interface. For this you use the #LocalBean.
#Stateless
#LocalBean
public class QuestFacade extends AbstractFacade<Quest> implements QuestFacadeLocal {
// some methods here as well as EntityManager injection ...
}
Injection can thus happen in two ways now:
#Named
#SessionScoped
public class QuestBean implements Serializable {
#EJB
protected QuestFacadeLocal questFacade; // possible because of local view
#EJB
protected QuestFacade questFacadeN; // possible because of no-interface view
// several methods delegating lookups to the questFacade ...
}
In practice I didn't found much use for having both methods available at the same time though, but maybe this adds to your understanding.
Apparently the problem was that I generated #Local session beans. Per this tutorial it is no longer necessary (?) to specify the #Local or #Remote interface. I still not completely understand the problem though.
I Hope this answer could potentialy save up some time to somebody :-)
Jarda

Categories

Resources