CDI with AbstractApplicationServlet and Injection

Hi all,

We are developing a web application in Vaadin, and we are using CDI as described in the 2. point on this link :
Creating JEE6 Vaadin Applications
- and as mentioned in the Packtub book titled Learning Vaadin.

Everything was ok, but now we discovered that applications started by the annotated servlet are dependent, because of (probably) synchronization block.

Try the following steps:

  1. Create the servlet:
package com.example.client;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;

import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;

@SuppressWarnings("serial")
@WebServlet(urlPatterns = "/*")
public class ClientServlet extends AbstractApplicationServlet {

    @Inject
    private ClientApplication application;

    @Override
    protected Application getNewApplication(HttpServletRequest request) throws ServletException {
	return this.application;
    }

    @Override
    protected Class<? extends Application> getApplicationClass() throws ClassNotFoundException {
	return this.application.getClass();
    }
}
  1. and the application:
package com.example.client;

import javax.enterprise.context.SessionScoped;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.vaadin.Application;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Label;
import com.vaadin.ui.Window;

@SessionScoped
public class ClientApplication extends Application implements ClickListener {

    private static final long serialVersionUID = -6484953958510955734L;

    @Override
    public void init() {
	Window mainWindow = new Window("Client Application");
	Label label = new Label("Hello Vaadin user");
	mainWindow.addComponent(label);
	this.setMainWindow(mainWindow);
	Button butt = new Button("go", this);
	mainWindow.addComponent(butt);
    }

    @Override
    public void buttonClick(ClickEvent event) {
	long i = 0;
	while (i < 1000000l) {
	    i++;
	    System.out.println(i);
	}
    }


}
  1. Run the application, and open an Internet Explorer and a Firefox or another browser window, load the application page into both of them.

  2. Click on one’s Go button - it starts working, produces output on the console - then try to reload the another page. It won’t be successful until the first cycle is finished…

This is a big problem, because all application instances on a server will be dependent… if a user runs a long-running statistics, then another user’s can’t load the application in their browser…

Am I wrong?

Thank You and Best Regards, Janos

Hi Janos

Your current setup will result in each session sharing the same Application instance and this is what’s causing the problems. Since each http-request is handled by the same Servlet instance, you can’t have a session-specific Application instance as a field in the servlet and return it in getNewApplication(…). So, instead of

@Inject
private ClientApplication application;

use

@Inject
private Instance application;

and obtain a session scoped instance of your application with application.get()
(
http://dev.vaadin.com/browser/svn/incubator/cdiutils/src/org/vaadin/virkki/cdiutils/application/AbstractCdiApplicationServlet.java
)

Also, remember to invalidate your session after Application.close() or you’ll end up with the same Application instance within a session even if you close the application (with ?restartApplication for example). Application life-cycle != session life-cycle by default.
(
http://dev.vaadin.com/browser/svn/incubator/cdiutils/src/org/vaadin/virkki/cdiutils/application/AbstractCdiApplication.java
)

This is all handled in
CDI Utils add-on
for you

Tomi

Hi Tomi,

I have modified my test code to use the mentioned plugin, but the result is same. :frowning:

Here are the sources:

package com.example.client;

import javax.servlet.annotation.WebServlet;

import org.vaadin.virkki.cdiutils.application.AbstractCdiApplicationServlet;

@WebServlet(urlPatterns = "/*")
public class ClientServlet extends AbstractCdiApplicationServlet {
}

package com.example.client;

import javax.enterprise.context.SessionScoped;

import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Label;
import com.vaadin.ui.Window;

import org.vaadin.virkki.cdiutils.application.AbstractCdiApplication;

@SessionScoped
public class ClientApplication extends AbstractCdiApplication implements ClickListener {

    private static final long serialVersionUID = -6484953958510955734L;


    @Override
    public void init() {

	Window mainWindow = new Window("Client Application");
	Label label = new Label("Hello Vaadin user");
	mainWindow.addComponent(label);
	this.setMainWindow(mainWindow);

	Button butt = new Button("go", this);
	mainWindow.addComponent(butt);

    }

    @Override
    public void buttonClick(ClickEvent event) {
	long i = 0;
	while (i < 1000000l) {
	    i++;
	    System.out.println(i);
	}
    }

}

Vaadin version is 6.7.2 .

Janos

We experienced the same problem when we used Instance at Application injection in the servlet.
I debugged the Vaadin code, and the blocking line was a synchronized(application) block, but the application instance itself different from the “running” application. So I don’t understand this. :frowning: I will debug it deeper, but please try this situation with your plugin too. I think the problem is not in the plugin, but in the conception instead. :frowning:

You’re right. Strange behavior indeed :frowning:

I hoped that I was wrong. :frowning:

The CDI feature was mentioned in the Packtub Vaadin book too, but this is completely wrong. Now we can’t use CDI in a Vaadin web application, if there are long-time method calls such as statistics query, and on heavily-used servers the user will block each other.

Can we somehow publish this anomaly to the Vaadin development team?

Ticket created: http://dev.vaadin.com/ticket/8071

Appears that the Application instances do differ, but what’s actually being locked by the synchronized block in AbstractCommunicationManager is the proxy instance which seems to be same in both sessions.

I tried an alternative solution (which works well by the way) and created a session scoped wrapper class for the Application. In this case AbstractCdiApplication itself is not a bean at all - surely it could be a dependent bean as well (not requiring a proxy).

@SessionScoped
public abstract class AbstractCdiApplicationWrapper {
	private final AbstractCdiApplication application;

	@SuppressWarnings("serial")
	public AbstractCdiApplicationWrapper() {
		super();
		application = new AbstractCdiApplication() {
			@Override
			public void init() {
				AbstractCdiApplicationWrapper.this.init();
			}
		};
	}

