Services – mit REST, JPA 2, EJB 3.2, JSF 2.2, Angular JS

Dienstag, 30. Juni 2015 von  
unter Fachartikel Architektur

Die Motivation

Das MVVM Framework ‘Angular JS‘ ermöglicht ebenfalls unter Einsatz des Router Design Patterns und des Front Controller Design Patterns das Erstellen von responsiven (Mobile) Applikationen zur Stammdatenpflege von über ein Service Interface verfügbaren Daten aus einem RESTful WebService. Die erstellte JEE7 Beispiel-Applikation ‘petstore‘ arbeitet auf Basis der Template-Technologie und ermöglicht die leichte Pflege von und die Suche nach Produkten bestimmter Kategorien und Bestellungen von Kunden, etc. Die Beispiel-Applikation verwendet die JPA-Entities des Petstore-JEE Beispiels aus den Sun-/Oracle-Blueprints und erweitert diese, außerdem werden mittels JBoss Forge sowohl JSF 2.2 Benutzerschnittstellen verfügbar gemacht, als auch die Angular JS GUIs. An diesem einfachen, übersichtlichen JEE7 Beispielprojekt wird dadurch die Verwendung der eingesetzten Technologien gezeigt und dieses als .war Archiv-Deployment auf dem JBoss WildFly 8.2 Application Server zum Test zur Verfügung gestellt.

TDD der Beispiel Applikation

Wie zusätzliche Selenium-Tests mit dem Selenium FireFox-PlugIn durchgeführt und diese Tests gespeichert werden können, ist bereits in diesem Blog-Eintrag hier beschrieben. Diese Selenium Tests können gespeichert und in einer Test-Suite zusammengefasst werden, um auch später jederzeit die korrekte Funktionsweise der Eingabe-Aktionen und Link-Aufrufe der Mobile Applikation automatisiert verifizieren zu können.

Die Technologien:

Die Beispiel-Applikation ‘petstore‘ verwendet im Frontend Angular.js und HTML5-/CSS3, als auch die JavaScript-Bibliotheken Bootstrap.js, Backbone.js, jQuery und jQuery Mobile, sowie die Underscore.js Tools.

Für das JAX-RS Service-Backend kommt Java EE zum Einsatz (Stateful/Stateless EJB 3.2 und JEE 7) und im Backend Model JPA 2.1 Entities. Die Applikation wurde auf dem ‘JBoss WildFly 8.2‘ und dem ‘JBoss EAP 6.3‘ Applikationsserver erfolgreich deployt und getestet und kann gerne weiterverwendet und als Open Source weiterentwickelt werden.

Für die Weiterentwicklung, den Build und das Deployment des Projekts ist mindestens Java 6 und Maven 3 erforderlich. Als Entwicklungsumgebungen wurde Eclipse 4.3/4.4 (Kepler/Luna) in Form des “JBoss Developer Studios 7.1.1/8.1.0“ mit Java 7 und Java 8 verwendet und die FireFox WebDeveloper IDE/Tools.

Hier die verwendete pom.xml (mit den WildFly JEE 7 Dependencies):

<?xml version=“1.0″ encoding=“UTF-8″?>
<project xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“ xmlns=“http://maven.apache.org/POM/4.0.0″
   xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance“>
<modelVersion>4.0.0</modelVersion>
<groupId>de.binaris</groupId>
<artifactId>petstore</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>petstore</name>
<description>Java EE 7 HTML5 JSF 2.2. Web Application</description>
<properties>
   <buildhelper.plugin.version>1.7</buildhelper.plugin.version>
   <jboss.home>${env.JBOSS_HOME}</jboss.home>
   <jboss.wfk.bom.version>2.6.0-redhat-1</jboss.wfk.bom.version>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <maven.build.timestamp.format>yyyyMMdd’T’HHmmss</maven.build.timestamp.format>
   <jboss.bom.version>6.2.3.GA</jboss.bom.version>
</properties>
<dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>org.wildfly.bom</groupId>
       <artifactId>jboss-javaee-7.0-with-tools</artifactId>
       <version>8.1.0.Final</version>
       <type>pom</type>
       <scope>import</scope>
     </dependency>
     <dependency>
       <groupId>org.wildfly.bom</groupId>
       <artifactId>jboss-javaee-7.0-with-hibernate</artifactId>
       <version>8.1.0.Final</version>
       <type>pom</type>
       <scope>import</scope>
     </dependency>
     <dependency>
       <groupId>org.wildfly.bom</groupId>
       <artifactId>jboss-javaee-7.0-with-resteasy</artifactId>
       <version>8.1.0.Final</version>
       <type>pom</type>
       <scope>import</scope>
     </dependency>
     <dependency>
       <groupId>org.jboss.spec</groupId>
       <artifactId>jboss-javaee-6.0</artifactId>
       <version>3.0.2.Final</version>
       <type>pom</type>
       <scope>import</scope>
     </dependency>
   </dependencies>
</dependencyManagement>
<dependencies>
   <dependency>
     <groupId>javax.enterprise</groupId>
     <artifactId>cdi-api</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.annotation</groupId>
     <artifactId>jboss-annotations-api_1.1_spec</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.interceptor</groupId>
     <artifactId>jboss-interceptors-api_1.1_spec</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.ws.rs</groupId>
     <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
     <version>1.0.0.Alpha1</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.hibernate.javax.persistence</groupId>
     <artifactId>hibernate-jpa-2.1-api</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.ejb</groupId>
     <artifactId>jboss-ejb-api_3.2_spec</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-validator</artifactId>
     <scope>provided</scope>
     <exclusions>
       <exclusion>
         <artifactId>slf4j-api</artifactId>
         <groupId>org.slf4j</groupId>
       </exclusion>
     </exclusions>
   </dependency>
   <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-jpamodelgen</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.arquillian.junit</groupId>
     <artifactId>arquillian-junit-container</artifactId>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.arquillian.protocol</groupId>
     <artifactId>arquillian-protocol-servlet</artifactId>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.shrinkwrap.resolver</groupId>
     <artifactId>shrinkwrap-resolver-depchain</artifactId>
     <type>pom</type>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.resteasy</groupId>
     <artifactId>resteasy-jackson2-provider</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.jboss.resteasy</groupId>
     <artifactId>resteasy-jaxrs</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>javax.faces</groupId>
     <artifactId>javax.faces-api</artifactId>
     <version>2.2</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-core</artifactId>
     <version>2.0.2</version>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.servlet</groupId>
     <artifactId>jboss-servlet-api_3.1_spec</artifactId>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.webjars</groupId>
     <artifactId>bootstrap</artifactId>
     <version>2.3.2</version>
   </dependency>
   <dependency>
     <groupId>org.primefaces</groupId>
     <artifactId>primefaces</artifactId>
     <version>4.0</version>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.servlet</groupId>
     <artifactId>jboss-servlet-api_3.0_spec</artifactId>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.ws.rs</groupId>
     <artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
   </dependency>
   <dependency>
     <groupId>org.jboss.spec.javax.transaction</groupId>
     <artifactId>jboss-transaction-api_1.1_spec</artifactId>
   </dependency>
</dependencies>
<repositories>
   <repository>
     <releases>
       <enabled>true</enabled>
     </releases>
     <snapshots>
       <enabled>false</enabled>
     </snapshots>
     <id>jboss-ga-repository</id>
     <url>http://maven.repository.redhat.com/techpreview/all</url>
   </repository>
</repositories>
<pluginRepositories>
   <pluginRepository>
     <releases>
       <enabled>true</enabled>
     </releases>
     <snapshots>
       <enabled>false</enabled>
     </snapshots>
     <id>jboss-ga-plugin-repository</id>
     <url>http://maven.repository.redhat.com/techpreview/all</url>
   </pluginRepository>
</pluginRepositories>
<build>
   <finalName>${project.artifactId}</finalName>
   <pluginManagement>
     <plugins>
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.3.1</version>
         <configuration>
           <source>1.7</source>
           <target>1.7</target>
         </configuration>
       </plugin>
       <plugin>
         <artifactId>maven-war-plugin</artifactId>
         <version>2.1.1</version>
         <configuration>
           <failOnMissingWebXml>false</failOnMissingWebXml>
           <archive>
             <manifestEntries>
               <Dependencies>org.jboss.as.naming,org.jboss.as.server,org.jboss.msc</Dependencies>
             </manifestEntries>
           </archive>
         </configuration>
       </plugin>
       <plugin>
         <groupId>org.jboss.as.plugins</groupId>
         <artifactId>jboss-as-maven-plugin</artifactId>
         <version>7.4.Final</version>
       </plugin>
     </plugins>
   </pluginManagement>
</build>
<profiles>
   <profile>
     <activation>
       <activeByDefault>true</activeByDefault>
     </activation>
     <build>
       <plugins>
         <plugin>
           <artifactId>maven-surefire-plugin</artifactId>
           <version>2.4.3</version>
           <configuration>
             <skip>true</skip>
           </configuration>
         </plugin>
       </plugins>
     </build>
   </profile>
   <profile>
     <id>arq-wildfly-managed</id>
     <dependencies>
       <dependency>
         <groupId>org.wildfly</groupId>
         <artifactId>wildfly-arquillian-container-managed</artifactId>
         <scope>test</scope>
       </dependency>
     </dependencies>
   </profile>
   <profile>
     <id>arq-wildfly-remote</id>
     <dependencies>
       <dependency>
         <groupId>org.wildfly</groupId>
         <artifactId>wildfly-arquillian-container-remote</artifactId>
         <scope>test</scope>
       </dependency>
     </dependencies>
   </profile>
   <profile>
     <id>mysql</id>
     <build>
       <resources>
         <resource>
           <directory>src/main/resources</directory>
         </resource>
         <resource>
           <directory>src/main/resources</directory>
           <includes>
             <include>**/*</include>
           </includes>
           <excludes>
             <exclude>META-INF/*</exclude>
           </excludes>
         </resource>
       </resources>
       <plugins>
         <plugin>
           <artifactId>maven-surefire-plugin</artifactId>
           <version>2.4.3</version>
           <configuration>
             <skip>true</skip>
           </configuration>
         </plugin>
       </plugins>
     </build>
   </profile>
   <profile>
     <id>release-dist</id>
     <build>
       <plugins>
         <plugin>
           <artifactId>maven-assembly-plugin</artifactId>
           <executions>
             <execution>
               <phase>package</phase>
               <goals>
                 <goal>single</goal>
               </goals>
             </execution>
           </executions>
           <configuration>
             <descriptors>
               <descriptor>src/main/assembly/assembly.xml</descriptor>
             </descriptors>
           </configuration>
         </plugin>
         <plugin>
           <artifactId>maven-surefire-plugin</artifactId>
           <configuration>
             <skip>true</skip>
           </configuration>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>exec-maven-plugin</artifactId>
            <version>1.2.1</version>
           <executions>
             <execution>
               <phase>compile</phase>
               <goals>
                 <goal>exec</goal>
               </goals>
             </execution>
           </executions>
           <configuration>
             <executable>git</executable>
             <arguments>
               <argument>init</argument>
             </arguments>
           </configuration>
         </plugin>
       </plugins>
     </build>
   </profile>
</profiles>
</project>

Wie in der pom.xml erkennbar ist, werden hier die folgenden JEE7 Artefakte für den JBoss WildFly verwendet und importiert:

WildFly JBoss Java EE 7 Specification APIs with Tools:
– jboss-javaee-7.0-with-tools

WildFly JBoss Java EE 7 Specification APIs with Resteasy:
– jboss-javaee-7.0-with-resteasy

WildFly JBoss Java EE 7 Specification APIs with Hibernate:
– jboss-javaee-7.0-with-hibernate

Weiterhin werden die folgenden JEE Dependencies verwendet:

– jboss-annotations-api_1.1_spec
– jboss-jaxrs-api_2.0_spec
– resteasy-jackson2-provider
– hibernate-jpa-2.1-api
– jboss-ejb-api_3.2_spec
– hibernate-jpamodelgen
– jboss-servlet-api_3.1_spec

Über CDI und JavaEE gibt es bereits Blog-Einträge in diesem Blog hier und hier. Die Aktivierung von CDI erfolgt, wie beschrieben, mittels beans.xml im /WEB-INF Verzeichnis.

Die Architektur:

a) Das Service Backend:

Die Beispiel-Applikation verwendet die folgenden Entities, die hier aufgeführt werden sollen:

– Address
– Country
– Category
– Customer
– Product
– Item
– OrderLine
– PurchaseOrder
– CreditCard
– CreditCardType

Die Relationen und Constraints (HibernateValidation) zeigen sich auch in den entsprechenden JPA 2.1 Entities und deren Annotationen. Hier beispielhaft die von der Applikation ‘petstore‘ verwendeten Entities:

1. Address:

package de.binaris.petstore.forge.model;
 

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* <p>
* A reusable representation of an address.
*
* Addresses are used in many places in an application,
* so regarding the DRY principle, the Address model is an embeddable
* entity. An embeddable entity appears as a child in the object model,
* but no relationship is established in the RDBMS.
* </p>
*/
@SuppressWarnings("serial")
@Embeddable
public class Address implements Serializable {
 
   @NotNull
   @Size(min = 5, max = 50, message = "must be 5-50 letters and spaces")
   private String street1;
  
   private String street2;
  
   @NotNull
   @Size(min = 2, max = 50, message = "must be 2-50 letters and spaces")
   private String city;
  
   @NotNull
   @Size(min = 2, max = 50, message = "must be 2-50 letters and spaces")
   private String state;
  
   @NotNull
   @Size(min = 1, max = 10, message = "must be 1-10 lettersand spaces")
   @Column(name = "zip_code")
   private String zipCode;
  
   @ManyToOne
   private Country country;
  
                public String getStreet1() {
                               return street1;
                }
 
                public void setStreet1(String street1) {

                }
 
                public String getStreet2() {
                               return street2;
                }
 
                public void setStreet2(String street2)
                               this.street2 = street2;
                }
 
                public String getCity() {
                               return city;
                }
 
                public void setCity(String city) {
                               this.city = city;
                }
 
                public String getState() {
                               return state;
                }
 
                public void setState(String state) {
                               this.state = state;
                }
               
                public String getZipCode() {
                               return zipCode;
                }
 
                public void setZipCode(String zipCode) {
                               this.zipCode = zipCode;
                }
 
                public Country getCountry() {
                               return country;
                }
               
                public void setCountry(Country country) {
                               this.country = country;
                }
               
   /* toString(), equals() and hashCode() for Address, using the natural identity of the object */
  
   @Override
   public boolean equals(Object o) {
       if (this == o)
           return true;
       if (o == null || getClass() != o.getClass())
           return false;
 
       Address address = (Address) o;
 
       if (city != null ? !city.equals(address.city) :address.city != null)
           return false;
       if (state != null ? !state.equals(address.state) : address.state != null)
           return false;
       if (country != null ? !country.getIsoCode().equals(address.country.getIsoCode()) : address.country.getIsoCode() != null)
               return false;
       if (street1 != null ? !street1.equals(address.street1) : address.street1 != null)
           return false;
       if (zipCode != null ? !zipCode.equals(address.zipCode) : address.zipCode != null)
               return false;
 
       return true;
   }
 
   @Override
   public int hashCode() {
       int result = street1 != null ? street1.hashCode() : 0;
       result = 31 * result + (city != null ? city.hashCode() : 0);
       result = 31 * result + (state != null ? state.hashCode() : 0);
       result = 31 * result + (zipCode != null ? zipCode.hashCode() : 0);
       result = 31 * result + (country.getIsoCode() != null ? country.getIsoCode().hashCode() : 0);
       return result;
   }
 
   @Override
   public String toString() {
       final StringBuilder sb = new StringBuilder();
       sb.append("Delivery Address: ");
       sb.append(street1).append(‚\“);
       if (street2 != null && !street2.isEmpty()) {
               sb.append(", ").append(street2).append(‚\“);
       }
     sb.append(", ").append(zipCode).append(‚\“);
       sb.append(" ").append(city).append(‚\“);
       sb.append(", ").append(state).append(‚\“);
       sb.append(", ").append(country.getIsoCode()).append(‚\“);
       return sb.toString();
   }
}

 2. Country:

package de.binaris.petstore.forge.model;

import java.io.Serializable;

