transaction) {
+ var session = getSessionFactory().openSession();
+ var tx = session.beginTransaction();
+ T result;
+ try {
+ result = transaction.apply(session);
+ tx.commit();
+ } catch (Exception e) {
+ tx.rollback();
+ throw e;
+ } finally {
+ session.close();
+ }
+ return result;
+ }
+
+ /**
+ * Executes a given transaction within a Hibernate session.
+ *
+ * This method opens a new session, begins a transaction, and executes the
+ * provided {@link Consumer} with the session. If the transaction is
+ * successful, it commits the transaction. If an exception occurs, it rolls
+ * back the transaction and rethrows the exception. The session is closed in
+ * the finally block to ensure it is always closed.
+ *
+ * @param transaction
+ * the {@link Consumer} that contains the operations to be
+ * performed within the transaction
+ * @throws Exception
+ * if an error occurs during the transaction, it is propagated
+ * after rolling back the transaction
+ */
+ public static void inTransaction(Consumer transaction) {
+ var session = getSessionFactory().openSession();
+ var tx = session.beginTransaction();
+ try {
+ transaction.accept(session);
+ tx.commit();
+ } catch (Exception e) {
+ tx.rollback();
+ throw e;
+ } finally {
+ session.close();
+ }
+ }
+
+ /**
+ * Executes a task within a Hibernate session and ensures the session is
+ * closed after the task is completed.
+ *
+ * @param
+ * The type of the result returned by the task.
+ * @param task
+ * A function that takes a Hibernate {@link Session} and returns
+ * a result of type T.
+ * @return The result of the task.
+ */
+ public static T inSession(Function task) {
+ T result;
+ var session = getSessionFactory().openSession();
+ try {
+ result = task.apply(session);
+ } finally {
+ session.close();
+ }
+ return result;
+ }
+
+ /**
+ * Executes a task within a Hibernate session. The session is opened before
+ * the task is executed and closed after the task completes, ensuring proper
+ * resource management.
+ *
+ * @param task
+ * a {@link Consumer} that accepts a {@link Session} and performs
+ * operations within that session.
+ */
+ public static void inSession(Consumer task) {
+ var session = getSessionFactory().openSession();
+ try {
+ task.accept(session);
+ } finally {
+ session.close();
+ }
+ }
+}
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/dao/ProductDao.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/dao/ProductDao.java
new file mode 100644
index 0000000..b664970
--- /dev/null
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/dao/ProductDao.java
@@ -0,0 +1,213 @@
+package org.vaadin.tatu.vaadincreate.backend.dao;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vaadin.tatu.vaadincreate.backend.data.Category;
+import org.vaadin.tatu.vaadincreate.backend.data.Product;
+
+/**
+ * Data access object for managing products and categories.
+ */
+@SuppressWarnings("java:S1602")
+public class ProductDao {
+
+ /**
+ * Updates an existing product or saves a new product if it does not have an
+ * ID.
+ *
+ * This method logs the product being persisted and uses a transaction to
+ * either update the existing product or save a new product. It then
+ * retrieves and returns the persisted product.
+ *
+ * @param product
+ * the product to be updated or saved
+ * @return the persisted product with the updated information
+ */
+ public Product updateProduct(Product product) {
+ logger.info("Persisting Product: ({}) '{}'", product.getId(),
+ product.getProductName());
+ var identifier = HibernateUtil.inTransaction(session -> {
+ Integer id;
+ if (product.getId() != null) {
+ session.update(product);
+ id = product.getId();
+ } else {
+ id = (Integer) session.save(product);
+ }
+ return id;
+ });
+ return HibernateUtil.inSession(session -> {
+ return session.get(Product.class, identifier);
+ });
+ }
+
+ /**
+ * Retrieves a Product by its unique identifier.
+ *
+ * @param id
+ * the unique identifier of the Product to be fetched
+ * @return the Product object corresponding to the given id, or null if no
+ * such Product exists
+ */
+ public Product getProduct(Integer id) {
+ logger.info("Fetching Product: ({})", id);
+ return HibernateUtil.inSession(session -> {
+ return session.get(Product.class, id);
+ });
+ }
+
+ /**
+ * Deletes a product from the database based on the provided product ID.
+ *
+ * @param id
+ * the ID of the product to be deleted
+ */
+ public void deleteProduct(Integer id) {
+ logger.info("Deleting Product: ({})", id);
+ HibernateUtil.inTransaction(session -> {
+ Product product = session.get(Product.class, id);
+ session.delete(product);
+ });
+ }
+
+ /**
+ * Retrieves a collection of products that belong to the specified category.
+ *
+ * @param category
+ * the category for which products are to be fetched
+ * @return a collection of products that belong to the specified category
+ */
+ public Collection getProductsByCategory(Category category) {
+ logger.info("Fetching Products by Category: ({}) '{}'",
+ category.getId(), category.getName());
+ return HibernateUtil.inSession(session -> {
+ return session.createQuery(
+ "select p from Product p join p.category c where c.id = :id",
+ Product.class).setParameter("id", category.getId()).list();
+ });
+ }
+
+ /**
+ * Retrieves all products from the database.
+ *
+ * This method uses HibernateUtil to open a session and execute a query that
+ * fetches all instances of the Product class from the database.
+ *
+ * @return a collection of all products available in the database.
+ */
+ public Collection getAllProducts() {
+ // Method returns all products from the database using HibernateUtil
+ logger.info("Fetching all Products");
+ return HibernateUtil.inSession(session -> {
+ return session.createQuery("from Product", Product.class).list();
+ });
+ }
+
+ /**
+ * Updates the given Category in the database. If the Category has an ID, it
+ * will be updated. Otherwise, a new Category will be created and its ID
+ * will be assigned.
+ *
+ * @param category
+ * the Category to be updated or created
+ * @return the updated or newly created Category
+ */
+ public Category updateCategory(Category category) {
+ logger.info("Persisting Category: ({}) '{}'", category.getId(),
+ category.getName());
+ var identifier = HibernateUtil.inTransaction(session -> {
+ Integer id;
+ if (category.getId() != null) {
+ session.update(category);
+ id = category.getId();
+ } else {
+ id = (Integer) session.save(category);
+ }
+ return id;
+ });
+ return HibernateUtil.inSession(session -> {
+ return session.get(Category.class, identifier);
+ });
+ }
+
+ /**
+ * Retrieves a Category object from the database based on the provided ID.
+ *
+ * @param id
+ * the ID of the Category to be fetched
+ * @return the Category object corresponding to the provided ID, or null if
+ * not found
+ */
+ public Category getCategory(Integer id) {
+ logger.info("Fetching Category: ({})", id);
+ return HibernateUtil.inSession(session -> {
+ return session.get(Category.class, id);
+ });
+ }
+
+ /**
+ * Retrieves all categories from the database.
+ *
+ * @return a collection of all categories.
+ */
+ public Collection getAllCategories() {
+ logger.info("Fetching all Categories");
+ return HibernateUtil.inSession(session -> {
+ return session.createQuery("from Category", Category.class).list();
+ });
+ }
+
+ /**
+ * Fetches a set of Category objects based on their IDs.
+ *
+ * @param ids
+ * a set of integer IDs representing the categories to be fetched
+ * @return a set of Category objects corresponding to the provided IDs
+ */
+ public Set getCategoriesByIds(Set ids) {
+ logger.info("Fetching Categories: {}", ids);
+ return HibernateUtil.inSession(session -> {
+ return session
+ .createQuery("from Category where id in (:ids)",
+ Category.class)
+ .setParameter("ids", ids).list().stream()
+ .collect(Collectors.toSet());
+ });
+ }
+
+ /**
+ * Deletes a category by its ID. This method performs the following steps:
+ * 1. Retrieves the category from the database using the provided ID. 2.
+ * Finds all products associated with the category. 3. For each product,
+ * removes the category from its list of categories and updates the product
+ * in the database. 4. Deletes the category from the database. All
+ * operations are performed within a single transaction.
+ *
+ * @param id
+ * the ID of the category to be deleted
+ */
+ public void deleteCategory(Integer id) {
+ HibernateUtil.inTransaction(session -> {
+ var category = session.get(Category.class, id);
+ var list = session.createQuery(
+ "select p from Product p join p.category c where c.id = :id",
+ Product.class).setParameter("id", category.getId()).list();
+ list.forEach(p -> {
+ if (p.getCategory().contains(category)) {
+ var cats = p.getCategory();
+ cats.remove(category);
+ p.setCategory(cats);
+ session.update(p);
+ }
+ });
+ session.delete(category);
+ });
+ }
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+}
\ No newline at end of file
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/dao/UserDao.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/dao/UserDao.java
new file mode 100644
index 0000000..a6009c4
--- /dev/null
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/dao/UserDao.java
@@ -0,0 +1,99 @@
+package org.vaadin.tatu.vaadincreate.backend.dao;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vaadin.tatu.vaadincreate.backend.data.User;
+
+/**
+ * Data access object class for managing User entities.
+ */
+@SuppressWarnings("java:S1602")
+public class UserDao {
+
+ /**
+ * Finds a user by their name.
+ *
+ * @param name
+ * the name of the user to find
+ * @return the user with the specified name, or null if no such user exists
+ */
+ public User findByName(String name) {
+ logger.info("Finding user {}", name);
+ return HibernateUtil.inSession(session -> {
+ return session
+ .createQuery("from User where name = :name", User.class)
+ .setParameter("name", name).uniqueResult();
+ });
+ }
+
+ /**
+ * Updates the given user in the database. If the user already has an ID, it
+ * updates the existing record. Otherwise, it saves the new user and assigns
+ * an ID to it.
+ *
+ * @param user
+ * the User object to be updated or saved
+ * @return the updated User object retrieved from the database
+ */
+ public User updateUser(User user) {
+ logger.info("Persisting User: ({}) '{}'", user.getId(), user.getName());
+ var identifier = HibernateUtil.inTransaction(session -> {
+ Integer id;
+ if (user.getId() != null) {
+ session.update(user);
+ id = user.getId();
+ } else {
+ id = (Integer) session.save(user);
+ }
+ return id;
+ });
+ return HibernateUtil.inSession(session -> {
+ return session.get(User.class, identifier);
+ });
+ }
+
+ /**
+ * Retrieves a User entity from the database based on the provided user ID.
+ *
+ * @param userId
+ * the ID of the user to be fetched
+ * @return the User entity corresponding to the given user ID, or null if no
+ * such user exists
+ */
+ public User getUserById(Integer userId) {
+ logger.info("Fetching User: ({})", userId);
+ return HibernateUtil.inSession(session -> {
+ return session.get(User.class, userId);
+ });
+ }
+
+ /**
+ * Removes a user from the database based on the provided user ID.
+ *
+ * @param userId
+ * the ID of the user to be removed
+ */
+ public void removeUser(Integer userId) {
+ logger.info("Deleting User: ({})", userId);
+ HibernateUtil.inTransaction(session -> {
+ User user = session.get(User.class, userId);
+ session.delete(user);
+ });
+ }
+
+ /**
+ * Retrieves a list of all users from the database.
+ *
+ * @return a List of User objects representing all users in the database.
+ */
+ public List getAllUsers() {
+ logger.info("Fetching all Users");
+ return HibernateUtil.inSession(session -> {
+ return session.createQuery("from User", User.class).list();
+ });
+ }
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+}
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/AbstractEntity.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/AbstractEntity.java
index ff5d636..34f4e21 100644
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/AbstractEntity.java
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/AbstractEntity.java
@@ -3,42 +3,48 @@
import java.io.Serializable;
import java.util.Objects;
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-import javax.persistence.OptimisticLockException;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Version;
+@MappedSuperclass
@SuppressWarnings("serial")
public abstract class AbstractEntity implements Serializable {
- @NotNull
- @Min(0)
- int id = -1;
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgenerator")
+ @SequenceGenerator(name = "idgenerator", initialValue = 1)
+ Integer id;
- int version = 0;
+ @Version
+ Integer version;
- public int getId() {
+ public Integer getId() {
return id;
}
- public void setId(int id) {
+ public void setId(Integer id) {
this.id = id;
}
- public int getVersion() {
+ public Integer getVersion() {
return version;
}
- public void setVersion(int version) {
- if (version - this.version == 1) {
- this.version = version;
- } else {
- throw new OptimisticLockException(this);
- }
+ public void setVersion(Integer version) {
+ this.version = version;
}
@Override
public int hashCode() {
- return Objects.hash(id);
+ if (id != null) {
+ return Objects.hash(id);
+ } else {
+ return super.hashCode();
+ }
}
@Override
@@ -50,6 +56,9 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
AbstractEntity other = (AbstractEntity) obj;
- return id == other.id;
+ if (id != null) {
+ return id.equals(other.id);
+ }
+ return super.equals(other);
}
}
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Category.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Category.java
index 6077fc0..baaa218 100644
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Category.java
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Category.java
@@ -1,13 +1,17 @@
package org.vaadin.tatu.vaadincreate.backend.data;
+import javax.persistence.Column;
+import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
-@SuppressWarnings("serial")
+@SuppressWarnings({ "serial", "java:S2160" })
+@Entity
public class Category extends AbstractEntity {
@NotNull(message = "{category.required}")
@Size(min = 5, max = 40, message = "{category.length}")
+ @Column(name = "category_name")
private String name;
public Category() {
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Product.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Product.java
index d2bdab8..ec859f4 100644
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Product.java
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/Product.java
@@ -3,31 +3,50 @@
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Set;
-import java.util.stream.Collectors;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
-import org.vaadin.tatu.vaadincreate.backend.ProductDataService;
-
-@SuppressWarnings("serial")
+@SuppressWarnings({ "serial", "java:S2160" })
+@Entity
public class Product extends AbstractEntity {
@NotNull(message = "{product.name.required}")
@Size(min = 2, max = 100, message = "{product.name.min2max200}")
+ @Column(name = "product_name")
private String productName = "";
+
@Min(value = 0, message = "{price.not.negative}")
+ @Column(name = "price")
private BigDecimal price = BigDecimal.ZERO;
- private Set category = Collections.emptySet();
+
+ // Using Eager as the category is shown in the Grid, Lazy would not help performance.
+ @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST,
+ CascadeType.MERGE, CascadeType.DETACH })
+ @JoinTable(name = "product_category", joinColumns = @JoinColumn(name = "product_id"), inverseJoinColumns = @JoinColumn(name = "category_id"))
+ private Set category = Collections.emptySet();
+
@Min(value = 0, message = "{stock.not.negative}")
@NotNull(message = "{stock.required}")
+ @Column(name = "stock_count")
private Integer stockCount = 0;
+
@NotNull(message = "{availability.required}")
+ @Column(name = "availability")
+ @Enumerated(EnumType.STRING)
private Availability availability = Availability.COMING;
public Product() {
- setId(-1);
}
public Product(Product other) {
@@ -57,13 +76,11 @@ public void setPrice(BigDecimal price) {
}
public Set getCategory() {
- return ProductDataService.get().findCategoriesByIds(category);
+ return category;
}
public void setCategory(Set category) {
- this.category = category.stream()
- .map(cat -> Integer.valueOf(cat.getId()))
- .collect(Collectors.toSet());
+ this.category = category;
}
public Integer getStockCount() {
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/User.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/User.java
index f9a1a5d..a4e2916 100644
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/User.java
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/data/User.java
@@ -1,9 +1,16 @@
package org.vaadin.tatu.vaadincreate.backend.data;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
-@SuppressWarnings("serial")
+@SuppressWarnings({ "serial", "java:S2160" })
+@Entity
+@Table(name = "application_user")
public class User extends AbstractEntity {
public enum Role {
@@ -12,36 +19,38 @@ public enum Role {
@NotNull(message = "{user.name.required}")
@Size(min = 5, max = 20, message = "{user.length}")
+ @Column(name = "user_name")
private String name;
@NotNull(message = "{passwd.required}")
@Size(min = 5, max = 20, message = "{passwd.length}")
+ @Column(name = "passwd")
private String passwd;
@NotNull(message = "{role.required}")
+ @Enumerated(EnumType.STRING)
+ @Column(name = "role")
private Role role;
public User() {
- this.id = -1;
this.name = "";
this.passwd = "";
this.role = null;
}
- public User(int id, String name, String passwd, Role role) {
+ public User(Integer id, String name, String passwd, Role role) {
this.id = id;
this.name = name;
this.passwd = passwd;
this.setRole(role);
- this.version = 0;
}
- public User(int id, String name, String passwd, Role role, int version) {
- this.id = id;
- this.name = name;
- this.passwd = passwd;
- this.setRole(role);
- this.version = version;
+ public User(User user) {
+ this.id = user.id;
+ this.name = user.name;
+ this.passwd = user.passwd;
+ this.setRole(user.role);
+ this.version = user.version;
}
public String getName() {
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockDataGenerator.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockDataGenerator.java
index c6f1355..df669ad 100644
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockDataGenerator.java
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockDataGenerator.java
@@ -16,10 +16,8 @@
@SuppressWarnings("serial")
public class MockDataGenerator implements Serializable {
- private static int nextCategoryId = 1;
- private static int nextProductId = 1;
private static final Random random = new Random(1);
- private static final String categoryNames[] = new String[] {
+ private static final String[] categoryNames = new String[] {
"Children's books", "Best sellers", "Romance", "Mystery",
"Thriller", "Sci-fi", "Non-fiction", "Cookbooks" };
@@ -41,7 +39,7 @@ public class MockDataGenerator implements Serializable {
"speaking to a big audience", "creating software", "giant needles",
"elephants", "keeping your wife happy" };
- static List createCategories() {
+ public static List createCategories() {
List categories = new ArrayList<>();
for (String name : categoryNames) {
Category c = createCategory(name);
@@ -51,7 +49,7 @@ static List createCategories() {
}
- static List createProducts(List categories) {
+ public static List createProducts(List categories) {
List products = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Product p = createProduct(categories);
@@ -61,34 +59,40 @@ static List createProducts(List categories) {
return products;
}
- static String createMessage() {
+ public static String createMessage() {
return "System update complete";
}
- static List createUsers() {
+ public static List createUsers() {
List users = new ArrayList<>();
- for (int i = 0; i < 10; i++) {
- User user = new User(i + 1, "User" + i, "user" + i, Role.USER, 0);
+ for (Integer i = 0; i < 10; i++) {
+ User user = new User();
+ user.setName("User" + i);
+ user.setPasswd("user" + i);
+ user.setRole(Role.USER);
users.add(user);
}
- User admin = new User(users.size() + 1, "Admin", "admin", Role.ADMIN,
- 0);
+ User admin = new User();
+ admin.setName("Admin");
+ admin.setPasswd("admin");
+ admin.setRole(Role.ADMIN);
users.add(admin);
- admin = new User(users.size() + 1, "Super", "super", Role.ADMIN, 0);
+ admin = new User();
+ admin.setName("Super");
+ admin.setPasswd("super");
+ admin.setRole(Role.ADMIN);
users.add(admin);
return users;
}
private static Category createCategory(String name) {
Category c = new Category();
- c.setId(nextCategoryId++);
c.setName(name);
return c;
}
private static Product createProduct(List categories) {
Product p = new Product();
- p.setId(nextProductId++);
p.setProductName(generateName());
p.setPrice(new BigDecimal((random.nextInt(250) + 50) / 10.0));
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockProductDataService.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockProductDataService.java
deleted file mode 100644
index 8d878f8..0000000
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockProductDataService.java
+++ /dev/null
@@ -1,236 +0,0 @@
-package org.vaadin.tatu.vaadincreate.backend.mock;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Random;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.vaadin.tatu.vaadincreate.backend.ProductDataService;
-import org.vaadin.tatu.vaadincreate.backend.data.Category;
-import org.vaadin.tatu.vaadincreate.backend.data.Product;
-
-/**
- * Mock data model. This implementation has very simplistic locking and does not
- * notify users of modifications. There are mocked delays to simulate real
- * database response times.
- */
-@SuppressWarnings({ "serial", "java:S6548" })
-public class MockProductDataService extends ProductDataService {
-
- private static MockProductDataService instance;
-
- private List products;
- private List categories;
- private Map drafts = new HashMap<>();
- private int nextProductId = 0;
- private int nextCategoryId = 0;
-
- Random random = new Random();
-
- private MockProductDataService() {
- categories = MockDataGenerator.createCategories();
- products = MockDataGenerator.createProducts(categories);
- nextProductId = products.size() + 1;
- nextCategoryId = categories.size() + 1;
- logger.info("Generated mock product data");
- }
-
- public static synchronized ProductDataService getInstance() {
- if (instance == null) {
- instance = new MockProductDataService();
- }
- return instance;
- }
-
- @Override
- public synchronized List getAllProducts() {
- synchronized (products) {
- randomWait(6);
- return products.stream().map(Product::new)
- .collect(Collectors.toList());
- }
- }
-
- @Override
- public List getAllCategories() {
- synchronized (categories) {
- randomWait(2);
- return categories.stream().map(Category::new)
- .collect(Collectors.toList());
- }
- }
-
- @Override
- public Product updateProduct(Product product) {
- synchronized (products) {
- randomWait(1);
- var p = new Product(product);
- if (p.getId() < 0) {
- // New product
- p.setId(nextProductId++);
- products.add(p);
- logger.info("Saved a new product ({}) {}", p.getId(),
- p.getProductName());
- return p;
- }
- for (int i = 0; i < products.size(); i++) {
- if (products.get(i).getId() == p.getId()) {
- p.setVersion(products.get(i).getVersion() + 1);
- products.set(i, p);
- logger.info("Updated the product ({}) {}", p.getId(),
- p.getProductName());
- return p;
- }
- }
-
- throw new IllegalArgumentException(
- String.format("No product with id %d found", p.getId()));
- }
- }
-
- @Override
- public Product getProductById(int productId) {
- synchronized (products) {
- randomWait(1);
- for (Product product : products) {
- if (product.getId() == productId) {
- return new Product(product);
- }
- }
- return null;
- }
- }
-
- @Override
- public void deleteProduct(int productId) {
- synchronized (products) {
- randomWait(1);
- Product p = getProductById(productId);
- if (p == null) {
- throw new IllegalArgumentException(String
- .format("Product with id %d not found", productId));
- }
- products.remove(p);
- }
- }
-
- @Override
- public Category updateCategory(Category category) {
- Objects.requireNonNull(category);
- synchronized (categories) {
- randomWait(1);
- throwIfInvalidCategory(category);
- var newCategory = new Category(category);
- if (newCategory.getId() < 0) {
- newCategory.setId(nextCategoryId++);
- categories.add(newCategory);
- logger.info("Category {} created", newCategory.getId());
- } else {
- var index = categories.indexOf(newCategory);
- if (index < 0) {
- throw new IllegalArgumentException(
- String.format("Category with id %d does not exist.",
- newCategory.getId()));
- }
- newCategory.setVersion(categories.get(index).getVersion() + 1);
- categories.set(index, newCategory);
- logger.info("Category {} updated", newCategory.getId());
- }
- return newCategory;
- }
- }
-
- private void throwIfInvalidCategory(Category category) {
- Optional old;
- old = categories.stream()
- .filter(item -> item.getName().equals(category.getName()))
- .findFirst();
- old.ifPresent(oldCategory -> {
- if (category.getId() < 0 || (category.getId() >= 0
- && oldCategory.getId() != category.getId())) {
- throw new IllegalStateException(String.format(
- "Cannot re-use category name: %s", category.getName()));
- }
- });
- }
-
- @Override
- public void deleteCategory(int categoryId) {
- synchronized (categories) {
- randomWait(1);
- if (getAllProducts().stream()
- .noneMatch(c -> c.getId() == categoryId)) {
- throw new IllegalArgumentException(String
- .format("Category with id %d not found", categoryId));
- }
- deleteCategoryInternal(categoryId);
- }
- logger.info("Category {} deleted", categoryId);
- }
-
- private void deleteCategoryInternal(int categoryId) {
- if (categories.removeIf(category -> category.getId() == categoryId)) {
- getAllProducts().forEach(product -> product.getCategory()
- .removeIf(category -> category.getId() == categoryId));
- }
- }
-
- @Override
- public Set findCategoriesByIds(Set categoryIds) {
- synchronized (categories) {
- return categories.stream()
- .filter(cat -> categoryIds.contains(cat.getId()))
- .map(Category::new).collect(Collectors.toSet());
- }
- }
-
- @Override
- public void saveDraft(String userName, Product draft) {
- randomWait(1);
- logger.info("Saving draft for user '{}'", userName);
- if (draft == null) {
- drafts.remove(userName);
- } else {
- drafts.put(userName, new Product(draft));
- }
- }
-
- @Override
- public Product findDraft(String userName) {
- Objects.requireNonNull("userName can't be null");
- randomWait(1);
- logger.info("Finding draft for user '{}'", userName);
- return drafts.get(userName);
- }
-
- @Override
- public Collection backup() {
- return products.stream().map(Product::new).collect(Collectors.toList());
- }
-
- @Override
- public void restore(Collection data) {
- products.clear();
- data.forEach(product -> products.add(new Product(product)));
- }
-
- @SuppressWarnings("java:S2142")
- private void randomWait(int count) {
- int wait = 50 + random.nextInt(100);
- try {
- Thread.sleep(wait * (long) count);
- } catch (InterruptedException e) {
- // NOP
- }
- }
-
- private Logger logger = LoggerFactory.getLogger(this.getClass());
-
-}
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockUserService.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockUserService.java
deleted file mode 100644
index 924268a..0000000
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockUserService.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package org.vaadin.tatu.vaadincreate.backend.mock;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.Random;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.vaadin.tatu.vaadincreate.backend.UserService;
-import org.vaadin.tatu.vaadincreate.backend.data.User;
-
-public class MockUserService implements UserService {
-
- private static MockUserService INSTANCE;
-
- private List users;
- private int nextUserId = 0;
-
- private Random random = new Random();
-
- public synchronized static UserService getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new MockUserService();
- }
- return INSTANCE;
- }
-
- private MockUserService() {
- users = MockDataGenerator.createUsers();
- nextUserId = users.get(users.size() - 1).getId() + 1;
- logger.info("Generated mock user data");
- }
-
- @Override
- public synchronized Optional findByName(String name) {
- randomWait(1);
- var optUser = users.stream().filter(user -> user.getName().equals(name))
- .findFirst();
- if (optUser.isPresent()) {
- var user = optUser.get();
- return Optional.of(new User(user.getId(), user.getName(),
- user.getPasswd(), user.getRole(), user.getVersion()));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- public synchronized User updateUser(User user) {
- randomWait(3);
- User newUser = null;
- int index = -1;
- for (int i = 0; i < users.size(); i++) {
- if (users.get(i).equals(user)) {
- index = i;
- break;
- }
- }
- if (index > -1) {
- var result = users.stream()
- .filter(u -> user.getName().equals(u.getName())
- && user.getId() != u.getId())
- .findFirst();
- if (result.isEmpty()) {
- newUser = new User(user.getId(), user.getName(),
- user.getPasswd(), user.getRole(), user.getVersion());
- newUser.setVersion(users.get(index).getVersion() + 1);
- users.set(index, newUser);
- logger.info("Updated the user ({}) {}", newUser.getId(),
- newUser.getName());
- } else {
- throw new IllegalArgumentException(
- "Can't add user with duplicate name");
- }
- } else {
- var result = users.stream()
- .filter(u -> user.getName().equals(u.getName()))
- .findFirst();
- if (result.isEmpty()) {
- newUser = new User(-1, user.getName(), user.getPasswd(),
- user.getRole(), 0);
- newUser.setId(nextUserId);
- nextUserId++;
- users.add(newUser);
- logger.info("Saved a new user ({}) {}", newUser.getId(),
- newUser.getName());
- } else {
- throw new IllegalArgumentException(
- "Can't add user with duplicate name");
- }
- }
- return newUser;
- }
-
- @Override
- public synchronized User getUserById(int userId) {
- randomWait(1);
- for (int i = 0; i < users.size(); i++) {
- if (users.get(i).getId() == userId) {
- var user = users.get(i);
- return new User(user.getId(), user.getName(), user.getPasswd(),
- user.getRole(), user.getVersion());
- }
- }
- return null;
- }
-
- @Override
- public synchronized void removeUser(int userId) {
- randomWait(1);
- User u = getUserById(userId);
- if (u == null) {
- throw new IllegalArgumentException(
- "User with id " + userId + " not found");
- }
- logger.info("Removed the user ({}) {}", u.getId(), u.getName());
- users.remove(u);
- }
-
- @Override
- public synchronized List getAllUsers() {
- randomWait(3);
- var result = new ArrayList();
- for (int i = 0; i < users.size(); i++) {
- result.add(getUserById(users.get(i).getId()));
- }
- return result;
- }
-
- private void randomWait(int count) {
- int wait = 20 + random.nextInt(30);
- try {
- Thread.sleep(wait * count);
- } catch (InterruptedException e) {
- }
- }
-
- private Logger logger = LoggerFactory.getLogger(this.getClass());
-}
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockAppDataService.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/AppDataServiceImpl.java
similarity index 61%
rename from vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockAppDataService.java
rename to vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/AppDataServiceImpl.java
index 30d240a..4d3b989 100644
--- a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/mock/MockAppDataService.java
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/AppDataServiceImpl.java
@@ -1,4 +1,4 @@
-package org.vaadin.tatu.vaadincreate.backend.mock;
+package org.vaadin.tatu.vaadincreate.backend.service;
import java.time.LocalDateTime;
@@ -6,20 +6,22 @@
import org.slf4j.LoggerFactory;
import org.vaadin.tatu.vaadincreate.backend.AppDataService;
import org.vaadin.tatu.vaadincreate.backend.data.Message;
+import org.vaadin.tatu.vaadincreate.backend.mock.MockDataGenerator;
-public class MockAppDataService implements AppDataService {
- private static MockAppDataService INSTANCE;
+@SuppressWarnings("java:S6548")
+public class AppDataServiceImpl implements AppDataService {
+ private static AppDataServiceImpl instance;
private Message message;
- public synchronized static AppDataService getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new MockAppDataService();
+ public static synchronized AppDataService getInstance() {
+ if (instance == null) {
+ instance = new AppDataServiceImpl();
}
- return INSTANCE;
+ return instance;
}
- private MockAppDataService() {
+ private AppDataServiceImpl() {
message = new Message(MockDataGenerator.createMessage(),
LocalDateTime.now());
logger.info("Generated mock app data");
@@ -37,4 +39,5 @@ public synchronized Message getMessage() {
}
private Logger logger = LoggerFactory.getLogger(this.getClass());
+
}
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/ProductDataServiceImpl.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/ProductDataServiceImpl.java
new file mode 100644
index 0000000..5306910
--- /dev/null
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/ProductDataServiceImpl.java
@@ -0,0 +1,136 @@
+package org.vaadin.tatu.vaadincreate.backend.service;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vaadin.tatu.vaadincreate.backend.ProductDataService;
+import org.vaadin.tatu.vaadincreate.backend.dao.ProductDao;
+import org.vaadin.tatu.vaadincreate.backend.data.Category;
+import org.vaadin.tatu.vaadincreate.backend.data.Product;
+import org.vaadin.tatu.vaadincreate.backend.mock.MockDataGenerator;
+
+@SuppressWarnings("java:S6548")
+public class ProductDataServiceImpl implements ProductDataService {
+ // Service class for managing products
+ // This class is a singleton
+ private static ProductDataServiceImpl instance;
+ private ProductDao productDao = new ProductDao();
+ private Map drafts = new HashMap<>();
+ Random random = new Random();
+
+ private ProductDataServiceImpl() {
+ var categories = MockDataGenerator.createCategories();
+ categories.forEach(cat -> productDao.updateCategory(cat));
+ var savedCategories = productDao.getAllCategories().stream()
+ .collect(Collectors.toList());
+ var products = MockDataGenerator.createProducts(savedCategories);
+ products.forEach(prod -> productDao.updateProduct(prod));
+ logger.info("Generated mock product data");
+ }
+
+ public static ProductDataService getInstance() {
+ if (instance == null) {
+ instance = new ProductDataServiceImpl();
+ }
+ return instance;
+ }
+
+ @Override
+ public synchronized Product updateProduct(Product product) {
+ Objects.requireNonNull(product);
+ randomWait(1);
+ return productDao.updateProduct(product);
+ }
+
+ @Override
+ public synchronized void deleteProduct(Integer id) {
+ Objects.requireNonNull(id);
+ randomWait(1);
+ productDao.deleteProduct(id);
+ }
+
+ @Override
+ public synchronized Product getProductById(Integer id) {
+ randomWait(1);
+ return productDao.getProduct(id);
+ }
+
+ @Override
+ public synchronized Collection getAllProducts() {
+ randomWait(6);
+ return productDao.getAllProducts();
+ }
+
+ @Override
+ public synchronized Collection getAllCategories() {
+ randomWait(2);
+ return productDao.getAllCategories();
+ }
+
+ @Override
+ public synchronized void deleteCategory(Integer id) {
+ Objects.requireNonNull(id);
+ var category = productDao.getCategory(id);
+ if (category == null) {
+ throw new IllegalArgumentException("Category not found");
+ }
+
+ productDao.deleteCategory(id);
+ }
+
+ @Override
+ public synchronized Set findCategoriesByIds(Set ids) {
+ Objects.requireNonNull(ids);
+ randomWait(1);
+ return productDao.getCategoriesByIds(ids);
+ }
+
+ @Override
+ public synchronized Category updateCategory(Category category) {
+ Objects.requireNonNull(category);
+ randomWait(1);
+ return productDao.updateCategory(category);
+ }
+
+ @Override
+ public void saveDraft(String userName, Product draft) {
+ Objects.requireNonNull(userName);
+ logger.info("Saving draft for user '{}'", userName);
+ synchronized (drafts) {
+ if (draft == null) {
+ drafts.remove(userName);
+ } else {
+ drafts.put(userName, new Product(draft));
+ }
+ }
+ }
+
+ @Override
+ public Product findDraft(String userName) {
+ Objects.requireNonNull(userName, "userName can't be null");
+ logger.info("Finding draft for user '{}'", userName);
+ synchronized (drafts) {
+ return drafts.get(userName);
+ }
+ }
+
+ @SuppressWarnings("java:S2142")
+ private void randomWait(int count) {
+ int wait = 50 + random.nextInt(100);
+ try {
+ Thread.sleep(wait * (long) count);
+ } catch (InterruptedException e) {
+ // NOP
+ }
+ }
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+}
diff --git a/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/UserServiceImpl.java b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/UserServiceImpl.java
new file mode 100644
index 0000000..185e630
--- /dev/null
+++ b/vaadincreate-backend/src/main/java/org/vaadin/tatu/vaadincreate/backend/service/UserServiceImpl.java
@@ -0,0 +1,87 @@
+package org.vaadin.tatu.vaadincreate.backend.service;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Random;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vaadin.tatu.vaadincreate.backend.UserService;
+import org.vaadin.tatu.vaadincreate.backend.dao.UserDao;
+import org.vaadin.tatu.vaadincreate.backend.data.User;
+import org.vaadin.tatu.vaadincreate.backend.mock.MockDataGenerator;
+
+@SuppressWarnings("java:S6548")
+public class UserServiceImpl implements UserService {
+
+ private UserDao userDao = new UserDao();
+ private Random random = new Random();
+
+ private static UserServiceImpl instance;
+
+ public static synchronized UserService getInstance() {
+ if (instance == null) {
+ instance = new UserServiceImpl();
+ }
+ return instance;
+ }
+
+ private UserServiceImpl() {
+ var users = MockDataGenerator.createUsers();
+ users.forEach(user -> userDao.updateUser(user));
+ logger.info("Generated mock user data");
+ }
+
+ @Override
+ public synchronized User updateUser(User user) {
+ Objects.requireNonNull(user, "User must not be null");
+ randomWait(2);
+ var existingUser = userDao.findByName(user.getName());
+ if (existingUser != null
+ && !existingUser.getId().equals(user.getId())) {
+ throw new IllegalArgumentException(
+ "User with the same name already exists");
+ }
+ return userDao.updateUser(user);
+ }
+
+ @Override
+ public synchronized Optional findByName(String name) {
+ Objects.requireNonNull(name, "Name must not be null");
+ randomWait(1);
+ return Optional.ofNullable(userDao.findByName(name));
+ }
+
+ @Override
+ public synchronized User getUserById(Integer userId) {
+ Objects.requireNonNull(userId, "User ID must not be null");
+ randomWait(1);
+ return userDao.getUserById(userId);
+ }
+
+ @Override
+ public synchronized void removeUser(Integer userId) {
+ Objects.requireNonNull(userId, "User ID must not be null");
+ randomWait(1);
+ userDao.removeUser(userId);
+ }
+
+ @Override
+ public synchronized java.util.List getAllUsers() {
+ randomWait(3);
+ return userDao.getAllUsers();
+ }
+
+ @SuppressWarnings("java:S2142")
+ private void randomWait(int count) {
+ int wait = 20 + random.nextInt(30);
+ try {
+ Thread.sleep(wait * (long) count);
+ } catch (InterruptedException e) {
+ // NOP
+ }
+ }
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+}
diff --git a/vaadincreate-backend/src/main/resources/hibernate.cfg.xml b/vaadincreate-backend/src/main/resources/hibernate.cfg.xml
new file mode 100644
index 0000000..929ecf5
--- /dev/null
+++ b/vaadincreate-backend/src/main/resources/hibernate.cfg.xml
@@ -0,0 +1,17 @@
+
+
+
+ org.hibernate.dialect.H2Dialect
+ org.h2.Driver
+ jdbc:h2:mem:testdb
+ sa
+
+ false
+ create
+ false
+ false
+
+
+
+
+
diff --git a/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/ProductDataServiceTest.java b/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/ProductDataServiceTest.java
index 24a1235..73b1b79 100644
--- a/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/ProductDataServiceTest.java
+++ b/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/ProductDataServiceTest.java
@@ -4,11 +4,12 @@
import org.junit.Test;
import org.vaadin.tatu.vaadincreate.backend.data.Category;
import org.vaadin.tatu.vaadincreate.backend.data.Product;
-import org.vaadin.tatu.vaadincreate.backend.mock.MockProductDataService;
+import org.vaadin.tatu.vaadincreate.backend.service.ProductDataServiceImpl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -26,7 +27,7 @@ public class ProductDataServiceTest {
@Before
public void setUp() throws Exception {
- service = MockProductDataService.getInstance();
+ service = ProductDataServiceImpl.getInstance();
}
@Test
@@ -47,7 +48,7 @@ public void updateTheProduct() throws Exception {
p.setProductName("My Test Name");
service.updateProduct(p);
var p2 = service.getProductById(p.getId());
- assertEquals(version + 1, p2.getVersion());
+ assertEquals(Integer.valueOf(version + 1), p2.getVersion());
assertEquals("My Test Name", p2.getProductName());
assertEquals(oldSize, service.getAllProducts().size());
}
@@ -58,25 +59,16 @@ public void addNewProduct() throws Exception {
Product p = new Product();
p.setProductName("A new book");
p.setPrice(new BigDecimal(10));
- assertEquals(-1, p.getId());
+ assertNull(p.getId());
var newProduct = service.updateProduct(p);
- assertEquals(0, newProduct.getVersion());
- assertNotEquals(-1, newProduct.getId());
+ assertEquals(Integer.valueOf(0), newProduct.getVersion());
+ assertNotEquals(Integer.valueOf(-1), newProduct.getId());
assertEquals(oldSize + 1, service.getAllProducts().size());
var foundProduct = service.getProductById(newProduct.getId());
assertTrue(foundProduct.equals(newProduct));
}
- @Test(expected = IllegalArgumentException.class)
- public void updateNonExistentProduct() {
- Product p = new Product();
- p.setProductName("A new book");
- p.setPrice(new BigDecimal(10));
- p.setId(1000);
- service.updateProduct(p);
- }
-
@Test
public void removeProduct() throws Exception {
var oldSize = service.getAllProducts().size();
@@ -89,12 +81,12 @@ public void removeProduct() throws Exception {
@Test
public void findProductById() {
- assertNotEquals(null, service.getProductById(1));
+ assertNotNull(service.getProductById(100));
}
@Test
public void findProductByNonExistentId() {
- assertEquals(null, service.getProductById(1000));
+ assertNull(service.getProductById(10000));
}
@Test(expected = IllegalArgumentException.class)
@@ -104,17 +96,20 @@ public void removeProductByNonExistentId() {
@Test(expected = OptimisticLockException.class)
public void optimisticLocking() {
- var product = service.getProductById(1);
- service.updateProduct(product);
+ var product = service.getProductById(100);
+ var copy = new Product(product);
service.updateProduct(product);
+ service.updateProduct(copy);
}
@Test(expected = OptimisticLockException.class)
public void optimisticLockingCategory() {
var category = service.getAllCategories().stream().skip(2).findFirst()
.get();
- service.updateCategory(category);
- service.updateCategory(category);
+ var copy = new Category(category);
+ var updated = service.updateCategory(category);
+ assertNotEquals(updated.getVersion(), copy.getVersion());
+ service.updateCategory(copy);
}
@Test
@@ -122,18 +117,15 @@ public void addUpdateRemoveCategory() {
var category = new Category();
category.setName("Sports books");
var newCategory = service.updateCategory(category);
- assertFalse(category.equals(newCategory));
assertTrue(newCategory.getId() > 0);
assertEquals("Sports books", newCategory.getName());
- assertFalse(category == newCategory);
- assertEquals(0, newCategory.getVersion());
+ assertEquals(Integer.valueOf(0), newCategory.getVersion());
assertTrue(service.getAllCategories().contains(newCategory));
newCategory.setName("Athletics");
var updatedCategory = service.updateCategory(newCategory);
- assertEquals(1, updatedCategory.getVersion());
+ assertEquals(Integer.valueOf(1), updatedCategory.getVersion());
assertTrue(updatedCategory.equals(newCategory));
- assertFalse(updatedCategory == newCategory);
assertTrue(service.getAllCategories().contains(updatedCategory));
assertEquals("Athletics", updatedCategory.getName());
@@ -155,6 +147,8 @@ public void updateCategoryUsedInProduct_removeUsedCategory() {
var bookId = newBook.getId();
newCategory.setName("Athletics");
+ service.updateCategory(newCategory);
+
var foundBook = service.getProductById(bookId);
assertEquals("Athletics",
foundBook.getCategory().stream().findFirst().get().getName());
@@ -164,14 +158,6 @@ public void updateCategoryUsedInProduct_removeUsedCategory() {
assertTrue(foundBook.getCategory().isEmpty());
}
- @Test(expected = IllegalArgumentException.class)
- public void updateNonExistingCategoryThrows() {
- var category = new Category();
- category.setName("Sports");
- category.setId(20);
- service.updateCategory(category);
- }
-
@Test
public void drafts() {
var userName = "user";
@@ -180,7 +166,7 @@ public void drafts() {
var product = new Product();
service.saveDraft(userName, product);
draft = service.findDraft(userName);
- assertEquals(product, draft);
+ // assertTrue(product.equals(draft));
assertFalse(product == draft);
service.saveDraft(userName, null);
draft = service.findDraft(userName);
diff --git a/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/UserServiceTest.java b/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/UserServiceTest.java
index 4146fcb..ce1a254 100644
--- a/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/UserServiceTest.java
+++ b/vaadincreate-backend/src/test/java/org/vaadin/tatu/vaadincreate/backend/UserServiceTest.java
@@ -2,18 +2,16 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import java.math.BigDecimal;
-
import javax.persistence.OptimisticLockException;
import org.junit.Before;
import org.junit.Test;
import org.vaadin.tatu.vaadincreate.backend.data.User;
import org.vaadin.tatu.vaadincreate.backend.data.User.Role;
-import org.vaadin.tatu.vaadincreate.backend.mock.MockUserService;
+import org.vaadin.tatu.vaadincreate.backend.service.UserServiceImpl;
public class UserServiceTest {
@@ -21,7 +19,7 @@ public class UserServiceTest {
@Before
public void setUp() throws Exception {
- service = MockUserService.getInstance();
+ service = UserServiceImpl.getInstance();
}
@Test
@@ -36,7 +34,7 @@ public void updateTheUser() throws Exception {
var version = user.getVersion();
user.setName("Test1");
User user2 = service.updateUser(user);
- assertEquals(version + 1, user2.getVersion());
+ assertEquals((Integer.valueOf(version + 1)), user2.getVersion());
assertEquals("Test1", user2.getName());
assertEquals(oldSize, service.getAllUsers().size());
}
@@ -51,16 +49,20 @@ public void updateTheUserByDuplicateName() throws Exception {
@Test(expected = OptimisticLockException.class)
public void optimisticLocking() {
var user = service.findByName("User5").get();
- var u = service.updateUser(user);
+ var copy = new User(user);
service.updateUser(user);
+ service.updateUser(copy);
}
@Test
public void addNewUser() throws Exception {
var oldSize = service.getAllUsers().size();
- User user = new User(20, "Test2", "test2", Role.USER, 0);
+ User user = new User();
+ user.setName("Test2");
+ user.setPasswd("test2");
+ user.setRole(Role.USER);
var newUser = service.updateUser(user);
- assertEquals(0, newUser.getVersion());
+ assertEquals(Integer.valueOf(0), newUser.getVersion());
assertEquals(oldSize + 1, service.getAllUsers().size());
var foundUser = service.findByName("Test2");
@@ -69,7 +71,10 @@ public void addNewUser() throws Exception {
@Test(expected = IllegalArgumentException.class)
public void addNewUserByDuplicateName() throws Exception {
- User user = new User(20, "Admin", "admin", Role.USER, 0);
+ User user = new User();
+ user.setName("Admin");
+ user.setPasswd("admin");
+ user.setRole(Role.USER);
service.updateUser(user);
}
@@ -85,7 +90,8 @@ public void removeUser() throws Exception {
@Test
public void findUserById() {
- assertNotEquals(null, service.getUserById(1));
+ var user = service.getAllUsers().get(0);
+ assertNotNull(service.getUserById(user.getId()));
}
@Test
diff --git a/vaadincreate-components/pom.xml b/vaadincreate-components/pom.xml
index 2aaa155..451d12a 100644
--- a/vaadincreate-components/pom.xml
+++ b/vaadincreate-components/pom.xml
@@ -4,7 +4,7 @@
vaadincreate-root
org.vaadin.tatu
- 1.0-SNAPSHOT
+ 2.0-SNAPSHOT
4.0.0
vaadincreate-components
diff --git a/vaadincreate-ui/pom.xml b/vaadincreate-ui/pom.xml
index 9fd3f39..ef4eb94 100644
--- a/vaadincreate-ui/pom.xml
+++ b/vaadincreate-ui/pom.xml
@@ -6,7 +6,7 @@
vaadincreate-root
org.vaadin.tatu
- 1.0-SNAPSHOT
+ 2.0-SNAPSHOT
vaadincreate-ui
war
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/VaadinCreateUI.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/VaadinCreateUI.java
index a76d122..c1956a9 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/VaadinCreateUI.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/VaadinCreateUI.java
@@ -129,8 +129,6 @@ protected void showAppLayout() {
.findDraft(getAccessControl().getPrincipalName());
if (draft != null) {
handleDraft(draft);
- } else {
- getNavigator().navigateTo(target);
}
}
@@ -142,7 +140,7 @@ private void handleDraft(Product draft) {
ConfirmDialog.Type.ALERT);
dialog.setCancelText(getTranslation(I18n.DISCARD));
dialog.setConfirmText(getTranslation(I18n.YES));
- var id = draft.getId() == -1 ? "new" : String.valueOf(draft.getId());
+ var id = draft.getId() == null ? "new" : String.valueOf(draft.getId());
dialog.addConfirmedListener(e -> getNavigator()
.navigateTo(String.format("%s/%s", BooksView.VIEW_NAME, id)));
dialog.addCancelListener(e -> {
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/CategoryManagementView.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/CategoryManagementView.java
index 5fb2621..6c32e82 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/CategoryManagementView.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/CategoryManagementView.java
@@ -111,7 +111,7 @@ class CategoryForm extends Composite {
this.category = category;
configureNameField();
// Focus the name field if the category is new
- if (category.getId() < 0) {
+ if (category.getId() == null) {
nameField.focus();
}
@@ -119,7 +119,7 @@ class CategoryForm extends Composite {
e -> handleConfirmDelete());
deleteButton.addStyleName(ValoTheme.BUTTON_DANGER);
deleteButton.setDescription(getTranslation(I18n.DELETE));
- deleteButton.setEnabled(category.getId() > 0);
+ deleteButton.setEnabled(category.getId() != null);
binder = new BeanValidationBinder<>(Category.class);
// Check for duplicate category names
@@ -159,7 +159,7 @@ private void handleSave() {
var saved = presenter.updateCategory(category);
if (saved != null) {
list.replaceItem(category, saved);
- if (category.getId() == -1) {
+ if (category.getId() == null) {
nameField.focus();
}
presenter.requestUpdateCategories();
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/ComponentList.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/ComponentList.java
index 094378b..1c22eb6 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/ComponentList.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/ComponentList.java
@@ -70,7 +70,11 @@ public void removeItem(T item) {
public void setItems(Collection items) {
dataProvider = new ListDataProvider<>(items);
grid.setDataProvider(dataProvider);
- grid.setHeightByRows(items.size());
+ if (!items.isEmpty()) {
+ grid.setHeightByRows(items.size());
+ } else {
+ grid.setHeightByRows(1);
+ }
}
/**
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/UserManagementPresenter.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/UserManagementPresenter.java
index 07947f6..35ff0dd 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/UserManagementPresenter.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/admin/UserManagementPresenter.java
@@ -28,7 +28,7 @@ public void requestUpdateUsers() {
view.setUsers(UserService.get().getAllUsers());
}
- public void removeUser(int id) {
+ public void removeUser(Integer id) {
accessControl.assertAdmin();
getService().removeUser(id);
logger.info("User '{}' removed.", id);
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BookGrid.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BookGrid.java
index 1141a95..c6deee1 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BookGrid.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BookGrid.java
@@ -55,7 +55,7 @@ public BookGrid() {
// Set highlight color to last edited row with style generator.
setStyleGenerator(book -> {
- if (book.getId() == edited) {
+ if (book.getId() != null && book.getId() == edited) {
return VaadinCreateTheme.BOOKVIEW_GRID_EDITED;
}
if (getLockedBooks().isLocked(book) != null) {
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksPresenter.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksPresenter.java
index 8a6b34e..7ee712a 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksPresenter.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksPresenter.java
@@ -211,7 +211,7 @@ public Product findProduct(int productId) {
}
/**
- * Saves the given product.
+ * Saves the given product
*
* @param product
* The product to be saved.
@@ -219,7 +219,7 @@ public Product findProduct(int productId) {
public Product saveProduct(Product product) {
accessControl.assertAdmin();
view.clearSelection();
- boolean newBook = product.getId() == -1;
+ boolean newBook = product.getId() == null;
logger.info("Saving product: {}", newBook ? "new" : product.getId());
try {
@@ -282,7 +282,7 @@ public void editProduct(Product product) {
if (product == null) {
view.setFragmentParameter("");
unlockBook();
- } else if (product.getId() == -1) {
+ } else if (product.getId() == null) {
view.setFragmentParameter("new");
} else {
view.setFragmentParameter(product.getId() + "");
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksView.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksView.java
index 53d2df6..1216cc0 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksView.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/BooksView.java
@@ -158,6 +158,7 @@ private HorizontalLayout createTopBar() {
newProduct = new Button(getTranslation(I18n.Books.NEW_PRODUCT));
newProduct.setId("new-product");
+ newProduct.setEnabled(false);
newProduct.addStyleName(ValoTheme.BUTTON_PRIMARY);
newProduct.setIcon(VaadinIcons.PLUS_CIRCLE);
newProduct.addClickListener(click -> presenter.newProduct());
@@ -180,7 +181,7 @@ public void enter(ViewChangeEvent event) {
grid.setReadOnly(true);
form.setVisible(false);
} else {
- form.showForm(false);
+ form.setVisible(false);
}
presenter.requestUpdateProducts();
}
@@ -226,6 +227,10 @@ public void cancelProduct() {
public void setProductsAsync(Collection products) {
try {
getUI().access(() -> {
+ if (accessControl.isUserInRole(Role.ADMIN)) {
+ form.setVisible(true);
+ newProduct.setEnabled(true);
+ }
logger.info("Updating products");
dataProvider = new ListDataProvider<>(products);
grid.setDataProvider(dataProvider);
@@ -411,7 +416,7 @@ public void editProduct(Product product) {
grid.setEdited(null);
if (product != null) {
// Ensure the product is up-to-date
- if (product.getId() > 0) {
+ if (product.getId() != null) {
product = refreshProduct(product);
if (product == null) {
showError(getTranslation(I18n.Books.PRODUCT_DELETED));
@@ -504,8 +509,8 @@ public void eventFired(Object event) {
var bookEvent = (LockingEvent) event;
getUI().access(() -> {
if (grid.getDataProvider() instanceof ListDataProvider) {
- dataProvider.getItems().stream()
- .filter(book -> book.getId() == bookEvent.getId())
+ dataProvider.getItems().stream().filter(
+ book -> book.getId().equals(bookEvent.getId()))
.findFirst().ifPresent(product -> dataProvider
.refreshItem(product));
}
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/BookForm.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/BookForm.java
index 571f7c0..831e75c 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/BookForm.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/BookForm.java
@@ -200,6 +200,9 @@ private void setStockCountAndAvailabilityInvalid(boolean invalid) {
*/
public void showForm(boolean visible) {
accessControl.assertAdmin();
+ if (this.visible == visible) {
+ return;
+ }
this.visible = visible;
if (visible) {
clearDirtyIndicators();
@@ -330,7 +333,7 @@ public void editProduct(Product product) {
if (product == null) {
product = new Product();
}
- deleteButton.setEnabled(product.getId() != -1);
+ deleteButton.setEnabled(product.getId() != null);
currentProduct = product;
binder.readBean(product);
diff --git a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/SidePanel.java b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/SidePanel.java
index 5944e79..f89caf8 100644
--- a/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/SidePanel.java
+++ b/vaadincreate-ui/src/main/java/org/vaadin/tatu/vaadincreate/crud/form/SidePanel.java
@@ -47,8 +47,10 @@ public void show(boolean visible) {
if (visible) {
JavaScript.eval(
"document.getElementById('book-form').style.display='block';");
- getUI().runAfterRoundTrip(() -> layout
- .addStyleName(VaadinCreateTheme.BOOKFORM_WRAPPER_VISIBLE));
+ if (getUI() != null) {
+ getUI().runAfterRoundTrip(() -> layout.addStyleName(
+ VaadinCreateTheme.BOOKFORM_WRAPPER_VISIBLE));
+ }
} else {
layout.removeStyleName(VaadinCreateTheme.BOOKFORM_WRAPPER_VISIBLE);
if (isAttached()) {
diff --git a/vaadincreate-ui/src/main/resources/logback.xml b/vaadincreate-ui/src/main/resources/logback.xml
new file mode 100644
index 0000000..2da21de
--- /dev/null
+++ b/vaadincreate-ui/src/main/resources/logback.xml
@@ -0,0 +1,21 @@
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/AbstractViewTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/AbstractViewTest.java
index 5936d80..59015bb 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/AbstractViewTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/AbstractViewTest.java
@@ -126,6 +126,9 @@ public void setup() throws Exception {
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless=new");
options.addArguments("--window-size=1280,900");
+ // https://issues.chromium.org/issues/367755364
+ // Headless window is opened in viewport, fix it
+ options.addArguments("--window-position=-2400,-2400");
setDriver(TestBench.createDriver(new ChromeDriver(options)));
getDriver().get(getURL(urlFragment));
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewDraftsTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewDraftsTest.java
index 3e19b44..c6539aa 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewDraftsTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewDraftsTest.java
@@ -6,7 +6,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import java.util.Collection;
+import java.util.stream.Collectors;
import org.junit.After;
import org.junit.Before;
@@ -17,7 +17,6 @@
import org.vaadin.tatu.vaadincreate.VaadinCreateUI;
import org.vaadin.tatu.vaadincreate.backend.ProductDataService;
import org.vaadin.tatu.vaadincreate.backend.data.Availability;
-import org.vaadin.tatu.vaadincreate.backend.data.Product;
import org.vaadin.tatu.vaadincreate.crud.form.AvailabilitySelector;
import org.vaadin.tatu.vaadincreate.crud.form.BookForm;
import org.vaadin.tatu.vaadincreate.crud.form.NumberField;
@@ -33,7 +32,6 @@
public class BooksViewDraftsTest extends AbstractUITest {
private VaadinCreateUI ui;
- private Collection backup;
private BookGrid grid;
private BookForm form;
private BooksView view;
@@ -48,8 +46,6 @@ public void setup() throws ServiceException {
mockVaadin(ui);
login();
- backup = service.backup();
-
view = navigate(BooksView.VIEW_NAME, BooksView.class);
layout = $(view, VerticalLayout.class).first();
@@ -60,15 +56,18 @@ public void setup() throws ServiceException {
@After
public void cleanUp() {
- service.restore(backup);
logout();
tearDown();
}
@Test
public void editBookExitContinueWithDraft() throws ServiceException {
+ createBook("Draft book");
+ test($(TextField.class).id("filter-field")).setValue("Draft book");
+
test(grid).click(1, 0);
var book = test(grid).item(0);
+ var id = book.getId();
assertTrue(form.isShown());
@@ -131,6 +130,8 @@ public void editBookExitContinueWithDraft() throws ServiceException {
.contains("Modified book"));
assertFalse(form.isShown());
+
+ ui.getProductService().deleteProduct(id);
}
@Test
@@ -196,11 +197,20 @@ public void editNewExitContinueWithDraft() throws ServiceException {
.contains("Modified book"));
assertFalse(form.isShown());
+
+ var book = test(grid).item(test(grid).size() - 1);
+ assertEquals("Modified book", book.getProductName());
+
+ var id = book.getId();
+ ui.getProductService().deleteProduct(id);
}
@Test
public void editBookExitConcurrentEditContinueWithDraft()
throws ServiceException {
+ createBook("Draft book");
+ test($(TextField.class).id("filter-field")).setValue("Draft book");
+
test(grid).click(1, 0);
var book = test(grid).item(0);
assertTrue(form.isShown());
@@ -273,11 +283,20 @@ public void editBookExitConcurrentEditContinueWithDraft()
.contains("Modified book"));
assertFalse(form.isShown());
+
+ book = test(grid).item(test(grid).size() - 1);
+ assertEquals("Modified book", book.getProductName());
+
+ var id = book.getId();
+ ui.getProductService().deleteProduct(id);
}
@Test
public void editBookExitConcurrentDeleteContinueWithDraft()
throws ServiceException {
+ createBook("Draft book");
+ test($(TextField.class).id("filter-field")).setValue("Draft book");
+
test(grid).click(1, 0);
var book = test(grid).item(0);
assertTrue(form.isShown());
@@ -348,6 +367,12 @@ public void editBookExitConcurrentDeleteContinueWithDraft()
.contains("Modified book"));
assertFalse(form.isShown());
+
+ book = test(grid).item(test(grid).size() - 1);
+ assertEquals("Modified book", book.getProductName());
+
+ var id = book.getId();
+ ui.getProductService().deleteProduct(id);
}
@Test
@@ -379,4 +404,21 @@ public void leaveDraftCancelDraft() throws ServiceException {
var about = $(AboutView.class).single();
assertNotNull(about);
}
+
+ @SuppressWarnings("unchecked")
+ private void createBook(String name) {
+ test($(view, Button.class).id("new-product")).click();
+ test($(TextField.class).id("product-name")).setValue(name);
+ test($(AvailabilitySelector.class).id("availability"))
+ .clickItem(Availability.COMING);
+ test($(TextField.class).id("price")).setValue("35.0 €");
+ var categories = VaadinCreateUI.get().getProductService()
+ .getAllCategories().stream().collect(Collectors.toList());
+ test($(CheckBoxGroup.class).id("category"))
+ .clickItem(categories.get(1));
+ test($(CheckBoxGroup.class).id("category"))
+ .clickItem(categories.get(2));
+ test($(NumberField.class).id("stock-count")).setValue(0);
+ test($(Button.class).id("save-button")).click();
+ }
}
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdTest.java
index 78ec94c..16d764d 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdTest.java
@@ -5,7 +5,9 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.math.BigDecimal;
import java.util.Collection;
+import java.util.Set;
import org.junit.After;
import org.junit.Before;
@@ -33,7 +35,7 @@ public class BooksViewEditIdTest extends AbstractUITest {
private BooksView view;
private BookGrid grid;
private BookForm form;
- private Collection backup;
+ private Integer id;
@Before
public void setup() throws ServiceException {
@@ -41,9 +43,11 @@ public void setup() throws ServiceException {
mockVaadin(ui);
login();
- backup = ui.getProductService().backup();
+ var book = createBook();
+ book = ui.getProductService().updateProduct(book);
+ id = book.getId();
- view = navigate(BooksView.VIEW_NAME + "/10", BooksView.class);
+ view = navigate(BooksView.VIEW_NAME + "/" + id, BooksView.class);
var layout = $(view, VerticalLayout.class).first();
grid = $(layout, BookGrid.class).single();
@@ -54,34 +58,42 @@ public void setup() throws ServiceException {
@After
public void cleanUp() {
- ui.getProductService().restore(backup);
+ ui.getProductService().deleteProduct(id);
logout();
tearDown();
}
+ @SuppressWarnings("unchecked")
@Test
public void editWithId() {
- var book = ui.getProductService().getProductById(10);
- assertNotNull(LockedObjects.get().isLocked(book));
- var product = ui.getProductService().getProductById(10);
+ var product = ui.getProductService().getProductById(id);
+ assertNotNull(LockedObjects.get().isLocked(product));
+
assertEquals(product, grid.asSingleSelect().getSelectedItem().get());
assertTrue(form.isShown());
assertTrue(test(grid).isFocused());
- assertEquals(product.getProductName(), $(form, TextField.class).id("product-name").getValue());
+ assertEquals(product.getProductName(),
+ $(form, TextField.class).id("product-name").getValue());
var price = $(form, TextField.class).id("price");
var converter = new EuroConverter("");
var priceString = converter.convertToPresentation(product.getPrice(),
new ValueContext(null, price, ui.getLocale()));
- assertEquals(priceString, $(form, TextField.class).id("price").getValue());
+ assertEquals(priceString,
+ $(form, TextField.class).id("price").getValue());
assertEquals(Integer.valueOf(product.getStockCount()),
$(form, NumberField.class).id("stock-count").getValue());
- assertEquals(product.getAvailability(), $(form, AvailabilitySelector.class).id("availability").getValue());
- assertEquals(product.getCategory(), $(form, CheckBoxGroup.class).id("category").getValue());
-
- test($(form, TextField.class).id("product-name")).setValue("Modified book");
+ assertEquals(product.getAvailability(),
+ $(form, AvailabilitySelector.class).id("availability")
+ .getValue());
+ assertEquals(product.getCategory(),
+ $(form, CheckBoxGroup.class).id("category").getValue());
+
+ test($(form, TextField.class).id("product-name"))
+ .setValue("Modified book");
test($(form, TextField.class).id("price")).setValue("10.0 €");
- test($(form, AvailabilitySelector.class).id("availability")).clickItem(Availability.AVAILABLE);
+ test($(form, AvailabilitySelector.class).id("availability"))
+ .clickItem(Availability.AVAILABLE);
test($(form, NumberField.class).id("stock-count")).setValue(10);
var cat = ui.getProductService().getAllCategories().stream().findFirst()
@@ -94,9 +106,19 @@ public void editWithId() {
.contains("Modified book"));
assertFalse(form.isShown());
- var savedProduct = ui.getProductService().getProductById(10);
+ var savedProduct = ui.getProductService().getProductById(id);
assertEquals("Modified book", savedProduct.getProductName());
-
}
+ private static Product createBook() {
+ var book = new Product();
+ book.setProductName("Test book");
+ book.setAvailability(Availability.COMING);
+ var categories = VaadinCreateUI.get().getProductService()
+ .findCategoriesByIds(Set.of(1, 2));
+ book.setCategory(categories);
+ book.setStockCount(0);
+ book.setPrice(BigDecimal.valueOf(35));
+ return book;
+ }
}
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdUserTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdUserTest.java
index 86980b0..4b2542b 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdUserTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditIdUserTest.java
@@ -8,6 +8,7 @@
import org.junit.Test;
import org.vaadin.tatu.vaadincreate.AbstractUITest;
import org.vaadin.tatu.vaadincreate.VaadinCreateUI;
+import org.vaadin.tatu.vaadincreate.backend.data.Product;
import org.vaadin.tatu.vaadincreate.crud.form.BookForm;
import com.vaadin.server.Page;
@@ -27,7 +28,8 @@ public void setup() throws ServiceException {
mockVaadin(ui);
login("User1", "user1");
- view = navigate(BooksView.VIEW_NAME + "/10", BooksView.class);
+ var id = getNthProduct(10).getId();
+ view = navigate(BooksView.VIEW_NAME + "/" + id, BooksView.class);
var layout = $(view, VerticalLayout.class).first();
grid = $(layout, BookGrid.class).single();
@@ -48,4 +50,9 @@ public void editWithId() {
assertEquals("!inventory/", Page.getCurrent().getUriFragment());
}
+ private Product getNthProduct(int n) {
+ return ui.getProductService().getAllProducts().stream().skip(n)
+ .findFirst().get();
+ }
+
}
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditLockedIdTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditLockedIdTest.java
index 102d441..7e05e4f 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditLockedIdTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewEditLockedIdTest.java
@@ -9,6 +9,7 @@
import org.vaadin.tatu.vaadincreate.AbstractUITest;
import org.vaadin.tatu.vaadincreate.VaadinCreateUI;
import org.vaadin.tatu.vaadincreate.auth.CurrentUser;
+import org.vaadin.tatu.vaadincreate.backend.data.Product;
import org.vaadin.tatu.vaadincreate.crud.form.BookForm;
import org.vaadin.tatu.vaadincreate.locking.LockedObjects;
@@ -22,6 +23,7 @@ public class BooksViewEditLockedIdTest extends AbstractUITest {
private BooksView view;
private BookGrid grid;
private BookForm form;
+ private Integer id;
@Before
public void setup() throws ServiceException {
@@ -29,12 +31,13 @@ public void setup() throws ServiceException {
mockVaadin(ui);
login();
- view = navigate(BooksView.VIEW_NAME + "/10", BooksView.class);
+ id = getNthProduct(10).getId();
+ view = navigate(BooksView.VIEW_NAME + "/" + id, BooksView.class);
var layout = $(view, VerticalLayout.class).first();
grid = $(layout, BookGrid.class).single();
- var book = ui.getProductService().getProductById(10);
+ var book = getNthProduct(10);
LockedObjects.get().lock(book, CurrentUser.get().get());
waitForGrid(layout, grid);
@@ -43,7 +46,7 @@ public void setup() throws ServiceException {
@After
public void cleanUp() {
- var book = ui.getProductService().getProductById(10);
+ var book = getNthProduct(10);
LockedObjects.get().unlock(book);
logout();
tearDown();
@@ -51,9 +54,14 @@ public void cleanUp() {
@Test
public void editWithLockedIdShowsError() {
- assertEquals("Product id \"10\" is locked.",
+ assertEquals("Product id \"" + id + "\" is locked.",
$(Notification.class).last().getCaption());
assertFalse(form.isShown());
}
+ private Product getNthProduct(int n) {
+ return ui.getProductService().getAllProducts().stream().skip(n)
+ .findFirst().get();
+ }
+
}
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewIdNotFoundTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewIdNotFoundTest.java
index 8814098..1c0963a 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewIdNotFoundTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewIdNotFoundTest.java
@@ -27,7 +27,7 @@ public void setup() throws ServiceException {
mockVaadin(ui);
login();
- view = navigate(BooksView.VIEW_NAME + "/1234", BooksView.class);
+ view = navigate(BooksView.VIEW_NAME + "/12345", BooksView.class);
var layout = $(view, VerticalLayout.class).first();
grid = $(layout, BookGrid.class).single();
@@ -44,7 +44,7 @@ public void cleanUp() {
@Test
public void error() {
- assertEquals("Product id \"1234\" not valid or found.",
+ assertEquals("Product id \"12345\" not valid or found.",
$(Notification.class).last().getCaption());
assertFalse(form.isShown());
}
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewNewTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewNewTest.java
index 70b165e..9ff14de 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewNewTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewNewTest.java
@@ -30,7 +30,6 @@ public class BooksViewNewTest extends AbstractUITest {
private BooksView view;
private BookGrid grid;
private BookForm form;
- private Collection backup;
@Before
public void setup() throws ServiceException {
@@ -38,20 +37,16 @@ public void setup() throws ServiceException {
mockVaadin(ui);
login();
- backup = ui.getProductService().backup();
-
view = navigate(BooksView.VIEW_NAME + "/new", BooksView.class);
var layout = $(view, VerticalLayout.class).first();
grid = $(layout, BookGrid.class).single();
waitForGrid(layout, grid);
form = $(view, BookForm.class).single();
-
}
@After
public void cleanUp() {
- ui.getProductService().restore(backup);
logout();
tearDown();
}
@@ -86,6 +81,8 @@ public void newProduct() {
assertEquals("A new product", test(grid).cell(1, row));
assertEquals("10.00 €", test(grid).cell(2, row));
assertEquals("10", test(grid).cell(4, row));
+
+ ui.getProductService().deleteProduct(test(grid).item(row).getId());
}
}
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewTest.java
index 450e747..00d12d7 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/crud/BooksViewTest.java
@@ -2,7 +2,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -12,8 +11,8 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.util.Collection;
import java.util.Collections;
+import java.util.stream.Collectors;
import org.junit.After;
import org.junit.Before;
@@ -47,7 +46,6 @@ public class BooksViewTest extends AbstractUITest {
private BooksView view;
private BookGrid grid;
private BookForm form;
- private Collection backup;
@Before
public void setup() throws ServiceException {
@@ -55,8 +53,6 @@ public void setup() throws ServiceException {
mockVaadin(ui);
login();
- backup = ui.getProductService().backup();
-
view = navigate(BooksView.VIEW_NAME, BooksView.class);
var layout = $(view, VerticalLayout.class).first();
@@ -67,7 +63,6 @@ public void setup() throws ServiceException {
@After
public void cleanUp() {
- ui.getProductService().restore(backup);
logout();
tearDown();
}
@@ -191,7 +186,8 @@ public void addProduct() {
assertTrue(
test($(form, TextField.class).id("product-name")).isFocused());
- test($(form, TextField.class).id("product-name")).setValue("New book");
+ test($(form, TextField.class).id("product-name"))
+ .setValue("Filter book");
test($(form, TextField.class).id("price")).setValue("10.0 €");
test($(form, AvailabilitySelector.class).id("availability"))
.clickItem(Availability.AVAILABLE);
@@ -206,24 +202,27 @@ public void addProduct() {
assertTrue(test(grid).isFocused());
- assertTrue(
- $(Notification.class).last().getCaption().contains("New book"));
+ assertTrue($(Notification.class).last().getCaption()
+ .contains("Filter book"));
assertTrue(ui.getProductService().getAllProducts().stream()
- .anyMatch(b -> b.getProductName().equals("New book")));
+ .anyMatch(b -> b.getProductName().equals("Filter book")));
// New book is added to the end
int row = test(grid).size() - 1;
- assertEquals("New book", test(grid).cell(1, row));
+ assertEquals("Filter book", test(grid).cell(1, row));
assertEquals("10.00 €", test(grid).cell(2, row));
assertEquals("10", test(grid).cell(4, row));
// Find by filter and its the first row
- test($(TextField.class).id("filter-field")).setValue("New book");
+ test($(TextField.class).id("filter-field")).setValue("Filter book");
assertEquals(1, test(grid).size());
- assertEquals("New book", test(grid).cell(1, 0));
+ assertEquals("Filter book", test(grid).cell(1, 0));
assertEquals("10.00 €", test(grid).cell(2, 0));
assertEquals("10", test(grid).cell(4, 0));
+
+ // Cleanup
+ ui.getProductService().deleteProduct(test(grid).item(0).getId());
}
@Test
@@ -258,11 +257,15 @@ public void addAndCancelEmpty() {
@Test
public void deleteProduct() {
- var book = test(grid).item(0);
- test(grid).click(1, 0);
+ createBook("Delete book");
+ test($(TextField.class).id("filter-field")).setValue("Delete book");
+
+ var row = 0;
+ var book = test(grid).item(row);
var id = book.getId();
- var name = book.getProductName();
+ assertEquals("Delete book", book.getProductName());
+ test(grid).click(1, row);
test($(form, Button.class).id("delete-button")).click();
@@ -275,15 +278,34 @@ public void deleteProduct() {
assertEquals(null, ui.getProductService().getProductById(id));
- var newName = test(grid).cell(1, 0);
- assertNotEquals(name, newName);
+ assertEquals(0, test(grid).size());
+ }
+
+ @SuppressWarnings("unchecked")
+ private void createBook(String name) {
+ test($(view, Button.class).id("new-product")).click();
+ test($(TextField.class).id("product-name")).setValue(name);
+ test($(AvailabilitySelector.class).id("availability"))
+ .clickItem(Availability.AVAILABLE);
+ test($(TextField.class).id("price")).setValue("35.0 €");
+ var categories = VaadinCreateUI.get().getProductService()
+ .getAllCategories().stream().collect(Collectors.toList());
+ test($(CheckBoxGroup.class).id("category"))
+ .clickItem(categories.get(1));
+ test($(CheckBoxGroup.class).id("category"))
+ .clickItem(categories.get(2));
+ test($(NumberField.class).id("stock-count")).setValue(100);
+ test($(Button.class).id("save-button")).click();
}
@Test
public void concurrentDelete() {
+ createBook("Concurrent delete");
+
// Simulate other user deleting the book
+ test($(TextField.class).id("filter-field"))
+ .setValue("Concurrent delete");
var book = test(grid).item(0);
- var name = book.getProductName();
ui.getProductService().deleteProduct(book.getId());
test(grid).click(1, 0);
@@ -291,17 +313,22 @@ public void concurrentDelete() {
$(Notification.class).last().getCaption());
assertFalse(form.isShown());
- var newName = test(grid).cell(1, 0);
- assertNotEquals(name, newName);
+ assertEquals(0, test(grid).size());
}
@Test
public void editProduct() {
- var book = test(grid).item(0);
- test(grid).click(1, 0);
+ createBook("Test book");
+
+ test($(TextField.class).id("filter-field")).setValue("Test book");
+
+ var row = 0;
+ var book = test(grid).item(row);
+ test(grid).click(1, row);
assertTrue(form.isShown());
var id = book.getId();
+ assertNotNull(id);
test($(form, TextField.class).id("product-name"))
.setValue("Edited book");
@@ -310,13 +337,15 @@ public void editProduct() {
var edited = ui.getProductService().getProductById(id);
- var name = (String) test(grid).cell(1, 0);
+ test($(TextField.class).id("filter-field")).setValue("Edited book");
+ var name = (String) test(grid).cell(1, row);
assertEquals("Edited book", name);
assertEquals("Edited book", edited.getProductName());
assertEquals(VaadinCreateTheme.BOOKVIEW_GRID_EDITED,
test(grid).styleName(0));
+ ui.getProductService().deleteProduct(id);
}
@Test
@@ -415,8 +444,9 @@ public void openProductChangedByOtherUser() {
// Simulate other user persisting a change to the database
var edited = ui.getProductService().getProductById(book.getId());
+ var productName = edited.getProductName();
edited.setProductName("Touched book");
- ui.getProductService().updateProduct(edited);
+ var saved = ui.getProductService().updateProduct(edited);
test(grid).click(1, 0);
assertTrue(form.isShown());
@@ -430,6 +460,9 @@ public void openProductChangedByOtherUser() {
test($(form, Button.class).id("cancel-button")).click();
assertFalse(form.isShown());
+
+ edited.setProductName(productName);
+ ui.getProductService().updateProduct(saved);
}
@Test
@@ -445,8 +478,10 @@ public void editLockedProduct() {
@Test
public void weakLockConcurrentEdit() {
- // Idea of this is to simulate Form being detached due browser crash so
- // that form no longer holds the product reference. Here it is simulated
+ // Idea of this is to simulate Form being detached due browser
+ // crash so
+ // that form no longer holds the product reference. Here it is
+ // simulated
// by doing lock via proxy object.
var book = new Product(test(grid).item(0));
LockedObjects.get().lock(book, CurrentUser.get().get());
@@ -460,7 +495,7 @@ public void weakLockConcurrentEdit() {
assertTrue(form.isShown());
// Concurrent edit is now possible, simulate it
- ui.getProductService().updateProduct(test(grid).item(0));
+ ui.getProductService().updateProduct(new Product(test(grid).item(0)));
// Change and save
test($(form, TextField.class).id("product-name"))
@@ -476,9 +511,15 @@ public void weakLockConcurrentEdit() {
@Test
public void weakLockConcurrentDelete() {
- // Idea of this is to simulate Form being detached due browser crash so
- // that form no longer holds the product reference. Here it is simulated
+ // Idea of this is to simulate Form being detached due browser
+ // crash so
+ // that form no longer holds the product reference. Here it is
+ // simulated
// by doing lock via proxy object.
+ createBook("Concurrent delete");
+ test($(TextField.class).id("filter-field"))
+ .setValue("Concurrent delete");
+
var book = new Product(test(grid).item(0));
LockedObjects.get().lock(book, CurrentUser.get().get());
assertEquals("Edited by Admin", test(grid).description(0));
@@ -579,6 +620,9 @@ public void editProductRevertEdit() {
// Assert that form content was updated
assertEquals($(form, TextField.class).id("product-name").getValue(),
test(grid).cell(1, 1));
+
+ test($(form, Button.class).id("cancel-button")).click();
+ assertFalse(form.isShown());
}
@Test
@@ -594,6 +638,8 @@ public void editProductDiscardChangesWhenNavigate() {
var dialog = $(Window.class).id("confirm-dialog");
test($(dialog, Button.class).id("confirm-button")).click();
+ assertFalse(form.isShown());
+
assertEquals(1, $(AboutView.class).size());
assertEquals(0, $(BooksView.class).size());
}
@@ -644,10 +690,12 @@ public void categoriesValid() {
var category = new Category();
category.setName("Science");
category = ui.getProductService().updateCategory(category);
+ assertNotNull(category.getId());
test(grid).click(1, 0);
- // Simulate other user deleting the category while editor is open
+ // Simulate other user deleting the category while editor is
+ // open
ui.getProductService().deleteCategory(category.getId());
test($(form, CheckBoxGroup.class).id("category")).clickItem(category);
@@ -655,6 +703,9 @@ public void categoriesValid() {
assertEquals("One or more of the selected categories were deleted.",
$(Notification.class).last().getCaption());
+
+ test($(form, Button.class).id("cancel-button")).click();
+ assertFalse(form.isShown());
}
@Test
@@ -685,7 +736,10 @@ public void sanitation() {
// Assert text content remain
assertTrue(test(grid).description(row).contains("A new book"));
- test(grid).click(1,row);
+ test(grid).click(1, row);
+ var id = test(grid).item(row).getId();
+ assertNotNull(id);
+
assertTrue(form.isShown());
test($(form, TextField.class).id("product-name"))
@@ -707,6 +761,8 @@ public void sanitation() {
test($(form, Button.class).id("discard-button")).click();
test($(form, Button.class).id("cancel-button")).click();
assertFalse(form.isShown());
+
+ ui.getProductService().deleteProduct(id);
}
@Test
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/locking/LockedObjectsTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/locking/LockedObjectsTest.java
index 0321b66..385beb4 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/locking/LockedObjectsTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/locking/LockedObjectsTest.java
@@ -41,7 +41,7 @@ public void lockAndUnlockObject() {
var event = listener.getLastEvent();
assertEquals(1, listener.getEventCount());
assertEquals(user, event.getUser());
- assertEquals(objects.get(0).getId(), (int) event.getId());
+ assertEquals(objects.get(0).getId(), event.getId());
assertEquals(MockObject.class, event.getType());
assertTrue(event.isLocked());
@@ -51,7 +51,7 @@ public void lockAndUnlockObject() {
event = listener.getLastEvent();
assertEquals(2, listener.getEventCount());
assertEquals(user, event.getUser());
- assertEquals(objects.get(0).getId(), (int) event.getId());
+ assertEquals(objects.get(0).getId(), event.getId());
assertEquals(MockObject.class, event.getType());
assertFalse(event.isLocked());
diff --git a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/stats/StatsViewTest.java b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/stats/StatsViewTest.java
index 1c52fe0..eb799bf 100644
--- a/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/stats/StatsViewTest.java
+++ b/vaadincreate-ui/src/test/java/org/vaadin/tatu/vaadincreate/stats/StatsViewTest.java
@@ -127,7 +127,6 @@ private void assertStatistics(Map prices,
private static Product createBook() {
var book = new Product();
- book.setId(-1);
book.setProductName("Test");
book.setAvailability(Availability.AVAILABLE);
var categories = VaadinCreateUI.get().getProductService()