├── README.md ├── desktop ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── vaadin │ └── swingersclub │ ├── CustomerForm.java │ └── SwingApplication.java ├── domain ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── vaadin │ └── domain │ └── model │ ├── Customer.java │ ├── CustomerStatus.java │ └── Gender.java ├── ejb-api ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── vaadin │ └── backend │ └── ejb │ └── CustomerFacadeRemote.java ├── pom.xml └── server ├── pom.xml └── src └── main ├── java └── org │ └── vaadin │ ├── backend │ └── ejb │ │ ├── CdiConfiguration.java │ │ ├── CustomerFacade.java │ │ └── CustomerRepository.java │ └── vaadinui │ ├── AppUI.java │ ├── CustomerForm.java │ └── CustomerListView.java ├── resources └── META-INF │ ├── apache-deltaspike.properties │ └── persistence.xml └── webapp └── WEB-INF └── beans.xml /README.md: -------------------------------------------------------------------------------- 1 | # Java EE example with Swing and Vaadin UIs 2 | 3 | This is a simple example application that has (Remote) EJB for Customer entities, and simple CRUD user interfaces implemented by both Swing based desktop application and Vaadin based web application. With the UI code examples, you'll see similarities with the programming model and can consider based on the example, what it might mean to convert your legacy desktop app to Vaadin based Web application. 4 | 5 | The Vaadin code is bit more "advanced", using databinding (instead of manually moving data from fields to entities), automatic bean validation and richer user experience. This could be naturally implemented with as low level APIs as with the Swing example and then there would be even more similarities, but this way you can see some best practices for Vaadin apps. 6 | 7 | ###The example contains following modules: 8 | 9 | * *domain* - (JPA) entities. JPA entities are used as DTOs as well. 10 | * *ejb-ap* - the API for the (Remote) EJB via updates to "customer database" are done 11 | * *server* - WAR project that contains both the EJB implementation and Vaadin UI. This could naturally be split to two modules (and EAR) as well. 12 | * *desktop* - A simple Swing based client application that uses the same EJB as the Vaadin UI 13 | 14 | ###To play with the demo: 15 | 16 | * build from top level with **mvn install** 17 | * import the project to your IDE and make one top level build 18 | * start the server module with **mvn tomee:run** from the module root or by deploying the server module manually to TomEE server configured in you IDE. 19 | * Web UI is then available at **http://localhost:8080/server-1.0-SNAPSHOT/** 20 | * The Swing UI can be launch directly from IDE by executing main method from SwingApplication class in desktop module. Note, that server naturally needs to be running. 21 | 22 | -------------------------------------------------------------------------------- /desktop/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | org.vaadin 5 | desktop 6 | 1.0-SNAPSHOT 7 | jar 8 | 9 | UTF-8 10 | 1.7 11 | 1.7 12 | 13 | 14 | 15 | 16 | 17 | maven-assembly-plugin 18 | 19 | 20 | 21 | org.vaadin.swingersclub.SwingApplication 22 | 23 | 24 | 25 | jar-with-dependencies 26 | 27 | 28 | 29 | 30 | make-assembly 31 | package 32 | 33 | single 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.vaadin 44 | ejb-api 45 | 1.0-SNAPSHOT 46 | 47 | 48 | org.apache.openejb 49 | openejb-client 50 | 4.7.1 51 | 52 | 53 | org.slf4j 54 | slf4j-api 55 | 1.7.10 56 | 57 | 60 | 61 | org.apache.openjpa 62 | openjpa 63 | 2.3.0 64 | 65 | 66 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/vaadin/swingersclub/CustomerForm.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.swingersclub; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.ActionListener; 5 | import javax.swing.Box; 6 | import javax.swing.BoxLayout; 7 | import javax.swing.JButton; 8 | import javax.swing.JLabel; 9 | import javax.swing.JPanel; 10 | import javax.swing.JTextField; 11 | import org.vaadin.domain.model.Customer; 12 | 13 | /** 14 | * 15 | * @author Matti Tahvonen 16 | */ 17 | public class CustomerForm extends JPanel implements ActionListener { 18 | 19 | JTextField firstName = new JTextField(); 20 | JTextField lastName = new JTextField(); 21 | JTextField email = new JTextField("yourname@yourdomain.com"); 22 | JButton create = new JButton("Create"); 23 | JButton update = new JButton("Update"); 24 | JButton delete = new JButton("Delete"); 25 | 26 | private final SwingApplication application; 27 | private Customer editedCustomer; 28 | 29 | public CustomerForm(SwingApplication application) { 30 | this.application = application; 31 | 32 | setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 33 | 34 | addWithCaption("First name:", firstName); 35 | addWithCaption("Last name:", lastName); 36 | addWithCaption("Email:", email); 37 | 38 | final Box actionButtons = Box.createHorizontalBox(); 39 | 40 | actionButtons.add(create); 41 | actionButtons.add(update); 42 | actionButtons.add(delete); 43 | 44 | add(actionButtons); 45 | 46 | create.addActionListener(this); 47 | update.addActionListener(this); 48 | delete.addActionListener(this); 49 | 50 | updateButtonStates(); 51 | 52 | setVisible(true); 53 | 54 | } 55 | 56 | @Override 57 | public void actionPerformed(ActionEvent e) { 58 | if (e.getSource() == delete) { 59 | application.getCustomerFacade().remove(editedCustomer); 60 | application.deselect(); 61 | clear(); 62 | } else { 63 | Customer c = editedCustomer; 64 | if (e.getSource() == create) { 65 | c = new Customer(); 66 | } 67 | c.setFirstName(firstName.getText()); 68 | c.setLastName(lastName.getText()); 69 | c.setEmail(email.getText()); 70 | application.getCustomerFacade().save(c); 71 | } 72 | application.refreshData(); 73 | } 74 | 75 | void editCustomer(Customer c) { 76 | this.editedCustomer = c; 77 | firstName.setText(c.getFirstName()); 78 | lastName.setText(c.getLastName()); 79 | email.setText(c.getEmail()); 80 | updateButtonStates(); 81 | } 82 | 83 | void clear() { 84 | editedCustomer = null; 85 | firstName.setText(""); 86 | lastName.setText(""); 87 | email.setText("your@email.com"); 88 | updateButtonStates(); 89 | } 90 | 91 | private void updateButtonStates() { 92 | update.setEnabled(editedCustomer != null); 93 | delete.setEnabled(editedCustomer != null); 94 | create.setEnabled(editedCustomer == null); 95 | } 96 | 97 | private void addWithCaption(String caption, JTextField f) { 98 | Box box = Box.createHorizontalBox(); 99 | box.add(new JLabel(caption)); 100 | box.add(Box.createHorizontalGlue()); 101 | box.add(f); 102 | 103 | add(box); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/vaadin/swingersclub/SwingApplication.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with this 5 | * work for additional information regarding copyright ownership. The ASF 6 | * licenses this file to You under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | * License for the specific language governing permissions and limitations under 16 | * the License. 17 | */ 18 | package org.vaadin.swingersclub; 19 | 20 | import java.awt.BorderLayout; 21 | import javax.naming.Context; 22 | import javax.naming.InitialContext; 23 | import javax.naming.NamingException; 24 | import javax.rmi.PortableRemoteObject; 25 | import javax.swing.*; 26 | import java.awt.event.ActionEvent; 27 | import java.awt.event.ActionListener; 28 | import java.util.List; 29 | import java.util.Properties; 30 | import javax.swing.event.ListSelectionEvent; 31 | import javax.swing.event.ListSelectionListener; 32 | import javax.swing.table.AbstractTableModel; 33 | import org.vaadin.backend.ejb.CustomerFacadeRemote; 34 | import org.vaadin.domain.model.Customer; 35 | 36 | public class SwingApplication extends JFrame { 37 | 38 | CustomerForm form; 39 | JLabel countLabel = new JLabel(); 40 | JButton newCustomer = new JButton("Add new"); 41 | 42 | String[] columnNames = new String[]{"first name", "last name", "email"}; 43 | private JTable table; 44 | 45 | private List customers; 46 | 47 | private CustomerFacadeRemote customerFacade; 48 | 49 | public static void main(String args[]) { 50 | new SwingApplication().createUI(); 51 | 52 | } 53 | 54 | void deselect() { 55 | table.getSelectionModel().clearSelection(); 56 | } 57 | 58 | class CustomerTableModel extends AbstractTableModel { 59 | 60 | @Override 61 | public int getRowCount() { 62 | return customers.size(); 63 | } 64 | 65 | @Override 66 | public int getColumnCount() { 67 | return 3; 68 | } 69 | 70 | @Override 71 | public Object getValueAt(int rowIndex, int columnIndex) { 72 | if (customers == null) { 73 | customers = customerFacade.findAll(); 74 | } 75 | Customer c = customers.get(rowIndex); 76 | switch (columnIndex) { 77 | case 0: 78 | return c.getFirstName(); 79 | case 1: 80 | return c.getLastName(); 81 | case 2: 82 | return c.getEmail(); 83 | } 84 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. 85 | } 86 | 87 | @Override 88 | public String getColumnName(int column) { 89 | return columnNames[column]; 90 | } 91 | 92 | } 93 | 94 | private void createUI() { 95 | final BorderLayout borderLayout = new BorderLayout(10, 10); 96 | setLayout(borderLayout); 97 | 98 | newCustomer.addActionListener(new ActionListener() { 99 | 100 | @Override 101 | public void actionPerformed(ActionEvent e) { 102 | form.clear(); 103 | } 104 | }); 105 | 106 | form = new CustomerForm(this); 107 | 108 | Box hbox = Box.createHorizontalBox(); 109 | hbox.add(newCustomer); 110 | hbox.add(Box.createGlue()); 111 | hbox.add(countLabel); 112 | add(hbox, BorderLayout.PAGE_START); 113 | 114 | table = new JTable(); 115 | table.getSelectionModel().setSelectionMode( 116 | ListSelectionModel.SINGLE_SELECTION); 117 | table.getSelectionModel().addListSelectionListener( 118 | new ListSelectionListener() { 119 | 120 | @Override 121 | public void valueChanged(ListSelectionEvent e) { 122 | Customer c = customers.get(e.getFirstIndex()); 123 | form.editCustomer(c); 124 | } 125 | }); 126 | add(new JScrollPane(table), BorderLayout.CENTER); 127 | 128 | add(form, BorderLayout.PAGE_END); 129 | 130 | refreshData(); 131 | 132 | setSize(640, 400); 133 | 134 | setVisible(true); 135 | } 136 | 137 | protected void refreshData() { 138 | customers = getCustomerFacade().findAll(); 139 | // Manual style, almost like IndexexCotainer or custom Container 140 | // in vaadin, see impl. 141 | table.setModel(new CustomerTableModel()); 142 | countLabel.setText("Customers in DB: " + customers.size()); 143 | } 144 | 145 | public CustomerFacadeRemote getCustomerFacade() { 146 | if (customerFacade == null) { 147 | try { 148 | final Object ref = new InitialContext( 149 | getJndiPropsCustomerServer()).lookup( 150 | "CustomerFacadeRemote"); 151 | customerFacade = (CustomerFacadeRemote) PortableRemoteObject. 152 | narrow(ref, CustomerFacadeRemote.class); 153 | } catch (NamingException ex) { 154 | throw new RuntimeException(ex); 155 | } 156 | } 157 | return customerFacade; 158 | } 159 | 160 | protected Properties getJndiPropsCustomerServer() { 161 | Properties props = new Properties(); 162 | props.put(Context.INITIAL_CONTEXT_FACTORY, 163 | "org.apache.openejb.client.RemoteInitialContextFactory"); 164 | props.put(Context.PROVIDER_URL, "http://127.0.0.1:8080/tomee/ejb"); 165 | return props; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /domain/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.vaadin 6 | swingersclub 7 | 1.0-SNAPSHOT 8 | 9 | domain 10 | jar 11 | 12 | 1.7 13 | 1.7 14 | 15 | -------------------------------------------------------------------------------- /domain/src/main/java/org/vaadin/domain/model/Customer.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.domain.model; 2 | 3 | import javax.persistence.*; 4 | import javax.validation.constraints.NotNull; 5 | import javax.validation.constraints.Pattern; 6 | import java.io.Serializable; 7 | import java.util.Date; 8 | 9 | /** 10 | * A standard JPA entity, like in any other Java application. 11 | */ 12 | @Entity 13 | public class Customer implements Serializable { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.AUTO) 17 | private Integer id; 18 | 19 | @Version int version; 20 | 21 | private String firstName; 22 | 23 | private String lastName; 24 | 25 | @Temporal(javax.persistence.TemporalType.DATE) 26 | private Date birthDate; 27 | 28 | private CustomerStatus status; 29 | 30 | private Gender gender; 31 | 32 | @NotNull(message = "Email is required") 33 | @Pattern(regexp = ".+@.+\\.[a-z]+", message = "Must be valid email") 34 | private String email; 35 | 36 | public Integer getId() { 37 | return id; 38 | } 39 | 40 | public void setId(Integer id) { 41 | this.id = id; 42 | } 43 | 44 | /** 45 | * Get the value of email 46 | * 47 | * @return the value of email 48 | */ 49 | public String getEmail() { 50 | return email; 51 | } 52 | 53 | /** 54 | * Set the value of email 55 | * 56 | * @param email new value of email 57 | */ 58 | public void setEmail(String email) { 59 | this.email = email; 60 | } 61 | 62 | /** 63 | * Get the value of status 64 | * 65 | * @return the value of status 66 | */ 67 | public CustomerStatus getStatus() { 68 | return status; 69 | } 70 | 71 | /** 72 | * Set the value of status 73 | * 74 | * @param status new value of status 75 | */ 76 | public void setStatus(CustomerStatus status) { 77 | this.status = status; 78 | } 79 | 80 | /** 81 | * Get the value of birthDate 82 | * 83 | * @return the value of birthDate 84 | */ 85 | public Date getBirthDate() { 86 | return birthDate; 87 | } 88 | 89 | /** 90 | * Set the value of birthDate 91 | * 92 | * @param birthDate new value of birthDate 93 | */ 94 | public void setBirthDate(Date birthDate) { 95 | this.birthDate = birthDate; 96 | } 97 | 98 | /** 99 | * Get the value of lastName 100 | * 101 | * @return the value of lastName 102 | */ 103 | public String getLastName() { 104 | return lastName; 105 | } 106 | 107 | /** 108 | * Set the value of lastName 109 | * 110 | * @param lastName new value of lastName 111 | */ 112 | public void setLastName(String lastName) { 113 | this.lastName = lastName; 114 | } 115 | 116 | /** 117 | * Get the value of firstName 118 | * 119 | * @return the value of firstName 120 | */ 121 | public String getFirstName() { 122 | return firstName; 123 | } 124 | 125 | /** 126 | * Set the value of firstName 127 | * 128 | * @param firstName new value of firstName 129 | */ 130 | public void setFirstName(String firstName) { 131 | this.firstName = firstName; 132 | } 133 | 134 | public Gender getGender() { 135 | return gender; 136 | } 137 | 138 | public void setGender(Gender gender) { 139 | this.gender = gender; 140 | } 141 | 142 | public boolean isPersisted() { 143 | return id != null; 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /domain/src/main/java/org/vaadin/domain/model/CustomerStatus.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.domain.model; 2 | 3 | public enum CustomerStatus { 4 | ImportedLead, NotContacted, Contacted, Customer, ClosedLost 5 | } 6 | -------------------------------------------------------------------------------- /domain/src/main/java/org/vaadin/domain/model/Gender.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.domain.model; 2 | 3 | public enum Gender { 4 | Female, Male 5 | } 6 | -------------------------------------------------------------------------------- /ejb-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.vaadin 6 | swingersclub 7 | 1.0-SNAPSHOT 8 | 9 | ejb-api 10 | jar 11 | 12 | 13 | org.vaadin 14 | domain 15 | 1.0-SNAPSHOT 16 | 17 | 18 | 19 | 1.7 20 | 1.7 21 | 22 | -------------------------------------------------------------------------------- /ejb-api/src/main/java/org/vaadin/backend/ejb/CustomerFacadeRemote.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package org.vaadin.backend.ejb; 7 | 8 | import java.util.List; 9 | import javax.ejb.Remote; 10 | import org.vaadin.domain.model.Customer; 11 | 12 | @Remote 13 | public interface CustomerFacadeRemote { 14 | 15 | Customer save(Customer customer); 16 | 17 | Customer findById(int id); 18 | 19 | void remove(Customer customer); 20 | 21 | List findAll(); 22 | 23 | List findRange(int startIndex, int maxResults); 24 | 25 | int count(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | org.vaadin 5 | swingersclub 6 | 1.0-SNAPSHOT 7 | pom 8 | 9 | UTF-8 10 | 11 | 12 | 13 | domain 14 | ejb-api 15 | desktop 16 | server 17 | 18 | 19 | 20 | 21 | javax 22 | javaee-web-api 23 | 6.0 24 | provided 25 | 26 | 27 | -------------------------------------------------------------------------------- /server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | swingersclub 6 | org.vaadin 7 | 1.0-SNAPSHOT 8 | 9 | 10 | org.vaadin 11 | server 12 | 1.0-SNAPSHOT 13 | war 14 | 15 | server 16 | 17 | 18 | ${project.build.directory}/endorsed 19 | UTF-8 20 | false 21 | 1.2.1 22 | 23 | 24 | 25 | 26 | 27 | org.apache.maven.plugins 28 | maven-compiler-plugin 29 | 3.1 30 | 31 | 1.7 32 | 1.7 33 | 34 | ${endorsed.dir} 35 | 36 | 37 | 38 | 39 | org.apache.openejb.maven 40 | tomee-maven-plugin 41 | 1.7.1 42 | 43 | 1.7.1 44 | plus 45 | 46 | 47 | 48 | 49 | 50 | 51 | vaadin-addons 52 | http://maven.vaadin.com/vaadin-addons 53 | 54 | 55 | 56 | 57 | 58 | org.vaadin 59 | ejb-api 60 | 1.0-SNAPSHOT 61 | 62 | 63 | org.apache.deltaspike.core 64 | deltaspike-core-api 65 | ${deltaspike.version} 66 | compile 67 | 68 | 69 | org.apache.deltaspike.core 70 | deltaspike-core-impl 71 | ${deltaspike.version} 72 | runtime 73 | 74 | 75 | org.apache.deltaspike.modules 76 | deltaspike-data-module-api 77 | ${deltaspike.version} 78 | compile 79 | 80 | 81 | org.apache.deltaspike.modules 82 | deltaspike-data-module-impl 83 | ${deltaspike.version} 84 | runtime 85 | 86 | 87 | 88 | 89 | org.vaadin 90 | cdi-helpers 91 | 1.8 92 | 93 | 94 | com.vaadin 95 | vaadin-client-compiled 96 | 7.3.9 97 | 98 | 99 | com.vaadin 100 | vaadin-themes 101 | 7.3.9 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /server/src/main/java/org/vaadin/backend/ejb/CdiConfiguration.java: -------------------------------------------------------------------------------- 1 | 2 | package org.vaadin.backend.ejb; 3 | 4 | import javax.enterprise.context.Dependent; 5 | import javax.enterprise.inject.Produces; 6 | import javax.persistence.EntityManager; 7 | import javax.persistence.PersistenceContext; 8 | 9 | public class CdiConfiguration { 10 | 11 | @Produces 12 | @Dependent 13 | @PersistenceContext(unitName = "customer-db") 14 | public EntityManager entityManager; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /server/src/main/java/org/vaadin/backend/ejb/CustomerFacade.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.backend.ejb; 2 | 3 | import java.util.List; 4 | import javax.ejb.Stateless; 5 | import javax.inject.Inject; 6 | import javax.persistence.EntityManager; 7 | import javax.persistence.PersistenceContext; 8 | import org.vaadin.domain.model.Customer; 9 | 10 | /** 11 | * A simple facade for Customer entity, implemented with DeltaSpike Data module. 12 | * 13 | * @author Matti Tahvonen 14 | */ 15 | @Stateless 16 | public class CustomerFacade implements CustomerFacadeRemote { 17 | 18 | @Inject 19 | CustomerRepository repository; 20 | 21 | @PersistenceContext 22 | EntityManager em; 23 | 24 | @Override 25 | public Customer save(Customer customer) { 26 | if(customer.isPersisted()) { 27 | // At least OpenEJB don't properly return indenfier for deserrialized 28 | // entity and DeltaSpike Data don't notice this, workaround this by 29 | // manually calling merge 30 | return em.merge(customer); 31 | } 32 | return repository.save(customer); 33 | } 34 | 35 | @Override 36 | public Customer findById(int id) { 37 | return repository.findBy(id); 38 | } 39 | 40 | @Override 41 | public void remove(Customer customer) { 42 | repository.remove(repository.findBy(customer.getId())); 43 | } 44 | 45 | @Override 46 | public List findAll() { 47 | return repository.findAll(); 48 | } 49 | 50 | @Override 51 | public List findRange(int startIndex, int maxResults) { 52 | return repository.findAll(startIndex, maxResults); 53 | } 54 | 55 | @Override 56 | public int count() { 57 | return repository.count().intValue(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /server/src/main/java/org/vaadin/backend/ejb/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | 2 | package org.vaadin.backend.ejb; 3 | 4 | import org.apache.deltaspike.data.api.EntityRepository; 5 | import org.apache.deltaspike.data.api.Repository; 6 | import org.vaadin.domain.model.Customer; 7 | 8 | @Repository(forEntity = Customer.class) 9 | public interface CustomerRepository extends EntityRepository { 10 | 11 | } -------------------------------------------------------------------------------- /server/src/main/java/org/vaadin/vaadinui/AppUI.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.vaadinui; 2 | 3 | import com.vaadin.annotations.Theme; 4 | import com.vaadin.annotations.Title; 5 | import com.vaadin.cdi.CDIUI; 6 | import org.vaadin.cdiviewmenu.ViewMenuUI; 7 | 8 | 9 | /** 10 | * Maps ViewMenuUI to root, provides automatic top level layout and navigation 11 | * for CDIView annotated Views. 12 | */ 13 | @CDIUI("") 14 | @Theme("valo") 15 | @Title("Simple CRM") 16 | public class AppUI extends ViewMenuUI { 17 | 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /server/src/main/java/org/vaadin/vaadinui/CustomerForm.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.vaadinui; 2 | 3 | import com.vaadin.ui.*; 4 | import com.vaadin.ui.themes.ValoTheme; 5 | 6 | import org.vaadin.domain.model.Customer; 7 | import org.vaadin.viritin.fields.MTextField; 8 | import org.vaadin.viritin.form.AbstractForm; 9 | import org.vaadin.viritin.label.Header; 10 | import org.vaadin.viritin.layouts.MFormLayout; 11 | import org.vaadin.viritin.layouts.MVerticalLayout; 12 | 13 | /** 14 | * A UI component built to modify Customer entities. The used superclass 15 | * provides binding to the entity object and e.g. Save/Cancel buttons by 16 | * default. In larger apps, you'll most likely have your own customized super 17 | * class for your forms. 18 | *