import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Cacheable
@Entity
public class Country implements Serializable {

private static final long serialVersionUID = 7005777625699126629L;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_entity_seq_gen_country")
@SequenceGenerator(name = "my_entity_seq_gen_country", sequenceName = "sequence_country",allocationSize = 1)
private Long id;

@NotNull
@Size(min = 2, max = 2, message = „must be exactly 2 letters“)
@Column(name = „iso_code“)
private String isoCode;

@NotNull
@Size(min = 2, max = 80, message = „must be 2-80 letters and spaces“)
private String name;

@NotNull
@Size(min = 2, max = 80, message = „must be 2-80 letters and spaces“)
@Column(name = „printable_name“)
private String printableName;

@NotNull
@Size(min = 3, max = 3, message = „must be exactly 3 letters“)
private String iso3;

@NotNull
@Size(min = 3, max = 3, message = „must be exactly 3 letters“)
private String numcode;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getIsoCode() {
return isoCode;
}

public void setIsoCode(String isoCode) {
this.isoCode = isoCode;
}

public String getPrintableName() {
return printableName;
}

public void setPrintableName(String printableName) {
this.printableName = printableName;
}

public String getIso3() {
return iso3;
}

public void setIso3(String iso3) {
this.iso3 = iso3;
}

public String getNumcode() {
return numcode;
}

public void setNumcode(String numcode) {
this.numcode = numcode;
}

@Override
public boolean equals(Object object) {
if (!(object instanceof Country)) {
return false;
}
Country castOther = (Country) object;
return id != null ? id.equals(castOther.getId()) : false;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : System.identityHashCode(this);
}

@Override
public String toString() {
return name + „, “ + isoCode;
}
}

3. Category:

package de.binaris.petstore.forge.model;

import static javax.persistence.CascadeType.MERGE;
import static javax.persistence.FetchType.EAGER;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Cacheable
@Entity
public class Category implements Serializable {

private static final long serialVersionUID = 7275789629777126729L;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = „my_entity_seq_gen_category“)
@SequenceGenerator(name = „my_entity_seq_gen_category“, sequenceName = „sequence_category“, allocationSize = 1)
private Long id;

@NotNull
@Size(min = 1, max = 30, message = „must be 1-30 letters and spaces“)
private String name;

@NotNull
@Size(min = 1, max = 3000, message = „must be 1-3000 letters and spaces“)
private String description;

@OneToMany(cascade = MERGE, fetch = EAGER, mappedBy = „category“)
private Set<Product> products = new HashSet<Product>();

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public Set<Product> getProducts() {
return products;
}

public void setProducts(Set<Product> products) {
this.products = products;
}

@Override
public boolean equals(Object object) {
if (!(object instanceof Category)) {
return false;
}
Category castOther = (Category) object;
return id != null ? id.equals(castOther.getId()) : false;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : System.identityHashCode(this);
}

@Override
public String toString() {
return name + „, “ + description;
}
}

4. Customer:

package de.binaris.petstore.forge.model;

import static javax.persistence.CascadeType.MERGE;
import static javax.persistence.FetchType.EAGER;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

import de.binaris.petstore.annotations.Login;

@Cacheable
@Entity
@NamedQueries({
@NamedQuery(name = „findByLogin“, query = „SELECT c FROM Customer c WHERE c.login = :login“),
@NamedQuery(name = „findByLoginAndPassword“, query = „SELECT c FROM Customer c WHERE c.login = :login AND c.password = :password“)
})
public class Customer implements Serializable {

private static final long serialVersionUID = 7975789629699126629L;

public static final String FIND_BY_LOGIN = „findByLogin“;
public static final String FIND_BY_LOGIN_PASSWORD = „findByLoginAndPassword“;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = „my_entity_seq_gen_customer“)
@SequenceGenerator(name = „my_entity_seq_gen_customer“, sequenceName = „sequence_customer“, allocationSize = 1)
private Long id;

@NotNull
@Size(min = 2, max = 50, message = „must be 2-50 letters and spaces“)
private String firstName;

@NotNull
@Size(min = 2, max = 50, message = „must be 2-50 letters and spaces“)
private String lastName;

@NotNull
private String phone;

@NotNull
@NotEmpty
@Email(message = „invalid email format“)
private String email;

@NotNull
@Size(min = 1, max = 10, message = „must be 1-10 letters and spaces“)
@Login
private String login;

@NotNull
@Size(min = 1, max = 256, message = „must be 1-256 letters and spaces“)
private String password;

@NotNull
@Column(name = „date_of_birth“)
@Past
@Temporal(TemporalType.DATE)
private Date dateOfBirth;

@Transient
private Integer age;

@OneToMany(cascade = MERGE, fetch = EAGER, mappedBy = „customer“)
private Set<PurchaseOrder> purchaseOrder = new HashSet<PurchaseOrder>();

private Address address = new Address();

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getLogin() {
return login;
}

public void setLogin(String login) {
this.login = login;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public Date getDateOfBirth() {
return dateOfBirth;
}

public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}

public Set<PurchaseOrder> getPurchaseOrder() {
return purchaseOrder;
}

public void setPurchaseOrder(Set<PurchaseOrder> purchaseOrder) {
this.purchaseOrder = purchaseOrder;
}

@Override
public boolean equals(Object object) {
if (!(object instanceof Customer)) {
return false;
}
Customer castOther = (Customer) object;
return id != null ? id.equals(castOther.getId()) : false;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : System.identityHashCode(this);
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(„Customer: „);
sb.append(‚\“).append(lastName).append(‚\“);
sb.append(„, „).append(‚\“).append(firstName).append(‚\“);
sb.append(„, „).append(‚\“).append(dateOfBirth).append(‚\“);
sb.append(„, „).append(‚\“).append(phone).append(‚\“);
sb.append(„, „).append(‚\“).append(email).append(‚\“);
return sb.toString();
}
}

5. Product:

package de.binaris.petstore.forge.model;

import java.io.Serializable;

import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Cacheable
@Entity
public class Product implements Serializable {

private static final long serialVersionUID = 797577262699127729L;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = „my_entity_seq_gen_product“)
@SequenceGenerator(name = „my_entity_seq_gen_product“, sequenceName = „sequence_product“, allocationSize = 1)
private Long id;

@NotNull
@Size(min = 1, max = 30, message = „must be 1-30 letters and spaces“)
private String name;

@NotNull
@Size(min = 1, max = 3000, message = „must be 1-3000 letters and spaces“)
private String description;

@ManyToOne
private Category category;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public Category getCategory() {
return category;
}

public void setCategory(Category category) {
this.category = category;
}

@Override
public boolean equals(Object object) {
if (!(object instanceof Product)) {
return false;
}
Product castOther = (Product) object;
return id != null ? id.equals(castOther.getId()) : false;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : System.identityHashCode(this);
}

@Override
public String toString() {
return name + „, “ + description;
}
}

6. Item:

package de.binaris.petstore.forge.model;

import java.io.Serializable;

import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Cacheable
@Entity
public class Item implements Serializable {

private static final long serialVersionUID = 79757512797127179L;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = „my_entity_seq_gen_item“)
@SequenceGenerator(name = „my_entity_seq_gen_item“, sequenceName = „sequence_item“, allocationSize = 1)
private Long id;

@NotNull
@Size(min = 1, max = 30, message = „must be 1-30 letters and spaces“)
private String name;

@NotNull
@Size(min = 1, max = 3000, message = „must be 1-3000 letters and spaces“)
private String description;

@Column(name = „image_path“)
private String imagePath;

@NotNull
@Column(name = „unit_cost“)
private Float unitCost;

@ManyToOne
private Product product;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getImagePath() {
return imagePath;
}

public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}

public Float getUnitCost() {
return unitCost;
}

public void setUnitCost(Float unitCost) {
this.unitCost = unitCost;
}

public Product getProduct() {
return product;
}

public void setProduct(Product product) {
this.product = product;
}

@Override
public boolean equals(Object object) {
if (!(object instanceof Item)) {
return false;
}
Item castOther = (Item) object;
return id != null ? id.equals(castOther.getId()) : false;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : System.identityHashCode(this);
}

@Override
public String toString() {
return name + „, “ + description;
}
}

7. OrderLine:

package de.binaris.petstore.forge.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

/**
* <p>
* An OrderLine may consist of one or more items.
*
* JPA requires to use the class level <code>@Table</code> name to ensure the
* entity-table relation, if required.
* </p>
*/
@Entity
@Table(name = „order_line“)
public class OrderLine implements Serializable {

private static final long serialVersionUID = 5012312375678916915L;

/**
* The ID of the OrderLine.
*/
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = „my_entity_seq_gen_order_line“)
@SequenceGenerator(name = „my_entity_seq_gen_order_line“, sequenceName = „sequence_order_line“, allocationSize = 1)
private Long id;

/**
* The quantity of items.
*/
@NotNull
@Min(value = 1, message = „minimum 1 item“)
private Integer quantity;

/**
* The item of the OrderLine.
*/
@ManyToOne
@NotNull
private Item item;

/**
* The purchaseOrder of the OrderLine.
*/
@ManyToOne
@NotNull
private PurchaseOrder purchaseOrder;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Integer getQuantity() {
return quantity;
}

public void setQuantity(Integer quantity) {
this.quantity = quantity;
}

public Item getItem() {
return item;
}

public void setItem(Item item) {
this.item = item;
}

public PurchaseOrder getPurchaseOrder() {
return purchaseOrder;
}

public void setPurchaseOrder(PurchaseOrder purchaseOrder) {
this.purchaseOrder = purchaseOrder;
}

public Float getSubTotal() {
return (item != null)? item.getUnitCost() * quantity : 0F;
}

/*
* toString(), equals() and hashCode() for OrderLine, using the natural
* identity of the object
*/

@Override
public boolean equals(Object object) {
if (!(object instanceof OrderLine)) {
return false;
}
OrderLine castOther = (OrderLine) object;
return id != null ? id.equals(castOther.getId()) : false;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : System.identityHashCode(this);
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(‚\“).append(„quantity: „).append(quantity).append(‚\“);
sb.append(‚\“).append(„, item: „).append(item.getName()).append(‚\“);
sb.append(‚\“).append(„, description: „).append(item.getDescription()).append(‚\“);
return sb.toString();
}
}

8. PurchaseOrder:

package de.binaris.petstore.forge.model;

import static javax.persistence.CascadeType.MERGE;
import static javax.persistence.FetchType.EAGER;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;

/**
* <p>
* An PurchaseOrder may consist of one or more orderlines.
*
* JPA requires to use the class level <code>@Table</code> name to ensure the
* entity-table relation, if required.
* </p>
*/
@Entity
@Table(name = „purchase_order“)
public class PurchaseOrder implements Serializable {

private static final long serialVersionUID = 7277723756789162915L;

/**
* The ID of the PurchaseOrder.
*/
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = „my_entity_seq_gen_purchase_order“)
@SequenceGenerator(name = „my_entity_seq_gen_purchase_order“, sequenceName = „sequence_purchase_order“, allocationSize = 1)
private Long id;

@NotNull
@Temporal(TemporalType.DATE)
@Column(name = „order_date“, updatable = false)
private Date orderDate;

@ManyToOne(fetch = EAGER)
@NotNull
private Customer customer;

@OneToMany(cascade = MERGE, fetch = EAGER, mappedBy = „purchaseOrder“)
private Set<OrderLine> orderLines = new HashSet<OrderLine>();

private Address deliveryAddress = new Address();

private CreditCard creditCard = new CreditCard();

private Float totalWithoutVat;

@Column(name = „vat_rate“)
private Float vatRate;

private Float vat;

private Float totalWithVat;

@Column(name = „discount_rate“)
private Float discountRate;

private Float discount;

private Float total;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

@PrePersist
private void setDefaultData() {
orderDate = new Date();
}

public Date getOrderDate() {
return orderDate;
}

public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}

public Customer getCustomer() {
return customer;
}

public void setCustomer(Customer customer) {
this.customer = customer;
}

public Set<OrderLine> getOrderLines() {
return orderLines;
}

public void setOrderLines(Set<OrderLine> orderLines) {
this.orderLines = orderLines;
}

public Address getDeliveryAddress() {
return deliveryAddress;
}

public void setDeliveryAddress(Address deliveryAddress) {
this.deliveryAddress = deliveryAddress;
}

public CreditCard getCreditCard() {
return creditCard;
}

public void setCreditCard(CreditCard creditCard) {
this.creditCard = creditCard;
}

public Float getTotalWithoutVat() {
return totalWithoutVat;
}

public void setTotalWithoutVat(Float totalWithoutVat) {
this.totalWithoutVat = totalWithoutVat;
}

public Float getVatRate() {
return vatRate;
}

public void setVatRate(Float vatRate) {
this.vatRate = vatRate;
}

public Float getVat() {
return vat;
}

public void setVat(Float vat) {
this.vat = vat;
}

public Float getTotalWithVat() {
return totalWithVat;
}

public void setTotalWithVat(Float totalWithVat) {
this.totalWithVat = totalWithVat;
}

public Float getDiscountRate() {
return discountRate;
}

public void setDiscountRate(Float discountRate) {
this.discountRate = discountRate;
}

public Float getDiscount() {
return discount;
}

public void setDiscount(Float discount) {
this.discount = discount;
}

public void setTotal(Float total) {
this.total = total;
}

public Float getTotal() {
if (orderLines == null || orderLines.isEmpty()) {
return 0f;
}
Float sum = 0f;
for (OrderLine orderLine : orderLines) {
sum += (orderLine.getSubTotal());
}
this.total = sum;
return total;
}

/*
* toString(), equals() and hashCode() for PurchaseOrder, using the natural
* identity of the object
*/

@Override
public boolean equals(Object object) {
if (!(object instanceof PurchaseOrder)) {
return false;
}
PurchaseOrder castOther = (PurchaseOrder) object;
return id != null ? id.equals(castOther.getId()) : false;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : System.identityHashCode(this);
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(‚\“).append(orderDate);
sb.append(„, „).append(‚\“).append(customer).append(‚\“);
sb.append(„, „).append(‚\“).append(orderLines).append(‚\“);
sb.append(„, „).append(‚\“).append(deliveryAddress).append(‚\“);
sb.append(„, „).append(‚\“).append(creditCard).append(‚\“);
return sb.toString();
}
}

9. CreditCard:

package de.binaris.petstore.forge.model;

import static javax.persistence.EnumType.STRING;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Enumerated;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@SuppressWarnings(„serial“)
@Embeddable
public class CreditCard implements Serializable {

@NotNull
@Size(min = 1, max = 30, message = „must be 1-30 numbers, letters and spaces“)
@Column(name = „credit_card_number“)
private String creditCardNumber;

@Column(name = „credit_card_type“)
@NotNull
@Enumerated(STRING)
private CreditCardType creditCardType;

@NotNull
@Size(min = 8, max = 10, message = „must be 8-10 letters and spaces for the preferred date format“)
@Column(name = „credit_card_expiry_date“)
private String creditCardExpDate;

public CreditCard() {
}

public CreditCard(String creditCardNumber, CreditCardType creditCardType, String creditCardExpDate) {
this.creditCardNumber = creditCardNumber;
this.creditCardType = creditCardType;
this.creditCardExpDate = creditCardExpDate;
}

public String getCreditCardNumber() {
return creditCardNumber;
}

public void setCreditCardNumber(String creditCardNumber) {
this.creditCardNumber = creditCardNumber;
}

public CreditCardType getCreditCardType() {
return creditCardType;
}

public void setCreditCardType(CreditCardType creditCardType) {
this.creditCardType = creditCardType;
}

public String getCreditCardExpDate() {
return creditCardExpDate;
}

public void setCreditCardExpDate(String creditCardExpDate) {
this.creditCardExpDate = creditCardExpDate;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CreditCard)) return false;

CreditCard that = (CreditCard) o;
if (!creditCardNumber.equals(that.creditCardNumber)) {
return false;
}
return true;
}

@Override
public int hashCode() {
return creditCardNumber.hashCode();
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(„creditCardNumber: ‚“);
for (int i=0; i < (creditCardNumber.length() – 3); i++) {
sb.append(„*“);
}
sb.append(creditCardNumber.substring(creditCardNumber.length() – 3)).append(‚\“);
sb.append(„, creditCardExpDate: ‚“).append(creditCardExpDate).append(‚\“);
return sb.toString();
}
}

10. CreditCardType:

package de.binaris.petstore.forge.model;

/**
* <p>
* The {@link CreditCardType} describes the types of credit card this application
* can handle and render.
*
* The media type is a <em>closed set</em> – as each different type of
* media requires support coded into the view layers,
* it cannot be expanded upon without rebuilding the application.
* It is therefore represented by an enumeration. When used, you
* should instruct JPA to store the enum value using it’s String representation,
* so that we can later reorder the enum members,
* without changing the data. This does mean we cannot change
* the names of credit card types once the app is put into production.
* To do this add <code>@Enumerated(STRING)</code> to the field declaration.
*
* The {@link CreditCardType} describes whether or not the
* type of media can be cached locally and used offline.
* </p>
*/
public enum CreditCardType {

/**
* The types of credit cards the application can currently handle.
*/
VISA(„Visa“, true),
MASTER_CARD(„Mastercard“, true),
AMERICAN_EXPRESS(„American Express“, true);

/**
* A human readable description of the credit card type.
*/
private final String description;

/**
* A boolean flag indicating whether the credit card type can be cached.
*/
private final boolean cacheable;

private CreditCardType(String description, boolean cacheable) {
this.description = description;
this.cacheable = cacheable;
}

public String getDescription() {
return description;
}

public boolean isCacheable() {
return cacheable;
}
}

