CDI Utils add-on

Sure. It’s simple.


@ApplicationScoped
public class BeanProvider implements Serializable {

    @Inject
    protected BeanManager beanManager;

    /**
     * This is a utility class replacing the need to use CDI Instance implementation.
     * Instance implementation of the get method keeps the reference in the container
     * and is not so happy with releasing them. This one creates the dependent beans
     * without container reference so created beans are garbage collected after the
     * reference is released.
     *
     * @param beanClass
     * @param <T>       the class of the bean to be instantiated
     * @return instance of the bean
     */
    public <T> T get(final Class<T> beanClass) {
        return get(beanClass, new AnnotationLiteral<Any>() { }, new AnnotationLiteral<Default>() { });
    }

    public <T> T get(final Class<T> beanClass, final Annotation... annotation) {
        Set<Bean<?>> beans = beanManager.getBeans(beanClass, annotation);

        Bean<T> bean = (Bean<T>) beans.iterator().next();
        CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean);
        T beanInstance = (T) beanManager.getReference(bean, beanClass, creationalContext);

        return beanInstance;
    }

Thank you Andy !

For the BeanManager class, I suppose you took it from seam dependencies right ?

t[quote=Jihad Guedouar]
Thank you Andy !

For the BeanManager class, I suppose you took it from seam dependencies right ?
[/quote]

BeanManager is your connection to the container. Standard in all Cdi containers.

Tomi, thank you for a great plugin.

I was wondering, does it work for Vaadin 7 alpha? I would guess not, because of the redesign of the application/root/view classes, right?

Secondly, would you recommend a new developer start with Vaadin 7, or with 6.x and the CDI utils? (Subjective, I know, but I would welcome any advice.)

Third, do you still need CDI Utils if you follow the setup rules Bobby Bisset laid out in his
blog entry a while ago
? (Here is the
full source code
).

Many thanks for the advice!

Hi Christopher

CDI Utils has been designed to be used with Vaadin 6 only. Haven’t tested it with Vaadin 7 but I’m pretty sure it’s a no go.

I don’t know about the current maturity of V7 but of course you can use the alpha releases already to familiarize yourself with the new api. If you’re building an application that needs to be stable now, choose Vaadin 6.x. Also keep in mind that CDI Utils is still experimental.

Bobby’s example doesn’t concern CDI or CDI Utils. He’s injecting an EJB directly to the servlet which is fine.

Hi Tomi,
I’ve spent some time with JProfiler on Vaadin and CDI Util add-on.

There is a memory leak. When the HttpSession ends then Application isn’t cleaned up from memory if you do not use some custom made additions like session guard or something.
Adding @PostConstruct on close in the AbstractCdiApplication fixes the bug, but this approach has one side effect. If you use reinitializeSession then in fact session will be closed. It can be worked around by adding additional property, which can be set before session reinitialization and in this case do not close the application.

Then it works as expected.

Regards,
A.

Hi Andy
I found the cause and a simple solution to the leak problem. The dependent application should be injected directly to the wrapper, not to the servlet as currently. This combined with proper exception handling in the application close() method fixes the problem. Thanks for pointing it out. I’ll update the add-on next week.

Tomi

Hi,
have you checked your solution with some kind of profiler?
I have wrote similar wrapper as your, but never instantiated the application in the servlet.

To be sure I’ve downloaded the latest version of the cdi utils and moved and done what you have said and it didn’t helped a much. Still application isn’t cleared from the memory.
But maybe I missed something.

I’ve spent a little bit more time with the profiler.

Your solution won’t work because the reference to the application object is kept by the AbstractWebApplicationContext also. Take a look at the applications hash map.
Even though the ApplicationWrapper will be destroyed by the CDI container the reference to the application stays in the application context hash map.
You have to inform application context that application has to be destroyed.

Prevously provided solution doesn’t work in all cases.
To workaround this I have added following method:


    @PreDestroy
    public void unboundUnusedSession() {
        if (!sessionReinitialised) {
            ((WebApplicationContext) getContext()).valueUnbound(null);
        }
        sessionReinitialised = false;
    }

Seams to work, but one application instance stays forever. Still don’t know why.
Regards.

Hi Tomi,

Thanks for the reply – I missed it because this forum doesn’t seem to automatically subscribe me. Grr. :slight_smile:

I guess I need to figure out exactly what CDI is, and why it might be useful…

Tomi,

I’m having trouble with an ambiguous injection. I’ve moved your addressbook example app to a maven style directory structure, adn I’m using maven to resolve dependencies. Do you think that might be causing this error?

WELD-001409 Ambiguous dependencies for type [Logger]
 with 
