How to inject a Session Bean into a Message Driven Bean? - glassfish

I'm reasonably new to Java EE, so this might be stupid.. bear with me pls :D
I would like to inject a stateless session bean into a message-driven bean. Basically, the MDB gets a JMS message, then uses a session bean to perform the work. The session bean holds the business logic.
Here's my Session Bean:
#Stateless
public class TestBean implements TestBeanRemote {
public void doSomething() {
// business logic goes here
}
}
The matching interface:
#Remote
public interface TestBeanRemote {
public void doSomething();
}
Here's my MDB:
#MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
#EJB
private TestBean testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}
So far, not rocket science, right?
Unfortunately, when deploying this to glassfish v3, and sending a message to the appropriate JMS Queue, I get errors that glassfish is unable to locate the TestBean EJB:
java.lang.IllegalStateException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/mvs.test.TestController/testBean' in SerialContext [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session' . Actual (possibly internal) Remote JNDI name used for lookup is 'mvs.test.TestBean#mvs.test.TestBean' [Root exception is javax.naming.NamingException: Lookup failed for 'mvs.test.TestBean#mvs.test.TestBean' in SerialContext [Root exception is javax.naming.NameNotFoundException: mvs.test.TestBean#mvs.test.TestBean not found]]]
So my questions are:
is this the correct way of injecting a session bean into another bean (particularly a message driven bean)?
why is the naming lookup failing?

Could you try to define things like this:
#Remote
public interface TestBeanRemote {
public void doSomething();
}
#Stateless(name="TestBeanRemote")
public class TestBean implements TestBeanRemote {
public void doSomething() {
// business logic goes here
}
}
And then in the MDB:
#MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
#EJB(beanName="TestBeanRemote")
private TestBeanRemote testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}
If this work, I'll try to provide an explanation :)

I think the problem of the very first example is that you are trying to inject the implementation of the EJB and not its interface. The local no-interface view of EJB 3.1 is just possible if you do not define any interface, not even a remote one. So changing the injection point to the following should work out:
#EJB
private TestBeanRemote testBean;
If you are using your application within a non clustered environment, so single JVM, you should think about changing the interface to #Local. As soon as you are accessing EJBs using their remote interface, you are getting a lot of overhead. Parameters and return values can not be accessed by reference anymore, but by value, as they are always copied (specification says so). This might lead to performence issues when dealing with more complex objects.
Hoped that helped.

It seems that my problem was related to Inversion of Control and caused by my lack of knowledge and Netbeans' suggestions for Class/Interface names.
I found out that - in order to find the the right bean and the right interface - I should name them properly. Here's what works:
#Remote
public interface Test {
public void doSomething();
}
#Stateless
public class TestBean implements Test {
public void doSomething() {
// business logic goes here
}
}
And in the MDB I access 'Test' not 'TestBean':
#MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
#EJB
private Test testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}

Ok, I found out that if I add the annotation #LocalBean to the session bean, it works. What the ...?

Related

java.lang.NullPointerException: null on AutoWiring a bean in StandAlone App