b) Der RESTful WebService mit den Service-Endpoints: 
Soweit die beschriebenen Entities der Beispiel-Applikation ‘petstore‘. Hieraus lassen sich mit dem JBoss Developer Studio 7.1 (entspricht Eclipse Kepler 4.3) und dem JBoss Forge PlugIn über das Kontextmenü auf dem Maven-Projekt der RESTful WebService mit den folgenden Service-Endpoints generieren:

1. CategoryEndpoint:

package de.binaris.petstore.forge.rest;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import de.binaris.petstore.forge.model.Category;
import de.binaris.petstore.forge.rest.dto.CategoryDTO;

/**
* The Category endpoint.
*/
@Stateless
@Path(„/categorys“)
public class CategoryEndpoint
{
@PersistenceContext(unitName = „PetstorePU“)
private EntityManager em;

@POST
@Consumes(„application/json“)
public Response create(CategoryDTO dto)
{
Category entity = dto.fromDTO(null, em);
em.persist(entity);
return Response.created(UriBuilder.fromResource(CategoryEndpoint.class).path(String.valueOf(entity.getId())).build()).build();
}

@DELETE
@Path(„/{id:[0-9][0-9]*}“)
public Response deleteById(@PathParam(„id“) Long id)
{
Category entity = em.find(Category.class, id);
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
em.remove(entity);
return Response.noContent().build();
}

@GET
@Path(„/{id:[0-9][0-9]*}“)
@Produces(„application/json“)
public Response findById(@PathParam(„id“) Long id)
{
TypedQuery<Category> findByIdQuery = em.createQuery(„SELECT DISTINCT c FROM Category c LEFT JOIN FETCH c.products WHERE c.id = :entityId ORDER BY c.id“, Category.class);
findByIdQuery.setParameter(„entityId“, id);
Category entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
CategoryDTO dto = new CategoryDTO(entity);
return Response.ok(dto).build();
}

@GET
@Produces(„application/json“)
public List<CategoryDTO> listAll()
{
final List<Category> searchResults = em.createQuery(„SELECT DISTINCT c FROM Category c LEFT JOIN FETCH c.products ORDER BY c.id“, Category.class).getResultList();
final List<CategoryDTO> results = new ArrayList<CategoryDTO>();
for (Category searchResult : searchResults)
{
CategoryDTO dto = new CategoryDTO(searchResult);
results.add(dto);
}
return results;
}

@PUT
@Path(„/{id:[0-9][0-9]*}“)
@Consumes(„application/json“)
public Response update(@PathParam(„id“) Long id, CategoryDTO dto)
{
TypedQuery<Category> findByIdQuery = em.createQuery(„SELECT DISTINCT c FROM Category c LEFT JOIN FETCH c.products WHERE c.id = :entityId ORDER BY c.id“, Category.class);
findByIdQuery.setParameter(„entityId“, id);
Category entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
entity = dto.fromDTO(entity, em);
entity = em.merge(entity);
return Response.noContent().build();
}
}

2. CountryEndpoint:

package de.binaris.petstore.forge.rest;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import de.binaris.petstore.forge.model.Country;
import de.binaris.petstore.forge.rest.dto.CountryDTO;

/**
* The Country endpoint.
*/
@Stateless
@Path(„/countrys“)
public class CountryEndpoint
{
@PersistenceContext(unitName = „PetstorePU“)
private EntityManager em;

@POST
@Consumes(„application/json“)
public Response create(CountryDTO dto)
{
Country entity = dto.fromDTO(null, em);
em.persist(entity);
return Response.created(UriBuilder.fromResource(CountryEndpoint.class).path(String.valueOf(entity.getId())).build()).build();
}

@DELETE
@Path(„/{id:[0-9][0-9]*}“)
public Response deleteById(@PathParam(„id“) Long id)
{
Country entity = em.find(Country.class, id);
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
em.remove(entity);
return Response.noContent().build();
}

@GET
@Path(„/{id:[0-9][0-9]*}“)
@Produces(„application/json“)
public Response findById(@PathParam(„id“) Long id)
{
TypedQuery<Country> findByIdQuery = em.createQuery(„SELECT DISTINCT c FROM Country c WHERE c.id = :entityId ORDER BY c.id“, Country.class);
findByIdQuery.setParameter(„entityId“, id);
Country entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
CountryDTO dto = new CountryDTO(entity);
return Response.ok(dto).build();
}

@GET
@Produces(„application/json“)
public List<CountryDTO> listAll()
{
final List<Country> searchResults = em.createQuery(„SELECT DISTINCT c FROM Country c ORDER BY c.id“, Country.class).getResultList();
final List<CountryDTO> results = new ArrayList<CountryDTO>();
for (Country searchResult : searchResults)
{
CountryDTO dto = new CountryDTO(searchResult);
results.add(dto);
}
return results;
}

@PUT
@Path(„/{id:[0-9][0-9]*}“)
@Consumes(„application/json“)
public Response update(@PathParam(„id“) Long id, CountryDTO dto)
{
TypedQuery<Country> findByIdQuery = em.createQuery(„SELECT DISTINCT c FROM Country c WHERE c.id = :entityId ORDER BY c.id“, Country.class);
findByIdQuery.setParameter(„entityId“, id);
Country entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
entity = dto.fromDTO(entity, em);
entity = em.merge(entity);
return Response.noContent().build();
}
}

3. CustomerEndpoint:

package de.binaris.petstore.forge.rest;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import de.binaris.petstore.forge.model.Customer;
import de.binaris.petstore.forge.rest.dto.CustomerDTO;

/**
* The Customer endpoint.
*/
@Stateless
@Path(„/customers“)
public class CustomerEndpoint
{
@PersistenceContext(unitName = „PetstorePU“)
private EntityManager em;

@POST
@Consumes(„application/json“)
public Response create(CustomerDTO dto)
{
Customer entity = dto.fromDTO(null, em);
em.persist(entity);
return Response.created(UriBuilder.fromResource(CustomerEndpoint.class).path(String.valueOf(entity.getId())).build()).build();
}

@DELETE
@Path(„/{id:[0-9][0-9]*}“)
public Response deleteById(@PathParam(„id“) Long id)
{
Customer entity = em.find(Customer.class, id);
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
em.remove(entity);
return Response.noContent().build();
}

@GET
@Path(„/{id:[0-9][0-9]*}“)
@Produces(„application/json“)
public Response findById(@PathParam(„id“) Long id)
{
TypedQuery<Customer> findByIdQuery = em.createQuery(„SELECT DISTINCT c FROM Customer c LEFT JOIN FETCH c.purchaseOrder LEFT JOIN FETCH c.country WHERE c.id = :entityId ORDER BY c.id“, Customer.class);
findByIdQuery.setParameter(„entityId“, id);
Customer entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
CustomerDTO dto = new CustomerDTO(entity);
return Response.ok(dto).build();
}

@GET
@Produces(„application/json“)
public List<CustomerDTO> listAll()
{
final List<Customer> searchResults = em.createQuery(„SELECT DISTINCT c FROM Customer c LEFT JOIN FETCH c.purchaseOrder LEFT JOIN FETCH c.country ORDER BY c.id“, Customer.class).getResultList();
final List<CustomerDTO> results = new ArrayList<CustomerDTO>();
for (Customer searchResult : searchResults)
{
CustomerDTO dto = new CustomerDTO(searchResult);
results.add(dto);
}
return results;
}

@PUT
@Path(„/{id:[0-9][0-9]*}“)
@Consumes(„application/json“)
public Response update(@PathParam(„id“) Long id, CustomerDTO dto)
{
TypedQuery<Customer> findByIdQuery = em.createQuery(„SELECT DISTINCT c FROM Customer c LEFT JOIN FETCH c.purchaseOrder LEFT JOIN FETCH c.country WHERE c.id = :entityId ORDER BY c.id“, Customer.class);
findByIdQuery.setParameter(„entityId“, id);
Customer entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
entity = dto.fromDTO(entity, em);
entity = em.merge(entity);
return Response.noContent().build();
}
}

4. ProductEndpoint:

package de.binaris.petstore.forge.rest;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import de.binaris.petstore.forge.model.Product;
import de.binaris.petstore.forge.rest.dto.ProductDTO;

/**
* The Product endpoint.
*/
@Stateless
@Path(„/products“)
public class ProductEndpoint
{
@PersistenceContext(unitName = „PetstorePU“)
private EntityManager em;

@POST
@Consumes(„application/json“)
public Response create(ProductDTO dto)
{
Product entity = dto.fromDTO(null, em);
em.persist(entity);
return Response.created(UriBuilder.fromResource(ProductEndpoint.class).path(String.valueOf(entity.getId())).build()).build();
}

@DELETE
@Path(„/{id:[0-9][0-9]*}“)
public Response deleteById(@PathParam(„id“) Long id)
{
Product entity = em.find(Product.class, id);
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
em.remove(entity);
return Response.noContent().build();
}

@GET
@Path(„/{id:[0-9][0-9]*}“)
@Produces(„application/json“)
public Response findById(@PathParam(„id“) Long id)
{
TypedQuery<Product> findByIdQuery = em.createQuery(„SELECT DISTINCT p FROM Product p LEFT JOIN FETCH p.category WHERE p.id = :entityId ORDER BY p.id“, Product.class);
findByIdQuery.setParameter(„entityId“, id);
Product entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
ProductDTO dto = new ProductDTO(entity);
return Response.ok(dto).build();
}

@GET
@Produces(„application/json“)
public List<ProductDTO> listAll()
{
final List<Product> searchResults = em.createQuery(„SELECT DISTINCT p FROM Product p LEFT JOIN FETCH p.category ORDER BY p.id“, Product.class).getResultList();
final List<ProductDTO> results = new ArrayList<ProductDTO>();
for (Product searchResult : searchResults)
{
ProductDTO dto = new ProductDTO(searchResult);
results.add(dto);
}
return results;
}

@PUT
@Path(„/{id:[0-9][0-9]*}“)
@Consumes(„application/json“)
public Response update(@PathParam(„id“) Long id, ProductDTO dto)
{
TypedQuery<Product> findByIdQuery = em.createQuery(„SELECT DISTINCT p FROM Product p LEFT JOIN FETCH p.category WHERE p.id = :entityId ORDER BY p.id“, Product.class);
findByIdQuery.setParameter(„entityId“, id);
Product entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
entity = dto.fromDTO(entity, em);
entity = em.merge(entity);
return Response.noContent().build();
}
}

5. ItemEndpoint:

package de.binaris.petstore.forge.rest;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import de.binaris.petstore.forge.model.Item;
import de.binaris.petstore.forge.rest.dto.ItemDTO;

/**
* The Item endpoint.
*/
@Stateless
@Path(„/items“)
public class ItemEndpoint
{
@PersistenceContext(unitName = „PetstorePU“)
private EntityManager em;

@POST
@Consumes(„application/json“)
public Response create(ItemDTO dto)
{
Item entity = dto.fromDTO(null, em);
em.persist(entity);
return Response.created(UriBuilder.fromResource(ItemEndpoint.class).path(String.valueOf(entity.getId())).build()).build();
}

@DELETE
@Path(„/{id:[0-9][0-9]*}“)
public Response deleteById(@PathParam(„id“) Long id)
{
Item entity = em.find(Item.class, id);
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
em.remove(entity);
return Response.noContent().build();
}

@GET
@Path(„/{id:[0-9][0-9]*}“)
@Produces(„application/json“)
public Response findById(@PathParam(„id“) Long id)
{
TypedQuery<Item> findByIdQuery = em.createQuery(„SELECT DISTINCT i FROM Item i LEFT JOIN FETCH i.product WHERE i.id = :entityId ORDER BY i.id“, Item.class);
findByIdQuery.setParameter(„entityId“, id);
Item entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
ItemDTO dto = new ItemDTO(entity);
return Response.ok(dto).build();
}

@GET
@Produces(„application/json“)
public List<ItemDTO> listAll()
{
final List<Item> searchResults = em.createQuery(„SELECT DISTINCT i FROM Item i LEFT JOIN FETCH i.product ORDER BY i.id“, Item.class).getResultList();
final List<ItemDTO> results = new ArrayList<ItemDTO>();
for (Item searchResult : searchResults)
{
ItemDTO dto = new ItemDTO(searchResult);
results.add(dto);
}
return results;
}

@PUT
@Path(„/{id:[0-9][0-9]*}“)
@Consumes(„application/json“)
public Response update(@PathParam(„id“) Long id, ItemDTO dto)
{
TypedQuery<Item> findByIdQuery = em.createQuery(„SELECT DISTINCT i FROM Item i LEFT JOIN FETCH i.product WHERE i.id = :entityId ORDER BY i.id“, Item.class);
findByIdQuery.setParameter(„entityId“, id);
Item entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
entity = dto.fromDTO(entity, em);
entity = em.merge(entity);
return Response.noContent().build();
}
}

6. OrderLineEndpoint:

package de.binaris.petstore.forge.rest;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import de.binaris.petstore.forge.model.OrderLine;
import de.binaris.petstore.forge.rest.dto.OrderLineDTO;

/**
* The OrderLine endpoint.
*/
@Stateless
@Path(„/orderlines“)
public class OrderLineEndpoint
{
@PersistenceContext(unitName = „PetstorePU“)
private EntityManager em;

@POST
@Consumes(„application/json“)
public Response create(OrderLineDTO dto)
{
OrderLine entity = dto.fromDTO(null, em);
em.persist(entity);
return Response.created(UriBuilder.fromResource(OrderLineEndpoint.class).path(String.valueOf(entity.getId())).build()).build();
}

@DELETE
@Path(„/{id:[0-9][0-9]*}“)
public Response deleteById(@PathParam(„id“) Long id)
{
OrderLine entity = em.find(OrderLine.class, id);
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
em.remove(entity);
return Response.noContent().build();
}

@GET
@Path(„/{id:[0-9][0-9]*}“)
@Produces(„application/json“)
public Response findById(@PathParam(„id“) Long id)
{
TypedQuery<OrderLine> findByIdQuery = em.createQuery(„SELECT DISTINCT o FROM OrderLine o LEFT JOIN FETCH o.item LEFT JOIN FETCH o.purchaseOrder WHERE o.id = :entityId ORDER BY o.id“, OrderLine.class);
findByIdQuery.setParameter(„entityId“, id);
OrderLine entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
OrderLineDTO dto = new OrderLineDTO(entity);
return Response.ok(dto).build();
}

@GET
@Produces(„application/json“)
public List<OrderLineDTO> listAll()
{
final List<OrderLine> searchResults = em.createQuery(„SELECT DISTINCT o FROM OrderLine o LEFT JOIN FETCH o.item LEFT JOIN FETCH o.purchaseOrder ORDER BY o.id“, OrderLine.class).getResultList();
final List<OrderLineDTO> results = new ArrayList<OrderLineDTO>();
for (OrderLine searchResult : searchResults)
{
OrderLineDTO dto = new OrderLineDTO(searchResult);
results.add(dto);
}
return results;
}

@PUT
@Path(„/{id:[0-9][0-9]*}“)
@Consumes(„application/json“)
public Response update(@PathParam(„id“) Long id, OrderLineDTO dto)
{
TypedQuery<OrderLine> findByIdQuery = em.createQuery(„SELECT DISTINCT o FROM OrderLine o LEFT JOIN FETCH o.item LEFT JOIN FETCH o.purchaseOrder WHERE o.id = :entityId ORDER BY o.id“, OrderLine.class);
findByIdQuery.setParameter(„entityId“, id);
OrderLine entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
entity = dto.fromDTO(entity, em);
entity = em.merge(entity);
return Response.noContent().build();
}
}

7. PurchaseOrderEndpoint:

package de.binaris.petstore.forge.rest;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import de.binaris.petstore.forge.model.PurchaseOrder;
import de.binaris.petstore.forge.rest.dto.PurchaseOrderDTO;