19 | * Note, that the advanced bean binding technology in Vaadin is able to take 20 | * advantage also from Bean Validation annotations that are used also by e.g. 21 | * JPA implementation. Check out annotations in Customer objects email field and 22 | * how they automatically reflect to the configuration of related fields in UI. 23 | *

24 | */ 25 | public class CustomerForm extends AbstractForm { 26 | 27 | // Prepare some basic field components that our bound to entity property 28 | // by naming convetion, you can also use PropertyId annotation 29 | TextField firstName = new MTextField("First name").withFullWidth(); 30 | TextField lastName = new MTextField("Last name").withFullWidth(); 31 | TextField email = new MTextField("Email").withFullWidth(); 32 | 33 | @Override 34 | protected Component createContent() { 35 | 36 | setStyleName(ValoTheme.LAYOUT_CARD); 37 | 38 | return new MVerticalLayout( 39 | new Header("Edit customer").setHeaderLevel(3), 40 | // Form layout puts caption on left, component on right 41 | new MFormLayout( 42 | firstName, 43 | lastName, 44 | email 45 | ).withFullWidth(), 46 | getToolbar() 47 | ).withStyleName(ValoTheme.LAYOUT_CARD); 48 | } 49 | 50 | @Override 51 | protected void adjustResetButtonState() { 52 | // Always true, closes the form even if not modified 53 | getResetButton().setEnabled(true); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /server/src/main/java/org/vaadin/vaadinui/CustomerListView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.vaadinui; 2 | 3 | import com.vaadin.cdi.CDIView; 4 | import com.vaadin.navigator.View; 5 | import com.vaadin.navigator.ViewChangeListener; 6 | import com.vaadin.server.FontAwesome; 7 | import com.vaadin.shared.ui.MarginInfo; 8 | import com.vaadin.ui.*; 9 | import org.vaadin.cdiviewmenu.ViewMenuItem; 10 | 11 | import javax.annotation.PostConstruct; 12 | import java.util.ArrayList; 13 | import javax.ejb.EJB; 14 | import org.vaadin.backend.ejb.CustomerFacadeRemote; 15 | import org.vaadin.domain.model.Customer; 16 | import org.vaadin.viritin.button.MButton; 17 | import org.vaadin.viritin.fields.MTable; 18 | import org.vaadin.viritin.fields.MValueChangeEvent; 19 | import org.vaadin.viritin.fields.MValueChangeListener; 20 | import org.vaadin.viritin.form.AbstractForm.DeleteHandler; 21 | import org.vaadin.viritin.form.AbstractForm.ResetHandler; 22 | import org.vaadin.viritin.form.AbstractForm.SavedHandler; 23 | import org.vaadin.viritin.label.Header; 24 | import org.vaadin.viritin.layouts.MHorizontalLayout; 25 | import org.vaadin.viritin.layouts.MVerticalLayout; 26 | 27 | /** 28 | * A view that lists Customers in a Table and lets user to choose one for 29 | * editing. There is also RIA features like on the fly filtering. 30 | */ 31 | @CDIView("") 32 | @ViewMenuItem(icon = FontAwesome.USERS, order = ViewMenuItem.BEGINNING) 33 | public class CustomerListView extends MVerticalLayout implements View, 34 | SavedHandler, ResetHandler, DeleteHandler { 35 | 36 | @EJB 37 | private CustomerFacadeRemote service; 38 | 39 | CustomerForm customerForm = new CustomerForm(); 40 | 41 | // Introduce and configure some UI components used on this view 42 | MTable bookTable = new MTable(Customer.class).withFullWidth(). 43 | withFullHeight().withProperties("firstName", "lastName", "email"); 44 | 45 | MHorizontalLayout mainContent = new MHorizontalLayout(bookTable). 46 | withFullWidth().withMargin(false); 47 | 48 | Header header = new Header("Customers").setHeaderLevel(2); 49 | 50 | Button addButton = new MButton(FontAwesome.PLUS_SQUARE, 51 | new Button.ClickListener() { 52 | 53 | @Override 54 | public void buttonClick(Button.ClickEvent event) { 55 | addBook(); 56 | } 57 | }); 58 | 59 | @PostConstruct 60 | public void init() { 61 | 62 | /* 63 | * Add value change listener to table that opens the selected book into 64 | * an editor. 65 | */ 66 | bookTable.addMValueChangeListener(new MValueChangeListener() { 67 | 68 | @Override 69 | public void valueChange(MValueChangeEvent event) { 70 | editBook(event.getValue()); 71 | } 72 | }); 73 | 74 | add( 75 | new MHorizontalLayout(header, addButton) 76 | .expand(header) 77 | .alignAll(Alignment.MIDDLE_LEFT) 78 | ); 79 | expand(mainContent); 80 | setMargin(true); 81 | 82 | listBooks(); 83 | } 84 | 85 | private void listBooks() { 86 | bookTable.setBeans(new ArrayList<>(service.findAll())); 87 | } 88 | 89 | void editBook(Customer book) { 90 | if (book != null) { 91 | openEditor(book); 92 | } else { 93 | closeEditor(); 94 | } 95 | } 96 | 97 | void addBook() { 98 | openEditor(new Customer()); 99 | } 100 | 101 | private void openEditor(Customer customer) { 102 | customerForm.setSavedHandler(this); 103 | customerForm.setResetHandler(this); 104 | customerForm.setDeleteHandler(customer.isPersisted() ? this : null); 105 | mainContent.addComponent(customerForm); 106 | customerForm.setEntity(customer); 107 | customerForm.focusFirst(); 108 | } 109 | 110 | private void closeEditor() { 111 | mainContent.removeComponent(customerForm); 112 | } 113 | 114 | @Override 115 | public void enter(ViewChangeListener.ViewChangeEvent event) { 116 | 117 | } 118 | 119 | @Override 120 | public void onSave(Customer entity) { 121 | service.save(entity); 122 | listBooks(); 123 | closeEditor(); 124 | } 125 | 126 | @Override 127 | public void onReset(Customer entity) { 128 | listBooks(); 129 | closeEditor(); 130 | } 131 | 132 | @Override 133 | public void onDelete(Customer entity) { 134 | service.remove(entity); 135 | closeEditor(); 136 | listBooks(); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /server/src/main/resources/META-INF/apache-deltaspike.properties: -------------------------------------------------------------------------------- 1 | globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy=org.apache.deltaspike.jpa.impl.transaction.ContainerManagedTransactionStrategy 2 | -------------------------------------------------------------------------------- /server/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | org.apache.openjpa.persistence.PersistenceProviderImpl 5 | org.vaadin.domain.model.Customer 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /server/src/main/webapp/WEB-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | --------------------------------------------------------------------------------