qualifiers [@Default]
 at injection point [[field]
 @Inject protected transient
 org.vaadin.virkki.cdiutils.mvp.ViewComponent.logger]. Possible 
dependencies [[Producer Method [Logger]
 with qualifiers [@Any 
@Default] declared as [[method]
 @Produces 
public org.vaadin.virkki.cdiutils.componentproducers.ComponentProducers.createLogger(InjectionPoint)], 
Producer Method [Logger]
 with qualifiers [@Any @Default]
 declared 
as [[method]
 @Produces public 
org.vaadin.virkki.cdiutils.componentproducers.ComponentProducers.createLogger(InjectionPoint)]]]

Your project builds fine without moving it to Maven.

Thanks!
Chris.

Well, as it turns out, it was my fault. Somehow there were two copies of cdi-utils being placed into my WEB-INF/lib directory – one with a hyphen, one without. I have no idea how or why, but removing one and recompiling fixed it. That’s why the injection was so strange. Both those signatures are identical. :slight_smile:

Hi Andy
Vaadin WebApplicationContext is bound to the user session. So as CDI Utils takes care that Vaadin application lifecycle equals http session lifecycle, it wouldn’t matter if application instances were left remaining in the applications map on session close (which they are not, at least not with the newest version).

The memory leak discussed was fixed in the newest version but as you said strangely a couple of Application instances are never gc’d. Appears that they are somehow bound to “ServiceContainerImpl$ServiceThread” by Weld. Even though the number remains stable, it’s certainly a problem and requires some in-depth studying. I’m using VisualVM for analyzing the heap btw.

Hi Christopher
Glad you figured it out. Also notice that I added @PreConfigured as an additional qualifier to the Logger producer method in the newest CDI Utils release. This is mainly to avoid collisions with other Logger producers that might be defined in the application or in other libraries.

Thank you for the clarification Tomi.

Another question: could you please explain what you meant by:

Because, if I understand correctly, a close event is called when the browser window closes. Will this close the user’s application? Or in other words, when does a user’s Application object get destroyed? This is important for me as I would like to have a single Application for each unique user for a very long time (hours even). I realize hitting the webapp from a different browser will create a new Application–that’s no problem.

And to understand better (can you tell I’m learning CDI as I go here?), any @Dependent (or @RequestScoped, @ConversationScoped) object will essentially be an @SessionScoped object, since it is injected into an object which, ultimately, has been injected into the Vaadin Application, which is @SessionScoped. Is this correct? That means all objects which are injected without using Instance<> will be essentially singletons in the context of that particular user’s @SessionScoped context? (Or in other words, the life of their Vaadin application object.)

I absolutely love your add-on, it’s great to learn CDI. And I appreciate your prompt help on this thread. :slight_smile:

Sorry for being a bother, but I have another question. I’m trying to figure out why you are using @Inject Instance and then calling get() every time you want a session-scoped object. Why not just @Inject T and use the object like that?

I’ve searched and searched, and it looks like some people view Instance as a CDI anti-pattern, UNLESS you’re specifically trying to get a new instance of the object at every get(). Since you’re calling session-scoped beans, you’re getting the same bean for that user’s session… so why use Instance and get()?

Thanks again Tomi!

I finally got around to implementing the missing piece. CDI Utils now provides a custom CDI scope for Vaadin applications and has reached beta. The new VaadinContext stores and provides contextual references to instances of beans decorated with @VaadinScoped annotation. It has two modes: @VaadinScoped(VaadinScope.WINDOW) (default) instances are specific to Vaadin application-level windows in multi-windowed applications. Each window and its submodules share the same instance of the bean. The other mode @VaadinScoped(VaadinScope.APPLICATION) declares beans whose instances are shared by all Windows inside a single Vaadin application. All Applications still have unique contexts. In single-windowed Vaadin applications the two modes don’t differ.

The new approach comes with some nice subsidiary benefits compared to previous versions. Application lifecycle no longer has to match http session lifecycle so I was able to drop the whole session invalidation logics in application class. Because of this even parallel applications in the same session are now supported. CDI Utils also provides an api for dereferencing bean instances or a whole VaadinScope.WINDOW context to free memory runtime. I also dropped the view interface member from CDI Utils MVP event mechanism qualifier so the new programming model is very simple. Check out the updated example project at
https://github.com/tomivirkki/cdiutils-addressbook
.

The current version is 0.9.9 beta and I’m planning on dropping the beta tag in the near future after some more testing and finishing touches. Any feedback during (and after) beta period is welcome. Many thanks to Andy O for assistance and fruitful dialogue during development.

Tomi

I get a weird error when I try to merge your framework with DontPush Ozone