/**
* The PurchaseOrder endpoint
*/
@Stateless
@Path(„/purchaseorders“)
public class PurchaseOrderEndpoint
{
@PersistenceContext(unitName = „PetstorePU“)
private EntityManager em;

@POST
@Consumes(„application/json“)
public Response create(PurchaseOrderDTO dto)
{
PurchaseOrder entity = dto.fromDTO(null, em);
em.persist(entity);
return Response.created(UriBuilder.fromResource(PurchaseOrderEndpoint.class).path(String.valueOf(entity.getId())).build()).build();
}

@DELETE
@Path(„/{id:[0-9][0-9]*}“)
public Response deleteById(@PathParam(„id“) Long id)
{
PurchaseOrder entity = em.find(PurchaseOrder.class, id);
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
em.remove(entity);
return Response.noContent().build();
}

@GET
@Path(„/{id:[0-9][0-9]*}“)
@Produces(„application/json“)
public Response findById(@PathParam(„id“) Long id)
{
TypedQuery<PurchaseOrder> findByIdQuery = em.createQuery(„SELECT DISTINCT p FROM PurchaseOrder p LEFT JOIN FETCH p.customer LEFT JOIN FETCH p.orderLines WHERE p.id = :entityId ORDER BY p.id“, PurchaseOrder.class);
findByIdQuery.setParameter(„entityId“, id);
PurchaseOrder entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
if (entity == null)
{
return Response.status(Status.NOT_FOUND).build();
}
PurchaseOrderDTO dto = new PurchaseOrderDTO(entity);
return Response.ok(dto).build();
}

@GET
@Produces(„application/json“)
public List<PurchaseOrderDTO> listAll()
{
final List<PurchaseOrder> searchResults = em.createQuery(„SELECT DISTINCT p FROM PurchaseOrder p LEFT JOIN FETCH p.customer LEFT JOIN FETCH p.orderLines ORDER BY p.id“, PurchaseOrder.class).getResultList();
final List<PurchaseOrderDTO> results = new ArrayList<PurchaseOrderDTO>();
for (PurchaseOrder searchResult : searchResults)
{
PurchaseOrderDTO dto = new PurchaseOrderDTO(searchResult);
results.add(dto);
}
return results;
}

@PUT
@Path(„/{id:[0-9][0-9]*}“)
@Consumes(„application/json“)
public Response update(@PathParam(„id“) Long id, PurchaseOrderDTO dto)
{
TypedQuery<PurchaseOrder> findByIdQuery = em.createQuery(„SELECT DISTINCT p FROM PurchaseOrder p LEFT JOIN FETCH p.customer LEFT JOIN FETCH p.orderLines WHERE p.id = :entityId ORDER BY p.id“, PurchaseOrder.class);
findByIdQuery.setParameter(„entityId“, id);
PurchaseOrder entity;
try
{
entity = findByIdQuery.getSingleResult();
}
catch (NoResultException nre)
{
entity = null;
}
entity = dto.fromDTO(entity, em);
entity = em.merge(entity);
return Response.noContent().build();
}
}

Die RESTful WebService-Endpoints verwenden wiederum die folgenden DTOs:

– AddressDTO
– CategoryDTO
– CountryDTO
– CreditCardDTO
– CustomerDTO
– ItemDTO
– NestedCategoryDTO
– NestedCountryDTO
– NestedCustomerDTO
– NestedItemDTO
– NestedOrderLineDTO
– NestedProductDTO
– NestedPurchaseOrderDTO
– OrderLineDTO
– ProductDTO
– PurchaseOrderDTO

1. AddressDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Address;
import javax.persistence.EntityManager;
import de.binaris.petstore.forge.rest.dto.NestedCountryDTO;

public class AddressDTO implements Serializable {

private static final long serialVersionUID = 1235678910111213157L;

private String street2;
private String street1;
private String zipCode;
private String state;
private NestedCountryDTO country;
private String city;

public AddressDTO() {
}

public AddressDTO(final Address entity) {
if (entity != null) {
this.street2 = entity.getStreet2();
this.street1 = entity.getStreet1();
this.zipCode = entity.getZipCode();
this.state = entity.getState();
this.country = new NestedCountryDTO(entity.getCountry());
this.city = entity.getCity();
}
}

public Address fromDTO(Address entity, EntityManager em) {
if (entity == null) {
entity = new Address();
}
entity.setStreet2(this.street2);
entity.setStreet1(this.street1);
entity.setZipCode(this.zipCode);
entity.setState(this.state);
if (this.country != null) {
entity.setCountry(this.country.fromDTO(entity.getCountry(), em));
}
entity.setCity(this.city);
return entity;
}

public String getStreet2() {
return this.street2;
}

public void setStreet2(final String street2) {
this.street2 = street2;
}

public String getStreet1() {
return this.street1;
}

public void setStreet1(final String street1) {
this.street1 = street1;
}

public String getZipCode() {
return this.zipCode;
}

public void setZipCode(final String zipCode) {
this.zipCode = zipCode;
}

public String getState() {
return this.state;
}

public void setState(final String state) {
this.state = state;
}

public NestedCountryDTO getCountry() {
return this.country;
}

public void setCountry(final NestedCountryDTO country) {
this.country = country;
}

public String getCity() {
return this.city;
}

public void setCity(final String city) {
this.city = city;
}
}

2. CategoryDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Category;
import javax.persistence.EntityManager;
import java.util.Set;
import java.util.HashSet;
import de.binaris.petstore.forge.rest.dto.NestedProductDTO;
import de.binaris.petstore.forge.model.Product;
import java.util.Iterator;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class CategoryDTO implements Serializable {

private static final long serialVersionUID = 2235678910111213156L;

private Long id;
private String description;
private String name;
private Set<NestedProductDTO> products = new HashSet<NestedProductDTO>();

public CategoryDTO() {
}

public CategoryDTO(final Category entity) {
if (entity != null) {
this.id = entity.getId();
this.description = entity.getDescription();
this.name = entity.getName();
Iterator<Product> iterProducts = entity.getProducts().iterator();
for (; iterProducts.hasNext();) {
Product element = iterProducts.next();
this.products.add(new NestedProductDTO(element));
}
}
}

public Category fromDTO(Category entity, EntityManager em) {
if (entity == null) {
entity = new Category();
}
entity.setDescription(this.description);
entity.setName(this.name);
Iterator<Product> iterProducts = entity.getProducts().iterator();
for (; iterProducts.hasNext();) {
boolean found = false;
Product product = iterProducts.next();
Iterator<NestedProductDTO> iterDtoProducts = this.getProducts()
.iterator();
for (; iterDtoProducts.hasNext();) {
NestedProductDTO dtoProduct = iterDtoProducts.next();
if (dtoProduct.getId().equals(product.getId())) {
found = true;
break;
}
}
if (found == false) {
iterProducts.remove();
}
}
Iterator<NestedProductDTO> iterDtoProducts = this.getProducts()
.iterator();
for (; iterDtoProducts.hasNext();) {
boolean found = false;
NestedProductDTO dtoProduct = iterDtoProducts.next();
iterProducts = entity.getProducts().iterator();
for (; iterProducts.hasNext();) {
Product product = iterProducts.next();
if (dtoProduct.getId().equals(product.getId())) {
found = true;
break;
}
}
if (found == false) {
Iterator<Product> resultIter = em
.createQuery(„SELECT DISTINCT p FROM Product p“,
Product.class).getResultList().iterator();
for (; resultIter.hasNext();) {
Product result = resultIter.next();
if (result.getId().equals(dtoProduct.getId())) {
entity.getProducts().add(result);
break;
}
}
}
}
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public String getDescription() {
return this.description;
}

public void setDescription(final String description) {
this.description = description;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}

public Set<NestedProductDTO> getProducts() {
return this.products;
}

public void setProducts(final Set<NestedProductDTO> products) {
this.products = products;
}
}

3. CountryDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Country;
import javax.persistence.EntityManager;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class CountryDTO implements Serializable {

private static final long serialVersionUID = 3235678910111213155L;

private Long id;
private String printableName;
private String numcode;
private String name;
private String iso3;
private String isoCode;

public CountryDTO() {
}

public CountryDTO(final Country entity) {
if (entity != null) {
this.id = entity.getId();
this.printableName = entity.getPrintableName();
this.numcode = entity.getNumcode();
this.name = entity.getName();
this.iso3 = entity.getIso3();
this.isoCode = entity.getIsoCode();
}
}

public Country fromDTO(Country entity, EntityManager em) {
if (entity == null) {
entity = new Country();
}
entity.setPrintableName(this.printableName);
entity.setNumcode(this.numcode);
entity.setName(this.name);
entity.setIso3(this.iso3);
entity.setIsoCode(this.isoCode);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public String getPrintableName() {
return this.printableName;
}

public void setPrintableName(final String printableName) {
this.printableName = printableName;
}

public String getNumcode() {
return this.numcode;
}

public void setNumcode(final String numcode) {
this.numcode = numcode;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}

public String getIso3() {
return this.iso3;
}

public void setIso3(final String iso3) {
this.iso3 = iso3;
}

public String getIsoCode() {
return this.isoCode;
}

public void setIsoCode(final String isoCode) {
this.isoCode = isoCode;
}
}

4. CreditCardDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.CreditCard;
import javax.persistence.EntityManager;
import de.binaris.petstore.forge.model.CreditCardType;

public class CreditCardDTO implements Serializable {

private static final long serialVersionUID = 5235678910111213153L;

private String creditCardNumber;
private String creditCardExpDate;
private CreditCardType creditCardType;

public CreditCardDTO() {
}

public CreditCardDTO(final CreditCard entity) {
if (entity != null) {
this.creditCardNumber = entity.getCreditCardNumber();
this.creditCardExpDate = entity.getCreditCardExpDate();
this.creditCardType = entity.getCreditCardType();
}
}

public CreditCard fromDTO(CreditCard entity, EntityManager em) {
if (entity == null) {
entity = new CreditCard();
}
entity.setCreditCardNumber(this.creditCardNumber);
entity.setCreditCardExpDate(this.creditCardExpDate);
entity.setCreditCardType(this.creditCardType);
return entity;
}

public String getCreditCardNumber() {
return this.creditCardNumber;
}

public void setCreditCardNumber(final String creditCardNumber) {
this.creditCardNumber = creditCardNumber;
}

public String getCreditCardExpDate() {
return this.creditCardExpDate;
}

public void setCreditCardExpDate(final String creditCardExpDate) {
this.creditCardExpDate = creditCardExpDate;
}

public CreditCardType getCreditCardType() {
return this.creditCardType;
}

public void setCreditCardType(final CreditCardType creditCardType) {
this.creditCardType = creditCardType;
}
}

5. CustomerDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.xml.bind.annotation.XmlRootElement;

import de.binaris.petstore.forge.model.Customer;
import de.binaris.petstore.forge.model.PurchaseOrder;

@XmlRootElement
public class CustomerDTO implements Serializable {

private static final long serialVersionUID = 6235678910111213152L;

private Date dateOfBirth;
private Long id;
private String lastName;
private String phone;
private AddressDTO address;
private String email;
private Set<NestedPurchaseOrderDTO> purchaseOrder = new HashSet<NestedPurchaseOrderDTO>();
private String login;
private String firstName;
private String password;

public CustomerDTO() {
}

public CustomerDTO(final Customer entity) {
if (entity != null) {
this.dateOfBirth = entity.getDateOfBirth();
this.id = entity.getId();
this.lastName = entity.getLastName();
this.phone = entity.getPhone();
this.address = new AddressDTO(entity.getAddress());
this.email = entity.getEmail();
Iterator<PurchaseOrder> iterPurchaseOrder = entity
.getPurchaseOrder().iterator();
for (; iterPurchaseOrder.hasNext();) {
PurchaseOrder element = iterPurchaseOrder.next();
this.purchaseOrder.add(new NestedPurchaseOrderDTO(element));
}
this.login = entity.getLogin();
this.firstName = entity.getFirstName();
this.password = entity.getPassword();
}
}

public Customer fromDTO(Customer entity, EntityManager em) {
if (entity == null) {
entity = new Customer();
}
entity.setDateOfBirth(this.dateOfBirth);
entity.setLastName(this.lastName);
entity.setPhone(this.phone);
if (this.address != null) {
entity.setAddress(this.address.fromDTO(entity.getAddress(), em));
}
entity.setEmail(this.email);
Iterator<PurchaseOrder> iterPurchaseOrder = entity.getPurchaseOrder()
.iterator();
for (; iterPurchaseOrder.hasNext();) {
boolean found = false;
PurchaseOrder purchaseOrder = iterPurchaseOrder.next();
Iterator<NestedPurchaseOrderDTO> iterDtoPurchaseOrder = this
.getPurchaseOrder().iterator();
for (; iterDtoPurchaseOrder.hasNext();) {
NestedPurchaseOrderDTO dtoPurchaseOrder = iterDtoPurchaseOrder
.next();
if (dtoPurchaseOrder.getId().equals(purchaseOrder.getId())) {
found = true;
break;
}
}
if (found == false) {
iterPurchaseOrder.remove();
}
}
Iterator<NestedPurchaseOrderDTO> iterDtoPurchaseOrder = this
.getPurchaseOrder().iterator();
for (; iterDtoPurchaseOrder.hasNext();) {
boolean found = false;
NestedPurchaseOrderDTO dtoPurchaseOrder = iterDtoPurchaseOrder
.next();
iterPurchaseOrder = entity.getPurchaseOrder().iterator();
for (; iterPurchaseOrder.hasNext();) {
PurchaseOrder purchaseOrder = iterPurchaseOrder.next();
if (dtoPurchaseOrder.getId().equals(purchaseOrder.getId())) {
found = true;
break;
}
}
if (found == false) {
Iterator<PurchaseOrder> resultIter = em
.createQuery(„SELECT DISTINCT p FROM PurchaseOrder p“,
PurchaseOrder.class).getResultList().iterator();
for (; resultIter.hasNext();) {
PurchaseOrder result = resultIter.next();
if (result.getId().equals(dtoPurchaseOrder.getId())) {
entity.getPurchaseOrder().add(result);
break;
}
}
}
}
entity.setLogin(this.login);
entity.setFirstName(this.firstName);
entity.setPassword(this.password);
entity = em.merge(entity);
return entity;
}

public Date getDateOfBirth() {
return this.dateOfBirth;
}

public void setDateOfBirth(final Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public String getLastName() {
return this.lastName;
}

public void setLastName(final String lastName) {
this.lastName = lastName;
}

public String getPhone() {
return this.phone;
}

public void setPhone(final String phone) {
this.phone = phone;
}

public AddressDTO getAddress() {
return this.address;
}

public void setAddress(final AddressDTO address) {
this.address = address;
}

public String getEmail() {
return this.email;
}

public void setEmail(final String email) {
this.email = email;
}

public Set<NestedPurchaseOrderDTO> getPurchaseOrder() {
return this.purchaseOrder;
}

public void setPurchaseOrder(final Set<NestedPurchaseOrderDTO> purchaseOrder) {
this.purchaseOrder = purchaseOrder;
}

public String getLogin() {
return this.login;
}

public void setLogin(final String login) {
this.login = login;
}

public String getFirstName() {
return this.firstName;
}

public void setFirstName(final String firstName) {
this.firstName = firstName;
}

public String getPassword() {
return this.password;
}

public void setPassword(final String password) {
this.password = password;
}
}

6. ItemDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Item;
import javax.persistence.EntityManager;
import de.binaris.petstore.forge.rest.dto.NestedProductDTO;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class ItemDTO implements Serializable {

private static final long serialVersionUID = 7235678910111213151L;

private NestedProductDTO product;
private Long id;
private Float unitCost;
private String imagePath;
private String description;
private String name;

public ItemDTO() {
}

public ItemDTO(final Item entity) {
if (entity != null) {
this.product = new NestedProductDTO(entity.getProduct());
this.id = entity.getId();
this.unitCost = entity.getUnitCost();
this.imagePath = entity.getImagePath();
this.description = entity.getDescription();
this.name = entity.getName();
}
}

public Item fromDTO(Item entity, EntityManager em) {
if (entity == null) {
entity = new Item();
}
if (this.product != null) {
entity.setProduct(this.product.fromDTO(entity.getProduct(), em));
}
entity.setUnitCost(this.unitCost);
entity.setImagePath(this.imagePath);
entity.setDescription(this.description);
entity.setName(this.name);
entity = em.merge(entity);
return entity;
}

public NestedProductDTO getProduct() {
return this.product;
}

public void setProduct(final NestedProductDTO product) {
this.product = product;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public Float getUnitCost() {
return this.unitCost;
}

public void setUnitCost(final Float unitCost) {
this.unitCost = unitCost;
}

public String getImagePath() {
return this.imagePath;
}

public void setImagePath(final String imagePath) {
this.imagePath = imagePath;
}

public String getDescription() {
return this.description;
}

public void setDescription(final String description) {
this.description = description;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}
}

7. ProductDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Product;
import javax.persistence.EntityManager;
import de.binaris.petstore.forge.rest.dto.NestedCategoryDTO;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class ProductDTO implements Serializable {

private static final long serialVersionUID = 7117777910111253391L;

private Long id;
private NestedCategoryDTO category;
private String description;
private String name;

public ProductDTO() {
}

public ProductDTO(final Product entity) {
if (entity != null) {
this.id = entity.getId();
this.category = new NestedCategoryDTO(entity.getCategory());
this.description = entity.getDescription();
this.name = entity.getName();
}
}

public Product fromDTO(Product entity, EntityManager em) {
if (entity == null) {
entity = new Product();
}
if (this.category != null) {
entity.setCategory(this.category.fromDTO(entity.getCategory(), em));
}
entity.setDescription(this.description);
entity.setName(this.name);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public NestedCategoryDTO getCategory() {
return this.category;
}

public void setCategory(final NestedCategoryDTO category) {
this.category = category;
}

public String getDescription() {
return this.description;
}

public void setDescription(final String description) {
this.description = description;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}
}

8. OrderLineDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.OrderLine;
import javax.persistence.EntityManager;
import de.binaris.petstore.forge.rest.dto.NestedItemDTO;
import de.binaris.petstore.forge.rest.dto.NestedPurchaseOrderDTO;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class OrderLineDTO implements Serializable {

private static final long serialVersionUID = 7117778910111233391L;

private Long id;
private Float subTotal;
private NestedItemDTO item;
private NestedPurchaseOrderDTO purchaseOrder;
private Integer quantity;

public OrderLineDTO() {
}

public OrderLineDTO(final OrderLine entity) {
if (entity != null) {
this.id = entity.getId();
this.subTotal = entity.getSubTotal();
this.item = new NestedItemDTO(entity.getItem());
this.purchaseOrder = new NestedPurchaseOrderDTO(
entity.getPurchaseOrder());
this.quantity = entity.getQuantity();
}
}

public OrderLine fromDTO(OrderLine entity, EntityManager em) {
if (entity == null) {
entity = new OrderLine();
}
if (this.item != null) {
entity.setItem(this.item.fromDTO(entity.getItem(), em));
}
if (this.purchaseOrder != null) {
entity.setPurchaseOrder(this.purchaseOrder.fromDTO(
entity.getPurchaseOrder(), em));
}
entity.setQuantity(this.quantity);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public Float getSubTotal() {
return this.subTotal;
}

public void setSubTotal(final Float subTotal) {
this.subTotal = subTotal;
}

public NestedItemDTO getItem() {
return this.item;
}

public void setItem(final NestedItemDTO item) {
this.item = item;
}

public NestedPurchaseOrderDTO getPurchaseOrder() {
return this.purchaseOrder;
}

public void setPurchaseOrder(final NestedPurchaseOrderDTO purchaseOrder) {
this.purchaseOrder = purchaseOrder;
}

public Integer getQuantity() {
return this.quantity;
}

public void setQuantity(final Integer quantity) {
this.quantity = quantity;
}
}

9. PurchaseOrderDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;

import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import javax.persistence.EntityManager;

import de.binaris.petstore.forge.model.PurchaseOrder;
import de.binaris.petstore.forge.model.OrderLine;
import de.binaris.petstore.forge.rest.dto.NestedCustomerDTO;
import de.binaris.petstore.forge.rest.dto.CreditCardDTO;
import de.binaris.petstore.forge.rest.dto.NestedOrderLineDTO;
import de.binaris.petstore.forge.rest.dto.AddressDTO;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class PurchaseOrderDTO implements Serializable {

private static final long serialVersionUID = 7117777710111753391L;

private Float total;
private Date orderDate;
private Float vat;
private Float totalWithVat;
private NestedCustomerDTO customer;
private Float vatRate;
private Float discount;
private Long id;
private CreditCardDTO creditCard;
private Set<NestedOrderLineDTO> orderLines = new HashSet<NestedOrderLineDTO>();
private Float discountRate;
private AddressDTO deliveryAddress;
private Float totalWithoutVat;

public PurchaseOrderDTO() {
}

public PurchaseOrderDTO(final PurchaseOrder entity) {
if (entity != null) {
this.total = entity.getTotal();
this.orderDate = entity.getOrderDate();
this.vat = entity.getVat();
this.totalWithVat = entity.getTotalWithVat();
this.customer = new NestedCustomerDTO(entity.getCustomer());
this.vatRate = entity.getVatRate();
this.discount = entity.getDiscount();
this.id = entity.getId();
this.creditCard = new CreditCardDTO(entity.getCreditCard());
Iterator<OrderLine> iterOrderLines = entity.getOrderLines()
.iterator();
for (; iterOrderLines.hasNext();) {
OrderLine element = iterOrderLines.next();
this.orderLines.add(new NestedOrderLineDTO(element));
}
this.discountRate = entity.getDiscountRate();
this.deliveryAddress = new AddressDTO(entity.getDeliveryAddress());
this.totalWithoutVat = entity.getTotalWithoutVat();
}
}

public PurchaseOrder fromDTO(PurchaseOrder entity, EntityManager em) {
if (entity == null) {
entity = new PurchaseOrder();
}
entity.setTotal(this.total);
entity.setOrderDate(this.orderDate);
entity.setVat(this.vat);
entity.setTotalWithVat(this.totalWithVat);
if (this.customer != null) {
entity.setCustomer(this.customer.fromDTO(entity.getCustomer(), em));
}
entity.setVatRate(this.vatRate);
entity.setDiscount(this.discount);
if (this.creditCard != null) {
entity.setCreditCard(this.creditCard.fromDTO(
entity.getCreditCard(), em));
}
Iterator<OrderLine> iterOrderLines = entity.getOrderLines().iterator();
for (; iterOrderLines.hasNext();) {
boolean found = false;
OrderLine orderLine = iterOrderLines.next();
Iterator<NestedOrderLineDTO> iterDtoOrderLines = this
.getOrderLines().iterator();
for (; iterDtoOrderLines.hasNext();) {
NestedOrderLineDTO dtoOrderLine = iterDtoOrderLines.next();
if (dtoOrderLine.getId().equals(orderLine.getId())) {
found = true;
break;
}
}
if (found == false) {
iterOrderLines.remove();
}
}
Iterator<NestedOrderLineDTO> iterDtoOrderLines = this.getOrderLines()
.iterator();
for (; iterDtoOrderLines.hasNext();) {
boolean found = false;
NestedOrderLineDTO dtoOrderLine = iterDtoOrderLines.next();
iterOrderLines = entity.getOrderLines().iterator();
for (; iterOrderLines.hasNext();) {
OrderLine orderLine = iterOrderLines.next();
if (dtoOrderLine.getId().equals(orderLine.getId())) {
found = true;
break;
}
}
if (found == false) {
Iterator<OrderLine> resultIter = em
.createQuery(„SELECT DISTINCT o FROM OrderLine o“,
OrderLine.class).getResultList().iterator();
for (; resultIter.hasNext();) {
OrderLine result = resultIter.next();
if (result.getId().equals(dtoOrderLine.getId())) {
entity.getOrderLines().add(result);
break;
}
}
}
}
entity.setDiscountRate(this.discountRate);
if (this.deliveryAddress != null) {
entity.setDeliveryAddress(this.deliveryAddress.fromDTO(
entity.getDeliveryAddress(), em));
}
entity.setTotalWithoutVat(this.totalWithoutVat);
entity = em.merge(entity);
return entity;
}

public Float getTotal() {
return this.total;
}

public void setTotal(final Float total) {
this.total = total;
}

public Date getOrderDate() {
return this.orderDate;
}

public void setOrderDate(final Date orderDate) {
this.orderDate = orderDate;
}

public Float getVat() {
return this.vat;
}

public void setVat(final Float vat) {
this.vat = vat;
}

public Float getTotalWithVat() {
return this.totalWithVat;
}

public void setTotalWithVat(final Float totalWithVat) {
this.totalWithVat = totalWithVat;
}

public NestedCustomerDTO getCustomer() {
return this.customer;
}

public void setCustomer(final NestedCustomerDTO customer) {
this.customer = customer;
}

public Float getVatRate() {
return this.vatRate;
}

public void setVatRate(final Float vatRate) {
this.vatRate = vatRate;
}

public Float getDiscount() {
return this.discount;
}

public void setDiscount(final Float discount) {
this.discount = discount;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public CreditCardDTO getCreditCard() {
return this.creditCard;
}

public void setCreditCard(final CreditCardDTO creditCard) {
this.creditCard = creditCard;
}

public Set<NestedOrderLineDTO> getOrderLines() {
return this.orderLines;
}

public void setOrderLines(final Set<NestedOrderLineDTO> orderLines) {
this.orderLines = orderLines;
}

public Float getDiscountRate() {
return this.discountRate;
}

public void setDiscountRate(final Float discountRate) {
this.discountRate = discountRate;
}

public AddressDTO getDeliveryAddress() {
return this.deliveryAddress;
}

public void setDeliveryAddress(final AddressDTO deliveryAddress) {
this.deliveryAddress = deliveryAddress;
}

public Float getTotalWithoutVat() {
return this.totalWithoutVat;
}

public void setTotalWithoutVat(final Float totalWithoutVat) {
this.totalWithoutVat = totalWithoutVat;
}
}

10. NestedCategoryDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Category;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

public class NestedCategoryDTO implements Serializable {

private static final long serialVersionUID = 7235678910111213150L;

private Long id;
private String description;
private String name;

public NestedCategoryDTO() {
}

public NestedCategoryDTO(final Category entity) {
if (entity != null) {
this.id = entity.getId();
this.description = entity.getDescription();
this.name = entity.getName();
}
}

public Category fromDTO(Category entity, EntityManager em) {
if (entity == null) {
entity = new Category();
}
if (this.id != null) {
TypedQuery<Category> findByIdQuery = em.createQuery(
„SELECT DISTINCT c FROM Category c WHERE c.id = :entityId“,
Category.class);
findByIdQuery.setParameter(„entityId“, this.id);
try {
entity = findByIdQuery.getSingleResult();
} catch (javax.persistence.NoResultException nre) {
entity = null;
}
return entity;
}
entity.setDescription(this.description);
entity.setName(this.name);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public String getDescription() {
return this.description;
}

public void setDescription(final String description) {
this.description = description;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}
}

11. NestedCountryDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Country;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

public class NestedCountryDTO implements Serializable {

private static final long serialVersionUID = 7335678910111213130L;

private Long id;
private String printableName;
private String numcode;
private String name;
private String iso3;
private String isoCode;

public NestedCountryDTO() {
}

public NestedCountryDTO(final Country entity) {
if (entity != null) {
this.id = entity.getId();
this.printableName = entity.getPrintableName();
this.numcode = entity.getNumcode();
this.name = entity.getName();
this.iso3 = entity.getIso3();
this.isoCode = entity.getIsoCode();
}
}

public Country fromDTO(Country entity, EntityManager em) {
if (entity == null) {
entity = new Country();
}
if (this.id != null) {
TypedQuery<Country> findByIdQuery = em.createQuery(
„SELECT DISTINCT c FROM Country c WHERE c.id = :entityId“,
Country.class);
findByIdQuery.setParameter(„entityId“, this.id);
try {
entity = findByIdQuery.getSingleResult();
} catch (javax.persistence.NoResultException nre) {
entity = null;
}
return entity;
}
entity.setPrintableName(this.printableName);
entity.setNumcode(this.numcode);
entity.setName(this.name);
entity.setIso3(this.iso3);
entity.setIsoCode(this.isoCode);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public String getPrintableName() {
return this.printableName;
}

public void setPrintableName(final String printableName) {
this.printableName = printableName;
}

public String getNumcode() {
return this.numcode;
}

public void setNumcode(final String numcode) {
this.numcode = numcode;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}

public String getIso3() {
return this.iso3;
}

public void setIso3(final String iso3) {
this.iso3 = iso3;
}

public String getIsoCode() {
return this.isoCode;
}

public void setIsoCode(final String isoCode) {
this.isoCode = isoCode;
}
}

12. NestedCustomerDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Customer;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.Date;
import de.binaris.petstore.forge.rest.dto.AddressDTO;

public class NestedCustomerDTO implements Serializable {

private static final long serialVersionUID = 7535678910111213150L;

private Date dateOfBirth;
private Long id;
private String lastName;
private String phone;
private AddressDTO address;
private String email;
private String login;
private String firstName;
private String password;

public NestedCustomerDTO() {
}

public NestedCustomerDTO(final Customer entity) {
if (entity != null) {
this.dateOfBirth = entity.getDateOfBirth();
this.id = entity.getId();
this.lastName = entity.getLastName();
this.phone = entity.getPhone();
this.address = new AddressDTO(entity.getAddress());
this.email = entity.getEmail();
this.login = entity.getLogin();
this.firstName = entity.getFirstName();
this.password = entity.getPassword();
}
}

public Customer fromDTO(Customer entity, EntityManager em) {
if (entity == null) {
entity = new Customer();
}
if (this.id != null) {
TypedQuery<Customer> findByIdQuery = em.createQuery(
„SELECT DISTINCT c FROM Customer c WHERE c.id = :entityId“,
Customer.class);
findByIdQuery.setParameter(„entityId“, this.id);
try {
entity = findByIdQuery.getSingleResult();
} catch (javax.persistence.NoResultException nre) {
entity = null;
}
return entity;
}
entity.setDateOfBirth(this.dateOfBirth);
entity.setLastName(this.lastName);
entity.setPhone(this.phone);
if (this.address != null) {
entity.setAddress(this.address.fromDTO(entity.getAddress(), em));
}
entity.setEmail(this.email);
entity.setLogin(this.login);
entity.setFirstName(this.firstName);
entity.setPassword(this.password);
entity = em.merge(entity);
return entity;
}

public Date getDateOfBirth() {
return this.dateOfBirth;
}

public void setDateOfBirth(final Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public String getLastName() {
return this.lastName;
}

public void setLastName(final String lastName) {
this.lastName = lastName;
}

public String getPhone() {
return this.phone;
}

public void setPhone(final String phone) {
this.phone = phone;
}

public AddressDTO getAddress() {
return this.address;
}

public void setAddress(final AddressDTO address) {
this.address = address;
}

public String getEmail() {
return this.email;
}

public void setEmail(final String email) {
this.email = email;
}

public String getLogin() {
return this.login;
}

public void setLogin(final String login) {
this.login = login;
}

public String getFirstName() {
return this.firstName;
}

public void setFirstName(final String firstName) {
this.firstName = firstName;
}

public String getPassword() {
return this.password;
}

public void setPassword(final String password) {
this.password = password;
}
}

13. NestedItemDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Item;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

public class NestedItemDTO implements Serializable {

private static final long serialVersionUID = 7735678910111213170L;

private Long id;
private Float unitCost;
private String imagePath;
private String description;
private String name;

public NestedItemDTO() {
}

public NestedItemDTO(final Item entity) {
if (entity != null) {
this.id = entity.getId();
this.unitCost = entity.getUnitCost();
this.imagePath = entity.getImagePath();
this.description = entity.getDescription();
this.name = entity.getName();
}
}

public Item fromDTO(Item entity, EntityManager em) {
if (entity == null) {
entity = new Item();
}
if (this.id != null) {
TypedQuery<Item> findByIdQuery = em.createQuery(
„SELECT DISTINCT i FROM Item i WHERE i.id = :entityId“,
Item.class);
findByIdQuery.setParameter(„entityId“, this.id);
try {
entity = findByIdQuery.getSingleResult();
} catch (javax.persistence.NoResultException nre) {
entity = null;
}
return entity;
}
entity.setUnitCost(this.unitCost);
entity.setImagePath(this.imagePath);
entity.setDescription(this.description);
entity.setName(this.name);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public Float getUnitCost() {
return this.unitCost;
}

public void setUnitCost(final Float unitCost) {
this.unitCost = unitCost;
}

public String getImagePath() {
return this.imagePath;
}

public void setImagePath(final String imagePath) {
this.imagePath = imagePath;
}

public String getDescription() {
return this.description;
}

public void setDescription(final String description) {
this.description = description;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}
}

14. NestedOrderLineDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.OrderLine;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

public class NestedOrderLineDTO implements Serializable {

private static final long serialVersionUID = 7935678910111213190L;

private Long id;
private Float subTotal;
private Integer quantity;

public NestedOrderLineDTO() {
}

public NestedOrderLineDTO(final OrderLine entity) {
if (entity != null) {
this.id = entity.getId();
this.subTotal = entity.getSubTotal();
this.quantity = entity.getQuantity();
}
}

public OrderLine fromDTO(OrderLine entity, EntityManager em) {
if (entity == null) {
entity = new OrderLine();
}
if (this.id != null) {
TypedQuery<OrderLine> findByIdQuery = em
.createQuery(
„SELECT DISTINCT o FROM OrderLine o WHERE o.id = :entityId“,
OrderLine.class);
findByIdQuery.setParameter(„entityId“, this.id);
try {
entity = findByIdQuery.getSingleResult();
} catch (javax.persistence.NoResultException nre) {
entity = null;
}
return entity;
}
entity.setQuantity(this.quantity);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public Float getSubTotal() {
return this.subTotal;
}

public void setSubTotal(final Float subTotal) {
this.subTotal = subTotal;
}

public Integer getQuantity() {
return this.quantity;
}

public void setQuantity(final Integer quantity) {
this.quantity = quantity;
}
}

15. NestedProductDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.Product;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

public class NestedProductDTO implements Serializable {

private static final long serialVersionUID = 7115678910111213191L;

private Long id;
private String description;
private String name;

public NestedProductDTO() {
}

public NestedProductDTO(final Product entity) {
if (entity != null) {
this.id = entity.getId();
this.description = entity.getDescription();
this.name = entity.getName();
}
}

public Product fromDTO(Product entity, EntityManager em) {
if (entity == null) {
entity = new Product();
}
if (this.id != null) {
TypedQuery<Product> findByIdQuery = em.createQuery(
„SELECT DISTINCT p FROM Product p WHERE p.id = :entityId“,
Product.class);
findByIdQuery.setParameter(„entityId“, this.id);
try {
entity = findByIdQuery.getSingleResult();
} catch (javax.persistence.NoResultException nre) {
entity = null;
}
return entity;
}
entity.setDescription(this.description);
entity.setName(this.name);
entity = em.merge(entity);
return entity;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public String getDescription() {
return this.description;
}

public void setDescription(final String description) {
this.description = description;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = name;
}
}

16. NestedPurchaseOrderDTO:

package de.binaris.petstore.forge.rest.dto;

import java.io.Serializable;
import de.binaris.petstore.forge.model.PurchaseOrder;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.Date;
import de.binaris.petstore.forge.rest.dto.CreditCardDTO;
import de.binaris.petstore.forge.rest.dto.AddressDTO;

public class NestedPurchaseOrderDTO implements Serializable {

private static final long serialVersionUID = 7117678910111213391L;

private Float total;
private Date orderDate;
private Float vat;
private Float totalWithVat;
private Float vatRate;
private Float discount;
private Long id;
private CreditCardDTO creditCard;
private Float discountRate;
private AddressDTO deliveryAddress;
private Float totalWithoutVat;

public NestedPurchaseOrderDTO() {
}

public NestedPurchaseOrderDTO(final PurchaseOrder entity) {
if (entity != null) {
this.total = entity.getTotal();
this.orderDate = entity.getOrderDate();
this.vat = entity.getVat();
this.totalWithVat = entity.getTotalWithVat();
this.vatRate = entity.getVatRate();
this.discount = entity.getDiscount();
this.id = entity.getId();
this.creditCard = new CreditCardDTO(entity.getCreditCard());
this.discountRate = entity.getDiscountRate();
this.deliveryAddress = new AddressDTO(entity.getDeliveryAddress());
this.totalWithoutVat = entity.getTotalWithoutVat();
}
}

public PurchaseOrder fromDTO(PurchaseOrder entity, EntityManager em) {
if (entity == null) {
entity = new PurchaseOrder();
}
if (this.id != null) {
TypedQuery<PurchaseOrder> findByIdQuery = em
.createQuery(
„SELECT DISTINCT p FROM PurchaseOrder p WHERE p.id = :entityId“,
PurchaseOrder.class);
findByIdQuery.setParameter(„entityId“, this.id);
try {
entity = findByIdQuery.getSingleResult();
} catch (javax.persistence.NoResultException nre) {
entity = null;
}
return entity;
}
entity.setTotal(this.total);
entity.setOrderDate(this.orderDate);
entity.setVat(this.vat);
entity.setTotalWithVat(this.totalWithVat);
entity.setVatRate(this.vatRate);
entity.setDiscount(this.discount);
if (this.creditCard != null) {
entity.setCreditCard(this.creditCard.fromDTO(
entity.getCreditCard(), em));
}
entity.setDiscountRate(this.discountRate);
if (this.deliveryAddress != null) {
entity.setDeliveryAddress(this.deliveryAddress.fromDTO(
entity.getDeliveryAddress(), em));
}
entity.setTotalWithoutVat(this.totalWithoutVat);
entity = em.merge(entity);
return entity;
}

public Float getTotal() {
return this.total;
}

public void setTotal(final Float total) {
this.total = total;
}

public Date getOrderDate() {
return this.orderDate;
}

public void setOrderDate(final Date orderDate) {
this.orderDate = orderDate;
}

public Float getVat() {
return this.vat;
}

public void setVat(final Float vat) {
this.vat = vat;
}

public Float getTotalWithVat() {
return this.totalWithVat;
}

public void setTotalWithVat(final Float totalWithVat) {
this.totalWithVat = totalWithVat;
}

public Float getVatRate() {
return this.vatRate;
}

public void setVatRate(final Float vatRate) {
this.vatRate = vatRate;
}

public Float getDiscount() {
return this.discount;
}

public void setDiscount(final Float discount) {
this.discount = discount;
}

public Long getId() {
return this.id;
}

public void setId(final Long id) {
this.id = id;
}

public CreditCardDTO getCreditCard() {
return this.creditCard;
}

public void setCreditCard(final CreditCardDTO creditCard) {
this.creditCard = creditCard;
}

public Float getDiscountRate() {
return this.discountRate;
}

public void setDiscountRate(final Float discountRate) {
this.discountRate = discountRate;
}

public AddressDTO getDeliveryAddress() {
return this.deliveryAddress;
}

public void setDeliveryAddress(final AddressDTO deliveryAddress) {
this.deliveryAddress = deliveryAddress;
}

public Float getTotalWithoutVat() {
return this.totalWithoutVat;
}

public void setTotalWithoutVat(final Float totalWithoutVat) {
this.totalWithoutVat = totalWithoutVat;
}
}

Nun können aus dem Kontext-Menü auf dem Maven-Projekt mittels Forge/Scaffold Untermenüpunkt die gewünschten Views generiert werden. Die Architektur und die Assoziationen für die Auswahl des Angular JS MVVM Frameworks wurden bereits im Blog-Eintrag Beispiel-Projekt educationorganizer hier eingehend erläutert und können dort nachgelesen werden. Für JSF 2.2 Views (Auswahl JSF) erhält man die folgenden BackingBeans mit den entsprechenden CDI Annotationen (@Named anstatt @ManagedBean, etc.):

– CategoryBean
– CountryBean
– CustomerBean
– ItemBean
– LocaleBean
– OrderLineBean
– ProductBean
– PurchaseOrderBean
– ViewUtils

Die BackingBeans im Detail:

1. CategoryBean:

package de.binaris.petstore.forge.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateful;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import de.binaris.petstore.forge.model.Category;
import de.binaris.petstore.forge.model.Product;
import java.util.Iterator;

/**
* Backing bean for Category entities.
* <p>
* This class provides CRUD functionality for all Category entities. It focuses
* purely on Java EE 6 standards (e.g. <tt>&#64;ConversationScoped</tt> for
* state management, <tt>PersistenceContext</tt> for persistence,
* <tt>CriteriaBuilder</tt> for searches) rather than introducing a CRUD
* framework or custom base class.
*/
@Named
@Stateful
@ConversationScoped
public class CategoryBean implements Serializable {

private static final long serialVersionUID = 7117791110111273391L;

/*
* Support creating and retrieving Category entities
*/

private Long id;

public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

private Category category;

public Category getCategory() {
return this.category;
}

@Inject
private Conversation conversation;

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public String create() {

this.conversation.begin();
return „create?faces-redirect=true“;
}

public void retrieve() {

if (FacesContext.getCurrentInstance().isPostback()) {
return;
}

if (this.conversation.isTransient()) {
this.conversation.begin();
}

if (this.id == null) {
this.category = this.example;
} else {
this.category = findById(getId());
}
}

public Category findById(Long id) {

return this.entityManager.find(Category.class, id);
}

/*
* Support updating and deleting Category entities
*/

public String update() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.category);
return „search?faces-redirect=true“;
} else {
this.entityManager.merge(this.category);
return „view?faces-redirect=true&id=“ + this.category.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
this.conversation.end();

try {
Category deletableEntity = findById(getId());
Iterator<Product> iterProducts = deletableEntity.getProducts()
.iterator();
for (; iterProducts.hasNext();) {
Product nextInProducts = iterProducts.next();
nextInProducts.setCategory(null);
iterProducts.remove();
this.entityManager.merge(nextInProducts);
}
this.entityManager.remove(deletableEntity);
this.entityManager.flush();
return „search?faces-redirect=true“;
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

/*
* Support searching Category entities with pagination
*/

private int page;
private long count;
private List<Category> pageItems;

private Category example = new Category();

public int getPage() {
return this.page;
}

public void setPage(int page) {
this.page = page;
}

public int getPageSize() {
return 10;
}

public Category getExample() {
return this.example;
}

public void setExample(Category example) {
this.example = example;
}

public void search() {
this.page = 0;
}

public void paginate() {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

// Populate this.count

CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
Root<Category> root = countCriteria.from(Category.class);
countCriteria = countCriteria.select(builder.count(root)).where(
getSearchPredicates(root));
this.count = this.entityManager.createQuery(countCriteria)
.getSingleResult();

// Populate this.pageItems

CriteriaQuery<Category> criteria = builder.createQuery(Category.class);
root = criteria.from(Category.class);
TypedQuery<Category> query = this.entityManager.createQuery(criteria
.select(root).where(getSearchPredicates(root)));
query.setFirstResult(this.page * getPageSize()).setMaxResults(
getPageSize());
this.pageItems = query.getResultList();
}

private Predicate[] getSearchPredicates(Root<Category> root) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
List<Predicate> predicatesList = new ArrayList<Predicate>();

String name = this.example.getName();
if (name != null && !““.equals(name)) {
predicatesList.add(builder.like(root.<String> get(„name“),
‚%‘ + name + ‚%‘));
}
String description = this.example.getDescription();
if (description != null && !““.equals(description)) {
predicatesList.add(builder.like(root.<String> get(„description“),
‚%‘ + description + ‚%‘));
}

return predicatesList.toArray(new Predicate[predicatesList.size()]);
}

public List<Category> getPageItems() {
return this.pageItems;
}

public long getCount() {
return this.count;
}

/*
* Support listing and POSTing back Category entities (e.g. from inside an
* HtmlSelectOneMenu)
*/

public List<Category> getAll() {

CriteriaQuery<Category> criteria = this.entityManager
.getCriteriaBuilder().createQuery(Category.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(Category.class))).getResultList();
}

@Resource
private SessionContext sessionContext;

public Converter getConverter() {

final CategoryBean ejbProxy = this.sessionContext
.getBusinessObject(CategoryBean.class);

return new Converter() {

@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {

return ejbProxy.findById(Long.valueOf(value));
}

@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {

if (value == null) {
return "";
}

return String.valueOf(((Category) value).getId());
}

};

}

/*
* Support adding children to bidirectional, one-to-many tables
*/

private Category add = new Category();

public Category getAdd() {
return this.add;
}

public Category getAdded() {
Category added = this.add;
this.add = new Category();
return added;
}
}

2. CountryBean:

package de.binaris.petstore.forge.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateful;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import de.binaris.petstore.forge.model.Country;

/**
* Backing bean for Country entities.
* <p>
* This class provides CRUD functionality for all Country entities. It focuses
* purely on Java EE 6 standards (e.g. <tt>&#64;ConversationScoped</tt> for
* state management, <tt>PersistenceContext</tt> for persistence,
* <tt>CriteriaBuilder</tt> for searches) rather than introducing a CRUD
* framework or custom base class.
*/
@Named
@Stateful
@ConversationScoped
public class CountryBean implements Serializable {

private static final long serialVersionUID = 7137791110753273391L;

/*
* Support creating and retrieving Country entities
*/

private Long id;

public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

private Country country;

public Country getCountry() {
return this.country;
}

@Inject
private Conversation conversation;

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public String create() {

this.conversation.begin();
return „create?faces-redirect=true“;
}

public void retrieve() {

if (FacesContext.getCurrentInstance().isPostback()) {
return;
}

if (this.conversation.isTransient()) {
this.conversation.begin();
}

if (this.id == null) {
this.country = this.example;
} else {
this.country = findById(getId());
}
}

public Country findById(Long id) {

return this.entityManager.find(Country.class, id);
}

/*
* Support updating and deleting Country entities
*/

public String update() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.country);
return „search?faces-redirect=true“;
} else {
this.entityManager.merge(this.country);
return „view?faces-redirect=true&id=“ + this.country.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
this.conversation.end();

try {
Country deletableEntity = findById(getId());

this.entityManager.remove(deletableEntity);
this.entityManager.flush();
return „search?faces-redirect=true“;
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

/*
* Support searching Country entities with pagination
*/

private int page;
private long count;
private List<Country> pageItems;

private Country example = new Country();

public int getPage() {
return this.page;
}

public void setPage(int page) {
this.page = page;
}

public int getPageSize() {
return 10;
}

public Country getExample() {
return this.example;
}

public void setExample(Country example) {
this.example = example;
}

public void search() {
this.page = 0;
}

public void paginate() {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

// Populate this.count

CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
Root<Country> root = countCriteria.from(Country.class);
countCriteria = countCriteria.select(builder.count(root)).where(
getSearchPredicates(root));
this.count = this.entityManager.createQuery(countCriteria)
.getSingleResult();

// Populate this.pageItems

CriteriaQuery<Country> criteria = builder.createQuery(Country.class);
root = criteria.from(Country.class);
TypedQuery<Country> query = this.entityManager.createQuery(criteria
.select(root).where(getSearchPredicates(root)));
query.setFirstResult(this.page * getPageSize()).setMaxResults(
getPageSize());
this.pageItems = query.getResultList();
}

private Predicate[] getSearchPredicates(Root<Country> root) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
List<Predicate> predicatesList = new ArrayList<Predicate>();

String name = this.example.getName();
if (name != null && !““.equals(name)) {
predicatesList.add(builder.like(root.<String> get(„name“),
‚%‘ + name + ‚%‘));
}
String isoCode = this.example.getIsoCode();
if (isoCode != null && !““.equals(isoCode)) {
predicatesList.add(builder.like(root.<String> get(„isoCode“),
‚%‘ + isoCode + ‚%‘));
}
String printableName = this.example.getPrintableName();
if (printableName != null && !““.equals(printableName)) {
predicatesList.add(builder.like(root.<String> get(„printableName“),
‚%‘ + printableName + ‚%‘));
}
String iso3 = this.example.getIso3();
if (iso3 != null && !““.equals(iso3)) {
predicatesList.add(builder.like(root.<String> get(„iso3“),
‚%‘ + iso3 + ‚%‘));
}
String numcode = this.example.getNumcode();
if (numcode != null && !““.equals(numcode)) {
predicatesList.add(builder.like(root.<String> get(„numcode“),
‚%‘ + numcode + ‚%‘));
}

return predicatesList.toArray(new Predicate[predicatesList.size()]);
}

public List<Country> getPageItems() {
return this.pageItems;
}

public long getCount() {
return this.count;
}

/*
* Support listing and POSTing back Country entities (e.g. from inside an
* HtmlSelectOneMenu)
*/

public List<Country> getAll() {

CriteriaQuery<Country> criteria = this.entityManager
.getCriteriaBuilder().createQuery(Country.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(Country.class))).getResultList();
}

@Resource
private SessionContext sessionContext;

public Converter getConverter() {

final CountryBean ejbProxy = this.sessionContext
.getBusinessObject(CountryBean.class);

return new Converter() {

@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {

return ejbProxy.findById(Long.valueOf(value));
}

@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {

if (value == null) {
return „“;
}

return String.valueOf(((Country) value).getId());
}
};
}

/*
* Support adding children to bidirectional, one-to-many tables
*/

private Country add = new Country();

public Country getAdd() {
return this.add;
}

public Country getAdded() {
Country added = this.add;
this.add = new Country();
return added;
}
}

3. CustomerBean:

package de.binaris.petstore.forge.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateful;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.validation.ValidationException;

import de.binaris.petstore.forge.model.Customer;
import de.binaris.petstore.forge.model.PurchaseOrder;

/**
* Backing bean for Customer entities (c-r-u-d operations, search, list, pagination).
* <p>
* This class provides CRUD functionality for all Customer entities. It focuses
* purely on Java EE 6 standards (e.g. <tt>&#64;ConversationScoped</tt> for
* state management, <tt>PersistenceContext</tt> for persistence,
* <tt>CriteriaBuilder</tt> for searches) rather than introducing a CRUD
* framework or custom base class.
*/
@Named
@Stateful
@ConversationScoped
public class CustomerBean implements Serializable {

private static final long serialVersionUID = 7157791350753273391L;

private Long id;

public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

private Customer customer;

public void setCustomer(Customer customer) {
this.customer = customer;
}

public Customer getCustomer() {
return this.customer;
}

@Inject
private Conversation conversation;

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public String create() {

this.conversation.begin();
return „create?faces-redirect=true“;
}

public void retrieve() {

if (FacesContext.getCurrentInstance().isPostback()) {
return;
}

if (this.conversation.isTransient()) {
this.conversation.begin();
}

if (this.id == null) {
this.customer = this.example;
} else {
this.customer = findById(getId());
}
}

public Customer findById(Long id) {
return this.entityManager.find(Customer.class, id);
}

public Customer findByLogin(String login) {
TypedQuery<Customer> typedQuery = this.entityManager.createNamedQuery(Customer.FIND_BY_LOGIN, Customer.class);
typedQuery.setParameter(„login“, login);
try {
return typedQuery.getSingleResult();
} catch (NoResultException e) {
return null;
}
}

public Customer findCustomer(String login, String pwd) {
TypedQuery<Customer> typedQuery = this.entityManager.createNamedQuery(Customer.FIND_BY_LOGIN_PASSWORD, Customer.class);
typedQuery.setParameter(„login“, login);
typedQuery.setParameter(„password“, pwd);
try {
return typedQuery.getSingleResult();
} catch (NoResultException e) {
return null;
}
}

public String createNew() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.customer);
return „signon?faces-redirect=true“;
} else {
this.entityManager.merge(this.customer);
return „signon?faces-redirect=true&id=“ + this.customer.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String update() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.customer);
return „search?faces-redirect=true“;
} else {
this.entityManager.merge(this.customer);
return „view?faces-redirect=true&id=“ + this.customer.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
this.conversation.end();

try {
Customer deletableEntity = findById(getId());
Iterator<PurchaseOrder> iterPurchaseOrder = deletableEntity
.getPurchaseOrder().iterator();
for (; iterPurchaseOrder.hasNext();) {
PurchaseOrder nextInPurchaseOrder = iterPurchaseOrder.next();
nextInPurchaseOrder.setCustomer(null);
iterPurchaseOrder.remove();
this.entityManager.merge(nextInPurchaseOrder);
}
this.entityManager.remove(deletableEntity);
this.entityManager.flush();
return „search?faces-redirect=true“;
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public boolean doesLoginAlreadyExist(final String login) {
if (login == null)
throw new ValidationException(„Login cannot be null“);
// Login has to be unique
TypedQuery<Customer> typedQuery = this.entityManager.createNamedQuery(Customer.FIND_BY_LOGIN, Customer.class);
typedQuery.setParameter(„login“, login);
try {
typedQuery.getSingleResult();
return true;
} catch (NoResultException e) {
return false;
}
}

private int page;
private long count;
private List<Customer> pageItems;

private Customer example = new Customer();

public int getPage() {
return this.page;
}

public void setPage(int page) {
this.page = page;
}

public int getPageSize() {
return 10;
}

public Customer getExample() {
return this.example;
}

public void setExample(Customer example) {
this.example = example;
}

public void search() {
this.page = 0;
}

public void paginate() {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

// Populate this.count

CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
Root<Customer> root = countCriteria.from(Customer.class);
countCriteria = countCriteria.select(builder.count(root)).where(
getSearchPredicates(root));
this.count = this.entityManager.createQuery(countCriteria)
.getSingleResult();

// Populate this.pageItems

CriteriaQuery<Customer> criteria = builder.createQuery(Customer.class);
root = criteria.from(Customer.class);
TypedQuery<Customer> query = this.entityManager.createQuery(criteria
.select(root).where(getSearchPredicates(root)));
query.setFirstResult(this.page * getPageSize()).setMaxResults(
getPageSize());
this.pageItems = query.getResultList();
}

private Predicate[] getSearchPredicates(Root<Customer> root) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
List<Predicate> predicatesList = new ArrayList<Predicate>();

String firstName = this.example.getFirstName();
if (firstName != null && !““.equals(firstName)) {
predicatesList.add(builder.like(root.<String> get(„firstName“),
‚%‘ + firstName + ‚%‘));
}
String lastName = this.example.getLastName();
if (lastName != null && !““.equals(lastName)) {
predicatesList.add(builder.like(root.<String> get(„lastName“),
‚%‘ + lastName + ‚%‘));
}
String phone = this.example.getPhone();
if (phone != null && !““.equals(phone)) {
predicatesList.add(builder.like(root.<String> get(„phone“),
‚%‘ + phone + ‚%‘));
}
String email = this.example.getEmail();
if (email != null && !““.equals(email)) {
predicatesList.add(builder.like(root.<String> get(„email“),
‚%‘ + email + ‚%‘));
}
String login = this.example.getLogin();
if (login != null && !““.equals(login)) {
predicatesList.add(builder.like(root.<String> get(„login“),
‚%‘ + login + ‚%‘));
}

return predicatesList.toArray(new Predicate[predicatesList.size()]);
}

public List<Customer> getPageItems() {
return this.pageItems;
}

public long getCount() {
return this.count;
}

/*
* Support listing and POSTing back Customer entities (e.g. from inside an
* HtmlSelectOneMenu)
*/

public List<Customer> getAll() {

CriteriaQuery<Customer> criteria = this.entityManager
.getCriteriaBuilder().createQuery(Customer.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(Customer.class))).getResultList();
}

@Resource
private SessionContext sessionContext;

public Converter getConverter() {

final CustomerBean ejbProxy = this.sessionContext
.getBusinessObject(CustomerBean.class);

return new Converter() {

@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {

return ejbProxy.findById(Long.valueOf(value));
}

@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {

if (value == null) {
return „“;
}

return String.valueOf(((Customer) value).getId());
}
};
}

/*
* Support adding children to bidirectional, one-to-many tables
*/

private Customer add = new Customer();

public Customer getAdd() {
return this.add;
}

public Customer getAdded() {
Customer added = this.add;
this.add = new Customer();
return added;
}
}

4. ItemBean:

package de.binaris.petstore.forge.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateful;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import de.binaris.petstore.forge.model.Item;
import de.binaris.petstore.forge.model.Product;

/**
* Backing bean for Item entities.
* <p>
* This class provides CRUD functionality for all Item entities. It focuses
* purely on Java EE 6 standards (e.g. <tt>&#64;ConversationScoped</tt> for
* state management, <tt>PersistenceContext</tt> for persistence,
* <tt>CriteriaBuilder</tt> for searches) rather than introducing a CRUD
* framework or custom base class.
*/

@Named
@Stateful
@ConversationScoped
public class ItemBean implements Serializable {

private static final long serialVersionUID = 7159791370753273391L;

/*
* Support creating and retrieving Item entities
*/

private Long id;

public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

private Item item;

public Item getItem() {
return this.item;
}

@Inject
private Conversation conversation;

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public String create() {

this.conversation.begin();
return „create?faces-redirect=true“;
}

public void retrieve() {

if (FacesContext.getCurrentInstance().isPostback()) {
return;
}

if (this.conversation.isTransient()) {
this.conversation.begin();
}

if (this.id == null) {
this.item = this.example;
} else {
this.item = findById(getId());
}
}

public Item findById(Long id) {

return this.entityManager.find(Item.class, id);
}

/*
* Support updating and deleting Item entities
*/

public String update() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.item);
return „search?faces-redirect=true“;
} else {
this.entityManager.merge(this.item);
return „view?faces-redirect=true&id=“ + this.item.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
this.conversation.end();

try {
Item deletableEntity = findById(getId());

this.entityManager.remove(deletableEntity);
this.entityManager.flush();
return „search?faces-redirect=true“;
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

/*
* Support searching Item entities with pagination
*/

private int page;
private long count;
private List<Item> pageItems;

private Item example = new Item();

public int getPage() {
return this.page;
}

public void setPage(int page) {
this.page = page;
}

public int getPageSize() {
return 10;
}

public Item getExample() {
return this.example;
}

public void setExample(Item example) {
this.example = example;
}

public void search() {
this.page = 0;
}

public void paginate() {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

// Populate this.count

CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
Root<Item> root = countCriteria.from(Item.class);
countCriteria = countCriteria.select(builder.count(root)).where(
getSearchPredicates(root));
this.count = this.entityManager.createQuery(countCriteria)
.getSingleResult();

// Populate this.pageItems

CriteriaQuery<Item> criteria = builder.createQuery(Item.class);
root = criteria.from(Item.class);
TypedQuery<Item> query = this.entityManager.createQuery(criteria
.select(root).where(getSearchPredicates(root)));
query.setFirstResult(this.page * getPageSize()).setMaxResults(
getPageSize());
this.pageItems = query.getResultList();
}

private Predicate[] getSearchPredicates(Root<Item> root) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
List<Predicate> predicatesList = new ArrayList<Predicate>();

String name = this.example.getName();
if (name != null && !““.equals(name)) {
predicatesList.add(builder.like(root.<String> get(„name“),
‚%‘ + name + ‚%‘));
}
String description = this.example.getDescription();
if (description != null && !““.equals(description)) {
predicatesList.add(builder.like(root.<String> get(„description“),
‚%‘ + description + ‚%‘));
}
String imagePath = this.example.getImagePath();
if (imagePath != null && !““.equals(imagePath)) {
predicatesList.add(builder.like(root.<String> get(„imagePath“),
‚%‘ + imagePath + ‚%‘));
}
Product product = this.example.getProduct();
if (product != null) {
predicatesList.add(builder.equal(root.get(„product“), product));
}

return predicatesList.toArray(new Predicate[predicatesList.size()]);
}

public List<Item> getPageItems() {
return this.pageItems;
}

public long getCount() {
return this.count;
}

/*
* Support listing and POSTing back Item entities (e.g. from inside an
* HtmlSelectOneMenu)
*/

public List<Item> getAll() {

CriteriaQuery<Item> criteria = this.entityManager.getCriteriaBuilder()
.createQuery(Item.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(Item.class))).getResultList();
}

@Resource
private SessionContext sessionContext;

public Converter getConverter() {

final ItemBean ejbProxy = this.sessionContext
.getBusinessObject(ItemBean.class);

return new Converter() {

@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {

return ejbProxy.findById(Long.valueOf(value));
}

@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {

if (value == null) {
return „“;
}

return String.valueOf(((Item) value).getId());
}
};
}

/*
* Support adding children to bidirectional, one-to-many tables
*/

private Item add = new Item();

public Item getAdd() {
return this.add;
}

public Item getAdded() {
Item added = this.add;
this.add = new Item();
return added;
}
}

5. LocaleBean:

package de.binaris.petstore.forge.view;

import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
import javax.inject.Named;

import de.binaris.petstore.annotations.Loggable;

import java.io.Serializable;
import java.util.Locale;

@Named
@SessionScoped
@Loggable
public class LocaleBean implements Serializable {

private static final long serialVersionUID = 5187997881833212772L;

@Produces
private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

public Locale getLocale() {
return locale;
}

public String getLanguage() {
return locale.getLanguage();
}

public void setLanguage(String language) {
locale = new Locale(language);
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}
}

6. OrderLineBean:

package de.binaris.petstore.forge.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateful;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import de.binaris.petstore.forge.model.OrderLine;
import de.binaris.petstore.forge.model.Item;
import de.binaris.petstore.forge.model.PurchaseOrder;

/**
* Backing bean for OrderLine entities.
* <p>
* This class provides CRUD functionality for all OrderLine entities. It focuses
* purely on Java EE 6 standards (e.g. <tt>&#64;ConversationScoped</tt> for
* state management, <tt>PersistenceContext</tt> for persistence,
* <tt>CriteriaBuilder</tt> for searches) rather than introducing a CRUD
* framework or custom base class.
*/

@Named
@Stateful
@ConversationScoped
public class OrderLineBean implements Serializable {

private static final long serialVersionUID = 7179991371753273391L;

/*
* Support creating and retrieving OrderLine entities
*/

private Long id;

public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

private OrderLine orderLine;

public OrderLine getOrderLine() {
return this.orderLine;
}

@Inject
private Conversation conversation;

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public String create() {

this.conversation.begin();
return „create?faces-redirect=true“;
}

public void retrieve() {

if (FacesContext.getCurrentInstance().isPostback()) {
return;
}

if (this.conversation.isTransient()) {
this.conversation.begin();
}

if (this.id == null) {
this.orderLine = this.example;
} else {
this.orderLine = findById(getId());
}
}

public OrderLine findById(Long id) {

return this.entityManager.find(OrderLine.class, id);
}

/*
* Support updating and deleting OrderLine entities
*/

public String update() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.orderLine);
return „search?faces-redirect=true“;
} else {
this.entityManager.merge(this.orderLine);
return „view?faces-redirect=true&id=“ + this.orderLine.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
this.conversation.end();

try {
OrderLine deletableEntity = findById(getId());
PurchaseOrder purchaseOrder = deletableEntity.getPurchaseOrder();
purchaseOrder.getOrderLines().remove(deletableEntity);
deletableEntity.setPurchaseOrder(null);
this.entityManager.merge(purchaseOrder);
this.entityManager.remove(deletableEntity);
this.entityManager.flush();
return „search?faces-redirect=true“;
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

/*
* Support searching OrderLine entities with pagination
*/

private int page;
private long count;
private List<OrderLine> pageItems;

private OrderLine example = new OrderLine();

public int getPage() {
return this.page;
}

public void setPage(int page) {
this.page = page;
}

public int getPageSize() {
return 10;
}

public OrderLine getExample() {
return this.example;
}

public void setExample(OrderLine example) {
this.example = example;
}

public void search() {
this.page = 0;
}

public void paginate() {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

// Populate this.count

CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
Root<OrderLine> root = countCriteria.from(OrderLine.class);
countCriteria = countCriteria.select(builder.count(root)).where(
getSearchPredicates(root));
this.count = this.entityManager.createQuery(countCriteria)
.getSingleResult();

// Populate this.pageItems

CriteriaQuery<OrderLine> criteria = builder
.createQuery(OrderLine.class);
root = criteria.from(OrderLine.class);
TypedQuery<OrderLine> query = this.entityManager.createQuery(criteria
.select(root).where(getSearchPredicates(root)));
query.setFirstResult(this.page * getPageSize()).setMaxResults(
getPageSize());
this.pageItems = query.getResultList();
}

private Predicate[] getSearchPredicates(Root<OrderLine> root) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
List<Predicate> predicatesList = new ArrayList<Predicate>();

Integer quantity = this.example.getQuantity();
if (quantity != null && quantity.intValue() != 0) {
predicatesList.add(builder.equal(root.get(„quantity“), quantity));
}
Item item = this.example.getItem();
if (item != null) {
predicatesList.add(builder.equal(root.get(„item“), item));
}
PurchaseOrder purchaseOrder = this.example.getPurchaseOrder();
if (purchaseOrder != null) {
predicatesList.add(builder.equal(root.get(„purchaseOrder“),
purchaseOrder));
}

return predicatesList.toArray(new Predicate[predicatesList.size()]);
}

public List<OrderLine> getPageItems() {
return this.pageItems;
}

public long getCount() {
return this.count;
}

/*
* Support listing and POSTing back OrderLine entities (e.g. from inside an
* HtmlSelectOneMenu)
*/

public List<OrderLine> getAll() {

CriteriaQuery<OrderLine> criteria = this.entityManager
.getCriteriaBuilder().createQuery(OrderLine.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(OrderLine.class)))
.getResultList();
}

@Resource
private SessionContext sessionContext;

public Converter getConverter() {

final OrderLineBean ejbProxy = this.sessionContext
.getBusinessObject(OrderLineBean.class);

return new Converter() {

@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {

return ejbProxy.findById(Long.valueOf(value));
}

@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {

if (value == null) {
return „“;
}

return String.valueOf(((OrderLine) value).getId());
}
};
}

/*
* Support adding children to bidirectional, one-to-many tables
*/

private OrderLine add = new OrderLine();

public OrderLine getAdd() {
return this.add;
}

public OrderLine getAdded() {
OrderLine added = this.add;
this.add = new OrderLine();
return added;
}
}

7. ProductBean:

package de.binaris.petstore.forge.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateful;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import de.binaris.petstore.forge.model.Product;
import de.binaris.petstore.forge.model.Category;

/**
* Backing bean for Product entities.
* <p>
* This class provides CRUD functionality for all Product entities. It focuses
* purely on Java EE 6 standards (e.g. <tt>&#64;ConversationScoped</tt> for
* state management, <tt>PersistenceContext</tt> for persistence,
* <tt>CriteriaBuilder</tt> for searches) rather than introducing a CRUD
* framework or custom base class.
*/

@Named
@Stateful
@ConversationScoped
public class ProductBean implements Serializable {

private static final long serialVersionUID = 7179791373757373591L;

/*
* Support creating and retrieving Product entities
*/

private Long id;

public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

private Product product;

public Product getProduct() {
return this.product;
}

@Inject
private Conversation conversation;

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public String create() {

this.conversation.begin();
return „create?faces-redirect=true“;
}

public void retrieve() {

if (FacesContext.getCurrentInstance().isPostback()) {
return;
}

if (this.conversation.isTransient()) {
this.conversation.begin();
}

if (this.id == null) {
this.product = this.example;
} else {
this.product = findById(getId());
}
}

public Product findById(Long id) {

return this.entityManager.find(Product.class, id);
}

/*
* Support updating and deleting Product entities
*/

public String update() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.product);
return „search?faces-redirect=true“;
} else {
this.entityManager.merge(this.product);
return „view?faces-redirect=true&id=“ + this.product.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
this.conversation.end();

try {
Product deletableEntity = findById(getId());
Category category = deletableEntity.getCategory();
category.getProducts().remove(deletableEntity);
deletableEntity.setCategory(null);
this.entityManager.merge(category);
this.entityManager.remove(deletableEntity);
this.entityManager.flush();
return „search?faces-redirect=true“;
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

/*
* Support searching Product entities with pagination
*/

private int page;
private long count;
private List<Product> pageItems;

private Product example = new Product();

public int getPage() {
return this.page;
}

public void setPage(int page) {
this.page = page;
}

public int getPageSize() {
return 10;
}

public Product getExample() {
return this.example;
}

public void setExample(Product example) {
this.example = example;
}

public void search() {
this.page = 0;
}

public void paginate() {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

// Populate this.count

CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
Root<Product> root = countCriteria.from(Product.class);
countCriteria = countCriteria.select(builder.count(root)).where(
getSearchPredicates(root));
this.count = this.entityManager.createQuery(countCriteria)
.getSingleResult();

// Populate this.pageItems

CriteriaQuery<Product> criteria = builder.createQuery(Product.class);
root = criteria.from(Product.class);
TypedQuery<Product> query = this.entityManager.createQuery(criteria
.select(root).where(getSearchPredicates(root)));
query.setFirstResult(this.page * getPageSize()).setMaxResults(
getPageSize());
this.pageItems = query.getResultList();
}

private Predicate[] getSearchPredicates(Root<Product> root) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
List<Predicate> predicatesList = new ArrayList<Predicate>();

String name = this.example.getName();
if (name != null && !““.equals(name)) {
predicatesList.add(builder.like(root.<String> get(„name“),
‚%‘ + name + ‚%‘));
}
String description = this.example.getDescription();
if (description != null && !““.equals(description)) {
predicatesList.add(builder.like(root.<String> get(„description“),
‚%‘ + description + ‚%‘));
}
Category category = this.example.getCategory();
if (category != null) {
predicatesList.add(builder.equal(root.get(„category“), category));
}

return predicatesList.toArray(new Predicate[predicatesList.size()]);
}

public List<Product> getPageItems() {
return this.pageItems;
}

public long getCount() {
return this.count;
}

/*
* Support listing and POSTing back Product entities (e.g. from inside an
* HtmlSelectOneMenu)
*/

public List<Product> getAll() {

CriteriaQuery<Product> criteria = this.entityManager
.getCriteriaBuilder().createQuery(Product.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(Product.class))).getResultList();
}

@Resource
private SessionContext sessionContext;

public Converter getConverter() {

final ProductBean ejbProxy = this.sessionContext
.getBusinessObject(ProductBean.class);

return new Converter() {

@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {

return ejbProxy.findById(Long.valueOf(value));
}

@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {

if (value == null) {
return „“;
}

return String.valueOf(((Product) value).getId());
}
};
}

/*
* Support adding children to bidirectional, one-to-many tables
*/

private Product add = new Product();

public Product getAdd() {
return this.add;
}

public Product getAdded() {
Product added = this.add;
this.add = new Product();
return added;
}
}

