Is it possible to integrate this with Spring-security and allow to change locale from login.form (select combo and onchange reload) ? Similar way as LocaleChangeInterceptor - eg. add parameter ?lang=en_US for example …
I won’t be able to do it. Using custom filter I am able to change vaadin locale and spring security messages, but spring:message in login.jsp still in browser locale
Im using Vaadin for just few days so I dont know much of the Vaadin internals, but Im wondering why not to do this like Wicket framework do ?
In Wicket:
1)Each component (including custom components) inherit from Component class.
2)Component class has default constructor which calls someting like getApplication().notifyComponentInstantiationListeners(this);
3)When you configure your application in Wicket (similar like you do this in Vaadin) you can register IComponentInstantiationListener which is notified about each wicket component creation
4)Wicket provides SpringComponentInjector which do the rest (auowire Component with spring beans)
This solution has many adventages:
1)simplicity, just one line in yout Application.init() method to configure
2)pure Java, no AspectJ, load time weaving etc required
3)all components are autowired - not only Application objects
Unfortuatly as far as I know Vaadin does not provide ComponentInstantiationListeners, so to let it work following changes should be done in Vaadin:
1)Add something similar to getApplication().notifyComponentInstantiationListeners(this); in AbstractComponentClass
2)Implement somehow (ThreadLocal?) getApplication() method
3)Write somethind similar to SpringComponentInjector
Here is an example of AddressBook example refactored to use Spring.
In this example all Vaadin components are created and injected by Spring without any instantiation listeners or helper classes, custom injectors etc.
Hope this helps
[added later]
Personally I don’t see any problems with using AspectJ but if you do, you can always use bean implementing ApplicationContextAware interface with static access to Spring context and get only one bean from there (MainWindow in this example) 12004.zip (13.4 KB)
OK, now I’ve done some more work on this Vaadin and Spring stuff. Here’s the latest result, which is finally getting close to the way I think it should work.
Up until now there still have been several problems with Vaadin+Spring relating to “scope mismatch”.
For example, if you have a Vaadin application object that registers as a listener on a persistent (non-Vaadin application) singleton, then that listener registration becomes a memory leak when the Vaadin application closes… not to mention the fact that your listener needs to find and synchronize on its associated Vaadin application instance before doing anything… but you can’t autowire in the associated Vaadin application instance because until now there’s no
scope=“vaadinApplication” (using
scope=“session” almost works… until you need your users to run more than one Application instance at a time).
Using Spring’s @Configurable annotation helps but has a similar problem if the bean being configured has a destroy method, because that method will never be called when the Vaadin application closes. Typically destroy methods are where you would unregister listeners so this is yet another opportunity for memory leaks.
So here is my attempt to address all these issues (these classes live in my
dellroad-stuff project):
(sub-class of
ContextApplication ) that creates a new Spring application context for each new Vaadin application instance. The parent context is the application context associated with the overall servlet context. This is analogous to what Spring’s
DispatcherServlet does.
A new AOP aspect that works on @Configurable beans, allowing them to be autowired by the
SpringContextApplication application context associated with the current Vaadin application instance (note:
not the parent context).
, a Spring factory bean that allows the
SpringContextApplication Vaadin application to itself appear within (and be autowired by) its associated application context
VaadinApplicationScope , which adds a custom Spring scope so you declare beans with
scope=“vaadinApplication” .
An example of this stuff is
on github here . When you run the demo you’ll see three beans displaying their properties:
MyBean - a bean in the usual Spring web application context associated with the servlet context (does not change when the Vaadin application restarts)
MyApplicationBean - a bean in the per-Vaadin application context (you get a new one each time the Vaadin application restarts)
ConfigurableBean - a @Configurable bean created in
MyApplicationBean with a
new ConfigurableBean() statement and automagically autowired by the AOP aspect
I’m interested to hear of other people’s thoughts, especially regarding the AOP stuff and serialization issues, as I’m still learning about the subtleties.
Great to see this, I will enjoy checking out your addon.
I have often wondered creating an addon that caters for all the combined wisdom that has been
accumulated on getting spring and vaadin playing well together, so good job.
First, I would like to be able to use the @Service, @Component, @Repository, etc. annotations for spring beans instead of declaring them in the application context. Are there any limitations on being able to do that?
How about adding controllers using @Controller?
You also mention communicating with Vaadin on background threads. Can you provide a use case and code sample of what you mean by this? I am very intrigued and think I have use for it if it is what I think it is.
Reason I ask is that we get an exception when trying to reach our servlet:
Br /Svante
[Servlet Error]
-[admin]
: java.lang.UnsupportedClassVersionError: (org/dellroad/stuff/vaadin/SpringContextApplication) bad major version at offset=6
at java.lang.ClassLoader.defineClassImpl(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:258)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at com.ibm.ws.classloader.CompoundClassLoader._defineClass(CompoundClassLoader.java:562)
at com.ibm.ws.classloader.CompoundClassLoader.findClass(CompoundClassLoader.java:514)
at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:388)
at java.lang.ClassLoader.loadClass(ClassLoader.java:597)
at java.lang.ClassLoader.defineClassImpl(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:258)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at com.ibm.ws.classloader.CompoundClassLoader._defineClass(CompoundClassLoader.java:562)
at com.ibm.ws.classloader.CompoundClassLoader.findClass(CompoundClassLoader.java:514)
at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:388)
at java.lang.ClassLoader.loadClass(ClassLoader.java:597)
at com.vaadin.terminal.gwt.server.ApplicationServlet.init(ApplicationServlet.java:68)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:227)
at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.init(ServletWrapper.java:340)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:435)
at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:524)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3548)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:269)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:818)
at com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1478)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:125)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:267)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:136)
at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:196)
at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:751)
at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)
2011-11-30 08:39:23,092 [Thread-13]
ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.dellroad.stuff.vaadin.ContextApplicationFactoryBean#0' defined in file
[/Users/tgregory/springsource/vfabric-tc-server-developer-2.6.1.RELEASE/spring-insight-instance/wtpwebapps/Presidio3/WEB-INF/classes/META-INF/spring/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: no current application found
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:567)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:282)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:204)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4723)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5226)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5221)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.IllegalStateException: no current application found
at org.dellroad.stuff.vaadin.ContextApplication.get(ContextApplication.java:260)
at org.dellroad.stuff.vaadin.ContextApplicationFactoryBean.getContextApplication(ContextApplicationFactoryBean.java:78)
at org.dellroad.stuff.vaadin.ContextApplicationFactoryBean.createInstance(ContextApplicationFactoryBean.java:52)
at org.dellroad.stuff.vaadin.ContextApplicationFactoryBean.createInstance(ContextApplicationFactoryBean.java:27)
at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:130)
at org.dellroad.stuff.vaadin.ContextApplicationFactoryBean.afterPropertiesSet(ContextApplicationFactoryBean.java:59)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 20 more
I’ve reviewed your code in Github and I do have a question.
In your WEB-INF directory, you have two spring configuration XML files. However, in the web.xml, you don’t reference either one. How does spring get initialized without referencing them in your web.xml?
Does the delroad stuff need to be in a separate initialization file?
Hello, I try to run the example and I got java.lang.ClassCastException exception as follows:
java.lang.ClassCastException: com.vaadin.terminal.gwt.server.ApplicationServlet
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1087)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:824)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:135)
at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:181)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:463)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:852)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:120)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:257)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1764)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:909)
at java.lang.Thread.run(Thread.java:662)
The tomcat failed to start.
My application server is Tomcat 7.0.19 under Eclipse 3.6
Spring Framework 3.0.0 (also tried 3.1.0 & 2.5.6)
dellroad-stuff-vaadin 1.0.189
Sorry for the slow response. For some reason I thought I was subscribed to this thread but actually was not…
The problem here is that you need to create a separate Spring application context for your application bean, and your ContextApplicationFactoryBean should live there.
To do this, create a file Presidio3Application.xml in your WEB-INF and put all per-Application beans, including ContextApplicationFactoryBean, in there. That context will have the normal servlet-wide Spring context as its parent. See
SpringContextApplication
for details.
Both files are given their default names.
For Spring,
classpath:WEB-INF/applicationContext.xml is the default location that
ContextLoaderListener looks for the servlet-wide context.
For SpringContextApplication,
classpath:WEB-INF/
ApplicationName .xml is the default location (in your case, it would be
classpath:WEB-INF/Presidio3Application.xml ).
I am confused with the @Vaadinconfigurable annotation. I have a bean with some autowired properties. Some of the them are defined in applicationContext.xml, the others are defined in MyApp.xml. It turns out both @Vaadinconfigurable & @Configurable will have same effect. For instance, I use Spring’s @Configurable for this bean, and those properties defined in MyApp.xml will still be autowired on this bean. What’s the difference between @Vaadinconfigurable and @Configurable?
Can you please provide more documentation how to use your addon especially the more advanced features? I was able to use the addon but I’m interested in the more sophisticated features like event listeners, background thread communication etc.
Unfortunately my Spring background is not strong enough ( especially the Spring Web MVC stuff ) to read the sourcecode and to understand all the features.
In the end I would like to be able to create an application where services, model and view are separated and the view only communicates with the services and the model firing events, the view should update by changing the model.
Do you think there is any chance you create such a step-by-step documentation?