When trying to use #AutoWire feature with one of StandAlone Application unable to do so instead getting Null Pointer Exception. Please highlight my mistakes if any. Your help is appreciated.
Spring Ver 5.1.5.RELEASE and we're not using any xml config file to tell spring there are annotated classes to look into instead using #ComponentScan or #EnableAutoConfiguration at the top of AppConfig and boost strap the Context from main() class as a first line. But Autowiring works perfectly with internal bean/java classes of jdk(Environment) but not with custom POJO classes. If we're trying to get through getBean method then it works. But I'm trying to avoid creating context everywhere and using getBean() Please Refer below and help me only with your valuable guidelines.
public class ContextMaster {
private static AnnotationConfigApplicationContext appContext;
public static AnnotationConfigApplicationContext getApplicationContext() {
if (appContext == null) {
appContext = new AnnotationConfigApplicationContext(ContextConfig.class);
//appContext = new AnnotationConfigApplicationContext("com.xx.xx.xxx","xx.xxx.xxxx.xxx.datamanager");
logger.debug("Context Invoked !!");
}
return appContext;
}
}
#Configuration
#EnableAutoConfiguration
#PropertySource("classpath:db.properties")
#EnableTransactionManagement
#ComponentScans(value = {
#ComponentScan(basePackages = "xxxxx.datamanager"),
#ComponentScan(basePackages = "com.xx.xx.xxx"),
#ComponentScan(basePackages = "com.xx.xx.xxx.utils")})
public class AppConfig {
#Autowired
private Environment env;
#Bean
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("db.driver"));
dataSource.setUrl(env.getProperty("db.url"));
return dataSource;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
//LocalSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
factoryBean.setDataSource(getDataSource());
Properties props=new Properties();
props.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
props.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
props.put("hibernate.cache.region.factory_class", env.getProperty("hibernate.cache.region.factory_class"));
factoryBean.setHibernateProperties(props);
factoryBean.setAnnotatedClasses(xx.class, xxxx.class, xxxx.class, xxx.class);
return factoryBean;
}
#Bean
public HibernateTransactionManager getTransactionManager() {
return transactionManager;
}
}
// Here is NPE thrown when tried with auto-configured bean
#Component
public class Good extends Good11 {
#Autowired
private RxxxDyyyyHelper rdh;
//RxxxDyyyyHelper rdh =
ContextHelper.getApplicationContext().getBean(RxxxDyyyyHelper .class);
rdh.setProperty(); // NPE here
rdh.getProperty(); // NPE
}
// Here we're trying to initiate the LosUtils class
public class LosUtils {
public static void main(String args[]) throws Exception {
AnnotationConfigApplicationContext applicationContext = `ContextHelper.getApplicationContext();`
}
It seems like you didn't put the full code here, because your Good class won't compile this way..

Resteasy and Google Guice: how to use multiple #ApplicationPath and resource with #Injection?

I created a project to test the dependency injection offered by Google Guice in my Jax-rs resources, using Resteasy.
My intentions are:
Use multiple #ApplicationPath for the versions of my API. In each class annotated with #ApplicationPath I load a set of classes for the specific version.
Each resource have a #Inject (from Google Guice) in his constructor to inject some services.
I created two classes annotated with #ApplicationPath: ApplicationV1RS and ApplicationV2RS. In both I added the same resources classes (UserResource and HelloResource), only for my test.
My Module is configured like this:
public class HelloModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(IGreeterService.class).to(GreeterService.class);
binder.bind(IUserService.class).to(UserService.class);
}
}
When I call http://localhost:9095/v1/hello/world or http://localhost:9095/v2/hello/world, I receive the same error:
java.lang.RuntimeException: RESTEASY003190: Could not find constructor
for class: org.jboss.resteasy.examples.guice.hello.HelloResource
Well, as I expected, this not works. The Google Guice is not "smart" to instantiate the resource classes using the construtor for me.
But I can't find a way to work. To be really honest, I'm really confuse about how the Google Guice, Jetty and Resteasy play with each other in this scenario.
If I abandon the idea of use #ApplicationPath, my resources work with Google Guice configuring my HelloModule like this:
public class HelloModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(HelloResource.class);
binder.bind(IGreeterService.class).to(GreeterService.class);
binder.bind(UserResource.class);
binder.bind(IUserService.class).to(UserService.class);
}
}
But in this case, I'm passing the control to register my resources (HelloResource and UserResource) to Guice. It's not flexible for me, I can't setup my multiple #ApplicationPath.
So, what I'm missing or not understanding?
I created a project with the problemetic code. Is very easy to setup and test: https://github.com/dherik/resteasy-guice-hello/tree/so-question/README.md
Thanks!
When you have getClasses method in your Application then it tries to create instance for all the registered resources using the default constructor which is missing in our Resources class. One way is to create a default constructor and Inject the dependencies through setter Injection.
And then instead of overriding getClasses in ApplicationV1RS and ApplicationV2RS you override getSingletons. Since Resources can be Singleton.
Below are the changes that I made to make it work the way you want.
ApplicationV1RS.java
#ApplicationPath("v1")
public class ApplicationV1RS extends Application {
private Set<Object> singletons = new HashSet<Object>();
public ApplicationV1RS(#Context ServletContext servletContext) {
}
#Override
public Set<Object> getSingletons() {
Injector injector = Guice.createInjector(new HelloModule());
HelloResource helloResource = injector.getInstance(HelloResource.class);
UserResource userResource = injector.getInstance(UserResource.class);
singletons.add(helloResource);
singletons.add(userResource);
return singletons;
}
}
ApplicationV2RS.java
#ApplicationPath("v2")
public class ApplicationV2RS extends Application {
private Set<Object> singletons = new HashSet<Object>();
public ApplicationV2RS(#Context ServletContext servletContext) {
}
#Override
public Set<Object> getSingletons() {
Injector injector = Guice.createInjector(new HelloModule());
HelloResource helloResource = injector.getInstance(HelloResource.class);
UserResource userResource = injector.getInstance(UserResource.class);
singletons.add(helloResource);
singletons.add(userResource);
return singletons;
}
}
HelloResource.java
#Path("hello")
public class HelloResource {
#Inject
private IGreeterService greeter;
public HelloResource() {
}
#GET
#Path("{name}")
public String hello(#PathParam("name") final String name) {
return greeter.greet(name);
}
}
UserResource.java
#Path("user")
public class UserResource {
#Inject
private IUserService userService;
public UserResource() {
}
#GET
#Path("{name}")
public String hello(#PathParam("name") final String name) {
return userService.getUser(name);
}
}
Add #Singleton to your Service Classes.
Hope it helps.
I have also pushed the code to forked repo. check it out

ejb in session context is allways null