8. PurchaseOrderBean:

package de.binaris.petstore.forge.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateful;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import de.binaris.petstore.forge.model.PurchaseOrder;
import de.binaris.petstore.forge.model.Customer;
import de.binaris.petstore.forge.model.OrderLine;
import java.util.Iterator;

/**
* Backing bean for PurchaseOrder entities.
* <p>
* This class provides CRUD functionality for all PurchaseOrder entities. It
* focuses purely on Java EE 6 standards (e.g. <tt>&#64;ConversationScoped</tt>
* for state management, <tt>PersistenceContext</tt> for persistence,
* <tt>CriteriaBuilder</tt> for searches) rather than introducing a CRUD
* framework or custom base class.
*/

@Named
@Stateful
@ConversationScoped
public class PurchaseOrderBean implements Serializable {

private static final long serialVersionUID = 7579795373757373577L;

/*
* Support creating and retrieving PurchaseOrder entities
*/

private Long id;

public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

private PurchaseOrder purchaseOrder;

public PurchaseOrder getPurchaseOrder() {
return this.purchaseOrder;
}

@Inject
private Conversation conversation;

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public String create() {

this.conversation.begin();
return „create?faces-redirect=true“;
}

public void retrieve() {

if (FacesContext.getCurrentInstance().isPostback()) {
return;
}

if (this.conversation.isTransient()) {
this.conversation.begin();
}

if (this.id == null) {
this.purchaseOrder = this.example;
} else {
this.purchaseOrder = findById(getId());
}
}

public PurchaseOrder findById(Long id) {

return this.entityManager.find(PurchaseOrder.class, id);
}

/*
* Support updating and deleting PurchaseOrder entities
*/

public String update() {
this.conversation.end();

try {
if (this.id == null) {
this.entityManager.persist(this.purchaseOrder);
return „search?faces-redirect=true“;
} else {
this.entityManager.merge(this.purchaseOrder);
return „view?faces-redirect=true&id=“
+ this.purchaseOrder.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
this.conversation.end();

try {
PurchaseOrder deletableEntity = findById(getId());
Customer customer = deletableEntity.getCustomer();
customer.getPurchaseOrder().remove(deletableEntity);
deletableEntity.setCustomer(null);
this.entityManager.merge(customer);
Iterator<OrderLine> iterOrderLines = deletableEntity
.getOrderLines().iterator();
for (; iterOrderLines.hasNext();) {
OrderLine nextInOrderLines = iterOrderLines.next();
nextInOrderLines.setPurchaseOrder(null);
iterOrderLines.remove();
this.entityManager.merge(nextInOrderLines);
}
this.entityManager.remove(deletableEntity);
this.entityManager.flush();
return „search?faces-redirect=true“;
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(e.getMessage()));
return null;
}
}

/*
* Support searching PurchaseOrder entities with pagination
*/

private int page;
private long count;
private List<PurchaseOrder> pageItems;

private PurchaseOrder example = new PurchaseOrder();

public int getPage() {
return this.page;
}

public void setPage(int page) {
this.page = page;
}

public int getPageSize() {
return 10;
}

public PurchaseOrder getExample() {
return this.example;
}

public void setExample(PurchaseOrder example) {
this.example = example;
}

public void search() {
this.page = 0;
}

public void paginate() {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

// Populate this.count

CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
Root<PurchaseOrder> root = countCriteria.from(PurchaseOrder.class);
countCriteria = countCriteria.select(builder.count(root)).where(
getSearchPredicates(root));
this.count = this.entityManager.createQuery(countCriteria)
.getSingleResult();

// Populate this.pageItems

CriteriaQuery<PurchaseOrder> criteria = builder
.createQuery(PurchaseOrder.class);
root = criteria.from(PurchaseOrder.class);
TypedQuery<PurchaseOrder> query = this.entityManager
.createQuery(criteria.select(root).where(
getSearchPredicates(root)));
query.setFirstResult(this.page * getPageSize()).setMaxResults(
getPageSize());
this.pageItems = query.getResultList();
}

private Predicate[] getSearchPredicates(Root<PurchaseOrder> root) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
List<Predicate> predicatesList = new ArrayList<Predicate>();

Customer customer = this.example.getCustomer();
if (customer != null) {
predicatesList.add(builder.equal(root.get(„customer“), customer));
}

return predicatesList.toArray(new Predicate[predicatesList.size()]);
}

public List<PurchaseOrder> getPageItems() {
return this.pageItems;
}

public long getCount() {
return this.count;
}

/*
* Support listing and POSTing back PurchaseOrder entities (e.g. from inside
* an HtmlSelectOneMenu)
*/

public List<PurchaseOrder> getAll() {

CriteriaQuery<PurchaseOrder> criteria = this.entityManager
.getCriteriaBuilder().createQuery(PurchaseOrder.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(PurchaseOrder.class)))
.getResultList();
}