	public Application getApplication() {
		return application;
	}

	public abstract void init();
}
@SuppressWarnings("serial")
public abstract class AbstractCdiApplicationServlet extends AbstractApplicationServlet {

	@Inject
	protected Instance<AbstractCdiApplicationWrapper> applicationWrapper;

	@Inject
	protected BeanManager beanManager;

	@Override
	protected Application getNewApplication(HttpServletRequest request) throws ServletException {
		return applicationWrapper.get().getApplication();
	}

	@Override
	protected Class<? extends Application> getApplicationClass() throws ClassNotFoundException {
		return AbstractCdiApplication.class;
	}
}

I will process this idea further and include the necessary updates in the next version of CDI Utils add-on. Good thing you pointed this out.

Wow! I’ll try this solution in my project. What do you think, when can you upload the new plugin version?

A question - if you create Application with constructor, and not with injection, then how you can use CDI in the application class? Do we have to inject everything into the wrapper instead of the Application?

I’m not an expert in the CDI, but in my opinion you won’t. If the object is instantiated with new operator then the container has nothing to do with it. But of course I may be wrong.

Regards.

As I mentioned, surely the Application could be injected to the wrapper as well. The Application scope must in that case be @Dependent (default) instead of @SessionScoped. I’ll probably end up with that approach in the (CDI Utils) update.

Even though injecting beans directly to the wrapper instead of the application is possible (In the wrapper init() you could for example set the main window by: getApplication().setMainWindow(window):wink: it might not be the best option. The wrapper should only be needed for obtaining the application instance related to current session somewhere trough injection.

That said, the simplest solution to the original problem would be just to annotate your application class with @Dependent (overriding @SessionScoped of AbstractCdiApplication). Just remember that (without the wrapper) you’ll not be able to inject the correct application instance anywhere else.

I’ve found interesting thread on seamframework.org.
Worth to read: http://seamframework.org/Community/DependentBeansDoubts

Ok, I’ve made some investigation. The problem is that AbstractCommunicationManager.doHandleUidlRequest is partially synchronized.
If the application has scope other then Dependent then in fact there is no real application object but the proxy to this object. Unfortunately every bean instance has one proxy. This causes the problem.

Temporary solution to this is made the Application @Dependat scope. In this case there is always the real object not the proxy but CDI still works.

Other solution has to be made by the Vaadin team. I think that synchronization should occur on the object in the application instance not the instance itself.

In fact wrapper proposed by Tomi is useless. Using wrapper you loose CDI. The same goal can be achieved, as I said, by changing the scope of the bean.

Regards,
A.

Yes, that’s what I proposed in my previous message. I also wrote “The wrapper should only be needed for obtaining the application instance related to current session somewhere trough injection.”, meaning that if you change the scope of your application to @Dependent, you cannot inject it anywhere else (but the servlet) unless you wrap it to a session scoped bean (the wrapper).

The wrapper implementation example in the previous post isn’t final. If you want to inject beans in your application class, naturally you cannot instantiate it trough constructor - it needs to be injected directly to the wrapper.

You can inject the @Dependant bean to any other bean witch is container managed. But the drawback of @Dependant bean is that it is not shared between other beans. It’s lifecycle is bound to the bean where it has been injected.

Looking in this particular case, you are right. If you inject the Application to other bean, you’ll get the new object. So dependent Application bean injection makes only sense to inject into servlet.

BTW, what kind of CDI container are you using. WELD from jboss doesn’t want inject your wrapper.

Exactly this is on jboss:

org.jboss.weld.exceptions.DefinitionException: WELD-000072 Managed bean declaring a passivating scope must be passivation capable. Bean: Managed Bean [class com.example.client.ClientApplicationWrapper]
with qualifiers [@Any @Default]

The wrapper have to implement Serializable interface.


...

@SessionScoped
public class ClientApplicationWrapper implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 2372604117485941510L;
    @Inject
    Instance<ClientApplication> application;
...

The built-in session and conversation scopes are passivating scopes, with them you have to implement Serializable.

I think, this is working, now I’m trying this in my big project.

I’ve never found the need to inject anything into the application class. Inject it into the servlet and pass it to the constructor of the Application class. Servlet instances are managed by the container, and there’s no need to impose any kind of lifecycle on the application class besides what Vaadin already does.

Here’s a somewhat old example, but I still use the same pattern:

http://blogs.oracle.com/bobby/entry/a_simple_ui_for_exploring

Or you can just see the
application with the servlet inner class here
. Note that the servlet doesn’t have to be an inner class of course. It can be its own class, inject whatever you want, and pass those objects into the constructor of the Application class. This all works because an injected EJB, for instance, isn’t really an instance of an EJB. It’s an EJB wrapper, and it’s ok for this wrapper to be serialized, passed around, etc. When it’s used during a call, the container does the right thing and grabs one from the pool, calls its business method, and returns it to the pool. Very simple to use in the Vaadin framework this way.

If you have other components in your app that need a reference to the injected object, just add a getter on your application class and the other components can reach it with their getApplication method.

Cheers,
Bobby

How CDI ( @EJB ) work in servlet with guice configuration?


public class TBServlet extends AbstractApplicationServlet {

    @EJB
    private SprManageRemote spr_manage;
    
    protected final Provider<TBApplication> applicationProvider;
        
    @Inject
    public TBServlet(Provider<TBApplication> applicationProvider) {
        this.applicationProvider = applicationProvider;
                
    }
    
    @Override
    protected Class getApplicationClass() throws ClassNotFoundException {
        return TBApplication.class;
    }

    @Override
    protected Application getNewApplication(HttpServletRequest request) throws ServletException {
        
        TBApplication app = applicationProvider.get();
        app.setSprManage(spr_manage);

        return app;
    }   

This code not work - ejb allways null.