JDAL Vaadin UI Library
Spring integration, form data binding and UI component library
JDAL Vaadin is a port of JDAL Swing Library to Vaadin including the following features:
Spring Integration:
- Spring custom namespace for configuring Vaadin components in bean definiton files.
- Serializable proxy support to allow injecting spring beans into Vaadin components with session pasitivation and replication across cluster nodes.
- Spring scope for Vaadin 7 UIs.
- Resource property editor to allow injecting resources in bean definition files.
- Spring UIProvider.
- Spring Security integration
- ListBeanContainer with support of indexed properties, ie person.addresses[0]
UI Library:
- Automatic and annotation driven form data binding between views and models.
- Support for JSR-303 and spring validators.
- Server side paged table with navigation and filtering support.
- Form building support class.
- Configurable login form
- Configurable button bar for Vaadin navigator.
And more...
Sample code
<!-- Book Table Definition --> <vaadin:table entity="org.jdal.samples.model.Book" filter-form="bookFilterEditor" scope="prototype"> <vaadin:columns> <vaadin:column name="id" display-name="ID" width="60" align="center"/> <vaadin:column name="name" display-name="Name" width="300" align="left" /> <vaadin:column name="author" display-name="Author" width="150" align="left" sort-property-name="author.name" /> <vaadin:column name="category" display-name="Category" width="200" align="left" sort-property-name="category.name" /> <vaadin:column name="isbn" display-name="ISBN" width="150" align="left" /> <vaadin:column name="publishedDate" display-name="Published Date" width="150" property-editor="customDateEditor"/> </vaadin:columns> </vaadin:table>
<!-- Top button menu --> <vaadin:button-bar id="buttonBar" scope="prototype"> <vaadin:actions> <vaadin:navigator-action caption="Books" view-name="bookMainView" icon="classpath:/org/freedesktop/tango/22x22/mimetypes/x-office-address-book.png"/> <vaadin:navigator-action caption="Authors" view-name="authorMainView" icon="classpath:/org/freedesktop/tango/22x22/apps/preferences-desktop-theme.png"/> <vaadin:navigator-action caption="Categories" view-name="categoryMainView" icon="classpath:/org/freedesktop/tango/22x22/places/folder.png" /> <vaadin:navigator-action caption="Users" view-name="userMainView" icon="classpath:/org/freedesktop/tango/22x22/apps/system-users.png"/> <vaadin:navigator-action caption="About" view-name="aboutMainView" icon="classpath:/org/freedesktop/tango/22x22/apps/help-browser.png"/> <bean class="org.jdal.vaadin.ui.action.ExitAction" p:caption="Exit" p:icon="classpath:/org/freedesktop/tango/22x22/actions/system-shutdown.png" /> </vaadin:actions> </vaadin:button-bar> <!-- Make main views ui scoped to avoid recreating thems in every page change --> <bean id="bookMainView" class="org.jdal.samples.vaadin.BookMainView" scope="ui" /> <bean id="authorMainView" class="org.jdal.samples.vaadin.AuthorMainView" scope="ui" /> <bean id="categoryMainView" class="org.jdal.samples.vaadin.CategoryMainView" scope="ui" /> <bean id="aboutMainView" class="org.jdal.samples.vaadin.AboutMainView" scope="ui" /> <bean id="userMainView" class="org.jdal.samples.vaadin.UserMainView" scope="ui" />
public class BookView extends AbstractView<Book> { private TextField name = new TextField(); private TextField isbn = new TextField(); private DateField publishedDate = new DateField(); @Initializer(orderBy="name") private ComboBox author = new ComboBox(); @Initializer(orderBy="name") private ComboBox category = new ComboBox(); public BookView() { this(new Book()); } public BookView(Book model) { super(model); } @PostConstruct public void init() { autobind(); } @Override protected Component buildPanel() { BoxFormBuilder fb = new BoxFormBuilder(); fb.setDefaultWidth(SimpleBoxFormBuilder.SIZE_FULL); fb.setFixedHeight(); fb.row(); fb.add(name, getMessage("Book.title")); fb.row(); fb.startBox(); fb.row(); fb.add(author, getMessage("Book.author")); fb.add(category, getMessage("Book.category")); fb.endBox(); fb.row(); fb.startBox(); fb.row(); fb.add(isbn, getMessage("Book.isbn")); fb.add(publishedDate, getMessage("Book.publishedDate"), 120); fb.endBox(); return fb.getForm(); } }
@Entity @Table(name="books") public class Book implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @NotEmpty private String name = ""; @NotNull @ManyToOne @JoinColumn(name="authorid") private Author author; @NotNull @ManyToOne @JoinColumn(name="categoryid") private Category category; private String isbn = ""; private Date publishedDate; // Getters and setters }
Book.title = Title Book.category = Category Book.author = Author Book.publishedDate = Published Date Book.isbn = ISBN BookFilter.publishedBefore = Before BookFilter.publishedAfter = After #Error Messages NotNull.Book.category= The category is required. NotEmpty.Book.name = The title is required. NotNull.Book.author = The autor is required. NotEmpty.Category.name = The category name is required. NotEmpty.Author.name = The author name is required. NotEmtpy.Author.surname = The author surname is required.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" default-init-method="init" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:vaadin="http://www.jdal.org/schema/vaadin" xmlns:jdal="http://www.jdal.org/schema/jdal" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http://www.jdal.org/schema/jdal http://www.jdal.org/schema/jdal/jdal-core.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd http://www.jdal.org/schema/vaadin http://www.jdal.org/schema/jdal/jdal-vaadin.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> <import resource="context/dao-context.xml"/> <import resource="context/view-context.xml" /> <!-- Enable @SerializableProxy support --> <bean id="serializableAnnotationBeanPostProcessor" class="org.jdal.aop.config.SerializableAnnotationBeanPostProcessor" /> <bean id="serializableProxyAdvisor" class="org.jdal.aop.SerializableProxyAdvisor" scope="prototype"/> <!-- Message Source --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames" value="i18n/jdal,i18n/i18n" /> <!-- Repalace with serializable proxy --> <jdal:serializable-proxy/> </bean> <!-- Needed for jdal library, don't delete --> <bean id="staticMessageSource" class="org.jdal.beans.StaticMessageSource"> <constructor-arg ref="messageSource" /> </bean> </beans>
<!-- UI Widgets --> <!-- Register default Vaadin components --> <vaadin:defaults /> <!-- Vaadin scoped beans are linked to UI class instances, Use with care, is still a beta component. --> <bean id="vaadinScopeConfigurer" class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="ui" value="org.jdal.vaadin.beans.VaadinScope" /> </map> </property> </bean> <!-- Application UI --> <bean id="uid" class="org.jdal.samples.vaadin.TestApp" scope="prototype" p:buttonBar-ref="buttonBar"/> <bean id="springViewProvider" class="org.jdal.vaadin.ui.SpringViewProvider" scope="prototype" p:defaultView="bookMainView" /> <!-- Top button menu --> <vaadin:button-bar id="buttonBar" scope="prototype"> <vaadin:actions> <vaadin:navigator-action caption="Books" view-name="bookMainView" icon="classpath:/org/freedesktop/tango/22x22/mimetypes/x-office-address-book.png"/> <vaadin:navigator-action caption="Authors" view-name="authorMainView" icon="classpath:/org/freedesktop/tango/22x22/apps/preferences-desktop-theme.png"/> <vaadin:navigator-action caption="Categories" view-name="categoryMainView" icon="classpath:/org/freedesktop/tango/22x22/places/folder.png" /> <vaadin:navigator-action caption="Users" view-name="userMainView" icon="classpath:/org/freedesktop/tango/22x22/apps/system-users.png"/> <vaadin:navigator-action caption="About" view-name="aboutMainView" icon="classpath:/org/freedesktop/tango/22x22/apps/help-browser.png"/> <bean class="org.jdal.vaadin.ui.action.ExitAction" p:caption="Exit" p:icon="classpath:/org/freedesktop/tango/22x22/actions/system-shutdown.png" /> </vaadin:actions> </vaadin:button-bar> <!-- Make main views ui scoped to avoid recreating thems in every page change --> <bean id="bookMainView" class="org.jdal.samples.vaadin.BookMainView" scope="ui" /> <bean id="authorMainView" class="org.jdal.samples.vaadin.AuthorMainView" scope="ui" /> <bean id="categoryMainView" class="org.jdal.samples.vaadin.CategoryMainView" scope="ui" /> <bean id="aboutMainView" class="org.jdal.samples.vaadin.AboutMainView" scope="ui" /> <bean id="userMainView" class="org.jdal.samples.vaadin.UserMainView" scope="ui" /> <!-- Abstract definition for Views --> <bean id="view" abstract="true"> <property name="controlInitializer" ref="controlInitializer"/> <property name="errorProcessors"> <list> <ref bean="errorProcessor" /> </list> </property> <property name="validator" ref="validator" /> </bean> <bean id="loginView" class="org.jdal.vaadin.auth.LoginView" parent="view" scope="prototype" p:width="400" p:height="250" p:applicationName="bookLibrary" p:applicationIcon="images/jdal-logo.png"/> <bean id="controlInitializer" class="org.jdal.vaadin.ui.bind.VaadinControlInitializer"> <property name="persistentService" ref="contextPersistentService" /> </bean> <!-- Spring JSR-303 validator --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <jdal:serializable-proxy /> </bean> <!-- Error Processor --> <bean id="errorProcessor" class="org.jdal.vaadin.ui.bind.UserErrorProcessor" /> <!-- Book Table Definition --> <vaadin:table entity="org.jdal.samples.model.Book" filter-form="bookFilterEditor" scope="prototype"> <vaadin:columns> <vaadin:column name="id" display-name="ID" width="60" align="center"/> <vaadin:column name="name" display-name="Name" align="left" /> <vaadin:column name="author" display-name="Author" width="150" align="left" sort-property-name="author.name" /> <vaadin:column name="category" display-name="Category" width="200" align="left" sort-property-name="category.name" /> <vaadin:column name="isbn" display-name="ISBN" width="150" align="left" /> <vaadin:column name="publishedDate" display-name="Published Date" width="150" property-editor="customDateEditor"/> </vaadin:columns> </vaadin:table> <bean id="customDateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor" scope="prototype"> <constructor-arg> <bean class="java.text.SimpleDateFormat"> <constructor-arg value="MM/dd/yyyy" /> </bean> </constructor-arg> <constructor-arg value="true" /> <jdal:serializable-proxy/> </bean> <!-- Book Form Editor --> <bean id="bookEditor" class="org.jdal.samples.vaadin.BookView" parent="view" scope="prototype" > <property name="width" value="600" /> <property name="height" value="300" /> <property name="persistentService" ref="bookService" /> </bean> <!-- View Dialog Prototype --> <bean id="viewDialog" class="org.jdal.vaadin.ui.form.ViewDialog" scope="prototype"/> <!-- The book Filter Editor --> <bean id="bookFilterEditor" class="org.jdal.samples.vaadin.BookFilterView" scope="prototype"> <property name="controlInitializer" ref="controlInitializer" /> </bean> <!-- Author Table --> <vaadin:table entity="org.jdal.samples.model.Author" filter-form="authorFilterView" scope="prototype"> <vaadin:columns> <vaadin:column name="id" display-name="ID" width="60" /> <vaadin:column name="name" display-name="Name"/> <vaadin:column name="surname" display-name="Surname" /> </vaadin:columns> </vaadin:table> <bean id="authorEditor" class="org.jdal.samples.vaadin.AuthorView" parent="view" scope="prototype" p:width="400" p:height="250" p:persistentService-ref="authorService" /> <bean id="authorFilterView" class="org.jdal.samples.vaadin.AuthorFilterView" scope="prototype" parent="view" /> <!-- Category Table --> <vaadin:table entity="org.jdal.samples.model.Category" filter-form="categoryFilterView" scope="prototype" > <vaadin:columns> <vaadin:column name="id" display-name="ID" width="60" /> <vaadin:column name="name" display-name="Name" /> </vaadin:columns> </vaadin:table> <bean id="categoryEditor" class="org.jdal.samples.vaadin.CategoryView" parent="view" scope="prototype" p:width="400" p:height="250" p:persistentService-ref="categoryService" /> <bean id="categoryFilterView" class="org.jdal.samples.vaadin.CategoryFilterView" scope="prototype" /> <!-- User Table --> <vaadin:table entity="org.jdal.samples.model.User" filter-form="userFilterView" scope="prototype"> <vaadin:columns> <vaadin:column name="id" display-name="ID" width="60" /> <vaadin:column name="username" display-name="User" width="120"/> <vaadin:column name="name" display-name="Name" /> <vaadin:column name="surname" display-name="Surname" /> <vaadin:column name="registerDate" display-name="Register Date" width="100" /> <vaadin:column name="email" display-name="Email" width="120" /> </vaadin:columns> </vaadin:table> <bean id="userEditor" class="org.jdal.samples.vaadin.UserView" parent="view" scope="prototype" p:width="500" p:height="300" p:persistentService-ref="userService" /> <bean id="userFilterView" class="org.jdal.samples.vaadin.UserFilterView" parent="view" scope="prototype" /> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdal="http://www.jdal.org/schema/jdal" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" default-init-method="init" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.jdal.org/schema/jdal http://www.jdal.org/schema/jdal/jdal-core.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:property-placeholder location="classpath:jdbc.properties"/> <jdbc:embedded-database id="dataSource" type="H2"> <jdbc:script location="classpath:create.sql"/> <jdbc:script location="classpath:import.sql"/> </jdbc:embedded-database> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="org.jdal.samples.model" /> <property name="jpaDialect"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/> </property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/> </bean> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> <property name="dataSource" ref="dataSource"/> </bean> <!-- DAOs --> <jdal:service entity="org.jdal.samples.model.Category"> <jdal:criteria name="categoryFilter" builder="categoryCriteriaBuilder" /> </jdal:service> <bean id="categoryCriteriaBuilder" class="org.jdal.samples.dao.jpa.CategoryCriteriaBuilder" /> <jdal:service entity="org.jdal.samples.model.Author"> <jdal:criteria name="authorFilter" builder="authorCriteriaBuilder" /> </jdal:service> <bean id="authorCriteriaBuilder" class="org.jdal.samples.dao.jpa.AuthorCriteriaBuilder" /> <jdal:service entity="org.jdal.samples.model.Book"> <jdal:criteria name="book" builder="bookCriteriaBuilder"/> </jdal:service> <bean id="bookCriteriaBuilder" class="org.jdal.samples.dao.jpa.BookCriteriaBuilder"/> <jdal:service entity="org.jdal.samples.model.User" dao-class="org.jdal.samples.dao.jpa.UserJpaDao"> <jdal:criteria name="userFilter" builder="userCriteriaBuilder" /> </jdal:service> <bean id="userCriteriaBuilder" class="org.jdal.samples.dao.jpa.UserCriteriaBuilder" /> <bean id="contextPersistentService" class="org.jdal.logic.ContextPersistentManager" /> <bean id="authService" class="org.jdal.auth.AuthManager"> <property name="userDao" ref="userDao" /> <property name="authStrategy" ref="authMd5" /> </bean> <bean id="authMd5" class="org.jdal.auth.AuthHashMD5" /> <!-- Tx Advice --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- the transactional semantics... --> <tx:attributes> <!-- all methods starting with 'get' and 'load' are read-only --> <tx:method name="get*" read-only="true"/> <tx:method name="load*" read-only="true"/> <!-- other methods use the default transaction settings --> <tx:method name="*"/> </tx:attributes> </tx:advice> <aop:config> <!-- Make all methods on Dao transactional --> <aop:pointcut id="txOperation" expression="execution(* org.jdal.dao.Dao.*(..)) or execution(* org.jdal.samples.dao.*.*(..)) or execution(* org.jdal.auth.AuthService.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txOperation"/> </aop:config> <beans profile="mysql"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClassName}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="acquireIncrement" value="3" /> <property name="minPoolSize" value="3" /> <property name="maxPoolSize" value="10" /> <property name="maxIdleTime" value="5" /> <property name="numHelperThreads" value="5" /> <property name="idleConnectionTestPeriod" value="10" /> <property name="autoCommitOnClose" value="false" /> <property name="preferredTestQuery" value="select 1;" /> <property name="testConnectionOnCheckin" value="true" /> <property name="checkoutTimeout" value="60000" /> </bean> </beans> </beans>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Vaadin Web Application</display-name> <context-param> <description>Vaadin production mode</description> <param-name>productionMode</param-name> <param-value>false</param-value> </context-param> <context-param> <description>Vaadin application class to start</description> <param-name>UIProvider</param-name> <param-value>org.jdal.vaadin.SpringUIProvider</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> <!-- Spring config --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>Vaadin Application Servlet</servlet-name> <servlet-class>com.vaadin.server.VaadinServlet</servlet-class> <init-param> <param-name>UI</param-name> <param-value>org.jdal.samples.vaadin.TestApp</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Vaadin Application Servlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
Links
- Issue Tracker
- Source Code
- Discussion Forum
- Online Demo
- Release Notes
- Reference Documentation
- Author Homepage
Compatibility
Was this helpful? Need more help?
Leave a comment or a question below. You can also join
the chat on Discord or
ask questions on StackOverflow.
Version
- Add initial support for Spring Security.
- Add a new ListBeanContainer with support for indexed properties, ie person.addresses[0].
- New @UiMapping annotation for mapping urls to UIs.
- New @ViewConfig annoation for configurig url mapping and access for Views.
- New attribute access in <vaadin:navigator-action > tag to set access role of the buttons in button bar.
- Add Role editor to samples.
- Released
- 2015-05-13
- Maturity
- STABLE
- License
- Apache License 2.0
Compatibility
- Framework
- Vaadin 7.0+
- Vaadin 6.0+ in 1.2.0
- Browser
- Internet Explorer
- Internet Explorer
- Internet Explorer
- Firefox
- Opera
- Safari
- Google Chrome
- Internet Explorer
JDAL Vaadin UI Library - Vaadin Add-on Directory
Spring integration, form data binding and UI component libraryJDAL Vaadin is a port of JDAL Swing Library to Vaadin including the following features:
Spring Integration:
- Spring custom namespace for configuring Vaadin components in bean definiton files.
- Serializable proxy support to allow injecting spring beans into Vaadin components with session pasitivation and replication across cluster nodes.
- Spring scope for Vaadin 7 UIs.
- Resource property editor to allow injecting resources in bean definition files.
- Spring UIProvider.
- Spring Security integration
- ListBeanContainer with support of indexed properties, ie person.addresses[0]
UI Library:
- Automatic and annotation driven form data binding between views and models.
- Support for JSR-303 and spring validators.
- Server side paged table with navigation and filtering support.
- Form building support class.
- Configurable login form
- Configurable button bar for Vaadin navigator.
And more...