@Resource
private SessionContext sessionContext;

public Converter getConverter() {

final PurchaseOrderBean ejbProxy = this.sessionContext
.getBusinessObject(PurchaseOrderBean.class);

return new Converter() {

@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {

return ejbProxy.findById(Long.valueOf(value));
}

@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {

if (value == null) {
return „“;
}

return String.valueOf(((PurchaseOrder) value).getId());
}
};
}

/*
* Support adding children to bidirectional, one-to-many tables
*/

private PurchaseOrder add = new PurchaseOrder();

public PurchaseOrder getAdd() {
return this.add;
}

public PurchaseOrder getAdded() {
PurchaseOrder added = this.add;
this.add = new PurchaseOrder();
return added;
}
}

9.ViewUtils:

package de.binaris.petstore.forge.view;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.Id;

/**
* Utilities for working with Java Server Faces views.
*/
public final class ViewUtils {

public static <T> List<T> asList(Collection<T> collection) {
if (collection == null) {
return null;
}
return new ArrayList<T>(collection);
}

public static String display(Object object) {

if (object == null) {
return null;
}
try {
// Invoke toString if declared in the class. If not found, the
// NoSuchMethodException is caught and handled
object.getClass().getDeclaredMethod(„toString“);
return object.toString();
} catch (NoSuchMethodException noMethodEx) {
try {
for (Field field : object.getClass().getDeclaredFields()) {
// Find the primary key field and display it
if (field.getAnnotation(Id.class) != null) {
// Find a matching getter and invoke it to display the
// key
for (Method method : object.getClass()
.getDeclaredMethods()) {
if (method.equals(new PropertyDescriptor(field
.getName(), object.getClass())
.getReadMethod())) {
return method.invoke(object).toString();
}
}
}
}
for (Method method : object.getClass().getDeclaredMethods()) {
// Find the primary key as a property instead of a field,
// and display it
if (method.getAnnotation(Id.class) != null) {
return method.invoke(object).toString();
}
}
} catch (Exception ex) {
// Unlikely, but abort and stop view generation if any exception
// is thrown
throw new RuntimeException(ex);
}
}
return null;
}

private ViewUtils() {
// private c’tor should only be called by getInstance() method
}
}