I did not get this issue with the previous betas…

Exception logged when Application start…

SEVERE: org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped
	at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:664)
	at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:77)
	at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:87)
	at org.vaadin.virkki.cdiutils.application.org$jboss$weld$bean-WEB-INF$lib$cdi-utils-0$9$9-ManagedBean-class_org$vaadin$virkki$cdiutils$application$RequestData_$$_WeldClientProxy.setApplication(org$jboss$weld$bean-WEB-INF$lib$cdi-utils-0$9$9-ManagedBean-class_org$vaadin$virkki$cdiutils$application$RequestData_$$_WeldClientProxy.java)
	at org.vaadin.virkki.cdiutils.application.AbstractCdiApplication.onRequestStart(AbstractCdiApplication.java:47)
	at org.vaadin.dontpush.server.DontPushOzoneWebApplicationContext.trxStart(DontPushOzoneWebApplicationContext.java:121)
	at org.vaadin.dontpush.server.SocketCommunicationManager.paintChanges(SocketCommunicationManager.java:143)
	at org.vaadin.dontpush.server.SocketCommunicationManager$1.run(SocketCommunicationManager.java:129)

edit:
As a note , it seems the application is working fine.

Well, it seems I found one problem though…

I cannot reference my components from an @Asynchronous method.

The component is a plain component ( not injected into its parent ) , it does not have any injected components in it either… ( However I dont think it is the Component that is the actual problem ).

The asynchronous actually do execute , but it cannot update components because the Application instance has a problem to resolve RequestScoped…

SEVERE: org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped
	at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:664)
	at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:77)
	at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:87)
	at org.vaadin.virkki.cdiutils.application.org$jboss$weld$bean-WEB-INF$lib$cdi-utils-0$9$9-ManagedBean-class_org$vaadin$virkki$cdiutils$application$RequestData_$$_WeldClientProxy.setApplication(org$jboss$weld$bean-WEB-INF$lib$cdi-utils-0$9$9-ManagedBean-class_org$vaadin$virkki$cdiutils$application$RequestData_$$_WeldClientProxy.java)
	at org.vaadin.virkki.cdiutils.application.AbstractCdiApplication.onRequestStart(AbstractCdiApplication.java:47)
	at org.vaadin.dontpush.server.DontPushOzoneWebApplicationContext.trxStart(DontPushOzoneWebApplicationContext.java:121)
	at org.vaadin.dontpush.server.SocketCommunicationManager.paintChanges(SocketCommunicationManager.java:143)
	at org.vaadin.dontpush.server.SocketCommunicationManager$1.run(SocketCommunicationManager.java:129)

Any Idee on how to work around this issue ?

Another issue is dereferenceBeanInstance(final Bean bean) in VaadinContext , you use AbstractView and AbstractPresenter , would it not be beter to use the interface classes instead, this will allow for custom implementation of View and Persenter , but currently dereferenceBeanInstance wont properly handle custom implementations of these interfaces unless they extend your AbstractView and AbstractPresenter.

ie:


           if (AbstractView.class.isAssignableFrom(bean.getBeanClass())) {
                // An AbstractView was dereferenced. The presenter should be
                // dereferenced as well
                Bean<?> removablePresenterBean = null;
                for (final Bean<?> presenterBean : instances.keySet()) {
                    if (AbstractPresenter.class.isAssignableFrom(presenterBean
                            .getBeanClass())) {
                        final ViewInterface viewInterface = presenterBean
                                .getBeanClass().getAnnotation(
                                        ViewInterface.class);
                        if (viewInterface.value().isAssignableFrom(
                                bean.getBeanClass())) {
                            removablePresenterBean = presenterBean;
                            break;
                        }
                    }
                }
                if (removablePresenterBean != null) {
                    dereferenceBeanInstance(removablePresenterBean);
                }
            }

Should this not read


           if (View.class.isAssignableFrom(bean.getBeanClass())) {
                // An AbstractView was dereferenced. The presenter should be
                // dereferenced as well
                Bean<?> removablePresenterBean = null;
                for (final Bean<?> presenterBean : instances.keySet()) {
                    if (Presenter.class.isAssignableFrom(presenterBean
                            .getBeanClass())) {
                        final ViewInterface viewInterface = presenterBean
                                .getBeanClass().getAnnotation(
                                        ViewInterface.class);
                        if (viewInterface.value().isAssignableFrom(
                                bean.getBeanClass())) {
                            removablePresenterBean = presenterBean;
                            break;
                        }
                    }
                }
                if (removablePresenterBean != null) {
                    dereferenceBeanInstance(removablePresenterBean);
                }
            }