category) {
73 | this.category = category;
74 | }
75 |
76 | public int getStockCount() {
77 | return stockCount;
78 | }
79 |
80 | public void setStockCount(int stockCount) {
81 | this.stockCount = stockCount;
82 | }
83 |
84 | public Availability getAvailability() {
85 | return availability;
86 | }
87 |
88 | public void setAvailability(Availability availability) {
89 | this.availability = availability;
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/test-util/src/main/java/com/vaadin/demo/testutil/FixedPhantomJSDriver.java:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright 2000-2016 Vaadin Ltd.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 | * use this file except in compliance with the License. You may obtain a copy of
7 | * the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | * License for the specific language governing permissions and limitations under
15 | * the License.
16 | */
17 | package com.vaadin.demo.testutil;
18 |
19 | import java.util.Map;
20 |
21 | import org.openqa.selenium.phantomjs.PhantomJSDriver;
22 | import org.openqa.selenium.remote.DesiredCapabilities;
23 | import org.openqa.selenium.remote.Response;
24 |
25 | import com.vaadin.testbench.TestBenchDriverProxy;
26 |
27 | /**
28 | * Phantom JS driver which waits for Vaadin to finish after every command and
29 | * not just after find commands.
30 | *
31 | * Workaround for https://dev.vaadin.com/ticket/19753
32 | *
33 | * @author Vaadin Ltd
34 | */
35 | public class FixedPhantomJSDriver extends PhantomJSDriver {
36 |
37 | private TestBenchDriverProxy testBenchDriverProxy;
38 |
39 | /**
40 | * Create a new driver instance.
41 | *
42 | * @param cap
43 | * the desired capabilities
44 | */
45 | public FixedPhantomJSDriver(DesiredCapabilities cap) {
46 | super(cap);
47 | }
48 |
49 | @Override
50 | protected Response execute(String driverCommand,
51 | Map parameters) {
52 | try {
53 | return super.execute(driverCommand, parameters);
54 | } finally {
55 | if (testBenchDriverProxy != null) {
56 | // Wait after all commands but avoid looping
57 | Object scriptParam = parameters.get("script");
58 | if (!"quit".equals(driverCommand)
59 | && !"executeScript".equals(driverCommand)
60 | && !(scriptParam instanceof String
61 | && ((String) scriptParam)
62 | .contains("window.vaadin"))) {
63 | testBenchDriverProxy.waitForVaadin();
64 | }
65 | }
66 | }
67 | }
68 |
69 | /**
70 | * Sets the TestBench proxy.
71 | *
72 | * @param testBenchDriverProxy
73 | * the TestBench proxy
74 | */
75 | public void setTestBenchDriverProxy(
76 | TestBenchDriverProxy testBenchDriverProxy) {
77 | this.testBenchDriverProxy = testBenchDriverProxy;
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/registration-form/src/main/java/com/vaadin/demo/registration/EmailOrPhoneValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 Vaadin Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.vaadin.demo.registration;
17 |
18 | import com.vaadin.data.ValidationResult;
19 | import com.vaadin.data.ValueContext;
20 | import com.vaadin.data.validator.AbstractValidator;
21 | import com.vaadin.data.validator.EmailValidator;
22 |
23 | class EmailOrPhoneValidator extends AbstractValidator {
24 |
25 | private final EmailValidator emailValidator;
26 |
27 | EmailOrPhoneValidator() {
28 | super("");
29 | emailValidator = new EmailValidator(
30 | "The string '{0}' is not a valid email address");
31 | }
32 |
33 | @Override
34 | public ValidationResult apply(String value, ValueContext context) {
35 | String val = value;
36 | // remove all spaces
37 | val = val.replace(" ", "");
38 | // if string starts from +0-9 ignoring spaces
39 | if (!startsWithCountryCode(val)) {
40 | return emailValidator.apply(value, context);
41 | }
42 | String digits = val.substring(1);
43 | // if string contains only + and digits (ignoring spaces)
44 | if (!hasOnlyDigits(digits)) {
45 | return ValidationResult.error(String.format(
46 | "The string '%s' is not a valid phone number. "
47 | + "Phone numbers should start with a plus sign followed by digits.",
48 | value));
49 | }
50 | // now there should be at least 10 digits
51 | if (digits.length() >= 10) {
52 | return ValidationResult.ok();
53 | }
54 | return ValidationResult.error(String.format(
55 | "The string '%s' is not a valid phone number. "
56 | + "Phone should start with a plus sign and contain at least 10 digits",
57 | value));
58 | }
59 |
60 | private boolean startsWithCountryCode(String phone) {
61 | return phone.length() >= 2 && phone.charAt(0) == '+'
62 | && Character.isDigit(phone.charAt(1));
63 | }
64 |
65 | private boolean hasOnlyDigits(String phone) {
66 | return phone.chars().allMatch(Character::isDigit);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/tree-database-example/src/main/java/org/vaadin/example/treegrid/jdbc/DBEngine.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.example.treegrid.jdbc;
2 |
3 | import org.apache.commons.dbcp2.BasicDataSource;
4 |
5 | import javax.sql.DataSource;
6 | import java.io.BufferedReader;
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.io.Reader;
10 | import java.sql.Connection;
11 | import java.sql.SQLException;
12 | import java.sql.Statement;
13 | import java.util.stream.Stream;
14 |
15 | /**
16 | * Database support class.
17 | * HSQLDB in-memory database is used. The data is uploaded automatically when
18 | * the database is accessed for the very first time.
19 | */
20 | @SuppressWarnings("WeakerAccess")
21 | public class DBEngine {
22 |
23 | private DBEngine() {
24 | }
25 |
26 | /**
27 | * Initialization-on-demand
28 | * @see More details at Wikipedia
29 | */
30 | private static class LazyHolder {
31 | static final DataSource INSTANCE = createDataSource();
32 | }
33 |
34 | public static DataSource getDataSource() {
35 | return LazyHolder.INSTANCE;
36 | }
37 |
38 | private static DataSource createDataSource() {
39 | BasicDataSource dataSource = new BasicDataSource();
40 | dataSource.setUrl("jdbc:hsqldb:mem:peopledb");
41 | dataSource.setUsername("SA");
42 | dataSource.setPassword("");
43 | try (Connection connection = dataSource.getConnection()) {
44 | uploadData(connection);
45 | } catch (SQLException e) {
46 | throw new RuntimeException(e);
47 | }
48 | return dataSource;
49 | }
50 |
51 | private static void uploadData(Connection connection) {
52 | Stream.of("db_ddl.sql", "db_dml.sql").forEach(scriptName ->
53 | {
54 | try (Statement statement = connection.createStatement();
55 | InputStream stream = DBEngine.class.getResourceAsStream(scriptName);
56 | Reader reader = new BufferedReader(new InputStreamReader(stream))) {
57 | StringBuilder text = new StringBuilder();
58 | for (int c; (c = reader.read()) >= 0; ) {
59 | if (c == ';') {
60 | statement.executeQuery(text.toString());
61 | text.setLength(0);
62 | } else {
63 | text.append((char) c);
64 | }
65 | }
66 | if (!"".equals(text.toString().trim())) {
67 | statement.executeQuery(text.toString());
68 | }
69 |
70 | } catch (Exception e) {
71 | throw new RuntimeException(e);
72 | }
73 | }
74 | );
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/crud/ProductGrid.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.crud;
2 |
3 | import java.util.Comparator;
4 | import java.util.stream.Collectors;
5 |
6 | import com.vaadin.framework8.samples.backend.data.Availability;
7 | import com.vaadin.framework8.samples.backend.data.Category;
8 | import com.vaadin.framework8.samples.backend.data.Product;
9 | import com.vaadin.icons.VaadinIcons;
10 | import com.vaadin.ui.Grid;
11 | import com.vaadin.ui.renderers.HtmlRenderer;
12 | import com.vaadin.ui.renderers.NumberRenderer;
13 |
14 | /**
15 | * Grid of products, handling the visual presentation and filtering of a set of
16 | * items. This version uses an in-memory data provider that is suitable for
17 | * small data sets.
18 | */
19 | public class ProductGrid extends Grid {
20 |
21 | public ProductGrid() {
22 | setSizeFull();
23 |
24 | addColumn(p -> String.valueOf(p.getId())).setCaption("Id")
25 | .setSortProperty("id");
26 | addColumn(Product::getProductName).setCaption("Product Name")
27 | .setSortProperty("productName");
28 | addColumn(Product::getPrice, new NumberRenderer()).setCaption("Price")
29 | .setStyleGenerator(c -> "align-right").setSortProperty("price");
30 | addColumn(p -> {
31 | Availability availability = p.getAvailability();
32 | return getTrafficLightIconHtml(availability) + " "
33 | + availability.name();
34 | }, new HtmlRenderer()).setCaption("Availability")
35 | .setSortProperty("availability");
36 | addColumn(Product::getStockCount, new NumberRenderer())
37 | .setCaption("Stock Count").setStyleGenerator(c -> "align-right")
38 | .setSortProperty("stockCount");
39 | addColumn(p -> p.getCategory().stream()
40 | .sorted(Comparator.comparing(Category::getId))
41 | .map(Category::getName).collect(Collectors.joining(", ")))
42 | .setCaption("Category").setSortable(false);
43 | }
44 |
45 | private String getTrafficLightIconHtml(Availability availability) {
46 | String color = "";
47 | if (availability == Availability.AVAILABLE) {
48 | color = "#2dd085";
49 | } else if (availability == Availability.COMING) {
50 | color = "#ffc66e";
51 | } else if (availability == Availability.DISCONTINUED) {
52 | color = "#f54993";
53 | }
54 |
55 | String iconCode = ""
58 | + Integer.toHexString(VaadinIcons.CIRCLE.getCodepoint())
59 | + ";";
60 | return iconCode;
61 | }
62 |
63 | public Product getSelectedRow() {
64 | return asSingleSelect().getValue();
65 | }
66 |
67 | public void refresh(Product product) {
68 | getDataCommunicator().refresh(product);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/rest-json-dataprovider-demo/src/main/java/com/vaadin/framework8/demo/restjson/RestDataProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 Vaadin Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.vaadin.framework8.demo.restjson;
17 |
18 | import java.io.IOException;
19 | import java.net.URL;
20 | import java.nio.charset.StandardCharsets;
21 | import java.util.AbstractList;
22 | import java.util.logging.Level;
23 | import java.util.logging.Logger;
24 | import java.util.stream.IntStream;
25 | import java.util.stream.Stream;
26 |
27 | import org.apache.commons.io.IOUtils;
28 |
29 | import com.vaadin.data.provider.AbstractBackEndDataProvider;
30 | import com.vaadin.data.provider.Query;
31 |
32 | import elemental.json.Json;
33 | import elemental.json.JsonArray;
34 | import elemental.json.JsonObject;
35 | import elemental.json.JsonValue;
36 |
37 | public class RestDataProvider
38 | extends AbstractBackEndDataProvider {
39 |
40 | private String restApiUrl;
41 |
42 | public RestDataProvider(String restApiUrl) {
43 | this.restApiUrl = restApiUrl;
44 | }
45 |
46 | @Override
47 | public Stream fetchFromBackEnd(Query query) {
48 | URL url;
49 | try {
50 | url = new URL(restApiUrl);
51 | String jsonData = IOUtils.toString(url, StandardCharsets.UTF_8);
52 | JsonObject json = Json.parse(jsonData);
53 |
54 | JsonArray results = json.getArray("results");
55 | return stream(results);
56 | } catch (IOException e) {
57 | Logger.getLogger(getClass().getName()).log(Level.SEVERE,
58 | "Error fetching JSON", e);
59 | // Must return something which matches size, or grid will keep
60 | // asking and asking...
61 | return IntStream.range(0, 200).mapToObj(i -> Json.createObject());
62 | }
63 | }
64 |
65 | @Override
66 | public int sizeInBackEnd(Query query) {
67 | return 200;
68 | }
69 |
70 | /**
71 | * Creates a stream from a JSON array.
72 | *
73 | * @param array
74 | * the JSON array to create a stream from
75 | * @return a stream of JSON values
76 | */
77 | private static Stream stream(JsonArray array) {
78 | assert array != null;
79 | return new AbstractList() {
80 | @Override
81 | public T get(int index) {
82 | return array.get(index);
83 | }
84 |
85 | @Override
86 | public int size() {
87 | return array.length();
88 | }
89 | }.stream();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/todomvc/src/main/java/com/vaadin/tutorial/todomvc/TodoJDBCDataProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 Vaadin Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.vaadin.tutorial.todomvc;
17 |
18 | import java.sql.Connection;
19 | import java.sql.PreparedStatement;
20 | import java.sql.ResultSet;
21 | import java.sql.SQLException;
22 |
23 | import com.vaadin.data.provider.Query;
24 |
25 | /**
26 | * JDBC DataProvider implementation with filtering supported.
27 | */
28 | class TodoJDBCDataProvider extends PreparedJDBCDataProvider {
29 |
30 | private final PreparedStatement resultSetStatement;
31 | private final PreparedStatement sizeStatement;
32 |
33 | private final PreparedStatement resultSetStatementFiltered;
34 | private final PreparedStatement sizeStatementFiltered;
35 |
36 | public TodoJDBCDataProvider(Connection connection) throws SQLException {
37 | super(connection, resultSet -> {
38 | Todo todo = new Todo();
39 | todo.setId(resultSet.getInt("id"));
40 | todo.setText(resultSet.getString("text"));
41 | todo.setCompleted(resultSet.getBoolean("completed"));
42 | return todo;
43 | });
44 |
45 | resultSetStatementFiltered =
46 | openStatement("SELECT * FROM todo WHERE completed = ?");
47 | sizeStatementFiltered =
48 | openStatement("SELECT count(*) FROM todo WHERE completed = ?");
49 |
50 | resultSetStatement = openStatement("SELECT * FROM todo");
51 | sizeStatement = openStatement("SELECT count(*) FROM todo");
52 |
53 | }
54 |
55 | @Override
56 | protected synchronized ResultSet rowCountStatement(Query query) throws SQLException {
57 | TaskFilter taskFilter = obtainFilterValue(query);
58 | if (taskFilter == TaskFilter.ALL) {
59 | return sizeStatement.executeQuery();
60 | } else {
61 | sizeStatementFiltered.setBoolean(1,
62 | taskFilter == TaskFilter.COMPLETED);
63 | return sizeStatementFiltered.executeQuery();
64 | }
65 | }
66 |
67 | @Override
68 | protected ResultSet resultSetStatement(
69 | Query query) throws SQLException {
70 | TaskFilter taskFilter = obtainFilterValue(query);
71 | if (taskFilter == TaskFilter.ALL) {
72 | return resultSetStatement.executeQuery();
73 | } else {
74 | resultSetStatementFiltered.setBoolean(1,
75 | taskFilter == TaskFilter.COMPLETED);
76 | return resultSetStatementFiltered.executeQuery();
77 | }
78 | }
79 |
80 | private TaskFilter obtainFilterValue(Query query) {
81 | assert query.getSortOrders() == null || query.getSortOrders().isEmpty();
82 | return query.getFilter().orElse(TaskFilter.ALL);
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/addressbook/README.md:
--------------------------------------------------------------------------------
1 | Addressbook Tutorial
2 | ====================
3 |
4 | This tutorial teaches you some of the basic concepts in [Vaadin Framework](https://vaadin.com). It is meant to be
5 | a fast read for learning how to get started - not an example on how application should be
6 | designed. Please note this example uses and requires Java 8 to work.
7 |
8 | 
9 |
10 |
11 | Running the example from the command line
12 | -------------------
13 | ```
14 | $ mvn jetty:run
15 | ```
16 |
17 | Open [http://localhost:8080/](http://localhost:8080/)
18 |
19 |
20 | Importing in IntelliJ IDEA 14
21 | --------------------
22 | These instructions were tested on IntelliJ IDEA 14 CE. You can get it from https://www.jetbrains.com/idea/
23 |
24 | To get the project up and running in IDEA, do:
25 | - File -> New -> Project from Version Control -> Git
26 | - The URL to use is https://github.com/vaadin/addressbook.git
27 | - If you get a message about "Non-managed pom.xml file found". Choose "Add as Maven Project"
28 | - If you get a message about no JDK or SDK being selected. Choose "Configure" and select your installed JDK. You can also set the JDK using File -> Project Structure
29 | - To start the project, find the "Maven Projects" tab on the right hand side of the screen and navigate to
30 | - Vaadin Web Application -> Plugins -> jetty -> jetty:run
31 | - Click the play button or right click and select Run (Select Debug instead to run in debug mode)
32 |
33 | You should now have a Jetty server running on localhost:8888. Navigate to http://localhost:8888 to play with the application
34 |
35 | Importing in NetBeans 8
36 | --------------------
37 | These instructions were tested on NetBeans 8.0.2. You can get it from https://www.netbeans.org
38 |
39 | To checkout and run the project in NetBeans, do:
40 | - Team -> Git -> Clone
41 | - Set repository URL to https://github.com/vaadin/addressbook.git
42 | - Finish
43 | - Right click the imported project (Vaadin Addressbook Application) and select Run
44 | - Select GlassFish Server 4.1 -> Remember in Current IDE Session -> OK
45 |
46 | You should now have a GlassFish server running on localhost:8080 and a browser tab should also be automatically opened with this location
47 |
48 | Importing in Eclipse
49 | --------------------
50 | These instructions were tested on Eclipse IDE for Java EE Developers Luna SR2. You can get it from http://eclipse.org/downloads/
51 |
52 | To checkout and run the project in Eclipse, do:
53 | - File -> Import...
54 | - Check out Maven Projects from SCM
55 | - Choose Git from SCM menu
56 | - If you do not see "Git" in the SCM menu, click "Find more SCM connectors in the m2e Marketplace" and install "m2e-egit". Restart Eclipse and start over.
57 | - Set the repository URL to https://github.com/vaadin/addressbook.git
58 | - Right click the imported "addressbook" and choose Run As -> Maven Build...
59 | - Set the goal to "jetty:run" and click "Run"
60 |
61 | You should now have a Jetty server running on localhost:8080. Navigate to [http://localhost:8080/](http://localhost:8080/) to play with the application
62 |
63 | To use the built in server adapters of Eclipse, instead of doing "Run As -> Maven Build..." you can do
64 | - Run As -> Run on Server
65 | - Select the server you want to run on, e.g. Apache Tomcat 8 and click ok
66 | - *Do not use the suggested J2EE Preview server* as it is outdated, deprecated and does not support Servlet 3, which is required for this application
67 |
--------------------------------------------------------------------------------
/addressbook/src/main/java/com/vaadin/tutorial/addressbook/backend/Contact.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.tutorial.addressbook.backend;
2 |
3 | import org.apache.commons.beanutils.BeanUtils;
4 |
5 | import java.io.Serializable;
6 | import java.time.Instant;
7 | import java.time.LocalDate;
8 | import java.util.Objects;
9 |
10 | /**
11 | * A simple DTO for the address book example.
12 | *
13 | * Serializable and cloneable Java Object that are typically persisted in the
14 | * database and can also be easily converted to different formats like JSON.
15 | */
16 | // Backend DTO class. This is just a typical Java backend implementation
17 | // class and nothing Vaadin specific.
18 | public class Contact implements Serializable, Cloneable {
19 |
20 | private Long id;
21 |
22 | private String firstName = "";
23 | private String lastName = "";
24 | private String phone = "";
25 | private String email = "";
26 | private LocalDate birthDate;
27 | private boolean doNotCall;
28 | private Instant createdTimestamp;
29 |
30 | public Contact() {
31 | createdTimestamp = Instant.now();
32 | }
33 |
34 | public long getCreatedTimestamp() {
35 | return createdTimestamp.toEpochMilli();
36 | }
37 |
38 | public boolean isDoNotCall() {
39 | return doNotCall;
40 | }
41 |
42 | public void setDoNotCall(boolean doNotCall) {
43 | this.doNotCall = doNotCall;
44 | }
45 |
46 | public Long getId() {
47 | return id;
48 | }
49 |
50 | public void setId(Long id) {
51 | this.id = id;
52 | }
53 |
54 | public String getFirstName() {
55 | return firstName;
56 | }
57 |
58 | public void setFirstName(String firstName) {
59 | this.firstName = firstName;
60 | }
61 |
62 | public String getLastName() {
63 | return lastName;
64 | }
65 |
66 | public void setLastName(String lastName) {
67 | this.lastName = lastName;
68 | }
69 |
70 | public String getPhone() {
71 | return phone;
72 | }
73 |
74 | public void setPhone(String phone) {
75 | this.phone = phone;
76 | }
77 |
78 | public String getEmail() {
79 | return email;
80 | }
81 |
82 | public void setEmail(String email) {
83 | this.email = email;
84 | }
85 |
86 | public LocalDate getBirthDate() {
87 | return birthDate;
88 | }
89 |
90 | public void setBirthDate(LocalDate birthDate) {
91 | this.birthDate = birthDate;
92 | }
93 |
94 | @Override
95 | public Contact clone() throws CloneNotSupportedException {
96 | try {
97 | Contact contact = (Contact) BeanUtils.cloneBean(this);
98 | contact.createdTimestamp = createdTimestamp;
99 | return contact;
100 | } catch (Exception ex) {
101 | throw new CloneNotSupportedException();
102 | }
103 | }
104 |
105 | public boolean containsText(String text) {
106 | text = text.toLowerCase();
107 |
108 | return Objects.toString(id, "").toLowerCase().contains(text)
109 | || Objects.toString(firstName, "").toLowerCase().contains(text)
110 | || Objects.toString(lastName, "").toLowerCase().contains(text)
111 | || Objects.toString(phone, "").toLowerCase().contains(text)
112 | || Objects.toString(email, "").toLowerCase().contains(text)
113 | || Objects.toString(birthDate, "").toLowerCase().contains(text);
114 | }
115 |
116 | @Override
117 | public String toString() {
118 | return "Contact{" + "id=" + id + ", firstName=" + firstName
119 | + ", lastName=" + lastName + ", phone=" + phone + ", email="
120 | + email + ", birthDate=" + birthDate + ", createdTimestamp="
121 | + createdTimestamp + ",doNotCall=" + doNotCall + '}';
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-backend/src/test/java/com/vaadin/framework8/samples/backend/DataServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.backend;
2 |
3 | import java.util.Collection;
4 | import java.util.Optional;
5 |
6 | import org.junit.Assert;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.test.context.junit4.SpringRunner;
13 |
14 | import com.vaadin.framework8.samples.backend.data.Category;
15 | import com.vaadin.framework8.samples.backend.data.Product;
16 | import com.vaadin.framework8.samples.backend.repository.CategoryRepository;
17 | import com.vaadin.framework8.samples.backend.repository.ProductRepository;
18 |
19 | /**
20 | * Simple unit test for the back-end data service.
21 | */
22 | @RunWith(SpringRunner.class)
23 | @SpringBootTest
24 | @DataJpaTest
25 | public class DataServiceTest {
26 |
27 | @Autowired
28 | private DataService service;
29 |
30 | @Autowired
31 | private ProductRepository productRepository;
32 |
33 | @Autowired
34 | private CategoryRepository categoryRepository;
35 |
36 | @Test
37 | public void update_product() {
38 | long count = productRepository.count();
39 | Product save = insertProduct("foo");
40 |
41 | Assert.assertNotEquals(-1, save.getId());
42 |
43 | Assert.assertEquals(count + 1, productRepository.count());
44 | Assert.assertEquals("foo", save.getProductName());
45 |
46 | save.setProductName("bar");
47 |
48 | Product update = service.updateProduct(save);
49 | Assert.assertEquals("bar", update.getProductName());
50 | }
51 |
52 | @Test
53 | public void dataServiceCanFetchProducts() {
54 | Product created = insertProduct("foo");
55 |
56 | Collection allProducts = service.getAllProducts();
57 | Optional found = allProducts.stream()
58 | .filter(product -> product.getId() == created.getId())
59 | .findFirst();
60 | Assert.assertTrue(found.isPresent());
61 | Assert.assertEquals(created.getProductName(),
62 | found.get().getProductName());
63 | }
64 |
65 | @Test
66 | public void dataServiceCanFetchCategories() {
67 | Category category = new Category();
68 | category.setName("foo");
69 |
70 | long count = categoryRepository.count();
71 | Category created = categoryRepository.save(category);
72 | Assert.assertNotEquals(-1, created.getId());
73 |
74 | Assert.assertEquals(count + 1, categoryRepository.count());
75 |
76 | Collection allProducts = service.getAllCategories();
77 | Optional found = allProducts.stream()
78 | .filter(cat -> cat.getId() == created.getId()).findFirst();
79 | Assert.assertTrue(found.isPresent());
80 | Assert.assertEquals(created.getName(), found.get().getName());
81 | }
82 |
83 | @Test
84 | public void deleteProduct() {
85 | Product created = insertProduct("foo");
86 | long count = productRepository.count();
87 |
88 | service.deleteProduct(created.getId());
89 | Assert.assertEquals(count - 1, productRepository.count());
90 |
91 | Assert.assertNull(productRepository.findOne(created.getId()));
92 | }
93 |
94 | @Test
95 | public void getProduct() {
96 | Product created = insertProduct("foo");
97 |
98 | Product product = service.getProduct(created.getId());
99 | Assert.assertEquals(created.getId(), product.getId());
100 | Assert.assertEquals(created.getProductName(), product.getProductName());
101 | }
102 |
103 | private Product insertProduct(String name) {
104 | Product product = new Product();
105 | product.setProductName(name);
106 |
107 | return productRepository.save(product);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/addressbook/src/main/java/com/vaadin/tutorial/addressbook/LeftPanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 Vaadin Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.vaadin.tutorial.addressbook;
17 |
18 | import com.vaadin.annotations.DesignRoot;
19 | import com.vaadin.tutorial.addressbook.backend.Contact;
20 | import com.vaadin.tutorial.addressbook.backend.ContactService;
21 | import com.vaadin.ui.Button;
22 | import com.vaadin.ui.Grid;
23 | import com.vaadin.ui.TextField;
24 | import com.vaadin.ui.VerticalLayout;
25 | import com.vaadin.ui.declarative.Design;
26 | import com.vaadin.ui.renderers.DateRenderer;
27 |
28 | import java.text.SimpleDateFormat;
29 | import java.time.ZoneId;
30 | import java.util.Date;
31 | import java.util.function.Consumer;
32 |
33 | /**
34 | * @author Vaadin Ltd
35 | */
36 | @DesignRoot
37 | public class LeftPanel extends VerticalLayout {
38 |
39 | /*
40 | * Hundreds of widgets. Vaadin's user interface components are just Java
41 | * objects that encapsulate and handle cross-browser support and
42 | * client-server communication. The default Vaadin components are in the
43 | * com.vaadin.ui package and there are over 500 more in
44 | * vaadin.com/directory.
45 | */
46 | private Grid contactList;
47 | private TextField filter;
48 | private Button newContact;
49 |
50 | void addEditListener(Runnable editListener) {
51 | /*
52 | * Synchronous event handling.
53 | *
54 | * Receive user interaction events on the server-side. This allows you
55 | * to synchronously handle those events. Vaadin automatically sends only
56 | * the needed changes to the web page without loading a new page.
57 | */
58 | newContact.addClickListener(e -> editListener.run());
59 |
60 | }
61 |
62 | void addFilterListener(Consumer listener) {
63 | filter.addValueChangeListener(e -> listener.accept(e.getValue()));
64 | }
65 |
66 | public LeftPanel() {
67 | Design.read(this);
68 | contactList.addColumn(Contact::getFirstName).setCaption("First Name");
69 | contactList.addColumn(Contact::getLastName).setCaption("Last Name");
70 | contactList.addColumn(Contact::getEmail).setCaption("Email");
71 | contactList
72 | .addColumn(
73 | c -> c.getBirthDate() == null ? null : Date.from(c.getBirthDate()
74 | .atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()),
75 | new DateRenderer(new SimpleDateFormat("M/d/yy")))
76 | .setCaption("Birth Date");
77 |
78 | contactList.addColumn(c -> c.isDoNotCall() ? "DO NOT CALL" : "")
79 | .setCaption("Do Not Call");
80 | }
81 |
82 | void refresh(String filter) {
83 | contactList.setItems(ContactService.getDemoService().findAll(filter));
84 | }
85 |
86 | void refresh() {
87 | refresh(getFilterValue());
88 | }
89 |
90 | void addSelectionListener(Consumer listener) {
91 | contactList.asSingleSelect()
92 | .addValueChangeListener(e -> listener.accept(e.getValue()));
93 | }
94 |
95 | void deselect() {
96 | Contact value = contactList.asSingleSelect().getValue();
97 | if (value != null) {
98 | contactList.getSelectionModel().deselect(value);
99 | }
100 | }
101 |
102 | String getFilterValue() {
103 | return filter.getValue();
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/SampleUI.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 |
5 | import com.vaadin.annotations.Push;
6 | import com.vaadin.annotations.Theme;
7 | import com.vaadin.annotations.Viewport;
8 | import com.vaadin.framework8.samples.about.AboutView;
9 | import com.vaadin.framework8.samples.authentication.AccessControl;
10 | import com.vaadin.framework8.samples.authentication.LoginScreen;
11 | import com.vaadin.framework8.samples.crud.SampleCrudView;
12 | import com.vaadin.icons.VaadinIcons;
13 | import com.vaadin.navigator.Navigator;
14 | import com.vaadin.navigator.ViewChangeListener;
15 | import com.vaadin.server.Responsive;
16 | import com.vaadin.server.VaadinRequest;
17 | import com.vaadin.spring.annotation.SpringUI;
18 | import com.vaadin.spring.navigator.SpringViewProvider;
19 | import com.vaadin.ui.CssLayout;
20 | import com.vaadin.ui.HorizontalLayout;
21 | import com.vaadin.ui.UI;
22 | import com.vaadin.ui.themes.ValoTheme;
23 |
24 | /**
25 | * Main UI class of the application that shows either the login screen or the
26 | * main view of the application depending on whether a user is signed in.
27 | *
28 | * The @Viewport annotation configures the viewport meta tags appropriately on
29 | * mobile devices. Instead of device based scaling (default), using responsive
30 | * layouts.
31 | */
32 | @Viewport("user-scalable=no,initial-scale=1.0")
33 | @Theme("mytheme")
34 | @SpringUI
35 | @Push
36 | public class SampleUI extends UI {
37 |
38 | @Autowired
39 | private AccessControl accessControl;
40 |
41 | @Autowired
42 | private SpringViewProvider viewProvider;
43 |
44 | private Menu menu;
45 |
46 | @Override
47 | protected void init(VaadinRequest vaadinRequest) {
48 | Responsive.makeResponsive(this);
49 | setLocale(vaadinRequest.getLocale());
50 | getPage().setTitle("My");
51 | if (!accessControl.isUserSignedIn()) {
52 | setContent(new LoginScreen(accessControl, this::showMainView));
53 | } else {
54 | showMainView();
55 | }
56 | }
57 |
58 | protected void showMainView() {
59 | addStyleName(ValoTheme.UI_WITH_MENU);
60 |
61 | HorizontalLayout layout = new HorizontalLayout();
62 | setContent(layout);
63 |
64 | layout.setStyleName("main-screen");
65 |
66 | CssLayout viewContainer = new CssLayout();
67 | viewContainer.addStyleName("valo-content");
68 | viewContainer.setSizeFull();
69 |
70 | Navigator navigator = new Navigator(this, viewContainer);
71 | navigator.addProvider(viewProvider);
72 | navigator.setErrorView(ErrorView.class);
73 |
74 | menu = new Menu(navigator);
75 | // View are registered automatically by Vaadin Spring support
76 | menu.addViewButton(SampleCrudView.VIEW_NAME, SampleCrudView.VIEW_NAME,
77 | VaadinIcons.EDIT);
78 | menu.addViewButton(AboutView.VIEW_NAME, AboutView.VIEW_NAME,
79 | VaadinIcons.INFO_CIRCLE);
80 |
81 | navigator.addViewChangeListener(new ViewChangeHandler());
82 |
83 | layout.addComponent(menu);
84 | layout.addComponent(viewContainer);
85 | layout.setExpandRatio(viewContainer, 1);
86 | layout.setSizeFull();
87 | layout.setSpacing(false);
88 |
89 | navigator.navigateTo(SampleCrudView.VIEW_NAME);
90 | }
91 |
92 | public static SampleUI get() {
93 | return (SampleUI) UI.getCurrent();
94 | }
95 |
96 | public AccessControl getAccessControl() {
97 | return accessControl;
98 | }
99 |
100 | private class ViewChangeHandler implements ViewChangeListener {
101 |
102 | @Override
103 | public boolean beforeViewChange(ViewChangeEvent event) {
104 | return true;
105 | }
106 |
107 | @Override
108 | public void afterViewChange(ViewChangeEvent event) {
109 | menu.setActiveView(event.getViewName());
110 | }
111 |
112 | };
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/todomvc/src/test/java/com/vaadin/tutorial/todomvc/TestDataProviderLimits.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 Vaadin Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.vaadin.tutorial.todomvc;
17 |
18 | import static org.junit.Assert.assertEquals;
19 |
20 | import java.sql.Connection;
21 | import java.sql.DriverManager;
22 | import java.sql.PreparedStatement;
23 | import java.sql.SQLException;
24 | import java.sql.Statement;
25 | import java.util.Collections;
26 | import java.util.List;
27 | import java.util.stream.Collectors;
28 |
29 | import org.junit.AfterClass;
30 | import org.junit.BeforeClass;
31 | import org.junit.Test;
32 |
33 | import com.vaadin.data.provider.Query;
34 |
35 | /**
36 | * Test JDBC
37 | *
38 | * @author Vaadin Ltd
39 | */
40 | public class TestDataProviderLimits {
41 | private static Connection conn;
42 | private static SimpleJDBCDataProvider dataProvider;
43 |
44 | @BeforeClass
45 | public static void setUpAll() throws SQLException {
46 | DriverManager.registerDriver(org.hsqldb.jdbc.JDBCDriver.driverInstance);
47 | conn = DriverManager.getConnection("jdbc:hsqldb:mem:dataproviderdb",
48 | "SA", "");
49 | // For safety sake
50 | try (Statement statement = conn.createStatement()) {
51 | statement.executeUpdate("DROP TABLE long_table");
52 | } catch (SQLException ignored) {
53 | }
54 | try (Statement statement = conn.createStatement()) {
55 | statement.executeUpdate(
56 | "CREATE TABLE long_table (i INTEGER PRIMARY KEY)");
57 | }
58 | try (PreparedStatement preparedStatement = conn
59 | .prepareStatement("INSERT INTO long_table VALUES (?)")) {
60 | for (int i = 0; i < 100; i++) {
61 | preparedStatement.setInt(1, i);
62 | preparedStatement.executeUpdate();
63 | }
64 | }
65 | dataProvider = new SimpleJDBCDataProvider<>(conn,
66 | "SELECT i FROM long_table ORDER BY i",
67 | resultSet -> resultSet.getInt(1));
68 | }
69 |
70 | private void doRetrieveTest(int offset, int limit, int expectedFirst,
71 | int expectedLast) {
72 | Query query = new Query<>(offset, limit,
73 | Collections.emptyList(), null, null);
74 | int size = dataProvider.size(query);
75 | assertEquals("Response size", expectedLast - expectedFirst + 1, size);
76 | List values = dataProvider.fetch(query)
77 | .collect(Collectors.toList());
78 | assertEquals(size, values.size());
79 | for (int i = 0; i < values.size(); i++) {
80 | assertEquals(i + expectedFirst, values.get(i).intValue());
81 | }
82 | }
83 |
84 | @Test
85 | public void retrieveInfinite() {
86 | doRetrieveTest(0, Integer.MAX_VALUE, 0, 99);
87 | }
88 |
89 | @Test
90 | public void retrieve100() {
91 | doRetrieveTest(0, 100, 0, 99);
92 | }
93 |
94 | @Test
95 | public void retrieve20() {
96 | doRetrieveTest(0, 20, 0, 19);
97 | }
98 |
99 | @Test
100 | public void retrieve20Shift() {
101 | doRetrieveTest(5, 20, 5, 24);
102 | }
103 |
104 | @Test
105 | public void retrieveEndOfRange() {
106 | doRetrieveTest(90, 20, 90, 99);
107 | }
108 |
109 | @AfterClass
110 | public static void tearDown() throws Exception {
111 | try (Statement statement = conn.createStatement()) {
112 | statement.executeUpdate("DROP TABLE long_table");
113 | }
114 | dataProvider.close();
115 | conn.close();
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/addressbook/src/main/java/com/vaadin/tutorial/addressbook/backend/ContactService.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.tutorial.addressbook.backend;
2 |
3 | import java.time.LocalDate;
4 | import java.util.ArrayList;
5 | import java.util.Collections;
6 | import java.util.Comparator;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.Random;
10 | import java.util.logging.Level;
11 | import java.util.logging.Logger;
12 |
13 | /**
14 | * Separate Java service class. Backend implementation for the address book
15 | * application, with "detached entities" simulating real world DAO. Typically
16 | * these something that the Java EE or Spring backend services provide.
17 | */
18 | // Backend service class. This is just a typical Java backend implementation
19 | // class and nothing Vaadin specific.
20 | public class ContactService {
21 |
22 | // Create dummy data by randomly combining first and last names
23 | static String[] fnames = { "Peter", "Alice", "John", "Mike", "Olivia",
24 | "Nina", "Alex", "Rita", "Dan", "Umberto", "Henrik", "Rene", "Lisa",
25 | "Linda", "Timothy", "Daniel", "Brian", "George", "Scott",
26 | "Jennifer" };
27 | static String[] lnames = { "Smith", "Johnson", "Williams", "Jones", "Brown",
28 | "Davis", "Miller", "Wilson", "Moore", "Taylor", "Anderson",
29 | "Thomas", "Jackson", "White", "Harris", "Martin", "Thompson",
30 | "Young", "King", "Robinson" };
31 |
32 | private static final ContactService INSTANCE = createDemoService();
33 |
34 | public static ContactService getDemoService() {
35 | return INSTANCE;
36 | }
37 |
38 | private static ContactService createDemoService() {
39 | final ContactService contactService = new ContactService();
40 |
41 | Random r = new Random(0);
42 | for (int i = 0; i < 100; i++) {
43 | Contact contact = new Contact();
44 | contact.setFirstName(fnames[r.nextInt(fnames.length)]);
45 | contact.setLastName(lnames[r.nextInt(fnames.length)]);
46 | contact.setEmail(contact.getFirstName().toLowerCase() + "@"
47 | + contact.getLastName().toLowerCase() + ".com");
48 | contact.setPhone("+ 358 555 " + (100 + r.nextInt(900)));
49 | LocalDate birthday = LocalDate.of(1930 + r.nextInt(70),
50 | 1 + r.nextInt(11), 1 + r.nextInt(27));
51 | contact.setBirthDate(birthday);
52 | contact.setDoNotCall(r.nextBoolean());
53 | contactService.save(contact);
54 | }
55 | return contactService;
56 | }
57 |
58 | private HashMap contacts = new HashMap<>();
59 | private long nextId = 0;
60 |
61 | public synchronized List findAll(String stringFilter) {
62 | ArrayList arrayList = new ArrayList<>();
63 | for (Contact contact : contacts.values()) {
64 | try {
65 | boolean passesFilter = stringFilter == null
66 | || stringFilter.isEmpty()
67 | || contact.containsText(stringFilter);
68 | if (passesFilter) {
69 | arrayList.add(contact.clone());
70 | }
71 | } catch (CloneNotSupportedException ex) {
72 | Logger.getLogger(ContactService.class.getName())
73 | .log(Level.SEVERE, null, ex);
74 | }
75 | }
76 | Collections.sort(arrayList, new Comparator() {
77 |
78 | @Override
79 | public int compare(Contact o1, Contact o2) {
80 | return (int) (o2.getId() - o1.getId());
81 | }
82 | });
83 | return arrayList;
84 | }
85 |
86 | public synchronized long count() {
87 | return contacts.size();
88 | }
89 |
90 | public synchronized void delete(Contact value) {
91 | contacts.remove(value.getId());
92 | }
93 |
94 | public synchronized void save(Contact entry) {
95 | if (entry.getId() == null) {
96 | entry.setId(nextId++);
97 | }
98 | try {
99 | entry = entry.clone();
100 | } catch (Exception ex) {
101 | throw new RuntimeException(ex);
102 | }
103 | contacts.put(entry.getId(), entry);
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/todomvc/src/main/java/com/vaadin/tutorial/todomvc/AbstractJDBCDataProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 Vaadin Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.vaadin.tutorial.todomvc;
17 |
18 | import com.vaadin.data.provider.AbstractBackEndDataProvider;
19 | import com.vaadin.data.provider.Query;
20 |
21 | import java.sql.Connection;
22 | import java.sql.ResultSet;
23 | import java.sql.SQLException;
24 | import java.sql.SQLFeatureNotSupportedException;
25 | import java.util.List;
26 | import java.util.Objects;
27 | import java.util.logging.Level;
28 | import java.util.logging.Logger;
29 | import java.util.stream.Stream;
30 |
31 | /**
32 | * Vaadin DataProvider over pure JDBC, base class.
33 | *
34 | * @param data transfer object. Might be POJO or Map.
35 | * @author Vaadin Ltd
36 | */
37 | @SuppressWarnings("WeakerAccess")
38 | public abstract class AbstractJDBCDataProvider
39 | extends AbstractBackEndDataProvider implements AutoCloseable {
40 | private static final Logger LOGGER = Logger
41 | .getLogger(AbstractJDBCDataProvider.class.getName());
42 | protected final java.sql.Connection connection;
43 | protected final DataRetriever jdbcReader;
44 |
45 | private int cachedSize = -1;
46 |
47 | public AbstractJDBCDataProvider(Connection connection,
48 | DataRetriever jdbcReader) {
49 | this.connection = Objects.requireNonNull(connection);
50 | this.jdbcReader = Objects.requireNonNull(jdbcReader);
51 | }
52 |
53 | protected static void closeResources(List extends AutoCloseable> statements) {
54 | for (AutoCloseable closeable : statements) {
55 | try {
56 | closeable.close();
57 | } catch (Exception e) {
58 | LOGGER.log(Level.WARNING,
59 | "Prepared closeable was closed with error", e);
60 | }
61 | }
62 | }
63 |
64 | @Override
65 | protected int sizeInBackEnd(Query query) {
66 | if (cachedSize < 0) {
67 | try (ResultSet resultSet = rowCountStatement(query)) {
68 | resultSet.next();
69 | cachedSize = resultSet.getInt(1);
70 | } catch (SQLException e) {
71 | throw new RuntimeException("Size SQL query failed", e);
72 | }
73 | }
74 | int size = cachedSize - query.getOffset();
75 | if (size < 0) {
76 | return 0;
77 | }
78 | return Math.min(size, query.getLimit());
79 | }
80 |
81 | protected abstract ResultSet rowCountStatement(Query query) throws SQLException;
82 |
83 | protected abstract ResultSet resultSetStatement(Query query) throws SQLException;
84 |
85 | @Override
86 | protected Stream fetchFromBackEnd(Query query) {
87 | try (ResultSet resultSet = resultSetStatement(query)){
88 | try {
89 | resultSet.absolute(query.getOffset());
90 | } catch (SQLFeatureNotSupportedException e) {
91 | for (int i = query.getOffset(); i > 0; i--) {
92 | resultSet.next();
93 | }
94 | }
95 | Stream.Builder builder = Stream.builder();
96 | for(int i =0; i < query.getLimit() && resultSet.next();i++) {
97 | builder.add(jdbcReader.readRow(resultSet));
98 | }
99 | return builder.build();
100 | } catch (SQLException e) {
101 | throw new RuntimeException("Data SQL query failed", e);
102 | }
103 | }
104 |
105 | @Override
106 | public void refreshAll() {
107 | cachedSize = -1;
108 | super.refreshAll();
109 | }
110 |
111 | @FunctionalInterface
112 | public interface DataRetriever {
113 | T readRow(ResultSet resultSet) throws SQLException;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/addressbook/src/main/java/com/vaadin/tutorial/addressbook/ContactForm.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.tutorial.addressbook;
2 |
3 | import com.vaadin.annotations.DesignRoot;
4 | import com.vaadin.data.Binder;
5 | import com.vaadin.data.Binder.Binding;
6 | import com.vaadin.data.validator.EmailValidator;
7 | import com.vaadin.event.ShortcutAction;
8 | import com.vaadin.server.SerializablePredicate;
9 | import com.vaadin.tutorial.addressbook.backend.Contact;
10 | import com.vaadin.tutorial.addressbook.backend.ContactService;
11 | import com.vaadin.ui.Button;
12 | import com.vaadin.ui.CheckBox;
13 | import com.vaadin.ui.DateField;
14 | import com.vaadin.ui.FormLayout;
15 | import com.vaadin.ui.Notification;
16 | import com.vaadin.ui.Notification.Type;
17 | import com.vaadin.ui.TextField;
18 | import com.vaadin.ui.declarative.Design;
19 | import com.vaadin.ui.themes.ValoTheme;
20 |
21 | /**
22 | * Create custom UI Components.
23 | *
24 | * Create your own Vaadin components by inheritance and composition. This is a
25 | * form component inherited from FormLayout. Use new Binder(Bean.class) and
26 | * binder.bindInstanceFields(form), to bind data fields from DTO to UI fields.
27 | * Similarly named field by naming convention or customized with @PropertyId
28 | * annotation.
29 | *
30 | * @author Vaadin Ltd
31 | */
32 | @DesignRoot
33 | public class ContactForm extends FormLayout {
34 |
35 | private TextField firstName;
36 | private TextField lastName;
37 | private TextField phone;
38 | private TextField email;
39 | private DateField birthDate;
40 | private CheckBox doNotCall;
41 | protected Button save;
42 | protected Button cancel;
43 |
44 | private final Binder binder = new Binder<>();
45 | private Contact contactBeingEdited;
46 |
47 | public ContactForm() {
48 | Design.read(this);
49 | configureComponents();
50 | }
51 |
52 | private void configureComponents() {
53 |
54 | final SerializablePredicate phoneOrEmailPredicate = v -> !phone
55 | .getValue().trim().isEmpty()
56 | || !email.getValue().trim().isEmpty();
57 |
58 | Binding emailBinding = binder.forField(email)
59 | .withValidator(phoneOrEmailPredicate,
60 | "Both phone and email cannot be empty")
61 | .withValidator(new EmailValidator("Incorrect email address"))
62 | .bind(Contact::getEmail, Contact::setEmail);
63 |
64 | Binding phoneBinding = binder.forField(phone)
65 | .withValidator(phoneOrEmailPredicate,
66 | "Both phone and email cannot be empty")
67 | .bind(Contact::getPhone, Contact::setPhone);
68 |
69 | // Trigger cross-field validation when the other field is changed
70 | email.addValueChangeListener(event -> phoneBinding.validate());
71 | phone.addValueChangeListener(event -> emailBinding.validate());
72 |
73 | firstName.setRequiredIndicatorVisible(true);
74 | lastName.setRequiredIndicatorVisible(true);
75 |
76 | binder.bind(firstName, Contact::getFirstName, Contact::setFirstName);
77 | binder.bind(lastName, Contact::getLastName, Contact::setLastName);
78 | binder.bind(doNotCall, Contact::isDoNotCall, Contact::setDoNotCall);
79 | binder.bind(birthDate, Contact::getBirthDate, Contact::setBirthDate);
80 |
81 | /*
82 | * Highlight primary actions.
83 | *
84 | * With Vaadin built-in styles you can highlight the primary save button
85 | * and give it a keyboard shortcut for a better UX.
86 | */
87 | save.setStyleName(ValoTheme.BUTTON_PRIMARY);
88 | save.setClickShortcut(ShortcutAction.KeyCode.ENTER);
89 |
90 | save.addClickListener(this::save);
91 | cancel.addClickListener(this::cancel);
92 |
93 | setVisible(false);
94 | }
95 |
96 | void edit(Contact contact) {
97 | contactBeingEdited = contact;
98 | if (contact != null) {
99 | binder.readBean(contact);
100 | firstName.focus();
101 | }
102 | setVisible(contact != null);
103 | }
104 |
105 | public void save(Button.ClickEvent event) {
106 | if (binder.writeBeanIfValid(contactBeingEdited)) {
107 | ContactService.getDemoService().save(contactBeingEdited);
108 |
109 | String msg = String.format("Saved '%s %s'.",
110 | contactBeingEdited.getFirstName(),
111 | contactBeingEdited.getLastName());
112 | Notification.show(msg, Type.TRAY_NOTIFICATION);
113 | getUI().getContent().refreshContacts();
114 | }
115 |
116 | }
117 |
118 | public void cancel(Button.ClickEvent event) {
119 | Notification.show("Cancelled", Type.TRAY_NOTIFICATION);
120 | getUI().getContent().deselect();
121 | }
122 |
123 | @Override
124 | public AddressbookUI getUI() {
125 | return (AddressbookUI) super.getUI();
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/tree-database-example/src/main/java/org/vaadin/example/treegrid/jdbc/TreeUI.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.example.treegrid.jdbc;
2 |
3 | import com.vaadin.annotations.VaadinServletConfiguration;
4 | import com.vaadin.data.ValueProvider;
5 | import com.vaadin.icons.VaadinIcons;
6 | import com.vaadin.server.Resource;
7 | import com.vaadin.server.VaadinRequest;
8 | import com.vaadin.server.VaadinServlet;
9 | import com.vaadin.ui.HorizontalLayout;
10 | import com.vaadin.ui.IconGenerator;
11 | import com.vaadin.ui.Panel;
12 | import com.vaadin.ui.Tree;
13 | import com.vaadin.ui.TreeGrid;
14 | import com.vaadin.ui.UI;
15 | import org.vaadin.example.treegrid.jdbc.pojo.Company;
16 | import org.vaadin.example.treegrid.jdbc.pojo.Department;
17 | import org.vaadin.example.treegrid.jdbc.pojo.NamedItem;
18 | import org.vaadin.example.treegrid.jdbc.pojo.Person;
19 |
20 | import javax.servlet.annotation.WebServlet;
21 | import java.util.Objects;
22 |
23 | /**
24 | * This UI is the application entry point.
25 | */
26 | @SuppressWarnings("unused")
27 | public class TreeUI extends UI {
28 |
29 | @Override
30 | protected void init(VaadinRequest vaadinRequest) {
31 | final HorizontalLayout layout = new HorizontalLayout();
32 | layout.setMargin(true);
33 | layout.setSizeFull();
34 | TreeGrid treeGrid = setupTreeGrid();
35 | treeGrid.setHeight("50%");
36 |
37 | Tree tree = setupTree();
38 | Panel treePanel = new Panel(tree);
39 | treePanel.setHeight("50%");
40 |
41 | layout.addComponentsAndExpand(treeGrid, treePanel);
42 |
43 | /* Next four listeners keep Tree and TreeGrid in sync - folders are open
44 | and closed synchronously in both components*/
45 | treeGrid.addExpandListener(expandEvent -> tree.expand(expandEvent.getExpandedItem()));
46 | treeGrid.addCollapseListener(expandEvent -> tree.collapse(expandEvent.getCollapsedItem()));
47 |
48 | tree.addExpandListener(expandEvent -> treeGrid.expand(expandEvent.getExpandedItem()));
49 | tree.addCollapseListener(expandEvent -> treeGrid.collapse(expandEvent.getCollapsedItem()));
50 |
51 | setContent(layout);
52 | }
53 |
54 | private TreeGrid setupTreeGrid() {
55 | TreeGrid treeGrid = new TreeGrid<>();
56 |
57 | treeGrid.addColumn(NamedItem::getName).setId("name").setCaption("Name");
58 | treeGrid.setHierarchyColumn("name");
59 |
60 | treeGrid.addColumn(ofPerson(Person::getFirstName)).setCaption("First Name");
61 | treeGrid.addColumn(ofPerson(Person::getLastName)).setCaption("Last Name");
62 | treeGrid.addColumn(new EmailGenerator()).setCaption("e-mail");
63 | treeGrid.addColumn(ofPerson(Person::getGender)).setCaption("Gender");
64 | treeGrid.setDataProvider(new PeopleDataProvider());
65 | return treeGrid;
66 | }
67 |
68 | private Tree setupTree() {
69 | Tree tree = new Tree<>();
70 | tree.setDataProvider(new PeopleDataProvider());
71 | tree.setItemCaptionGenerator(NamedItem::getName);
72 | tree.setItemIconGenerator(new PeopleIconGenerator());
73 | return tree;
74 | }
75 |
76 | @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
77 | @VaadinServletConfiguration(ui = TreeUI.class, productionMode = false)
78 | public static class MyUIServlet extends VaadinServlet {
79 | }
80 |
81 | private static ValueProvider ofPerson(ValueProvider personExtractor) {
82 | return (NamedItem item) -> {
83 | if (item instanceof Person) {
84 | return personExtractor.apply((Person) item);
85 | } else {
86 | return "--";
87 | }
88 | };
89 | }
90 |
91 | private static class PeopleIconGenerator implements IconGenerator {
92 | @Override
93 | public Resource apply(NamedItem p) {
94 | if (p instanceof Person) {
95 | String gender = Objects.toString(((Person) p).getGender(), "");
96 | switch (gender.toUpperCase()) {
97 | case "MALE":
98 | return VaadinIcons.MALE;
99 | case "FEMALE":
100 | return VaadinIcons.FEMALE;
101 | default:
102 | return VaadinIcons.USER;
103 | }
104 | } else if (p instanceof Department) {
105 | return VaadinIcons.GROUP;
106 | } else {
107 | return VaadinIcons.OFFICE;
108 | }
109 | }
110 | }
111 |
112 | public static class EmailGenerator implements ValueProvider {
113 |
114 | @Override
115 | public String apply(NamedItem namedItem) {
116 | if (namedItem instanceof Company) return ((Company) namedItem).getEmail();
117 | if (namedItem instanceof Person) return ((Person) namedItem).getEmail();
118 | return "--";
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/crud/SampleCrudLogic.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.crud;
2 |
3 | import java.io.Serializable;
4 |
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
7 | import org.springframework.context.ApplicationContext;
8 | import org.springframework.context.annotation.Scope;
9 |
10 | import com.vaadin.framework8.samples.SampleUI;
11 | import com.vaadin.framework8.samples.backend.DataService;
12 | import com.vaadin.framework8.samples.backend.data.Product;
13 | import com.vaadin.server.Page;
14 | import com.vaadin.spring.annotation.SpringComponent;
15 |
16 | /**
17 | * This class provides an interface for the logical operations between the CRUD
18 | * view, its parts like the product editor form and the data provider, including
19 | * fetching and saving products.
20 | *
21 | * Having this separate from the view makes it easier to test various parts of
22 | * the system separately, and to e.g. provide alternative views for the same
23 | * data.
24 | */
25 | @SpringComponent
26 | public class SampleCrudLogic implements Serializable {
27 |
28 | private SampleCrudView view;
29 |
30 | @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON)
31 | @SpringComponent
32 | public static class SampleCrudLogicFactory {
33 |
34 | @Autowired
35 | private ApplicationContext context;
36 |
37 | public SampleCrudLogic createLogic(SampleCrudView view) {
38 | SampleCrudLogic logic = context.getBean(SampleCrudLogic.class);
39 | logic.init(view);
40 | return logic;
41 | }
42 | }
43 |
44 | @Autowired
45 | private DataService dataService;
46 |
47 | private SampleCrudLogic() {
48 | }
49 |
50 | public void init() {
51 | editProduct(null);
52 | // Hide and disable if not admin
53 | if (!SampleUI.get().getAccessControl().isUserInRole("admin")) {
54 | view.setNewProductEnabled(false);
55 | }
56 | }
57 |
58 | public void cancelProduct() {
59 | setFragmentParameter("");
60 | view.clearSelection();
61 | view.editProduct(null);
62 | }
63 |
64 | /**
65 | * Update the fragment without causing navigator to change view
66 | */
67 | private void setFragmentParameter(String productId) {
68 | String fragmentParameter;
69 | if (productId == null || productId.isEmpty()) {
70 | fragmentParameter = "";
71 | } else {
72 | fragmentParameter = productId;
73 | }
74 |
75 | Page page = SampleUI.get().getPage();
76 | page.setUriFragment(
77 | "!" + SampleCrudView.VIEW_NAME + "/" + fragmentParameter,
78 | false);
79 | }
80 |
81 | public void enter(String productId) {
82 | if (productId != null && !productId.isEmpty()) {
83 | if (productId.equals("new")) {
84 | newProduct();
85 | } else {
86 | // Ensure this is selected even if coming directly here from
87 | // login
88 | try {
89 | int pid = Integer.parseInt(productId);
90 | Product product = findProduct(pid);
91 | view.selectRow(product);
92 | } catch (NumberFormatException e) {
93 | }
94 | }
95 | }
96 | }
97 |
98 | private Product findProduct(int productId) {
99 | return dataService.getProduct(productId);
100 | }
101 |
102 | public void saveProduct(Product product) {
103 | view.showSaveNotification(product.getProductName() + " ("
104 | + product.getId() + ") updated");
105 | view.clearSelection();
106 | view.editProduct(null);
107 | view.updateProduct(product);
108 | setFragmentParameter("");
109 | }
110 |
111 | public void deleteProduct(Product product) {
112 | dataService.deleteProduct(product.getId());
113 | view.showSaveNotification(product.getProductName() + " ("
114 | + product.getId() + ") removed");
115 |
116 | view.clearSelection();
117 | view.editProduct(null);
118 | view.removeProduct(product);
119 | setFragmentParameter("");
120 | }
121 |
122 | public void editProduct(Product product) {
123 | if (product == null) {
124 | setFragmentParameter("");
125 | } else {
126 | setFragmentParameter(product.getId() + "");
127 | }
128 | view.editProduct(product);
129 | }
130 |
131 | public void newProduct() {
132 | view.clearSelection();
133 | setFragmentParameter("new");
134 | view.editProduct(new Product());
135 | }
136 |
137 | public void rowSelected(Product product) {
138 | if (SampleUI.get().getAccessControl().isUserInRole("admin")) {
139 | view.editProduct(product);
140 | }
141 | }
142 |
143 | private void init(SampleCrudView view) {
144 | this.view = view;
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-backend/src/main/java/com/vaadin/framework8/samples/backend/MockDataGenerator.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.backend;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.ArrayList;
5 | import java.util.HashSet;
6 | import java.util.List;
7 | import java.util.Random;
8 | import java.util.Set;
9 |
10 | import javax.annotation.PostConstruct;
11 |
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
14 | import org.springframework.context.annotation.Scope;
15 | import org.springframework.stereotype.Component;
16 |
17 | import com.vaadin.framework8.samples.backend.data.Availability;
18 | import com.vaadin.framework8.samples.backend.data.Category;
19 | import com.vaadin.framework8.samples.backend.data.Product;
20 | import com.vaadin.framework8.samples.backend.repository.CategoryRepository;
21 | import com.vaadin.framework8.samples.backend.repository.ProductRepository;
22 |
23 | /**
24 | * Mock data initializer.
25 | *
26 | * Fills in-memory data base each time when application is started.
27 | *
28 | * @author Vaadin Ltd
29 | *
30 | */
31 | @Component
32 | @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
33 | public class MockDataGenerator {
34 |
35 | @Autowired
36 | private ProductRepository productRespoitory;
37 |
38 | @Autowired
39 | private CategoryRepository categoryRepository;
40 |
41 | private static final Random random = new Random(1);
42 | private static final String categoryNames[] = new String[] {
43 | "Children's books", "Best sellers", "Romance", "Mystery",
44 | "Thriller", "Sci-fi", "Non-fiction", "Cookbooks" };
45 |
46 | private static String[] word1 = new String[] { "The art of", "Mastering",
47 | "The secrets of", "Avoiding", "For fun and profit: ",
48 | "How to fail at", "10 important facts about",
49 | "The ultimate guide to", "Book of", "Surviving", "Encyclopedia of",
50 | "Very much", "Learning the basics of", "The cheap way to",
51 | "Being awesome at", "The life changer:", "The Vaadin way:",
52 | "Becoming one with", "Beginners guide to",
53 | "The complete visual guide to", "The mother of all references:" };
54 |
55 | private static String[] word2 = new String[] { "gardening",
56 | "living a healthy life", "designing tree houses", "home security",
57 | "intergalaxy travel", "meditation", "ice hockey",
58 | "children's education", "computer programming", "Vaadin TreeTable",
59 | "winter bathing", "playing the cello", "dummies", "rubber bands",
60 | "feeling down", "debugging", "running barefoot",
61 | "speaking to a big audience", "creating software", "giant needles",
62 | "elephants", "keeping your wife happy" };
63 |
64 | @PostConstruct
65 | private void init() {
66 | List categories = createCategories();
67 | createProducts(categories);
68 | }
69 |
70 | private List createCategories() {
71 | List categories = new ArrayList<>();
72 | for (String name : categoryNames) {
73 | Category c = createCategory(name);
74 | categories.add(c);
75 | }
76 | return categories;
77 |
78 | }
79 |
80 | private void createProducts(List categories) {
81 | List products = new ArrayList<>();
82 | for (int i = 0; i < 100; i++) {
83 | Product p = createProduct(categories);
84 | products.add(p);
85 | }
86 | }
87 |
88 | private Category createCategory(String name) {
89 | Category category = new Category();
90 | category.setName(name);
91 | return categoryRepository.save(category);
92 | }
93 |
94 | private Product createProduct(List categories) {
95 | Product product = new Product();
96 | product.setProductName(generateName());
97 |
98 | product.setPrice(new BigDecimal((random.nextInt(250) + 50) / 10.0));
99 | product.setAvailability(Availability.values()[random
100 | .nextInt(Availability.values().length)]);
101 | if (product.getAvailability() == Availability.AVAILABLE) {
102 | product.setStockCount(random.nextInt(523));
103 | }
104 |
105 | product.setCategory(getCategory(categories, 1, 2));
106 | return productRespoitory.save(product);
107 | }
108 |
109 | private Set getCategory(List categories, int min,
110 | int max) {
111 | int nr = random.nextInt(max) + min;
112 | HashSet productCategories = new HashSet<>();
113 | for (int i = 0; i < nr; i++) {
114 | productCategories
115 | .add(categories.get(random.nextInt(categories.size())));
116 | }
117 |
118 | return productCategories;
119 | }
120 |
121 | private String generateName() {
122 | return word1[random.nextInt(word1.length)] + " "
123 | + word2[random.nextInt(word2.length)];
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/Menu.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import com.vaadin.icons.VaadinIcons;
7 | import com.vaadin.navigator.Navigator;
8 | import com.vaadin.server.Page;
9 | import com.vaadin.server.Resource;
10 | import com.vaadin.server.ThemeResource;
11 | import com.vaadin.server.VaadinSession;
12 | import com.vaadin.ui.Alignment;
13 | import com.vaadin.ui.Button;
14 | import com.vaadin.ui.Button.ClickEvent;
15 | import com.vaadin.ui.Button.ClickListener;
16 | import com.vaadin.ui.CssLayout;
17 | import com.vaadin.ui.HorizontalLayout;
18 | import com.vaadin.ui.Image;
19 | import com.vaadin.ui.Label;
20 | import com.vaadin.ui.MenuBar;
21 | import com.vaadin.ui.MenuBar.Command;
22 | import com.vaadin.ui.MenuBar.MenuItem;
23 | import com.vaadin.ui.themes.ValoTheme;
24 |
25 | /**
26 | * Responsive navigation menu presenting a list of available views to the user.
27 | */
28 | public class Menu extends CssLayout {
29 |
30 | private static final String VALO_MENUITEMS = "valo-menuitems";
31 | private static final String VALO_MENU_TOGGLE = "valo-menu-toggle";
32 | private static final String VALO_MENU_VISIBLE = "valo-menu-visible";
33 | private Navigator navigator;
34 | private Map viewButtons = new HashMap<>();
35 |
36 | private CssLayout menuItemsLayout;
37 | private CssLayout menuPart;
38 |
39 | public Menu(Navigator navigator) {
40 | this.navigator = navigator;
41 | setPrimaryStyleName(ValoTheme.MENU_ROOT);
42 | menuPart = new CssLayout();
43 | menuPart.addStyleName(ValoTheme.MENU_PART);
44 |
45 | // header of the menu
46 | final HorizontalLayout top = new HorizontalLayout();
47 | top.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
48 | top.addStyleName(ValoTheme.MENU_TITLE);
49 | Label title = new Label("My CRUD");
50 | title.addStyleName(ValoTheme.LABEL_H3);
51 | title.setSizeUndefined();
52 | Image image = new Image(null, new ThemeResource("img/table-logo.png"));
53 | image.setStyleName("logo");
54 | top.addComponent(image);
55 | top.addComponent(title);
56 | menuPart.addComponent(top);
57 |
58 | // logout menu item
59 | MenuBar logoutMenu = new MenuBar();
60 | logoutMenu.addItem("Logout", VaadinIcons.SIGN_OUT, new Command() {
61 |
62 | @Override
63 | public void menuSelected(MenuItem selectedItem) {
64 | VaadinSession.getCurrent().getSession().invalidate();
65 | Page.getCurrent().reload();
66 | }
67 | });
68 |
69 | logoutMenu.addStyleName("user-menu");
70 | menuPart.addComponent(logoutMenu);
71 |
72 | // button for toggling the visibility of the menu when on a small screen
73 | final Button showMenu = new Button("Menu", new ClickListener() {
74 | @Override
75 | public void buttonClick(final ClickEvent event) {
76 | if (menuPart.getStyleName().contains(VALO_MENU_VISIBLE)) {
77 | menuPart.removeStyleName(VALO_MENU_VISIBLE);
78 | } else {
79 | menuPart.addStyleName(VALO_MENU_VISIBLE);
80 | }
81 | }
82 | });
83 | showMenu.addStyleName(ValoTheme.BUTTON_PRIMARY);
84 | showMenu.addStyleName(ValoTheme.BUTTON_SMALL);
85 | showMenu.addStyleName(VALO_MENU_TOGGLE);
86 | showMenu.setIcon(VaadinIcons.MENU);
87 | menuPart.addComponent(showMenu);
88 |
89 | // container for the navigation buttons, which are added by addView()
90 | menuItemsLayout = new CssLayout();
91 | menuItemsLayout.setPrimaryStyleName(VALO_MENUITEMS);
92 | menuPart.addComponent(menuItemsLayout);
93 |
94 | addComponent(menuPart);
95 | }
96 |
97 | /**
98 | * Creates a navigation button to the view identified by {@code name} using
99 | * {@code caption} and {@code icon}.
100 | *
101 | * @param name
102 | * view name
103 | * @param caption
104 | * view caption in the menu
105 | * @param icon
106 | * view icon in the menu
107 | */
108 | public void addViewButton(final String name, String caption,
109 | Resource icon) {
110 | Button button = new Button(caption, new ClickListener() {
111 |
112 | @Override
113 | public void buttonClick(ClickEvent event) {
114 | navigator.navigateTo(name);
115 |
116 | }
117 | });
118 | button.setPrimaryStyleName(ValoTheme.MENU_ITEM);
119 | button.setIcon(icon);
120 | menuItemsLayout.addComponent(button);
121 | viewButtons.put(name, button);
122 | }
123 |
124 | /**
125 | * Highlights a view navigation button as the currently active view in the
126 | * menu. This method does not perform the actual navigation.
127 | *
128 | * @param viewName
129 | * the name of the view to show as active
130 | */
131 | public void setActiveView(String viewName) {
132 | for (Button button : viewButtons.values()) {
133 | button.removeStyleName("selected");
134 | }
135 | Button selected = viewButtons.get(viewName);
136 | if (selected != null) {
137 | selected.addStyleName("selected");
138 | }
139 | menuPart.removeStyleName(VALO_MENU_VISIBLE);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/authentication/LoginScreen.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.authentication;
2 |
3 | import java.io.Serializable;
4 |
5 | import com.vaadin.event.ShortcutAction;
6 | import com.vaadin.server.Page;
7 | import com.vaadin.shared.ui.ContentMode;
8 | import com.vaadin.ui.Alignment;
9 | import com.vaadin.ui.Button;
10 | import com.vaadin.ui.Component;
11 | import com.vaadin.ui.CssLayout;
12 | import com.vaadin.ui.FormLayout;
13 | import com.vaadin.ui.Label;
14 | import com.vaadin.ui.Notification;
15 | import com.vaadin.ui.PasswordField;
16 | import com.vaadin.ui.TextField;
17 | import com.vaadin.ui.VerticalLayout;
18 | import com.vaadin.ui.themes.ValoTheme;
19 |
20 | /**
21 | * UI content when the user is not logged in yet.
22 | */
23 | public class LoginScreen extends CssLayout {
24 |
25 | private TextField username;
26 | private PasswordField password;
27 | private Button login;
28 | private Button forgotPassword;
29 | private LoginListener loginListener;
30 | private AccessControl accessControl;
31 |
32 | public LoginScreen(AccessControl accessControl,
33 | LoginListener loginListener) {
34 | this.loginListener = loginListener;
35 | this.accessControl = accessControl;
36 | buildUI();
37 | username.focus();
38 | }
39 |
40 | private void buildUI() {
41 | addStyleName("login-screen");
42 |
43 | // login form, centered in the available part of the screen
44 | Component loginForm = buildLoginForm();
45 |
46 | // layout to center login form when there is sufficient screen space
47 | // - see the theme for how this is made responsive for various screen
48 | // sizes
49 | VerticalLayout centeringLayout = new VerticalLayout();
50 | centeringLayout.setStyleName("centering-layout");
51 | centeringLayout.addComponent(loginForm);
52 | centeringLayout.setMargin(false);
53 | centeringLayout.setComponentAlignment(loginForm,
54 | Alignment.MIDDLE_CENTER);
55 |
56 | // information text about logging in
57 | CssLayout loginInformation = buildLoginInformation();
58 |
59 | addComponent(centeringLayout);
60 | addComponent(loginInformation);
61 | }
62 |
63 | private Component buildLoginForm() {
64 | FormLayout loginForm = new FormLayout();
65 |
66 | loginForm.addStyleName("login-form");
67 | loginForm.setSizeUndefined();
68 | loginForm.setMargin(false);
69 |
70 | loginForm.addComponent(username = new TextField("Username", "admin"));
71 | username.setWidth(15, Unit.EM);
72 | loginForm.addComponent(password = new PasswordField("Password"));
73 | password.setWidth(15, Unit.EM);
74 | password.setDescription("Write anything");
75 | CssLayout buttons = new CssLayout();
76 | buttons.setStyleName("buttons");
77 | loginForm.addComponent(buttons);
78 |
79 | buttons.addComponent(login = new Button("Login"));
80 | login.setDisableOnClick(true);
81 | login.addClickListener(new Button.ClickListener() {
82 | @Override
83 | public void buttonClick(Button.ClickEvent event) {
84 | try {
85 | login();
86 | } finally {
87 | login.setEnabled(true);
88 | }
89 | }
90 | });
91 | login.setClickShortcut(ShortcutAction.KeyCode.ENTER);
92 | login.addStyleName(ValoTheme.BUTTON_FRIENDLY);
93 |
94 | buttons.addComponent(forgotPassword = new Button("Forgot password?"));
95 | forgotPassword.addClickListener(new Button.ClickListener() {
96 | @Override
97 | public void buttonClick(Button.ClickEvent event) {
98 | showNotification(new Notification("Hint: Try anything"));
99 | }
100 | });
101 | forgotPassword.addStyleName(ValoTheme.BUTTON_LINK);
102 | return loginForm;
103 | }
104 |
105 | private CssLayout buildLoginInformation() {
106 | CssLayout loginInformation = new CssLayout();
107 | loginInformation.setStyleName("login-information");
108 | Label loginInfoText = new Label(
109 | "Login Information
"
110 | + "Log in as "admin" to have full access. Log in with any other username to have read-only access. For all users, any password is fine",
111 | ContentMode.HTML);
112 | loginInfoText.setWidth("100%");
113 | loginInformation.addComponent(loginInfoText);
114 | return loginInformation;
115 | }
116 |
117 | private void login() {
118 | if (accessControl.signIn(username.getValue(), password.getValue())) {
119 | loginListener.loginSuccessful();
120 | } else {
121 | showNotification(new Notification("Login failed",
122 | "Please check your username and password and try again.",
123 | Notification.Type.HUMANIZED_MESSAGE));
124 | username.focus();
125 | }
126 | }
127 |
128 | private void showNotification(Notification notification) {
129 | // keep the notification visible a little while after moving the
130 | // mouse, or until clicked
131 | notification.setDelayMsec(2000);
132 | notification.show(Page.getCurrent());
133 | }
134 |
135 | public interface LoginListener extends Serializable {
136 | void loginSuccessful();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/tree-database-example/src/main/java/org/vaadin/example/treegrid/jdbc/PeopleDataProvider.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.example.treegrid.jdbc;
2 |
3 | import com.vaadin.data.provider.AbstractBackEndHierarchicalDataProvider;
4 | import com.vaadin.data.provider.HierarchicalQuery;
5 | import org.vaadin.example.treegrid.jdbc.pojo.Company;
6 | import org.vaadin.example.treegrid.jdbc.pojo.Department;
7 | import org.vaadin.example.treegrid.jdbc.pojo.NamedItem;
8 | import org.vaadin.example.treegrid.jdbc.pojo.Person;
9 |
10 | import java.sql.Connection;
11 | import java.sql.PreparedStatement;
12 | import java.sql.ResultSet;
13 | import java.sql.SQLException;
14 | import java.sql.SQLFeatureNotSupportedException;
15 | import java.util.stream.Stream;
16 |
17 | /**
18 | * Example of AbstractHierarchicalDataProvider, based on top of pure JDBC.
19 | */
20 | public class PeopleDataProvider extends AbstractBackEndHierarchicalDataProvider {
21 |
22 | @Override
23 | public int getChildCount(HierarchicalQuery query) {
24 | NamedItem parent = query.getParent();
25 | int count;
26 | if (parent instanceof Person) {
27 | return 0;
28 | } else if (parent instanceof Department) {
29 | count = readInt("SELECT COUNT(*) FROM people WHERE department_id=?", parent);
30 | } else if (parent instanceof Company) {
31 | count = readInt("SELECT COUNT(*) FROM department WHERE company_id=?", parent);
32 | } else {
33 | count = readInt("SELECT COUNT(*) FROM company", null);
34 | }
35 | return count - query.getOffset();
36 | }
37 |
38 | @Override
39 | protected Stream fetchChildrenFromBackEnd(HierarchicalQuery query) {
40 | NamedItem parent = query.getParent();
41 | if (parent instanceof Person) {
42 | return Stream.empty();
43 | }
44 | DataRetriever retriever;
45 | String sql;
46 | if (parent instanceof Department) {
47 | sql = "SELECT * FROM people WHERE department_id=?";
48 | retriever = resultSet -> new Person(resultSet.getLong("id"),
49 | resultSet.getLong("department_id"),
50 | resultSet.getString("first_name"),
51 | resultSet.getString("last_name"),
52 | resultSet.getString("email"),
53 | resultSet.getString("gender")
54 | );
55 | } else if (parent instanceof Company) {
56 | sql = "SELECT * FROM department WHERE company_id=?";
57 | retriever = resultSet -> new Department(
58 | resultSet.getLong("department_id"),
59 | resultSet.getLong("company_id"),
60 | resultSet.getString("department_name"));
61 | } else {
62 | sql = "SELECT * FROM company";
63 | retriever = resultSet -> new Company(resultSet.getLong("company_id"),
64 | resultSet.getString("company_name"),
65 | resultSet.getString("company_email"));
66 | }
67 | try (Connection connection = DBEngine.getDataSource().getConnection();
68 | PreparedStatement statement = connection.prepareStatement(sql)) {
69 | if (parent != null) {
70 | statement.setLong(1, parent.getId());
71 | }
72 |
73 | return readResultSet(query, retriever, statement);
74 | } catch (SQLException e) {
75 | throw new RuntimeException(e);
76 | }
77 | }
78 |
79 | private Stream readResultSet(HierarchicalQuery query, DataRetriever retriever, PreparedStatement statement) throws SQLException {
80 | try (ResultSet resultSet = statement.executeQuery()) {
81 | safeSkipRows(resultSet, query.getOffset());
82 | if (resultSet.isAfterLast()) {
83 | return Stream.empty();
84 | }
85 | Stream.Builder builder = Stream.builder();
86 | int limit = query.getLimit();
87 | for (int i = 0; i < limit && resultSet.next(); i++) {
88 | builder.add(retriever.readRow(resultSet));
89 | }
90 | return builder.build();
91 | }
92 | }
93 |
94 | private void safeSkipRows(ResultSet resultSet, int skipRowCount) throws SQLException {
95 | try {
96 | resultSet.relative(skipRowCount);
97 | } catch (SQLFeatureNotSupportedException e) {
98 | for (int i = 0; i < skipRowCount; i++) {
99 | if (!resultSet.next()) return;
100 | }
101 | }
102 | }
103 |
104 | @Override
105 | public boolean hasChildren(NamedItem item) {
106 | return getChildCount(new HierarchicalQuery<>(null, item)) > 0;
107 | }
108 |
109 | @Override
110 | public Object getId(NamedItem item) {
111 | return item.getClass().getCanonicalName() + item.getId();
112 | }
113 |
114 | @FunctionalInterface
115 | public interface DataRetriever {
116 | T readRow(ResultSet resultSet) throws SQLException;
117 | }
118 |
119 | private int readInt(String sql, NamedItem parent) {
120 | try (Connection connection = DBEngine.getDataSource().getConnection();
121 | PreparedStatement statement = connection.prepareStatement(sql)) {
122 | if (parent != null) statement.setLong(1, parent.getId());
123 | try (ResultSet resultSet = statement.executeQuery()) {
124 | resultSet.next();
125 | return resultSet.getInt(1);
126 | }
127 | } catch (SQLException e) {
128 | throw new RuntimeException(e);
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/crud/ProductDataProviderImpl.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.crud;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collection;
5 | import java.util.List;
6 | import java.util.Locale;
7 | import java.util.stream.Collectors;
8 | import java.util.stream.Stream;
9 | import java.util.stream.StreamSupport;
10 |
11 | import javax.transaction.Transactional;
12 |
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.data.domain.PageRequest;
15 | import org.springframework.data.domain.Pageable;
16 | import org.springframework.data.domain.Sort;
17 | import org.springframework.data.domain.Sort.Direction;
18 | import org.springframework.data.domain.Sort.Order;
19 | import org.springframework.stereotype.Service;
20 |
21 | import com.vaadin.data.provider.AbstractBackEndDataProvider;
22 | import com.vaadin.data.provider.Query;
23 | import com.vaadin.framework8.samples.backend.data.Availability;
24 | import com.vaadin.framework8.samples.backend.data.Category;
25 | import com.vaadin.framework8.samples.backend.data.Product;
26 | import com.vaadin.framework8.samples.backend.repository.CategoryRepository;
27 | import com.vaadin.framework8.samples.backend.repository.ProductRepository;
28 | import com.vaadin.shared.data.sort.SortDirection;
29 | import com.vaadin.ui.UI;
30 |
31 | /**
32 | * DataProvider implementation for managing {@code ProductRepository} and
33 | * filtering.
34 | */
35 | @Service
36 | public class ProductDataProviderImpl
37 | extends AbstractBackEndDataProvider
38 | implements ProductDataProvider {
39 |
40 | private static class PageQuery {
41 | Pageable pageable;
42 | int pageOffset;
43 | }
44 |
45 | @Autowired
46 | private ProductRepository productRepo;
47 |
48 | @Autowired
49 | private CategoryRepository categoryRepo;
50 |
51 | @Override
52 | @Transactional
53 | public int sizeInBackEnd(Query t) {
54 | return (int) getItems(getPaging(t).pageable, getFilter(t)).count();
55 | }
56 |
57 | private String getFilter(Query t) {
58 | return t.getFilter().orElse(null);
59 | }
60 |
61 | @Override
62 | @Transactional
63 | public Stream fetchFromBackEnd(Query t) {
64 | PageQuery pageQuery = getPaging(t);
65 | return getItems(pageQuery.pageable, getFilter(t))
66 | .skip(pageQuery.pageOffset).limit(t.getLimit());
67 | }
68 |
69 | @Transactional
70 | @Override
71 | public void save(Product product) {
72 | productRepo.save(product);
73 | refreshAll();
74 | }
75 |
76 | @Transactional
77 | @Override
78 | public void delete(Product product) {
79 | productRepo.delete(product);
80 | refreshAll();
81 | }
82 |
83 | private Collection getFilteredCategories(String string) {
84 | return categoryRepo.findAllByNameContainingIgnoreCase(string);
85 | }
86 |
87 | private List getFilteredAvailabilities(String string) {
88 | Locale locale = UI.getCurrent().getLocale();
89 | return Arrays.stream(Availability.values())
90 | .filter(a -> a.name().toLowerCase(locale).contains(string))
91 | .collect(Collectors.toList());
92 | }
93 |
94 | private Stream getItems(Pageable page, String filterText) {
95 | if (filterText == null || filterText.isEmpty()) {
96 | return StreamSupport.stream(productRepo.findAll(page).spliterator(),
97 | false);
98 | }
99 | String filter = filterText.toLowerCase(UI.getCurrent().getLocale());
100 | return productRepo
101 | .findDistinctByProductNameContainingIgnoreCaseOrAvailabilityInOrCategoryIn(
102 | filter, getFilteredAvailabilities(filter),
103 | getFilteredCategories(filter), page)
104 | .stream();
105 | }
106 |
107 | /**
108 | * Return a PageQuery object containing page request and offset in page.
109 | *
110 | * @param q
111 | * the original query
112 | * @return paged query
113 | */
114 | private PageQuery getPaging(Query q) {
115 | final PageQuery p = new PageQuery();
116 | int start = q.getOffset();
117 | int end = q.getOffset() + q.getLimit();
118 |
119 | if (start < end - start) {
120 | p.pageable = getPageRequest(q, 0, end);
121 | p.pageOffset = q.getOffset();
122 | } else {
123 | // Calculate the page that fits the full requested index range
124 | int size = end - start;
125 | while (start / size != (end - 1) / size) {
126 | ++size;
127 | }
128 | p.pageable = getPageRequest(q, start / size, size);
129 | // Set the offset on page to filter out unneeded results
130 | p.pageOffset = start % size;
131 | }
132 |
133 | return p;
134 | }
135 |
136 | private PageRequest getPageRequest(Query q, int pageIndex,
137 | int pageLength) {
138 | if (!q.getSortOrders().isEmpty()) {
139 | return new PageRequest(pageIndex, pageLength, getSorting(q));
140 | } else {
141 | return new PageRequest(pageIndex, pageLength);
142 | }
143 | }
144 |
145 | private Sort getSorting(Query q) {
146 | return new Sort(q.getSortOrders().stream()
147 | .map(so -> new Order(
148 | so.getDirection() == SortDirection.ASCENDING
149 | ? Direction.ASC : Direction.DESC,
150 | so.getSorted()))
151 | .collect(Collectors.toList()));
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/crud/SampleCrudView.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.crud;
2 |
3 | import javax.annotation.PostConstruct;
4 |
5 | import org.springframework.beans.factory.annotation.Autowired;
6 |
7 | import com.vaadin.data.provider.ConfigurableFilterDataProvider;
8 | import com.vaadin.framework8.samples.backend.DataService;
9 | import com.vaadin.framework8.samples.backend.data.Product;
10 | import com.vaadin.framework8.samples.crud.ProductForm.ProductFormFactory;
11 | import com.vaadin.framework8.samples.crud.SampleCrudLogic.SampleCrudLogicFactory;
12 | import com.vaadin.icons.VaadinIcons;
13 | import com.vaadin.navigator.View;
14 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
15 | import com.vaadin.spring.annotation.SpringView;
16 | import com.vaadin.ui.Alignment;
17 | import com.vaadin.ui.Button;
18 | import com.vaadin.ui.CssLayout;
19 | import com.vaadin.ui.HorizontalLayout;
20 | import com.vaadin.ui.Notification;
21 | import com.vaadin.ui.Notification.Type;
22 | import com.vaadin.ui.TextField;
23 | import com.vaadin.ui.VerticalLayout;
24 | import com.vaadin.ui.themes.ValoTheme;
25 |
26 | /**
27 | * A view for performing create-read-update-delete operations on products.
28 | *
29 | * See also {@link SampleCrudLogic} for fetching the data, the actual CRUD
30 | * operations and controlling the view based on events from outside.
31 | */
32 | @SpringView(name = SampleCrudView.VIEW_NAME)
33 | public class SampleCrudView extends CssLayout implements View {
34 |
35 | public static final String VIEW_NAME = "Inventory";
36 | private ProductGrid grid;
37 |
38 | @Autowired
39 | private ProductFormFactory formFactory;
40 |
41 | @Autowired
42 | private DataService dataService;
43 |
44 | @Autowired
45 | private ProductDataProvider dataProvider;
46 |
47 | private ProductForm form;
48 |
49 | private SampleCrudLogic viewLogic;
50 | private Button newProduct;
51 |
52 | @Autowired
53 | private SampleCrudLogicFactory logicFactory;
54 | private TextField filter;
55 | private ConfigurableFilterDataProvider filterDataProvider;
56 |
57 | public HorizontalLayout createTopBar() {
58 | filter = new TextField();
59 | filter.setStyleName("filter-textfield");
60 | filter.setPlaceholder("Filter");
61 | // Trigger a refresh of data when the filter is updated
62 | filter.addValueChangeListener(
63 | event -> filterDataProvider.setFilter(event.getValue()));
64 |
65 | newProduct = new Button("New product");
66 | newProduct.addStyleName(ValoTheme.BUTTON_PRIMARY);
67 | newProduct.setIcon(VaadinIcons.PLUS_CIRCLE);
68 | newProduct.addClickListener(event -> viewLogic.newProduct());
69 |
70 | HorizontalLayout topLayout = new HorizontalLayout();
71 | topLayout.setWidth("100%");
72 | topLayout.addComponent(filter);
73 | topLayout.addComponent(newProduct);
74 | topLayout.setComponentAlignment(filter, Alignment.MIDDLE_LEFT);
75 | topLayout.setExpandRatio(filter, 1);
76 | topLayout.setStyleName("top-bar");
77 | return topLayout;
78 | }
79 |
80 | @Override
81 | public void enter(ViewChangeEvent event) {
82 | viewLogic.enter(event.getParameters());
83 | }
84 |
85 | public void showError(String msg) {
86 | Notification.show(msg, Type.ERROR_MESSAGE);
87 | }
88 |
89 | public void showSaveNotification(String msg) {
90 | Notification.show(msg, Type.TRAY_NOTIFICATION);
91 | }
92 |
93 | public void setNewProductEnabled(boolean enabled) {
94 | newProduct.setEnabled(enabled);
95 | }
96 |
97 | public void clearSelection() {
98 | grid.getSelectionModel().deselectAll();
99 | }
100 |
101 | public void selectRow(Product row) {
102 | grid.getSelectionModel().select(row);
103 | }
104 |
105 | public Product getSelectedRow() {
106 | return grid.getSelectedRow();
107 | }
108 |
109 | public void editProduct(Product product) {
110 | if (product != null) {
111 | form.addStyleName("visible");
112 | form.setEnabled(true);
113 | } else {
114 | form.removeStyleName("visible");
115 | // Issue #286
116 | // form.setEnabled(false);
117 | }
118 | form.editProduct(product);
119 | }
120 |
121 | public void updateProduct(Product product) {
122 | dataProvider.save(product);
123 | // TODO: Grid used to scroll to the updated item
124 | }
125 |
126 | public void removeProduct(Product product) {
127 | dataProvider.delete(product);
128 | }
129 |
130 | @PostConstruct
131 | private void init() {
132 | viewLogic = logicFactory.createLogic(this);
133 |
134 | setSizeFull();
135 | addStyleName("crud-view");
136 | HorizontalLayout topLayout = createTopBar();
137 |
138 | grid = new ProductGrid();
139 | grid.asSingleSelect().addValueChangeListener(
140 | event -> viewLogic.rowSelected(grid.getSelectedRow()));
141 |
142 | filterDataProvider = dataProvider.withConfigurableFilter();
143 | grid.setDataProvider(filterDataProvider);
144 |
145 | VerticalLayout barAndGridLayout = new VerticalLayout();
146 | barAndGridLayout.addComponent(topLayout);
147 | barAndGridLayout.addComponent(grid);
148 | barAndGridLayout.setSizeFull();
149 | barAndGridLayout.setMargin(false);
150 | barAndGridLayout.setSpacing(false);
151 | barAndGridLayout.setExpandRatio(grid, 1);
152 | barAndGridLayout.setStyleName("crud-main-layout");
153 |
154 | addComponent(barAndGridLayout);
155 |
156 | form = formFactory.createForm(viewLogic);
157 | form.setCategories(dataService.getAllCategories());
158 | addComponent(form);
159 |
160 | viewLogic.init();
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/src/main/java/com/vaadin/framework8/samples/crud/ProductForm.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.framework8.samples.crud;
2 |
3 | import java.text.DecimalFormat;
4 | import java.text.NumberFormat;
5 | import java.util.Collection;
6 | import java.util.Locale;
7 |
8 | import javax.annotation.PostConstruct;
9 |
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
12 | import org.springframework.context.ApplicationContext;
13 | import org.springframework.context.annotation.Scope;
14 |
15 | import com.vaadin.data.BeanValidationBinder;
16 | import com.vaadin.data.Binder;
17 | import com.vaadin.data.Result;
18 | import com.vaadin.data.StatusChangeEvent;
19 | import com.vaadin.data.ValueContext;
20 | import com.vaadin.data.converter.StringToIntegerConverter;
21 | import com.vaadin.framework8.samples.backend.data.Availability;
22 | import com.vaadin.framework8.samples.backend.data.Category;
23 | import com.vaadin.framework8.samples.backend.data.Product;
24 | import com.vaadin.server.Page;
25 | import com.vaadin.spring.annotation.SpringComponent;
26 |
27 | /**
28 | * A form for editing a single product.
29 | *
30 | * Using responsive layouts, the form can be displayed either sliding out on the
31 | * side of the view or filling the whole screen - see the theme for the related
32 | * CSS rules.
33 | */
34 | @SpringComponent
35 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
36 | public class ProductForm extends ProductFormDesign {
37 |
38 | private SampleCrudLogic viewLogic;
39 | private final Binder binder = new BeanValidationBinder<>(Product.class);
40 |
41 | @SpringComponent
42 | @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
43 | public static class ProductFormFactory {
44 |
45 | @Autowired
46 | private ApplicationContext context;
47 |
48 | public ProductForm createForm(SampleCrudLogic logic) {
49 | ProductForm form = context.getBean(ProductForm.class);
50 | form.init(logic);
51 | return form;
52 | }
53 | }
54 |
55 | private static class StockPriceConverter extends StringToIntegerConverter {
56 |
57 | public StockPriceConverter() {
58 | super("Could not convert value to " + Integer.class.getName());
59 | }
60 |
61 | @Override
62 | protected NumberFormat getFormat(Locale locale) {
63 | // do not use a thousands separator, as HTML5 input type
64 | // number expects a fixed wire/DOM number format regardless
65 | // of how the browser presents it to the user (which could
66 | // depend on the browser locale)
67 | DecimalFormat format = new DecimalFormat();
68 | format.setMaximumFractionDigits(0);
69 | format.setDecimalSeparatorAlwaysShown(false);
70 | format.setParseIntegerOnly(true);
71 | format.setGroupingUsed(false);
72 | return format;
73 | }
74 |
75 | @Override
76 | public Result convertToModel(String value,
77 | ValueContext context) {
78 | Result result = super.convertToModel(value, context);
79 | return result.map(stock -> stock == null ? 0 : stock);
80 | }
81 |
82 | }
83 |
84 | private Product currentProduct;
85 |
86 | private ProductForm() {
87 | }
88 |
89 | public void setCategories(Collection categories) {
90 | category.setItems(categories);
91 | }
92 |
93 | public void editProduct(Product product) {
94 | currentProduct = product;
95 | setUpData();
96 |
97 | delete.setEnabled(product != null && product.getId() != -1);
98 |
99 | // Scroll to the top
100 | // As this is not a Panel, using JavaScript
101 | String scrollScript = "window.document.getElementById('" + getId()
102 | + "').scrollTop = 0;";
103 | Page.getCurrent().getJavaScript().execute(scrollScript);
104 | }
105 |
106 | @PostConstruct
107 | private void init() {
108 | addStyleName("product-form");
109 |
110 | availability.setItems(Availability.values());
111 |
112 | binder.forField(price).withConverter(new EuroConverter()).bind("price");
113 | binder.forField(productName).bind("productName");
114 |
115 | binder.forField(availability).bind("availability");
116 |
117 | save.addClickListener(event -> onSave());
118 |
119 | cancel.addClickListener(event -> viewLogic.cancelProduct());
120 | delete.addClickListener(event -> onDelete());
121 | discard.addClickListener(event -> setUpData());
122 |
123 | category.setItemCaptionGenerator(Category::getName);
124 | binder.forField(category).bind("category");
125 | binder.forField(stockCount).withConverter(new StockPriceConverter())
126 | .bind("stockCount");
127 |
128 | binder.addStatusChangeListener(this::updateButtons);
129 | }
130 |
131 | private void onSave() {
132 | if (binder.writeBeanIfValid(currentProduct)) {
133 | viewLogic.saveProduct(currentProduct);
134 | }
135 | }
136 |
137 | private void onDelete() {
138 | if (currentProduct != null) {
139 | viewLogic.deleteProduct(currentProduct);
140 | }
141 | }
142 |
143 | private void init(SampleCrudLogic logic) {
144 | viewLogic = logic;
145 | }
146 |
147 | private void updateButtons(StatusChangeEvent event) {
148 | boolean changes = event.getBinder().hasChanges();
149 | boolean validationErrors = event.hasValidationErrors();
150 |
151 | save.setEnabled(!validationErrors && changes);
152 | discard.setEnabled(changes);
153 | }
154 |
155 | private void setUpData() {
156 | if (currentProduct != null) {
157 | binder.readBean(currentProduct);
158 | } else {
159 | binder.removeBean();
160 | }
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/spring-demo/spring-demo-ui/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | spring-demo
6 | com.vaadin.framework8
7 | 8.1.6
8 |
9 | 4.0.0
10 |
11 | spring-demo-ui
12 | spring-demo-ui
13 | war
14 |
15 |
16 |
17 |
18 | ${project.groupId}
19 | spring-demo-backend
20 | ${project.version}
21 |
22 |
23 |
24 | com.vaadin
25 | vaadin-spring-boot-starter
26 |
27 |
28 |
29 | com.vaadin
30 | vaadin-shared
31 |
32 |
33 | com.vaadin
34 | vaadin-push
35 |
36 |
37 | com.vaadin
38 | vaadin-client-compiled
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-test
44 | test
45 |
46 |
47 |
48 | com.vaadin.framework8
49 | test-util
50 | test
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | org.apache.maven.plugins
59 | maven-war-plugin
60 |
61 |
64 | true
65 |
67 | WEB-INF/classes/VAADIN/gwt-unitCache/**,
68 | WEB-INF/classes/VAADIN/widgetsets/WEB-INF/**
69 |
70 |
71 |
72 | com.vaadin
73 | vaadin-maven-plugin
74 |
75 |
76 |
77 | update-theme
78 |
80 | compile-theme
81 |
82 |
83 |
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-maven-plugin
88 | 1.5.1.RELEASE
89 |
90 | ${skipTests}
91 |
96 | true
97 | -Djava.security.egd=file:/dev/./urandom
98 | -Dserver.port=8888
99 |
100 |
101 |
102 | pre-integration-test
103 |
104 | start
105 |
106 |
107 |
108 | post-integration-test
109 |
110 | stop
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
120 |
121 | org.eclipse.m2e
122 | lifecycle-mapping
123 | 1.0.0
124 |
125 |
126 |
127 |
128 |
129 | com.vaadin
130 |
131 | vaadin-maven-plugin
132 |
133 |
134 | [7.6.8,)
135 |
136 |
137 | update-theme
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/todomvc/src/main/java/com/vaadin/tutorial/todomvc/TodoModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 Vaadin Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.vaadin.tutorial.todomvc;
17 |
18 | import java.sql.Connection;
19 | import java.sql.DriverManager;
20 | import java.sql.PreparedStatement;
21 | import java.sql.ResultSet;
22 | import java.sql.SQLException;
23 | import java.sql.Statement;
24 |
25 | import javax.sql.DataSource;
26 |
27 | import org.apache.commons.dbcp2.BasicDataSource;
28 |
29 | /**
30 | * Model for the database, HSQLDB dialect is used, in-memory database
31 | *
32 | * @author Vaadin Ltd
33 | */
34 | public class TodoModel {
35 |
36 | /*
37 | * Basic pollable DataSource is used here. That is mandatory for any web
38 | * application: In case of high load application the pool limits number of
39 | * physical database connections. In case of low load application,
40 | * connection pool fixes stall jdbc connection problem.
41 | */
42 | private volatile static BasicDataSource dataSource;
43 |
44 | private final Connection conn;
45 | private final TodoJDBCDataProvider dataProvider;
46 |
47 | public TodoModel() {
48 | try {
49 | DriverManager
50 | .registerDriver(org.hsqldb.jdbc.JDBCDriver.driverInstance);
51 | conn = getDataSource().getConnection();
52 | dataProvider = setupDataProvider();
53 | } catch (SQLException e) {
54 | throw new RuntimeException("Model initialization failed", e);
55 | }
56 | }
57 |
58 | private static DataSource getDataSource() {
59 | if (dataSource == null) {
60 | synchronized (TodoModel.class) {
61 | // Standard double check trick to avoid double initialization
62 | // in case of race conditions
63 | if (dataSource == null) {
64 | dataSource = new BasicDataSource();
65 | dataSource.setUrl("jdbc:hsqldb:mem:tododb");
66 | dataSource.setUsername("SA");
67 | dataSource.setPassword("");
68 | try (Connection connection = dataSource.getConnection()) {
69 | setupDatabase(connection);
70 | } catch (SQLException e) {
71 | throw new RuntimeException(e);
72 | }
73 | }
74 | }
75 | }
76 | return dataSource;
77 | }
78 |
79 | private TodoJDBCDataProvider setupDataProvider() throws SQLException {
80 | return new TodoJDBCDataProvider(conn);
81 | }
82 |
83 | private static void setupDatabase(Connection connection) {
84 | try (Statement s = connection.createStatement()) {
85 | s.execute(
86 | "CREATE TABLE todo (id INTEGER IDENTITY PRIMARY KEY, text VARCHAR(255) , completed BOOLEAN)");
87 | } catch (SQLException ignored) {
88 | // Nothing to do here, because
89 | // the table already exists, re-creation failed
90 | }
91 | }
92 |
93 | public int getCompleted() {
94 | return readInteger("select count(*) from todo where COMPLETED");
95 | }
96 |
97 | private int readInteger(String sql) {
98 | try (Statement s = conn.createStatement()) {
99 | ResultSet resultSet = s.executeQuery(sql);
100 | resultSet.next();
101 | return resultSet.getInt(1);
102 | } catch (SQLException e) {
103 | throw new RuntimeException(
104 | String.format("Data retrieve failed(%s)", sql), e);
105 | }
106 | }
107 |
108 | public int getActive() {
109 | return readInteger("select count(*) from todo where not COMPLETED");
110 | }
111 |
112 | public TodoJDBCDataProvider getDataProvider() {
113 | return dataProvider;
114 | }
115 |
116 | public Todo persist(Todo todo) {
117 | if (todo.getId() < 0) {
118 | try (PreparedStatement s = conn.prepareStatement(
119 | "INSERT INTO todo(id, text, completed) VALUES (NULL, ?, ?)",
120 | Statement.RETURN_GENERATED_KEYS)) {
121 | s.setString(1, todo.getText());
122 | s.setBoolean(2, todo.isCompleted());
123 | s.executeUpdate();
124 | ResultSet generatedKeys = s.getGeneratedKeys();
125 | generatedKeys.next();
126 | todo.setId(generatedKeys.getInt(1));
127 | } catch (SQLException e) {
128 | throw new RuntimeException("ToDo insertion failed", e);
129 | }
130 | } else {
131 | try (PreparedStatement s = conn.prepareStatement(
132 | "UPDATE todo SET text= ?,completed=? WHERE id = ?")) {
133 | s.setString(1, todo.getText());
134 | s.setBoolean(2, todo.isCompleted());
135 | s.setInt(3, todo.getId());
136 | s.execute();
137 | if (s.getUpdateCount() != 1) {
138 | throw new RuntimeException(
139 | "Todo update failed (non-existing id?): " + todo);
140 | }
141 | } catch (SQLException e) {
142 | throw new RuntimeException("Todo update failed", e);
143 | }
144 | }
145 | return todo;
146 | }
147 |
148 | public void drop(Todo todo) {
149 | try (Statement s = conn.createStatement()) {
150 | s.execute("DELETE FROM todo WHERE id = " + todo.getId());
151 | if (s.getUpdateCount() != 1) {
152 | throw new RuntimeException(
153 | "Deletion failed(non-existing id?): " + todo);
154 | }
155 | } catch (SQLException e) {
156 | throw new RuntimeException("Deletion failed", e);
157 | }
158 | }
159 |
160 | public void clearCompleted() {
161 | try (Statement s = conn.createStatement()) {
162 | s.execute("DELETE FROM todo WHERE completed");
163 | } catch (SQLException e) {
164 | throw new RuntimeException("Deletion of completed items failed", e);
165 | }
166 | }
167 |
168 | public void markAllCompleted(boolean completed) {
169 | try (PreparedStatement s = conn
170 | .prepareStatement("UPDATE todo SET completed=?")) {
171 | s.setBoolean(1, completed);
172 | s.execute();
173 | } catch (SQLException e) {
174 | throw new RuntimeException("Update failed", e);
175 | }
176 | }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/registration-form/src/main/java/com/vaadin/demo/registration/RegistrationFormUI.java:
--------------------------------------------------------------------------------
1 | package com.vaadin.demo.registration;
2 |
3 | import java.util.Objects;
4 |
5 | import javax.servlet.annotation.WebServlet;
6 |
7 | import com.vaadin.annotations.Theme;
8 | import com.vaadin.annotations.Title;
9 | import com.vaadin.annotations.VaadinServletConfiguration;
10 | import com.vaadin.data.Binder;
11 | import com.vaadin.data.Binder.Binding;
12 | import com.vaadin.data.BindingValidationStatus;
13 | import com.vaadin.data.BindingValidationStatus.Status;
14 | import com.vaadin.data.HasValue;
15 | import com.vaadin.data.Validator;
16 | import com.vaadin.icons.VaadinIcons;
17 | import com.vaadin.server.VaadinRequest;
18 | import com.vaadin.server.VaadinServlet;
19 | import com.vaadin.ui.AbstractTextField;
20 | import com.vaadin.ui.Button;
21 | import com.vaadin.ui.HorizontalLayout;
22 | import com.vaadin.ui.Label;
23 | import com.vaadin.ui.Layout;
24 | import com.vaadin.ui.Notification;
25 | import com.vaadin.ui.Notification.Type;
26 | import com.vaadin.ui.PasswordField;
27 | import com.vaadin.ui.TextField;
28 | import com.vaadin.ui.UI;
29 | import com.vaadin.ui.VerticalLayout;
30 | import com.vaadin.ui.themes.ValoTheme;
31 |
32 | @Title("Registration Form")
33 | @Theme("registration")
34 | public class RegistrationFormUI extends UI {
35 |
36 | private static final int WIDTH = 350;
37 |
38 | private final Binder binder = new Binder<>();
39 |
40 | private Binding passwordBinding;
41 | private Binding confirmPasswordBinding;
42 |
43 | private boolean showConfirmPasswordStatus;
44 |
45 | private static final String VALID = "valid";
46 |
47 | private void addToLayout(Layout layout, AbstractTextField textField,
48 | String placeHolderText) {
49 | textField.setPlaceholder(placeHolderText);
50 | Label statusMessage = new Label();
51 | statusMessage.setVisible(false);
52 | statusMessage.addStyleName("validation-message");
53 | textField.setData(statusMessage);
54 | HorizontalLayout horizontalLayout = new HorizontalLayout();
55 | horizontalLayout.setSpacing(false);
56 | horizontalLayout.addComponent(textField);
57 | textField.setWidth(WIDTH, Unit.PIXELS);
58 | horizontalLayout.addComponent(statusMessage);
59 | layout.addComponent(horizontalLayout);
60 | }
61 |
62 | @Override
63 | protected void init(VaadinRequest request) {
64 | VerticalLayout layout = new VerticalLayout();
65 | layout.setWidth(100, Unit.PERCENTAGE);
66 | setContent(layout);
67 |
68 | TextField fullNameField = new TextField();
69 | addToLayout(layout, fullNameField, "Full name");
70 |
71 | binder.forField(fullNameField).asRequired("Full name may not be empty")
72 | .withValidationStatusHandler(
73 | status -> commonStatusChangeHandler(status,
74 | fullNameField))
75 | .bind(Person::getFullName, Person::setFullName);
76 |
77 | TextField phoneOrEmailField = new TextField();
78 | addToLayout(layout, phoneOrEmailField, "Phone or Email");
79 | binder.forField(phoneOrEmailField)
80 | .withValidator(new EmailOrPhoneValidator())
81 | .withValidationStatusHandler(
82 | status -> commonStatusChangeHandler(status,
83 | phoneOrEmailField))
84 | .bind(Person::getEmailOrPhone, Person::setEmailOrPhone);
85 |
86 | PasswordField passwordField = new PasswordField();
87 | addToLayout(layout, passwordField, "Password");
88 | passwordBinding = binder.forField(passwordField)
89 | .withValidator(new PasswordValidator())
90 | .withValidationStatusHandler(
91 | status -> commonStatusChangeHandler(status,
92 | passwordField))
93 | .bind(Person::getPassword, Person::setPassword);
94 | passwordField.addValueChangeListener(
95 | event -> confirmPasswordBinding.validate());
96 |
97 | PasswordField confirmPasswordField = new PasswordField();
98 | addToLayout(layout, confirmPasswordField, "Password again");
99 |
100 | confirmPasswordBinding = binder.forField(confirmPasswordField)
101 | .withValidator(Validator.from(this::validateConfirmPasswd,
102 | "Password doesn't match"))
103 | .withValidationStatusHandler(
104 | status -> confirmPasswordStatusChangeHandler(status,
105 | confirmPasswordField))
106 | .bind(Person::getPassword, (person, pwd) -> {
107 | });
108 |
109 | layout.addComponent(createButton());
110 |
111 | fullNameField.focus();
112 |
113 | binder.setBean(new Person());
114 | }
115 |
116 | private Button createButton() {
117 | Button button = new Button("Sign Up", event -> save());
118 | button.addStyleName(ValoTheme.BUTTON_PRIMARY);
119 | button.setWidth(WIDTH, Unit.PIXELS);
120 | return button;
121 | }
122 |
123 | private void commonStatusChangeHandler(BindingValidationStatus> event,
124 | AbstractTextField field) {
125 | Label statusLabel = (Label) field.getData();
126 | statusLabel.setVisible(!event.getStatus().equals(Status.UNRESOLVED));
127 | switch (event.getStatus()) {
128 | case OK:
129 | statusLabel.setValue("");
130 | statusLabel.setIcon(VaadinIcons.CHECK);
131 | statusLabel.getParent().addStyleName(VALID);
132 | break;
133 | case ERROR:
134 | statusLabel.setIcon(VaadinIcons.CLOSE);
135 | statusLabel.setValue(event.getMessage().orElse("Unknown error"));
136 | statusLabel.getParent().removeStyleName(VALID);
137 | default:
138 | break;
139 | }
140 | }
141 |
142 | private void confirmPasswordStatusChangeHandler(
143 | BindingValidationStatus> event, AbstractTextField field) {
144 | commonStatusChangeHandler(event, field);
145 | Label statusLabel = (Label) field.getData();
146 | statusLabel.setVisible(showConfirmPasswordStatus);
147 | }
148 |
149 | private boolean validateConfirmPasswd(String confirmPasswordValue) {
150 | showConfirmPasswordStatus = false;
151 | if (confirmPasswordValue.isEmpty()) {
152 | return true;
153 |
154 | }
155 | BindingValidationStatus status = passwordBinding.validate();
156 | if (status.isError()) {
157 | return true;
158 | }
159 | showConfirmPasswordStatus = true;
160 | HasValue> pwdField = passwordBinding.getField();
161 | return Objects.equals(pwdField.getValue(), confirmPasswordValue);
162 | }
163 |
164 | private void save() {
165 | Person person = new Person();
166 | if (binder.writeBeanIfValid(person)) {
167 | Notification.show("Registration data saved successfully",
168 | String.format("Full name '%s', email or phone '%s'",
169 | person.getFullName(), person.getEmailOrPhone()),
170 | Type.HUMANIZED_MESSAGE);
171 | } else {
172 | Notification.show(
173 | "Registration could not be saved, please check all fields",
174 | Type.ERROR_MESSAGE);
175 | }
176 | }
177 |
178 | @WebServlet(urlPatterns = "/*")
179 | @VaadinServletConfiguration(ui = RegistrationFormUI.class, productionMode = false)
180 | public static class MyUIServlet extends VaadinServlet {
181 | }
182 | }
183 |
--------------------------------------------------------------------------------