i have created sigleton session bean which keeps one connection to my mongo database. It works well in jax-rs class when using #EJB annotation - after controller is contructed and bean is injected it calls init method anotated with #PostConstruct.
Then i created similar class, which is implementing SecurityContext. I used same pattern as in controller, but it is not working properly. init() method is never called and EJB instance is always null.
So is there a way to inject EJB to my SecurityContext implemetation ? it works well unless i try to inject and use MongoConnection
my singleton session bean I use to connect mongo database:
#Singleton
#Startup
public class MongoConnection {
#PostConstruct
public void init() {
// initialize properties
}
I use it in JAX-RS controller. it works here, also in classes inherited from EntityController.
Produces(MediaType.APPLICATION_JSON)
public class EntityController extends Application {
#Context
private UriInfo context;
**#EJB
protected MongoConnection connection;**
public EntityController() {
#PostConstruct
void init() {
...
connection.getMongo();
connection.getDatabaseName();
...
}
}
I implemented my own security context, which is looking for loged user roles in mongo database.
public class MongoSecurityContext implements SecurityContext {
**#EJB
private MongoConnection connection;**
public MongoSecurityContext() {
}
#PostConstruct
void init() {
...
connection.getMongo();
connection.getDatabaseName();
...
}
public MongoSecurityContext(ContainerRequestContext requestContext) {
token = requestContext.getHeaderString("token");
}
#Override
public boolean isUserInRole(String roleName) {
//**connection is allways null**, so it returns false;
if (connection == null)
return false;
}
}
EDIT:
I forget, i also have this warning in glassfish 4 console:
A provider extremeteacher.mongo.connection.MongoConnectionEjb registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider extremeteacher.mongo.connection.MongoConnectionEjb will be ignored
EDIT2:
#Provider
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) {
requestContext.setSecurityContext(new MongoSecurityContext(requestContext)) ;
}
}
Injection does not work for objects created with new because the container is never given control to perform the injection. I recommend moving the #EJB to the filter and passing it to the MongoSecurityContext constructor.

Failed to create EJB in REST service

I have a problem with injecting EJB inside of a REST service (using jersey on glassfish 3.2 server) and I'm puzzled.
I have an EJB interface declared as:
import javax.ejb.Local;
#Local
public interface TestServiceLocal {
public String getText();
}
and the class bean that implements it:
import javax.ejb.Local;
import javax.ejb.Stateless;
/**
* Session Bean implementation class TestService
*/
#Stateless
#Local(TestServiceLocal.class)
public class TestService implements Serializable, TestServiceLocal {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public TestService() {
// TODO Auto-generated constructor stub
}
#Override
public String getText() {
return this.getClass().getName();
}
}
The REST service looks like:
#Path("/service")
#Stateless
public class TestRestService {
#EJB(beanName="TestService")
private TestServiceLocal testService;
public TestRestService () {
}
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/events")
public String getText() {
return testService.getText();
}
}
The problem is that when the REST service is called the bean cannot be created:
SEVERE: EJB5070: Exception creating stateless session bean : [TestRestService]
WARNING: EJB5184:A system exception occurred during an invocation on EJB TestRestService, method: public java.lang.String TestRestService.getText()
WARNING: javax.ejb.EJBException: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
at com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:454)
at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:2547)
at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1899)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
at com.sun.proxy.$Proxy839.getText(Unknown Source)
I had already took a look at the answers posted here but none of them seemed to work for me. Any help will be appreciated. Thank you!
PS: I forgot to mentioned (don't know if it's relevant). My project is created under eclipse Juno as Dynamic Web Project.

EJB 3.1 : Singleton bean not getting injected inside another stateless bean though both beans are getting registered

Here is my bean that is trying to inject a singleton bean InformationService :
#Path("/information/{name}")
#Stateless (name="InformationResource")
public class InformationResource {
#EJB
private InformationService appService;
#GET
#Produces(MediaType.APPLICATION_XML)
public Information getInfo(#PathParam("name") String name){
return appService.getMap().get(name);
}
#PUT
#POST
#Consumes(MediaType.APPLICATION_XML)
public Information putInfo(#PathParam("name") String name, Information info){
return appService.getMap().put(name,info);
}
#DELETE
public void deleteInfo(#PathParam("name") String name){
appService.getMap().remove(name);
}
}
This is the InformationService class
#Singleton
public class InformationService {
private Map<String,Information> map;
#PostConstruct
public void init(){
map = new HashMap<String,Information>();
map.put("daud", new Information("B.Tech","Lucknow"));
map.put("anuragh", new Information("M.Sc","Delhi"));
}
public Map<String,Information> getMap(){
return map;
}
}
Its part of a very simple JAX-RS implementation and I am deploying as war in JBoss 6.1 Final. The problem is that InformationService throwing a NullPointerException when I make the proper get request. If I initialize appService explicitly, everything works fine. Why is #EJB annotation not working ?
Are you using Jersey as REST implementation? If so, EJB injection is not supported out of the box.
This link provides more information on this and also a solution.
Check that your #Singleton is javax.ejb.Singleton.
Any other exceptions before NPE ?