Vaadin Spring + Multithreaded Environment

Hi Folks.

I integrated Vaadin Spring and it works pretty well.
I use Spring managed UIs and Views. For my lagacy code I wrote the following class:

package com.myapp.app_base.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringBeans implements ApplicationContextAware
{
    /**
     * The applicationContext
     */
    private static ApplicationContext applicationContext;
    
    /**
     * Searches for the bean with the passed name.
     *
     * @param name
     *        - The name to search for in the application context.
     *        
     * @return An instance of the bean.
     */
    public static Object getBean( String name )
    {
        return applicationContext.getBean( name );
    }

    /**
     * Searches for the bean with the passed class.
     *
     * @param clazz
     *        - The class search for in the application context.
     *        
     * @return An instance of the bean.
     */
    public static <T> T getBean( Class<T> clazz )
    {
        return applicationContext.getBean( clazz );
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
    {
        SpringBeans.applicationContext = applicationContext;
    }
}

With this class I’m able to access Spring managed beans in my lagacy code. This works fine within the current UI and it’s subcomponents.

Now I start a Job via

[code]
scheduledTaskRegistrar.getScheduler().schedule(task.getRunnable(), new Trigger(){

        @Override
        public Date nextExecutionTime(TriggerContext triggerContext)
        {
            if(triggerContext.lastCompletionTime() == null)
            {
                return new Date();                    
            }
            return null;
        }
        
    })

[/code]Where scheduledTaskRegistrar is an instance of org.springframework.scheduling.config.ScheduledTaskRegistrar
This snippet triggers a one time job in a new Thread. If I try to run this I get the following exception:

16:06:03,705 ERROR TaskUtils$LoggingErrorHandler :95 - Unexpected error occurred in scheduled task. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appointmentBC': Scope 'vaadin-ui' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No VaadinSession bound to current thread at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:354) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:219) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1057) at com.myapp.app_base.util.SpringBeans.getBean(SpringBeans.java:39) at com.myapp.util.AppointmentGenerator.createICSAppointments(AppointmentGenerator.java:806) at com.myapp.app_base.jobs.AppointmentGeneratorJob.generateAppointmentsInternal(AppointmentGeneratorJob.java:64) at com.myapp.app_base.jobs.AppointmentGeneratorJob.generateAppointments(AppointmentGeneratorJob.java:36) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.IllegalStateException: No VaadinSession bound to current thread at com.vaadin.spring.internal.UIScopeImpl$VaadinSessionBeanStoreRetrievalStrategy.getVaadinSession(UIScopeImpl.java:128) at com.vaadin.spring.internal.UIScopeImpl$VaadinSessionBeanStoreRetrievalStrategy.getUIStore(UIScopeImpl.java:139) at com.vaadin.spring.internal.UIScopeImpl$VaadinSessionBeanStoreRetrievalStrategy.getBeanStore(UIScopeImpl.java:168) at com.vaadin.spring.internal.UIScopeImpl.getBeanStore(UIScopeImpl.java:105) at com.vaadin.spring.internal.UIScopeImpl.get(UIScopeImpl.java:81) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:339) ... 22 more This is why the new Thread does not have any reference to the current UI and current vaadin session which are needed in UIScopeImpl to retrieve the proper instances from the spring application context.

I could pass a reference of UI.getCurrent() to the runnable and use UI.setCurrent(…) whichin it. Wouls you guys recommend this solution?

Question:
How do I solve this problem and whats the best practice for that?
If I want to change the UI there is UI.getCurrent().access…
Is there a solutution for my case?

Thank you very much.
Christoph

Hello Christoph,

Currently, there is no built in way of making the current UI and session available to another thread. Personally, I normally pass the UI instance to the thread and access it directly. Any updates to the UI would go through the UI.access(…) method. This method will also take care of populating the current session and UI, so the scopes should work as well.

-Petter-

Hi Petter.

Thanks for the reply. OK, I could pass around the reference to the current UI. But is it save to:

  1. pass the reference to the runnable (you suggested this) AND
  2. do the following in the runnable.run()
    UI.setCurrent(theUIReference);

Doing this I would have two threads referencing the same UI via the CurrentInstance way.
And UIScopeImpl would work because UI.getCurrent() would not return null.

Thanks,
Christoph

I assume you mean the runnable that is passed to UI.access(). You don’t need to call UI.setCurrent() inside that runnable, because Vaadin already does that for you.

-Petter-

Hi Peter.

No, I didn’t mean the runnable for UI.access. I know that in that case vaadin does all the plumping for me.
I mean to write an own runnable, put that to the taskscheduler which starts that runnable in a seperated thread using Spring. There is no Vaadin. But when try to use @Autowired in that runnable which references an UIScope’d Bean the UIScopeImpl will complain that there is no current UI. And thats my Question:

Is it save to do UI.setCurrent(theUIReference); in that own runnable?

Thanks a lot for your time.
Christoph

The UIScopeImpl is locking the session before accessing it, so IMO it should be safe to call UI.setCurrent(theUIReference) inside that runnable.

Hi Petter.

This awnsers my question. Thank you very much for your time :slight_smile:

Cheers,
Christoph