CDI Utils add-on


NOTICE!
This post relates to an early version of Cdi Utils and many things have changed since then. For example CDI Utils no longer uses @SessionScoped but defines a custom scope for Vaadin Applications.

I’ve released a new add-on to Vaadin directory called
CDI Utils
. CDI (Contexts and Dependency Injection) is a JavaEE standard that consists of two fundamental parts: It allows you to bind bean instances to contexts with well-defined life-cycles and inject instances to beans in a type-safe way.

Using CDI in your Vaadin application increases its maintainability by making it more flexible/loosely coupled and can obsolete boilerplate code such as inter-component listeners (CDI has a built-in event bus) and Thread-local pattern (Application reference can be obtained anywhere by injecting). Vaadin fully supports CDI from version 6.7 up.

CDI Utils add-on provides some utilities for CDI/Vaadin applications:

[b]

  1. AbstractCdiApplication/AbstractCdiApplicationServlet (configured and ready for use)
    [/b]
    The AbstractCdiApplication is basically a session scoped Vaadin Application that also invalidates the session after application.close()


2. Lightweight MVP framework

2.1.Extend View interface for your view
2.2.Create view instance that extends AbstractView and implements your View extension
2.3.Extend AbstractPresenter and annotate it with @ViewInterface(YourViewInterface.class)
That’s it.
-The correct view instance is then automatically injected to your presenter (Your view control logic can then reside in the presenter)
-The view should use CDI’s built-in event bus to fire events that are observed by the presenter. The add-on provides a utility for this: fireViewEvent(ParameterDTO). The ParameterDTO can be used to transfer any data to the presenter (CDI Event observers only accept one parameter)
-Call yourViewImplementationInstance.openView() each time the view is accessed (this will eventually invoke yourPresenterInstance.viewOpened())


3.Producers for declaratively defined Vaadin components (@Preconfigured -annotation)

Inject preconfigured Vaadin Components to your views. For example:

@Preconfigured(captionKey=“btnUpdate”, implementation=NativeButton.class)
private Button button;

Notice that if you’re planning on implementing the TextBundle interface (if you intend to use the “captionKey” attribute of @Preconfigured or AbstractView.getText() that is) and using Weld version prior to 1.1.1 it will not work. Library-to-application visibility has been fixed in Weld 1.1.1,

Also, due to limitations of default CDI scope types, only one Vaadin Application is allowed/session. This is a known issue and fixing it would require implementing a custom CDI scope for Vaadin applications. I’ll look into this later but currently all components and application can be bound to session scope as the session will be invalidated by AbstractCdiApplication after it’s been closed.

