diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..d1baf75 --- /dev/null +++ b/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..607f702 --- /dev/null +++ b/.project @@ -0,0 +1,42 @@ + + + person-service + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/README.md b/README.md index f57af54..0682468 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,84 @@ Person Service ============== -A simple JPA backend service that loads data from a CSV file and make it -accessible through `Person` entity. +**You can clone this project and import it directly into Eclipse** -It can be easily upgraded to read/write from a real database instead of the CSV -file. +A simple JPA backend service that loads data from a CSV file and make it accessible through `Person` entity. -You can modify the provided demo data from `Persons.csv` located under -`src/resources`. +It can be easily upgraded to read/write from a real database instead of the CSV file. + +You can modify the provided demo data from `Persons.csv` located under `src/resources`. + +Watch step by step on how to use this backend in a Vaadin project +- + +[![Vaadin Demo Coding in a Youtube Video](http://img.youtube.com/vi/Lwhg3NrOLVA/0.jpg)](https://www.youtube.com/watch?v=Lwhg3NrOLVA) + +Referencing This Project Into Another Maven Project +- + +After installing this project locally, you can reference it by including it as a dependency into the front-end project. Most probably you will need to include JavaEE dependencies as well: + +```xml + + ... + + + javax + javaee-api + 7.0 + provided + + + + org.vaadin.stepbystep + person-service + 2.0 + + + ... + +``` + +Usage +- + +- Inject `PersonService`. +- Call `getEntries()` to return a list of `Person`. +- Call `delete()` or `save()` to update a given entity. +- Call `getFirst()` to retrieve the first entity. +- Call `getById()` to retrieve an entity by its id. + +Example +- + +```java + @Inject + PersonService service; + + void load() { + component.bind(service.getEntries()); + } +``` + +Obtain Maven dependency +- + +You can obtain the maven dependency from [Vaadin Directory](https://vaadin.com/directory/#!addon/demo-person-service) without any downloads or installs. + +Import & Install Using CLI +- + +Platform and IDE independent, you can install this project locally using the following three commands: +```bash + $ git clone git@github.com:amahdy/person-service.git + $ cd person-service + $ mvn install +``` +Or alternatively: Import Into Eclipse -=================== +- This project is easy to import into Eclipse from the [eclipse-project branch](https://github.com/amahdy/person-service/tree/eclipse-project). Here are the direct steps to get started: @@ -58,51 +125,3 @@ This project is easy to import into Eclipse from the [eclipse-project branch](ht **Step 11) You should get a BUILD SUCCESS in the Console, now the project is ready to be used locally** ![You should get a BUILD SUCCESS in the Console, now the project is ready to be used locally](/readme_files/step11.png?raw=true "You should get a BUILD SUCCESS in the Console, now the project is ready to be used locally") - -Referencing this project into another Maven project -=================================================== -After installing this project locally, you can easily reference it by including it as a dependecy into the front-end project. Most porbably you will need to include JavaEE dependencies as well: - -```xml - - ... - - - javax - javaee-api - 7.0 - provided - - - - org.vaadin.stepbystep - person-service - 1.0 - - - ... - -``` - -Usage -===== - -- Inject `PersonService`. -- Call `loadData()` to load the data from the CSV file. -- Call `getEntries()` to return a list of `Person`. -- Call `delete()` or `save()` to update a given entity. - -Example -======= - -```java - @Inject - PersonService service; - - @PostConstruct - void load() { - service.loadData(); - - container.bind(service.getEntries()); - } -``` diff --git a/pom.xml b/pom.xml index 9789052..d761ada 100644 --- a/pom.xml +++ b/pom.xml @@ -6,8 +6,11 @@ org.vaadin.stepbystep person-service jar - 1.0 - Person Service: Step by step backend demo for a Vaadin app + 2.0 + Demo Person Service + + AMahdy + 3 @@ -18,6 +21,12 @@ 1.8 1.8 1.4.1 + ${project.version} + + ${project.name} + ${project.organization.name} + Apache License 2.0 + ${project.artifactId}-${project.version}.jar @@ -62,5 +71,26 @@ + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + true + + true + true + + + + 1 + ${Vaadin-License-Title} + + + + + diff --git a/src/main/java/org/vaadin/stepbystep/person/backend/LocalDateAttributeConverter.java b/src/main/java/org/vaadin/stepbystep/person/backend/LocalDateAttributeConverter.java new file mode 100644 index 0000000..9a6bc4e --- /dev/null +++ b/src/main/java/org/vaadin/stepbystep/person/backend/LocalDateAttributeConverter.java @@ -0,0 +1,20 @@ +package org.vaadin.stepbystep.person.backend; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import java.sql.Date; +import java.time.LocalDate; + +@Converter(autoApply = true) +public class LocalDateAttributeConverter implements AttributeConverter { + + @Override + public Date convertToDatabaseColumn(LocalDate locDate) { + return (locDate == null ? null : Date.valueOf(locDate)); + } + + @Override + public LocalDate convertToEntityAttribute(Date sqlDate) { + return (sqlDate == null ? null : sqlDate.toLocalDate()); + } +} diff --git a/src/main/java/org/vaadin/stepbystep/person/backend/Person.java b/src/main/java/org/vaadin/stepbystep/person/backend/Person.java index a7ba60f..7cfcb47 100644 --- a/src/main/java/org/vaadin/stepbystep/person/backend/Person.java +++ b/src/main/java/org/vaadin/stepbystep/person/backend/Person.java @@ -1,14 +1,12 @@ package org.vaadin.stepbystep.person.backend; -import java.util.Date; - import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Lob; -import javax.persistence.Temporal; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; +import java.time.LocalDate; /** * A domain object example. In a real application this would probably be a JPA @@ -18,20 +16,19 @@ @Entity public class Person extends AbstractEntity { - @NotNull(message = "Firstname is required") - @Size(min = 3, max = 40, message = "Firstname must be longer than 3 and less than 40 characters") - private String firstname; + @NotNull(message = "First Name is required") + @Size(min = 3, max = 40, message = "First Name must be longer than 3 and less than 40 characters") + private String firstName; - @NotNull(message = "Lastname is required") - @Size(min = 3, max = 40, message = "Lastname must be longer than 3 and less than 40 characters") - private String lastname; + @NotNull(message = "Last Name is required") + @Size(min = 3, max = 40, message = "Last Name must be longer than 3 and less than 40 characters") + private String lastName; @NotNull(message = "Email is required") @Pattern(regexp = ".+@.+\\.[a-z]+", message = "Must be valid email") private String email; - @Temporal(javax.persistence.TemporalType.DATE) - private Date birthDate; + private LocalDate dateOfBirth; private boolean remind = false; @@ -44,20 +41,20 @@ public class Person extends AbstractEntity { public Person() { } - public String getFirstname() { - return firstname; + public String getFirstName() { + return firstName; } - public void setFirstname(String firstname) { - this.firstname = firstname; + public void setFirstName(String firstName) { + this.firstName = firstName; } - public String getLastname() { - return lastname; + public String getLastName() { + return lastName; } - public void setLastname(String lastname) { - this.lastname = lastname; + public void setLastName(String lastName) { + this.lastName = lastName; } public boolean isRemind() { @@ -76,12 +73,12 @@ public void setEmail(String email) { this.email = email; } - public Date getBirthDate() { - return birthDate; + public LocalDate getDateOfBirth() { + return dateOfBirth; } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; + + public void setDateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; } public String getPicture() { diff --git a/src/main/java/org/vaadin/stepbystep/person/backend/PersonService.java b/src/main/java/org/vaadin/stepbystep/person/backend/PersonService.java index 59ac4ef..79fe6c2 100644 --- a/src/main/java/org/vaadin/stepbystep/person/backend/PersonService.java +++ b/src/main/java/org/vaadin/stepbystep/person/backend/PersonService.java @@ -1,18 +1,19 @@ package org.vaadin.stepbystep.person.backend; +import javax.annotation.PostConstruct; +import javax.ejb.Stateless; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.text.ParseException; -import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.List; - -import javax.ejb.Stateless; -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import java.util.Locale; /** * EJB to hide JPA related stuff from the UI layer. @@ -33,17 +34,32 @@ public List getEntries() { return entryRepo.findAll(); } - public void save(Person entity) { - entryRepo.save(entity); + public Person getFirst() { + return entryRepo.findAll(0, 1).get(0); + } + + public Person getById(Long id) { + return entryRepo.findById(id).getSingleResult(); + } + + public Person save(Person entity) { + return entryRepo.saveAndFlush(entity); } public void delete(Person entity) { // Hibernate cannot remove detached, reattach... - entryRepo.remove(entryRepo.findBy(entity.getId())); + entryRepo.removeAndFlush(entryRepo.findBy(entity.getId())); } + @PostConstruct public void loadData() { + if(entryRepo.count() != 0) { + return; + } + + // Fill in demo data + String csvFile = "Persons.csv"; BufferedReader br = null; String line = ""; @@ -54,21 +70,18 @@ public void loadData() { InputStream inputStream = getClass().getClassLoader().getResourceAsStream(csvFile); br = new BufferedReader(new InputStreamReader(inputStream)); - SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yy"); + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("d-MMM-yy") + .withLocale(Locale.US); while ((line = br.readLine()) != null) { String[] person = line.split(cvsSplitBy); Person entry = new Person(); // entry.setId(Long.parseLong(person[0])); - entry.setFirstname(person[1]); - entry.setLastname(person[2]); + entry.setFirstName(person[1]); + entry.setLastName(person[2]); entry.setEmail(person[3]); - try { - entry.setBirthDate(sdf.parse(person[4])); - } catch (ParseException e) { - e.printStackTrace(); - } + entry.setDateOfBirth(LocalDate.parse(person[4], dtf)); entry.setRemind(Math.random() > 0.5); entry.setPicture(person[5]); entry.setNotes(person[6]); diff --git a/src/resources/META-INF/persistence.xml b/src/resources/META-INF/persistence.xml index 2c44b2b..7c08e06 100644 --- a/src/resources/META-INF/persistence.xml +++ b/src/resources/META-INF/persistence.xml @@ -5,9 +5,9 @@ server will generate a test database automatically for you. For production deployment you'll want to configure data source in your app server and poin it to your database. --> - + - +