Die Konfiguration des JBoss WildFly Application Servers kann ebenfalls im bereits vorhandenen Blog-Eintrag hier nachgelesen werden.

Sollen nun anstatt der JSF 2.2 Views die Angular JS Views erzeugt werden, so löscht man einfach das Package de.binaris.petstore.forge.view und das gesamte Unterverzeichnis src/main/webapp (am besten vorher eine Kopie des petstore-Projekts namens petstore-angularjs anlegen und dann auf der Kopie weiterarbeiten). Anschließend wählt man im Kontext-Menü Forge/Scaffold den Untermenüpunkt Angular JS aus, wodurch die Angular JS Views im project petstore-angularjs generiert werden.

Eine fertig Version ohne Beispiel-Konfiguration der Beispiel-Applikation ‘petstore‘ kann hier heruntergeladen, in ein beliebiges Verzeichnis ausgepackt und durch Starten von standalone.bat (Windows) oder standalone.sh (Linux) sofort gestartet werden. Nach ihrer Installation ist die Beispiel-Applikation aufrufbar unter der folgenden Url: http://localhost:8080/petstore

Die Test-Frameworks und die Tests

a) Arquillian Tests für das Service-Backend

wurden in diesem Blog-Eintrag hier bereits erklärt.

b) QUnit-Tests für die REST-Services

wurden in diesem Blog-Eintrag hier bereits erklärt.

c) Selenium Tests für die Benutzerschnittstelle

wurden in diesem Blog-Eintrag hier bereits erklärt.

Bei dieser Gelegenheit darf auch auf das sehr effektive und interessante Seminar “TDD mit Java”

hier und hier von Binaris Informatik hingewiesen werden.

Wie Test-Suites, die mit dem Selenium IDE PlugIn durchgeführt wurden und automatisiert ausgeführt werden können, erstellt werden, wurde bereits in diesem vorigen Blog Eintrag hier beschrieben.

Hier nun auch das Basis-Projekt petstore.zip zum Download, woraus mittels JBoss Forge PlugIn der RESTful WebService und die ausgewählten Views generiert werden können.

Hier die import.sql zum Anlegen der MySQL-Datenbank zum Download.

Hier der WildFly 8.2 als Zip-Archiv zum Download und Entpacken:
http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip

Installation/Start der Beispiel-Applikation:
– Im JBoss Developer Studio 7.1. das Basis-Projekt importieren und per maven clean install bauen
– Die JPA-Entities im Projekt verwenden und die entsprechenden Service- und GUI-Layer erzeugen.
– Die pom.xml durch die zu Anfang gelistete pom.xml ersetzen und das Projekt ins JBoss Developer Studio 8.1.0 importieren und erneut per Maven bauen (gerne auch mit Java 8).
– Die MySQL-Datenbank per import.sql-Skript anlegen.
– JAVA_HOME, JBOSS_HOME entsprechend setzen und
in der standalone.bat oder standalone.sh verwenden oder den vorkonfigurierten Server entpacken und noch die folgende datasource in der standalone/configuration/standalone.xml eintragen:

<datasource jndi-name=“java:jboss/datasources/PetstoreDatasource“ pool-name=“PetstoreDS“
       enabled=“true“>
       <connection-url>jdbc:mysql://localhost:3306/petstore</connection-url>
       <driver>mysql-connector-java-5.1.34.jar</driver>
       <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
       <pool>
               <min-pool-size>10</min-pool-size>
               <max-pool-size>100</max-pool-size>
               <prefill>true</prefill>
       </pool>
       <security>
               <user-name>root</user-name>
               <password>das entsprechende Passwort</password>
       </security>
       <statement>
               <prepared-statement-cache-size>32</prepared-statement-cache-size>
               <share-prepared-statements>true</share-prepared-statements>
       </statement>
</datasource>

– petstore.war ins Server-Unterverzeichnis /standalone/deployments speichern
– Neben petstore.war eine leere Textdatei namens petstore.war.dodeploy speichen.
– Genauso mit dem Projekt petstore-angularjs verfahren.
– Server starten per standalone.bat oder standalone.sh, http://localhost:8080/petstore/ aufrufen
– Entsprechend http://localhost:8080/petstore-angularjs/ aufrufen, beide Projekte arbeiten auf derselben Datasource.
– Die Selenium Tests per Selenium IDE PlugIn/Recorder erstellen und ausführen.

Allen interessierten Leserinnen und Lesern weiterhin viel Freude bei der agilen Softwareentwicklung mittels Scrum und dem Test Driven Development mit Java, sowie schöne Sommerferien und einen erholsamen Urlaub.

Kommentare

5 Kommentare zu “Services – mit REST, JPA 2, EJB 3.2, JSF 2.2, Angular JS”

  1. Von Services – mit REST, JPA 2, EJB 3.2, JSF 2.2, Angular JS, Bootstrap, JBoss Forge : Softwareentwicklung, Projektmanagement & Schulung | binaris informatik GmbH am Donnerstag, 1. Oktober 2015 08:29

    […] und ‘library-angularjs‘ mittels JBoss Forge erstellt werden, ist in diesem Blog-Eintrag hier bereits beschrieben worden, und wie in der pom.xml des jeweiligen Beispielprojekts nach erfolgtem […]

  2. Von Services – mit REST, JPA 2, EJB 3.2, WebFrameworks, JBoss WildFly 9 : Softwareentwicklung, Projektmanagement & Schulung | binaris informatik GmbH am Samstag, 31. Oktober 2015 21:05

    […] mittels JBoss Forge erstellt werden, ist bereits in diesem Blog-Eintrag hier bereits beschrieben worden, und wie in der pom.xml des jeweiligen Beispielprojekts nach erfolgtem […]

  3. Von Services – mit Angular JS, REST, JPA 2, JEE7 auf JBoss WildFly 9 : Softwareentwicklung, Projektmanagement & Schulung | binaris informatik GmbH am Donnerstag, 26. November 2015 19:54

    […] Beispiel-Applikation verwendet die JPA-Entities des Petstore-JEE Beispiels aus diesem Blog-Eintrag hier und erweitert diese, außerdem werden mittels JBoss Forge sowohl JSF 2.2 Benutzerschnittstellen […]

  4. Von WebApps – mit REST, JPA 2, EJB 3.2, Angular JS, JSF 2.2 auf JBoss WildFly 10 : Softwareentwicklung, Projektmanagement & Schulung | binaris informatik GmbH am Sonntag, 31. Januar 2016 12:04

    […] mittels JBoss Forge erstellt werden, ist bereits in diesem Blog-Eintrag hier beschrieben worden, und wie in der pom.xml des jeweiligen Beispielprojekts nach erfolgtem Download […]

  5. Von WebApps – mit JSF 2.2, Primefaces 5, REST, JPA 2, JEE7, JBoss WildFly 10 : Softwareentwicklung, Projektmanagement & Schulung | binaris informatik GmbH am Sonntag, 28. Februar 2016 19:41

    […] mittels JBoss Forge erstellt werden, ist bereits in diesem Blog-Eintrag hier beschrieben worden, und wie in der pom.xml des jeweiligen Beispielprojekts nach erfolgtem Download […]