Quick start:

  1. Add empty beans.xml -file (CDI marker file) to your project under WEB-INF dir
  2. Add cdiutils*.jar to your project under WEB-INF/lib
  3. Create your Application class by extending AbstractCdiApplication
  4. Extend AbstractCdiApplicationServlet and annotate it with @WebServlet(urlPatterns = “/*”)
  5. Deploy to JavaEE/Web profile -compatible container (CDI apps can also be run on servlet containers etc. but some further configuration is required)

Hello

Can i use this add-on with inheritance ??

i wrote some application :


public class ShopWebApplication extends ShopMasterApplication
{
	 @WebServlet(urlPatterns = "/*")
	public static class CUDemoApplicationServlet extends AbstractCdiApplicationServlet {

		private static final long serialVersionUID = 1L;
     }
	

	private static final long serialVersionUID = 1L;

	@Override
	public void init() 
	{
		super.init();
		Window window = new Window("MainWindow");
		Label label = new Label("Main window");
		window.addComponent(label);
		setMainWindow(window);
	}

}

And :


public class ShopMasterApplication extends AbstractCdiApplication
{
	
	
	private static final long serialVersionUID = 1L;

	@Override
	public void init() {
		
		
	}
//doing other work.. 
}

And i have got exception :


22:26:10,304 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web]
.[default-host]
.
[/vshop].[vshop.vshop.vaadin.ShopWebApplication$CUDemoApplicationServlet]
] (http-localhost.localdomain-127.0.0.1-8080-1) Servlet.service() for servlet vshop.vshop.vaadin.ShopWebApplication$CUDemoApplicationServlet threw exception: org.jboss.weld.exceptions.AmbiguousResolutionException: WELD-001318 Cannot resolve an ambiguous dependency between [Managed Bean [class vshop.vshop.vaadin.ShopMasterApplication]
 with qualifiers [@Any @Default]
, Managed Bean [class vshop.vshop.vaadin.ShopWebApplication]
 with qualifiers [@Any @Default]
]
	at org.jboss.weld.manager.BeanManagerImpl.resolve(BeanManagerImpl.java:1201) [weld-core-1.1.2.Final.jar:2011-07-26 15:02]

	at org.jboss.weld.manager.BeanManagerImpl.getBean(BeanManagerImpl.java:809) [weld-core-1.1.2.Final.jar:2011-07-26 15:02]

	at org.jboss.weld.bean.builtin.InstanceImpl.get(InstanceImpl.java:108) [weld-core-1.1.2.Final.jar:2011-07-26 15:02]

	at org.vaadin.virkki.cdiutils.application.AbstractCdiApplicationServlet.getNewApplication(AbstractCdiApplicationServlet.java:34) [cdi-utils-0.8.5.jar:]

	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.createApplication(AbstractApplicationServlet.java:978) [vaadin-6.7.0.beta1.jar:]

	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.findApplicationInstance(AbstractApplicationServlet.java:801) [vaadin-6.7.0.beta1.jar:]

	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:456) [vaadin-6.7.0.beta1.jar:]

	at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67) [weld-core-1.1.2.Final.jar:2011-07-26 15:02]

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:139) [jboss-as-web-7.0.1.Final.jar:7.0.1.Final]

	at org.jboss.as.web.NamingValve.invoke(NamingValve.java:57) [jboss-as-web-7.0.1.Final.jar:7.0.1.Final]

	at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:49) [jboss-as-jpa-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:154) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:667) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:952) [jbossweb-7.0.1.Final.jar:7.0.1.Final]

	at java.lang.Thread.run(Thread.java:636) [:1.6.0_20]


Its posible use inheritance with CDI ??? thx for answer

In this case ShopWebApplication and ShopMasterApplication are both implementations of AbstractCdiApplication. When the container tries to obtain an implementation of AbstractCdiApplication for injecting into AbstractCdiApplicationServlet, it finds two different implementations with same qualifiers and this results in ambiguous dependency.

Try disabling ShopMasterApplication by annotating it with @Alternative:

@Alternative
public class ShopMasterApplication extends AbstractCdiApplication{

Played with CDI and CDIUtils today and got an interesting issue - when Window is covered by CDI, no modification UIDL are send anymore to the client.

Let me show the example: In the use case below, onClick event in a window modifies text in a button. But the modification is never shown in UI until you refresh the browser.
But once you remove @Inject MainWindow from the TestApp application class and instantiate MainWindow manually - it works fine and updated button title displays in browser immediately.

Any ideas on what is preventing Vaadin from normal functionality in such case ?

I tried both with my own app and also by using base classes from CDIUtuls add-on but with the same result. The only way was to fallback to old good ThreadLocal pattern (the main idea of injecting MainWindow is to be able to inject a TestApp instance in it later and use it for UI logic purposes).

The servlet:
(The same when using abstract servlet from CDI)

@WebServlet(name="TestServlet", urlPatterns={"/*"}, initParams={@WebInitParam(name="widgetset", value="ru.shifu")})
public class TestAppServlet extends AbstractApplicationServlet //AbstractCdiApplicationServlet
{
    @Inject
    TestApp application;

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

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

The App:

@SessionScoped
public class TestApp extends Application
{

    @EJB
    private HelloShifu greeter;

    @Inject
    private MainWindow w;

    public void init()
    {
        addWindow(w);
        setMainWindow(w);
        w.addComponent(new Label(greeter.hello("dll")));
    }

 }

And the window:

@SessionScoped
public class MainWindow extends Window
{
    @Inject
    private TestApp app;

    public MainWindow()
    {
        super("shifu.ru");
        final Button b = new Button("test me");
        b.setImmediate(true);
        b.addListener(new Button.ClickListener()
        {
            public void buttonClick(final Button.ClickEvent clickEvent)
            {
                b.setCaption("" + System.currentTimeMillis());
            }
        });
        addComponent(b);
        setImmediate(true);
    }

}

This issue has been reported earlier (
http://dev.vaadin.com/ticket/7774
).
Vaadin Window appears to be a bit problematic when used with CDI. I ran into a similar issue with it as well: Tried to close a
session scoped
subwindow by pressing the cross in the upper right corner. close()->parent.removeWindow(this) was called but “this” was never removed from the parent Window’s subwindows. I wonder if it has something to do with proxies because these problems don’t seem to occur when using dependent(default)-scoped Windows (which don’t create a proxy instance). Some research is needed apparently.

PS: I noticed you inject your app to the Servlet with::
@Inject
TestApp application;
Mind that this will give you the same Application instance for every session/user. Use Instance instead.

Thanks, Tomi,
so it seems old good ThreadLocal is not retired :slight_smile:

Hm, I did use this construction for a couple of projects already and did not notice “same instance” effect. Thanks for noting, I’ll recheck this again.

Dmitri

Hi Tomi

Can you please supply some basic samples.
The addon page has some basic ones : https://vaadin.com/directory#addon/cdi-utils

Can you add some projects you play with.

Thanks! Very nice addon.

regard
Richard

Hi Richard
I’ve actually been meaning to add an example project for CDI Utils for a while now and already did some work on implementing a CDI version of the Address Book example (long version). I’ll try to get it finished soon. Subscribe to this thread to get informed when ready.

Hi,
Really great add-on !
Just wondering if it’s not possible to make the view “accessible” in the renderer ? My goal is to improve the testeability of the renderer (my idea was to Mock the view in unit tests)
If you’ve any idea, I could be really interested.
Thanks
Steve

Hi Steve
According to CDI specification, you can inject Views and beans of any type only to JavaEE-components such as servlets and other beans. This means that if you need to access them somewhere else, you’ll have to use JNDI lookup first to get the BeanManager instance (java:comp/BeanManager) and then use its APIs to get access to the contextual beans.
However the best way to test CDI software is to use Arquillian (http://www.jboss.org/arquillian) which for example allows you to inject beans directly to your test classes.

Tomi

An example project demonstrating the parallel use of Vaadin, CDI and CDI Utils add-on has been added to
https://github.com/tomivirkki/cdiutils-addressbook

Hi Tomi,

please note, that there’s no need for the private closed attribute, since this is not DRY.
I’d suggest referring to the isRunning() method .

Cheers,
Sebastian

Addon is nice and is doing its job. But there is a one drawback in it. All the Presenters and the Views are SessionScoped. It doesn’t matter if you have the only few of them, but in the real application it is a real pain in the … Let’s imagine that we have them a hundreds. All of them are instantiated and initialized on application start up. So for each user logged in the application you have a big memory consumption as all the views and presenters have to be available. For example, let say we have a login view and the main view. After login to the application the login view is useless, but as it is session scoped is leaves at the memory until the session (http) ends. It is the only sample. Other case is that the user not allways use all the views. E.g. in the e-banking user logins, do the transfer and logouts. But in this case we have all other views instantiated, which the user even do not see. In the internet application is the big drawback in my opinion.

Personally I facing the problem described above. I think that something like ConversationScoped context should be implemented. In fact the mentioned scope works only for the JSF, so it can’t be simply used. :slight_smile:

Nevertheless good work and keep going.

Hi Andy
Even though the presenters are session-scoped, they’re not necessarily initialized when session starts. As with all Vaadin applications the whole view tree should not be initialized on first request but lazily only when needed. When CDI Utils AbstractView viewOpened() is called (by the application logic) it fires an Event that will cause a presenter for the view to be initialized. Presenters don’t exist until the method is called. Use Instance<> to utilize lazy loading. Example:
https://github.com/tomivirkki/cdiutils-addressbook

According to CDI specification, once created you can’t remove a bean instance from an active scope. They’re automatically removed when the scope (in the case od CDI Utils presenters, session) dies. So as you said, this is a drawback in using session scoped presenters.

New version of CDI Utils (0.9.0) has been released. The updated revision introduces some improvements in session lifecycle management and the issue discussed in
this
thread is handled in the new version as well.

The CDI utils seems interesting, but, can it be used in a Vaadin Portlet? I would really like for that to be the case, but it’s unclear to me whether it’s possible.

eg: I’m using GlassFish 3.1.2 to host Liferay and creating Vaadin portlets.

I’m using the full EE GlassFish, not the Web Profile.

regards,
peter

Hi,
According to Instance use. It has more cons then pros. Instance in fact is useless in case of lazy loading, because every object taken from instance stays forever in the container, as the container handles the reference to it. This is known drawback in the CDI 1.0 specification. Solution to this will came with 1.1 spec.

According to scopes. I’ve found interesting seam framework extension which will probably be the standard in the 1.1 CDI. Currently it names Seam3 Conversation SPI written by Aleš Justin. see http://relation.to/18358.lace

I investigate it know, but I have some problems with specifying the start and end points of the conversation. When I’ll win the fight I sent feedback to the forum :slight_smile:

Regards,
A.

Hi Peter
Unfortunately CDI Utils doesn’t currently work with portlets.

Ok, as I promissed to share knowledge about conversion scope in Vaadin I do so.

First of all, the problem with conversion scope is with a conversation propagation. Conversation has to stay alive during requests. It can be achieved by using “cid” request parameter, but unfortunately in Vaadin there is no way to do this (or maybe is, but I do not know how :))

So to propagate the conversation I use the session attribute. To made it work I wrote a simple conversation wrapper, like follow:


public class CConversation implements Serializable {
    @Inject
    private Conversation conversation;

    @Inject
    private BeanProvider provider;

    public boolean isTransient() {
        return conversation.isTransient();
    }

    public String getId() {
        return conversation.getId();
    }

    public void begin() {
        if (conversation.isTransient()) {
            conversation.begin();
            HttpSession session = provider.get(HttpSession.class);
            session.setAttribute("cid", conversation.getId());
        }
    }

    public void end() {
        if (!conversation.isTransient()) {
            HttpSession session = provider.get(HttpSession.class);
            session.removeAttribute("cid");
            conversation.end();
        }
    }

    public void setTimeout(long timeout) {
        if (!conversation.isTransient()) {
            conversation.setTimeout(timeout);
        }
    }
}

BeanProvider is my class which technically does the same work as the Instance<…> do, but doesn’t store the references to the beans taken from the container.

Binding the conversation with the user application instance take place in the AbstractCdiApplication



    @Inject
    private SeamConversationContext<HttpServletRequest> conversationContext;

    @Override
    public void onRequestStart(final HttpServletRequest request, final HttpServletResponse response) {
        String cid = (String) request.getSession().getAttribute("cid");
        conversationContext.associate((HttpServletRequest) request).activate(cid);

        loginEvent.fire(new RenewSessionLengthEvent());
    }
...

    @Override
    public void onRequestEnd(final HttpServletRequest request, final HttpServletResponse response) {
        if (closed) {
            conversationContext.deactivate().dissociate((HttpServletRequest) request);
            logger.debug("End http session: " + request.getSession().getId());
            request.getSession().invalidate();
        }
    }

All Views and Presenters which have to be conversation scoped are annotated with @ConversationScoped.
Conversation begins at the first initView method of the ViewImpl classes chain. Ends at the detach method of the view, or eventually at MainPresenter which calls conversion.end() on each view change.

To work this following maven dependencies from jboss repository are required (if using WELD CDI implementation):


        <dependency>
            <groupId>org.jboss.seam.conversation</groupId>
            <artifactId>seam-conversation-spi</artifactId>
            <version>3.2.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.seam.conversation</groupId>
            <artifactId>seam-conversation-weld</artifactId>
            <version>3.2.0-SNAPSHOT</version>
        </dependency>

There are other implementations too, but I don’t tested them. Weld works like a charm.

I use the maven build intensively so I do not know how to do this other way :slight_smile: Sorry, do not ask :slight_smile:

Thats all. Happy coding :slight_smile:

Andy

Thx Andy for the tip !

The only thing that I don’t understand it’s the BeanProvider, can you provide us the code of this class please ?

Thanks !