Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
1
Session: Pattern of the Entity Layer
Good ol' DAO & DomainStore
The GenericDAO
TransferObject and DataTransferObject
Large amounts of data
A key does the trick
Adding some data dynamically
Tips & Tricks
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
2
Objectives
Learn about:
✔ Get an idea about the challenges at the entity layer
✔ Learn how to access data in a performant manner
✔ Learn how to deal with large chunks of data
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
3
Some orientation
Consumer
Consumer
Layer
Integration
Layer
Business Process
Layer
Services
Layer
Component
Layer
OS
Layer
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
4
ECB Pattern
Entity Control Boundary
✔ Based upon Robustness Diagrams
(http://www.agilemodeling.com/artifacts/robustnessDiagram.htm)
➢ Boundary: user interface
➢ Control: actual process or activity
➢ Entity: a concept from an enterprise context.
✔ Elements are generic enough to be mapped either to service-
oriented or object-oriented architectures.
Boundary Control Entity
Adam Bien
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
5
Services, components and patterns
Boundary Control Entity
DAO &
Domain
Store
Generic
DAO
Singleton
Service
Starter
Dual View
SOA Facade
Lightweight
asynchronous
Facade
Multichannel
Facade
TO
&
DTO
Paginator
Bean
Locator
Multichannel
Facade
Resource
Binder
Payload
Extractor
Aynchronous
Resource
Integrator
Infrastructure
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
6
Module
Good ol' DAO &
Domain Store
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
7
Do you remember ...
Long, long time ago:
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
8
Implementing a DAO
For implementing a DAO, we have to implement the following
steps.
✔ An interface which defines methods for various operations related
to the domain object
(here: User).
✔ Concrete classes which implement DAO interface
(here: H2UserDAO)
✔ Factory/Abstract Factory class to get a
reference to DAO object
(here: DAOFactory)
✔ A DataSource to establish a connection
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
9
Data Access Object (DAO)
Is DAO still needed?
✔ Adam Bien quoted:
➢ DAO pattern is actually no more interesting for general
data access.
➢ JPA comes already with the EntityManager which provides already
generic data access functionality. The usage cannot be simpler.
✔ Anyhow, data access is crucial, therefore there still might be some
place to use it …
✔ After some discussion:
I would say: it depends. It depends how complex your application really is.
– Adam Bien: http://www.infoq.com/news/2007/09/jpa-dao
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
10
Domain Store
Purpose:
✔ Pattern mainly used prior to EJB 3.0 / JPA
✔ Avoid putting persistence details in your Business Objects.
✔ Not want to use entity beans
✔ Application might be running in a web container.
✔ Object model uses inheritance and
complex relationships.
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
11
Domain Store
UML class diagram
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
12
Why bothering?
The architecture as we know it right now has some
disadvantages:
✔ Boilerplate code as you have to have DAOs for each and every
domain class / persistent entity
✔ So the MDA people might wrote generators
for CRUD methods
(but this is proprietary and only few
people might know how to maintain and
enhance it)
✔ Maybe you want to take advantage of a
few principles of OO like delegation and
inheritance
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
13
Lab
Implement DataAccessObject
(not more than 15 min.)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
14
Module
The Generic DAO
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
15
GenericDAO
✔ The EntityManager already is an implementation of the DAO
Pattern
✔ Dedicated DAOs are exception to the rule as the EntityManager can
be injected into the SLSBs / SFSBs
=> still a lot of boilerplate code in the dedicated
services (createX, createY, findByA, findByB)
✔ For many services plain CRUD methods
plus sophisticated finder methods might do
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
16
GenericDAO
UML Diagram
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
17
A common superclass
Might be helpful ...
@MappedSuperclass
public abstract class BaseEntity implements Serializable
{
@Version
private long version;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Temporal(TemporalType.DATE)
private Date creationDate;
public BaseEntity()
{ //lazy }
public Date getCreationDate()
{ return creationDate; }
public void setCreationDate(Date creationDate)
{ this.creationDate = creationDate; }
public long getId()
{ return id; }
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
18
The GenericDAO class
Just a SLSB ...
@Stateless(mappedName = "ejb/facade/GenericDAOService")
@Remote(GenericDAO.class)
public class GenericDAOBean implements GenericDAO
{
private static final Logger log = LoggerFactory.getLogger(GenericDAOBean.class);
@PersistenceContext
private EntityManager em;
…
// create, read, update and delete will follow
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
19
Using Generics
… to persist or update an instance
public <T extends BaseEntity> T createOrUpdateEntity(T entity)
{
// as we have no id yet, it must be freshly brewed
if (entity.getId() == 0)
{
log.debug("createOrUpdateEntity::create:: {}", entity);
this.em.persist(entity);
}
// if there is an id, we must have dealt with it before
else
{
log.debug("createOrUpdateEntity::update:: {}", entity);
this.em.merge(entity);
}
this.em.flush();
return entity;
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
20
Using Generics
✔ … find an instance by key
public <T extends BaseEntity> T findEntityById(Class<T> clazz, long id)
{
log.debug("findEntityById:: class= {}, id= {}", clazz, id);
return this.em.find(clazz, id);
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
21
Using Generics
✔ … to delete an instance
public void deleteEntity(BaseEntity entity)
{
log.debug("deleteEntity:: {}", entity);
// updating it first ...
entity = (BaseEntity) this.em.merge(entity);
// ... then killing it
this.em.remove(entity);
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
22
Using Generics
✔ … to invoke a (named) query dynamically
public <T extends BaseEntity> List<T> findByNamedQuery(Class<T> clazz,
String queryName, String[] paramNames, Object[] values)
{
TypedQuery<T> query = this.em.createNamedQuery(queryName, clazz);
if (paramNames != null)
{
for (int i = 0; i < paramNames.length; i++)
{
query.setParameter(paramNames[i], values[i]);
}
}
List<T> result = query.getResultList();
log.debug("findByNamedQuery:: result={}", result);
return (List<T>) result;
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
23
Lab
Implement GenericDAO
(not more than 15 min.)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
24
Module
The Domain-Specific DAO
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
25
Domain-specific DAO
✔ A type-safe DAO operating on a specific domain object
✔ Extends the GenericDAO with domain-specific extensions and
additional functionality (e.g. specific queries with specific return
types => Transfer Object)
✔ In practice, GenericDAO and
Domain-specific DAO are used
together
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
26
Example
✔ Presumed, you want to get some DataTransferObject, the domain-
specific DAO is the only place you can implement it.
✔ Either you implement all other methods as well or … you think
about some more sophisticated architecture.
@Stateless(mappedName = "ejb/facade/UserManagementService")
@Remote(UserManagementService.class)
public class UserManagementServiceBean implements UserManagementService
{
@PersistenceContext
private EntityManager em;
public UserPersonDTO findUserPersonDTOByCredentials(String user, String pwd)
{
//public UserPersonDTO(long userId, long personId, String user, String firstname)
String jpql = "SELECT NEW
de.brockhaus.userMgmt.dto.UserPersonDTO(
u.id, p.id, u.user, p.firstName, p.lastName)
FROM User u, Person p WHERE u.user = :user AND u.password = :pwd)";
Query q = this.em.createQuery(jpql);
q.setParameter("user", user);
q.setParameter("pwd", pwd);
return (UserPersonDTO) q.getSingleResult();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
27
What about this?
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
28
Lab
Implement Domain-specific DAO
(not more than 15 min.)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
29
Module
TransferObject &
DataTransferObject
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
30
The Problem
✔ On can say, the problem with EJB 2.1 is solved by detached
entities of EJB 3.x, why to introduce an new class just to transfer
data?
✔ Although Transfer Objects might provide a client- / consumer-
specific view to the persistence layer and might keep the interfaces
stable.
✔ In a SOA, exposing the domain layer directly to
the consumer would make further extensions
impossible; TO's can hide changes to some
degree (for the price of an additional translation
layer).
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
31
JPA POJOs might be the best choice when
they play the role of DTOs.
✔ Loading:
Web developers building on top of the EJB3 architecture tried to
use objects that were not loaded eagerly, and then the middle
layer developers have to to change the way data load was done.
✔ Performance:
A business method using a set of POJOs had as an extra load the
eagerly loaded POJOs, no matter if this business method needed
them or not: if another business method was using one of the
POJOs, then you have to load even if you don’t need it. This
overhead can be irrelevant in unit testing, but it’s relevant in
stressed systems.
✔ Robustness:
Changes in the ER to OO mapping were propagated to the web
layer, forcing the web development team to refactor their code to
fix the problem.
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
32
And now?
✔ Don't design lasagna architectures (dozens of layers with only little
beef)
✔ Decoupling is not a sufficient justification for using TOs (as they
are in most cases just duplicates of the original) and therefore
would violate the DRY principle.
✔ There are enough cases:
➢ Additional view to the domain model
➢ Abstracting von legacy data
➢ Enforcements of eager loading
✔ Store TOs in a dedicated subpackage
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
33
DTOs: SELECT NEW
✔ JPA allows to create objects on the fly using SELECT NEW
✔ The DTO itself (note the constructor)
public class UserPersonDTO implements Serializable
{
private long userId;
private long personId;
private String user;
private String firstname;
private String lastname;
public UserPersonDTO(long userId, long personId, String user,
String firstname, String lastname)
{
...
Adam Bien has named this
as detached DTO strategy
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
34
DTO's: SELECT NEW
✔ The SLSB:
@Stateless(mappedName = "ejb/facade/UserManagementService")
@Remote(UserManagementService.class)
public class UserManagementServiceBean extends GenericServiceBean
implements UserManagementService
{
@PersistenceContext
private EntityManager em;
private Logger log = LoggerFactory.getLogger(this.getClass());
public UserPersonDTO findUserPersoDTOByCredentials(String user, String pwd)
{
//public UserPersonDTO(long userId, long personId, String user, String firstname)
String jpql = "SELECT NEW
de.brockhaus.userMgmt.dto.UserPersonDTO(u.id, p.id, u.user,
p.firstName, p.lastName)
FROM User u, Person p WHERE u.user = :user AND
u.password = :pwd)";
Query q = this.em.createQuery(jpql);
q.setParameter("user", user);
q.setParameter("pwd", pwd);
return (UserPersonDTO) q.getSingleResult();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
35
Table View
According to Adam Bien:
✔ SQL Views can be considered either as best practice
or an anti-pattern. It depends on the perspective.
✔ Sometimes, however, it is required to provide an
efficient way to iterate over an excerpt or even a set
of related entities, but return a different “view” to the
client. This can be achieved by:
➢ fetching the entities with EntityManager and merging them together
inside a Session Bean (a Service). This approach is neither fast, nor
easy to maintain. Especially the merging and extraction of entity data
is error-prone and can become quite complex.
➢ Another option is the execution of more complex native SQL-
statements and mapping them into existing entities or TOs.
✔ For SQL queries there is no difference between views and tables,
so you can easily map a JPA entity to a view transparently.
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
36
Table View
Sample view:
CREATE VIEW UserPersonDTO
AS SELECT u.id, u.password, u.user, u.person_id, p.firstname, p.lastname
FROM User u INNER JOIN PERSON p on u.person_id = p.id
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
37
Using the view
✔ … just like a normal entity
@Entity
@Table(name="USERPERSONDTO")
public class UserPersonDTO implements Serializable
{
@Id
@Column(name = "ID")
private long userId;
@Column(name="PERSON_ID")
private long personId;
private String user;
private String firstname;
private String lastname;
...
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
38
Table View
✔ Although seen in the light of handling large amount of data,
creating a SQL view and mapping a DTO to it might be helpful in
the field of DTO as well …
✔ Will be covered in detail later.
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
39
DTOs: Builder Pattern
✔ Abstract steps of construction of objects so that different
implementations of these steps can construct different
representations of objects.
✔ Separate the construction of a complex object from its
representation. By doing so, the same construction process can
create different representations
✔ Joshua Bloch quoted:
The builder pattern is a good choice
when designing classes whose
constructors or static factories
would have more than a handful
of parameters.
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
40
DTOs: Builder Pattern
✔ Outer class, private constructor:
public class PersonUserDTO implements Serializable
{
private long userId;
private long personId;
private String user;
private String firstname;
private String lastname;
/**
* private constructor so no one can invoke
* @param builder
*/
private PersonUserDTO(PersonUserDTOBuilder builder)
{
this.userId = builder.personId;
this.userId = builder.userId;
}
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
41
DTOs: Builder Pattern
✔ Inner class
/**
* static inner builder class
*/
public static class PersonUserDTOBuilder{
private long userId;
private long personId;
private String user;
private String firstname;
private String lastname;
public PersonUserDTO build(){
return new PersonUserDTO(this);
}
public PersonUserDTOBuilder userId(long userId){
this.userId = userId;
return this;
}
public PersonUserDTOBuilder personId(long personId){
this.personId = personId;
return this;
}
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
42
DTOs: Builder Pattern
✔ Building:
PersonUserDTO dto =
new PersonUserDTO.PersonUserDTOBuilder().personId(1).userId(1).build();
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
43
DTOs: Apache BeanUtils / Dozer
✔ … might be an alternative as well but are not within the scope of
this training.
✔ You might check here:
http://www.javaranch.com/journal/2003/07/TouringTheCommonsPart1.html
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
44
Lab
Implement DTO using SELECT NEW
(not more than 15 min.)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
45
Module
Large amounts of data
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
46
Dealing with large amounts of data
When to use
✔ Displaying / iterating over a large amount of data
✔ Data can't be loaded at once at the client but has to be cached at
the server
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
47
The simplest case
✔ The classical Value List Handler pattern is already implemented
by JPA / the EntityManager.
public <T extends BaseEntity> List<T> findAll(Class<T> clazz, int lowNo, int maxNo)
{
TypedQuery<? extends BaseEntity> query = (TypedQuery<? extends BaseEntity>)
this.em.createQuery("FROM " + clazz.getSimpleName(), clazz);
query.setFirstResult(lowNo);
query.setMaxResults(maxNo);
return (List<T>) query.getResultList();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
48
Lab
Implement Value List Handler using JPA 2.0
(not more than 15 min.)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
49
Module
A key does the trick
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
50
Ids and keys
✔ Primary Key:
Uniquely identifies a row in a table
=> @Id annotation
✔ Surrogate Key:
Primary key that has no relation to the data, usually generated
=> @GeneratedValue annotation
✔ Natural or Business Key:
➢ A key that combines a number of columns to uniquely define the rows
of a database table.
➢ Composite keys are sometimes used because the choice of key relates
in some way to the end-user business domain.
Impact on hashCode()
and equals()
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
51
Business keys
✔ So we can introduce a business key at the level of BaseEntity
which:
➢ might be set to a value according to UUID pattern by default and might
be set to any other business key
➢ needs to be unique:
(@Column(unique = true))
➢ introduce a generic method:
findByKey(String key)
/** the business key */
@Column(unique = true)
private String key;
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
52
Utilizing JPA
✔ Take into consideration to implement a findByKey(String key)
method at GenericDAO
✔ Take into consideration to set a default value according to UUID
pattern:
➢ After generating 1 billion UUIDs every second for the next 100 years,
the probability of creating just one duplicate would be about 50%.
➢ The probability of one duplicate would be about 50% if every person on
earth owns 600 million UUIDs.
public BaseEntity()
{
this.key = UUID.randomUUID().toString();
this.creationDate = new Date(System.currentTimeMillis());
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
53
The finder method
✔ To be implemented at our GenericDAO LocalBean:
public <T extends BaseEntity> T findEntityByKey(Class<T> clazz, String key)
{
TypedQuery<T> query = this.em.createQuery("FROM " +
clazz.getSimpleName() +
" AS c WHERE c.key = :key", clazz);
query.setParameter("key", key);
return query.getSingleResult();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
54
Strong references?
✔ Referencing data across (functional) modules / systems
Boundary Control Entity
Boundary Control Entity
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
55
Foreign key relationships
✔ Using foreign keys using JPA:
ID Key Name BAR_FK
1 One FooOne 1
2 Two FooTwo 1
3 Three FooThree 2
Foo
ID Key Name BAR_FK
1 One FooOne 1
2 Two FooTwo 1
3 Three FooThree 2
Foo
Bar
ID Key Name
1 One BarOne
2 Two BarTwo
3 Three BarThree
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
56
Foreign key relationships
Pretty inflexible as:
✔ You can't exchange one component for another
(e.g. your Bar component vs. 3rd party Bar component / system)
✔ You can't import data easily as everything depends on the ID of
Bar
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
57
„Soft“ relationships based on keys
✔ Providing an example, a vendor might reside at one component
(e.g. SCM), products bought reside at another component (e.g.
Product-Definition at ERP)
✔ Making use of @ElementCollection at „many“ side
✔ Just a normal String attribute at „one“ side
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
58
„Soft“ relationships based on keys
✔ References independant of business keys
ID Key Name Vendor_KEY
1 One FooOne One
2 Two FooTwo One
3 Three FooThree Two
Product
Vendor
ID Key Name
1 One AcmeOne
2 Two AcmeTwo
3 Three AcmeThree
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
59
Advantages/Disadvantages
✔ Pretty flexible
✔ No type safety within associations anymore
✔ Maybe some performance impact
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
60
Lab
Implement Business Keys
(not more than 15 min.)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
61
Module
Adding some data
dynamically
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
62
Why?
✔ Sometimes there might be the need to enhance the datamodel at
runtime (and not at compile- and deploy-time)
✔ JPA provides a lot of support, e.g.
➢ Generation of tables and constraints at deploy-time
➢ Dynamic data model due to @ElementCollection
➢ Embedded objects due to @Embeddable
➢ Criteria API for runtime queries
✔ Unfortunately sometimes even this isn't enough
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
63
Let's take a walk
@ElementCollection
✔ Presumed a person has several email addresses:
Unfortunately
of just one data type
@ElementCollection
private List<String> emails;
{
emails = new ArrayList<String>();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
64
Let's take a walk
@Embedded
✔ Weapon of choice when designing compositions
✔ Embedded class will not have any primary key on it's own
@Embeddable
public class Address implements Serializable
{
private String city;
private String country;
private String street;
private String zipCode;
private String houseNo;
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
...
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
65
Let's take a walk
@Embedded
public class Person extends BaseEntity
{
...
@Embedded
private Address address;
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
66
Let's take a walk
Collection of embeddable objects
✔ Similar to a @OneToMany except the target objects are embeddables
and have no Id.
✔ This allows for a @OneToMany to be defined without a inverse
@ManyToOne, as the parent is responsible for storing the foreign key
in the target object's table.
✔ JPA 2.0 does support collections of embeddable objects through
the @ElementCollection mapping.
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
67
Let's take a walk
Querying
✔ Embeddable objects cannot be queried directly, but they can be
queried in the context of their parent.
✔ Typically it is best to select the parent, and access the embeddable
from the parent.
SELECT employee.period
FROM Employee employee
WHERE employee.period.endDate = :param
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
68
But what if ...
✔ Some sketch taken from ISA-95 specification for Manufacturing
Execution Systems (I'm sure you can find similar in your domain)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
69
But what if ...
The description of these PersonProperties according to ISA-95
✔ Several datatypes
✔ Ranges and lists of
Values
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
70
But what if ...
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
71
But what if ...
✔ Example provided within the solutions
✔ This approach leads to records with lot's of null values in it
✔ Experimental!
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
72
Presentation
Dynamic data model
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
73
Module
Tips and tricks
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
74
Not patterns
✔ … just hints and best practices:
➢ Names of named queries
➢ Key generation
➢ Wrappers for numbers
➢ SerialVersionUID
➢ hashCode and equals
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
75
Names of NamedQueries
✔ Using a NamedQuery sometimes look like trial and error if you're
not using a consistent naming strategy:
✔ ClassName.QueryName might be an option (but still you have to
guess the name of the query)
✔ Using constants might be a better option
@Entity
@NamedQueries({
@NamedQuery(name = "User.findByCredentials",
query = " FROM User AS u WHERE u.user = :user AND password = :pwd" )
}
)
public class User extends BaseEntity
{
private static final long serialVersionUID = 4616273573516105734L;
public static final String FIND_BY_CREDENTIALS = "User.findByCredentials";
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
76
Names of NamedQueries
✔ Invocation
public User findUserByCredentials(String user, String pwd)
{
TypedQuery<User> q = this.em.createNamedQuery(User.FIND_BY_CREDENTIALS, User.class);
q.setParameter("user", user);
q.setParameter("pwd", pwd);
return q.getSingleResult();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
77
hashCode and equals
✔ Normally, most Java objects provide a built-in equals() and
hashCode() based on the object's identity; so each new() object will
be different from all others.
✔ But what in case of JPA: the id will be set
once the object is persisted for the first time.
✔ What in the case, you put these objects to
a map prior to saving it?
✔ To avoid this problem it is recommended
using the "semi"-unique attributes of your
persistent class to implement equals()
and hashCode().
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
78
hashCode and equals
Using Apache BeanUtils make things easier:
✔ Overwrite hashCode() in BaseEntity:
@Override
public int hashCode()
{
HashCodeBuilder hcb = new HashCodeBuilder();
hcb.append(this.key);
return hcb.toHashCode();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
79
hashCode and equals
✔ Overwrite equals() in Base Entity
@Override
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (!(obj instanceof BaseEntity))
{
return false;
}
BaseEntity that = (BaseEntity) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.getKey(), that.getKey());
return eb.isEquals();
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
80
hashCode and equals
✔ For completeness overwrite toString() as well
at BaseEntity:
at subclass:
@Override
public String toString()
{
ToStringBuilder tsb = new ToStringBuilder(this);
tsb.append("key", this.key);
return tsb.toString();
}
@Override
public String toString()
{
ToStringBuilder builder = new ToStringBuilder(this);
builder.appendSuper(super.toString());
builder.append(this.user);
return builder.toString();
}
de.brockhaus.userMgmt.entity.User@9a9b65[id=5,key=64d75dd7-3960-4e20-8279-
95f4a4e88eae,user=peterp]
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
81
SerialVersionUID
… for Persistent Entities
✔ Not mandated by spec but recommended for every class
implementing java.io.Serializable.
✔ From spec: If a serializable class does not explicitly declare a
serialVersionUID, then the serialization runtime will calculate a
default serialVersionUID value for that class based on various
aspects of the class. However, it is strongly
recommended that all serializable classes
explicitly declare serialVersionUID.
✔ Once you make use of it, change it everytime you
change the class!
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
82
Key generation
✔ JPA supports several strategies, not all are the
same (by meanings of portability):
➢ Table -the persistence provider must assign
primary keys for the entity using an underlying
database table to ensure uniqueness
➢ Sequence - specify the use of a database
sequence to ensure uniqueness
➢ Identity - specify the use of a database
identity column
➢ Auto - the persistence provider should pick an appropriate strategy for
the particular database
✔ If it comes to portability (e.g. if you are about to develop a product
running on several databases), Table seems to be the best option.
✔ If it comes to performance, Identity and sequence might be better.
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
83
Generating keys
Automatic ID Generation:
✔ provider will use whatever strategy it wants to generate identifiers
✔ generation strategy for development or prototyping only
✔ getting you up'n' running more quickly when the database schema
is generated
✔ Default strategy!
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId()
{
return id;
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
84
Generating keys
Generation using a table / table generator
✔ Using a table to store key values
✔ Portable amongs vendors
@Id
@TableGenerator(
name="PersonId_Gen",
table="GEN_ID",
pkColumnName="GEN_OBJECT",
pkColumnValue="Person",
valueColumnName="GEN_ID",
initialValue=10,
allocationSize=1)
@GeneratedValue(strategy=GenerationType.TABLE,generator="PersonId_Gen")
// more simple
//@GeneratedValue(strategy=GenerationType.TABLE)
public long getId()
{
return id;
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
85
Generating keys
Generation using a Database Sequence
✔ Not supported by every database vendor!
✔ If not supported, choose Table strategy
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
public long getId()
{
return id;
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
86
Generating keys
Generation using Database Identity
✔ Adds an identity column to the table
✔ Not supported by all database vendors
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public long getId()
{
return id;
}
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
87
Wrappers for numbers
✔ If you use a primitive on a nullable field JPA (at least using
Hibernate in JBoss) will throw an error when it reads a null value
from the database and attempts to put that value into a primitive
field.
✔ You can search for days to
find this error!
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
88
Lab
Implement some hints
(not more than 15 min.)
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
89
Review
Session Review:
✔ Can you name the principles behind DAO, Generic DAO and
Domain-specific DAO?
✔ How does pagination help?
✔ Why do we need to have DTOs?
Copyright by Brockhaus GmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt
90
Recommeded reading
✔ http://java.sun.com/blueprints/corej2eepatterns/
✔ http://www.corej2eepatterns.com/Patterns2ndEd/
✔ Adam Bien, J2EE Patterns,
Addison Wesley 2002,
ISBN: 3-8273-1903-X
✔ Floyd Marinescu, Ed Roman:
Ejb Design Patterns: Advanced Patterns,
Processes, and Idioms; Wiley & Sons,
ISBN-10: 0471208310
✔ And other ...
Photo: Bundesarchiv

Java EE Pattern: The Entity Layer

  • 1.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 1 Session: Pattern of the Entity Layer Good ol' DAO & DomainStore The GenericDAO TransferObject and DataTransferObject Large amounts of data A key does the trick Adding some data dynamically Tips & Tricks
  • 2.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 2 Objectives Learn about: ✔ Get an idea about the challenges at the entity layer ✔ Learn how to access data in a performant manner ✔ Learn how to deal with large chunks of data
  • 3.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 3 Some orientation Consumer Consumer Layer Integration Layer Business Process Layer Services Layer Component Layer OS Layer
  • 4.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 4 ECB Pattern Entity Control Boundary ✔ Based upon Robustness Diagrams (http://www.agilemodeling.com/artifacts/robustnessDiagram.htm) ➢ Boundary: user interface ➢ Control: actual process or activity ➢ Entity: a concept from an enterprise context. ✔ Elements are generic enough to be mapped either to service- oriented or object-oriented architectures. Boundary Control Entity Adam Bien
  • 5.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 5 Services, components and patterns Boundary Control Entity DAO & Domain Store Generic DAO Singleton Service Starter Dual View SOA Facade Lightweight asynchronous Facade Multichannel Facade TO & DTO Paginator Bean Locator Multichannel Facade Resource Binder Payload Extractor Aynchronous Resource Integrator Infrastructure
  • 6.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 6 Module Good ol' DAO & Domain Store
  • 7.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 7 Do you remember ... Long, long time ago:
  • 8.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 8 Implementing a DAO For implementing a DAO, we have to implement the following steps. ✔ An interface which defines methods for various operations related to the domain object (here: User). ✔ Concrete classes which implement DAO interface (here: H2UserDAO) ✔ Factory/Abstract Factory class to get a reference to DAO object (here: DAOFactory) ✔ A DataSource to establish a connection
  • 9.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 9 Data Access Object (DAO) Is DAO still needed? ✔ Adam Bien quoted: ➢ DAO pattern is actually no more interesting for general data access. ➢ JPA comes already with the EntityManager which provides already generic data access functionality. The usage cannot be simpler. ✔ Anyhow, data access is crucial, therefore there still might be some place to use it … ✔ After some discussion: I would say: it depends. It depends how complex your application really is. – Adam Bien: http://www.infoq.com/news/2007/09/jpa-dao
  • 10.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 10 Domain Store Purpose: ✔ Pattern mainly used prior to EJB 3.0 / JPA ✔ Avoid putting persistence details in your Business Objects. ✔ Not want to use entity beans ✔ Application might be running in a web container. ✔ Object model uses inheritance and complex relationships.
  • 11.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 11 Domain Store UML class diagram
  • 12.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 12 Why bothering? The architecture as we know it right now has some disadvantages: ✔ Boilerplate code as you have to have DAOs for each and every domain class / persistent entity ✔ So the MDA people might wrote generators for CRUD methods (but this is proprietary and only few people might know how to maintain and enhance it) ✔ Maybe you want to take advantage of a few principles of OO like delegation and inheritance
  • 13.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 13 Lab Implement DataAccessObject (not more than 15 min.)
  • 14.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 14 Module The Generic DAO
  • 15.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 15 GenericDAO ✔ The EntityManager already is an implementation of the DAO Pattern ✔ Dedicated DAOs are exception to the rule as the EntityManager can be injected into the SLSBs / SFSBs => still a lot of boilerplate code in the dedicated services (createX, createY, findByA, findByB) ✔ For many services plain CRUD methods plus sophisticated finder methods might do
  • 16.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 16 GenericDAO UML Diagram
  • 17.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 17 A common superclass Might be helpful ... @MappedSuperclass public abstract class BaseEntity implements Serializable { @Version private long version; @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Temporal(TemporalType.DATE) private Date creationDate; public BaseEntity() { //lazy } public Date getCreationDate() { return creationDate; } public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } public long getId() { return id; } }
  • 18.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 18 The GenericDAO class Just a SLSB ... @Stateless(mappedName = "ejb/facade/GenericDAOService") @Remote(GenericDAO.class) public class GenericDAOBean implements GenericDAO { private static final Logger log = LoggerFactory.getLogger(GenericDAOBean.class); @PersistenceContext private EntityManager em; … // create, read, update and delete will follow
  • 19.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 19 Using Generics … to persist or update an instance public <T extends BaseEntity> T createOrUpdateEntity(T entity) { // as we have no id yet, it must be freshly brewed if (entity.getId() == 0) { log.debug("createOrUpdateEntity::create:: {}", entity); this.em.persist(entity); } // if there is an id, we must have dealt with it before else { log.debug("createOrUpdateEntity::update:: {}", entity); this.em.merge(entity); } this.em.flush(); return entity; }
  • 20.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 20 Using Generics ✔ … find an instance by key public <T extends BaseEntity> T findEntityById(Class<T> clazz, long id) { log.debug("findEntityById:: class= {}, id= {}", clazz, id); return this.em.find(clazz, id); }
  • 21.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 21 Using Generics ✔ … to delete an instance public void deleteEntity(BaseEntity entity) { log.debug("deleteEntity:: {}", entity); // updating it first ... entity = (BaseEntity) this.em.merge(entity); // ... then killing it this.em.remove(entity); }
  • 22.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 22 Using Generics ✔ … to invoke a (named) query dynamically public <T extends BaseEntity> List<T> findByNamedQuery(Class<T> clazz, String queryName, String[] paramNames, Object[] values) { TypedQuery<T> query = this.em.createNamedQuery(queryName, clazz); if (paramNames != null) { for (int i = 0; i < paramNames.length; i++) { query.setParameter(paramNames[i], values[i]); } } List<T> result = query.getResultList(); log.debug("findByNamedQuery:: result={}", result); return (List<T>) result; }
  • 23.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 23 Lab Implement GenericDAO (not more than 15 min.)
  • 24.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 24 Module The Domain-Specific DAO
  • 25.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 25 Domain-specific DAO ✔ A type-safe DAO operating on a specific domain object ✔ Extends the GenericDAO with domain-specific extensions and additional functionality (e.g. specific queries with specific return types => Transfer Object) ✔ In practice, GenericDAO and Domain-specific DAO are used together
  • 26.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 26 Example ✔ Presumed, you want to get some DataTransferObject, the domain- specific DAO is the only place you can implement it. ✔ Either you implement all other methods as well or … you think about some more sophisticated architecture. @Stateless(mappedName = "ejb/facade/UserManagementService") @Remote(UserManagementService.class) public class UserManagementServiceBean implements UserManagementService { @PersistenceContext private EntityManager em; public UserPersonDTO findUserPersonDTOByCredentials(String user, String pwd) { //public UserPersonDTO(long userId, long personId, String user, String firstname) String jpql = "SELECT NEW de.brockhaus.userMgmt.dto.UserPersonDTO( u.id, p.id, u.user, p.firstName, p.lastName) FROM User u, Person p WHERE u.user = :user AND u.password = :pwd)"; Query q = this.em.createQuery(jpql); q.setParameter("user", user); q.setParameter("pwd", pwd); return (UserPersonDTO) q.getSingleResult(); }
  • 27.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 27 What about this?
  • 28.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 28 Lab Implement Domain-specific DAO (not more than 15 min.)
  • 29.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 29 Module TransferObject & DataTransferObject
  • 30.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 30 The Problem ✔ On can say, the problem with EJB 2.1 is solved by detached entities of EJB 3.x, why to introduce an new class just to transfer data? ✔ Although Transfer Objects might provide a client- / consumer- specific view to the persistence layer and might keep the interfaces stable. ✔ In a SOA, exposing the domain layer directly to the consumer would make further extensions impossible; TO's can hide changes to some degree (for the price of an additional translation layer).
  • 31.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 31 JPA POJOs might be the best choice when they play the role of DTOs. ✔ Loading: Web developers building on top of the EJB3 architecture tried to use objects that were not loaded eagerly, and then the middle layer developers have to to change the way data load was done. ✔ Performance: A business method using a set of POJOs had as an extra load the eagerly loaded POJOs, no matter if this business method needed them or not: if another business method was using one of the POJOs, then you have to load even if you don’t need it. This overhead can be irrelevant in unit testing, but it’s relevant in stressed systems. ✔ Robustness: Changes in the ER to OO mapping were propagated to the web layer, forcing the web development team to refactor their code to fix the problem.
  • 32.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 32 And now? ✔ Don't design lasagna architectures (dozens of layers with only little beef) ✔ Decoupling is not a sufficient justification for using TOs (as they are in most cases just duplicates of the original) and therefore would violate the DRY principle. ✔ There are enough cases: ➢ Additional view to the domain model ➢ Abstracting von legacy data ➢ Enforcements of eager loading ✔ Store TOs in a dedicated subpackage
  • 33.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 33 DTOs: SELECT NEW ✔ JPA allows to create objects on the fly using SELECT NEW ✔ The DTO itself (note the constructor) public class UserPersonDTO implements Serializable { private long userId; private long personId; private String user; private String firstname; private String lastname; public UserPersonDTO(long userId, long personId, String user, String firstname, String lastname) { ... Adam Bien has named this as detached DTO strategy
  • 34.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 34 DTO's: SELECT NEW ✔ The SLSB: @Stateless(mappedName = "ejb/facade/UserManagementService") @Remote(UserManagementService.class) public class UserManagementServiceBean extends GenericServiceBean implements UserManagementService { @PersistenceContext private EntityManager em; private Logger log = LoggerFactory.getLogger(this.getClass()); public UserPersonDTO findUserPersoDTOByCredentials(String user, String pwd) { //public UserPersonDTO(long userId, long personId, String user, String firstname) String jpql = "SELECT NEW de.brockhaus.userMgmt.dto.UserPersonDTO(u.id, p.id, u.user, p.firstName, p.lastName) FROM User u, Person p WHERE u.user = :user AND u.password = :pwd)"; Query q = this.em.createQuery(jpql); q.setParameter("user", user); q.setParameter("pwd", pwd); return (UserPersonDTO) q.getSingleResult(); }
  • 35.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 35 Table View According to Adam Bien: ✔ SQL Views can be considered either as best practice or an anti-pattern. It depends on the perspective. ✔ Sometimes, however, it is required to provide an efficient way to iterate over an excerpt or even a set of related entities, but return a different “view” to the client. This can be achieved by: ➢ fetching the entities with EntityManager and merging them together inside a Session Bean (a Service). This approach is neither fast, nor easy to maintain. Especially the merging and extraction of entity data is error-prone and can become quite complex. ➢ Another option is the execution of more complex native SQL- statements and mapping them into existing entities or TOs. ✔ For SQL queries there is no difference between views and tables, so you can easily map a JPA entity to a view transparently.
  • 36.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 36 Table View Sample view: CREATE VIEW UserPersonDTO AS SELECT u.id, u.password, u.user, u.person_id, p.firstname, p.lastname FROM User u INNER JOIN PERSON p on u.person_id = p.id
  • 37.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 37 Using the view ✔ … just like a normal entity @Entity @Table(name="USERPERSONDTO") public class UserPersonDTO implements Serializable { @Id @Column(name = "ID") private long userId; @Column(name="PERSON_ID") private long personId; private String user; private String firstname; private String lastname; ...
  • 38.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 38 Table View ✔ Although seen in the light of handling large amount of data, creating a SQL view and mapping a DTO to it might be helpful in the field of DTO as well … ✔ Will be covered in detail later.
  • 39.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 39 DTOs: Builder Pattern ✔ Abstract steps of construction of objects so that different implementations of these steps can construct different representations of objects. ✔ Separate the construction of a complex object from its representation. By doing so, the same construction process can create different representations ✔ Joshua Bloch quoted: The builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters.
  • 40.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 40 DTOs: Builder Pattern ✔ Outer class, private constructor: public class PersonUserDTO implements Serializable { private long userId; private long personId; private String user; private String firstname; private String lastname; /** * private constructor so no one can invoke * @param builder */ private PersonUserDTO(PersonUserDTOBuilder builder) { this.userId = builder.personId; this.userId = builder.userId; } }
  • 41.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 41 DTOs: Builder Pattern ✔ Inner class /** * static inner builder class */ public static class PersonUserDTOBuilder{ private long userId; private long personId; private String user; private String firstname; private String lastname; public PersonUserDTO build(){ return new PersonUserDTO(this); } public PersonUserDTOBuilder userId(long userId){ this.userId = userId; return this; } public PersonUserDTOBuilder personId(long personId){ this.personId = personId; return this; } }
  • 42.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 42 DTOs: Builder Pattern ✔ Building: PersonUserDTO dto = new PersonUserDTO.PersonUserDTOBuilder().personId(1).userId(1).build();
  • 43.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 43 DTOs: Apache BeanUtils / Dozer ✔ … might be an alternative as well but are not within the scope of this training. ✔ You might check here: http://www.javaranch.com/journal/2003/07/TouringTheCommonsPart1.html
  • 44.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 44 Lab Implement DTO using SELECT NEW (not more than 15 min.)
  • 45.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 45 Module Large amounts of data
  • 46.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 46 Dealing with large amounts of data When to use ✔ Displaying / iterating over a large amount of data ✔ Data can't be loaded at once at the client but has to be cached at the server
  • 47.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 47 The simplest case ✔ The classical Value List Handler pattern is already implemented by JPA / the EntityManager. public <T extends BaseEntity> List<T> findAll(Class<T> clazz, int lowNo, int maxNo) { TypedQuery<? extends BaseEntity> query = (TypedQuery<? extends BaseEntity>) this.em.createQuery("FROM " + clazz.getSimpleName(), clazz); query.setFirstResult(lowNo); query.setMaxResults(maxNo); return (List<T>) query.getResultList(); }
  • 48.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 48 Lab Implement Value List Handler using JPA 2.0 (not more than 15 min.)
  • 49.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 49 Module A key does the trick
  • 50.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 50 Ids and keys ✔ Primary Key: Uniquely identifies a row in a table => @Id annotation ✔ Surrogate Key: Primary key that has no relation to the data, usually generated => @GeneratedValue annotation ✔ Natural or Business Key: ➢ A key that combines a number of columns to uniquely define the rows of a database table. ➢ Composite keys are sometimes used because the choice of key relates in some way to the end-user business domain. Impact on hashCode() and equals()
  • 51.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 51 Business keys ✔ So we can introduce a business key at the level of BaseEntity which: ➢ might be set to a value according to UUID pattern by default and might be set to any other business key ➢ needs to be unique: (@Column(unique = true)) ➢ introduce a generic method: findByKey(String key) /** the business key */ @Column(unique = true) private String key;
  • 52.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 52 Utilizing JPA ✔ Take into consideration to implement a findByKey(String key) method at GenericDAO ✔ Take into consideration to set a default value according to UUID pattern: ➢ After generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%. ➢ The probability of one duplicate would be about 50% if every person on earth owns 600 million UUIDs. public BaseEntity() { this.key = UUID.randomUUID().toString(); this.creationDate = new Date(System.currentTimeMillis()); }
  • 53.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 53 The finder method ✔ To be implemented at our GenericDAO LocalBean: public <T extends BaseEntity> T findEntityByKey(Class<T> clazz, String key) { TypedQuery<T> query = this.em.createQuery("FROM " + clazz.getSimpleName() + " AS c WHERE c.key = :key", clazz); query.setParameter("key", key); return query.getSingleResult(); }
  • 54.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 54 Strong references? ✔ Referencing data across (functional) modules / systems Boundary Control Entity Boundary Control Entity
  • 55.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 55 Foreign key relationships ✔ Using foreign keys using JPA: ID Key Name BAR_FK 1 One FooOne 1 2 Two FooTwo 1 3 Three FooThree 2 Foo ID Key Name BAR_FK 1 One FooOne 1 2 Two FooTwo 1 3 Three FooThree 2 Foo Bar ID Key Name 1 One BarOne 2 Two BarTwo 3 Three BarThree
  • 56.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 56 Foreign key relationships Pretty inflexible as: ✔ You can't exchange one component for another (e.g. your Bar component vs. 3rd party Bar component / system) ✔ You can't import data easily as everything depends on the ID of Bar
  • 57.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 57 „Soft“ relationships based on keys ✔ Providing an example, a vendor might reside at one component (e.g. SCM), products bought reside at another component (e.g. Product-Definition at ERP) ✔ Making use of @ElementCollection at „many“ side ✔ Just a normal String attribute at „one“ side
  • 58.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 58 „Soft“ relationships based on keys ✔ References independant of business keys ID Key Name Vendor_KEY 1 One FooOne One 2 Two FooTwo One 3 Three FooThree Two Product Vendor ID Key Name 1 One AcmeOne 2 Two AcmeTwo 3 Three AcmeThree
  • 59.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 59 Advantages/Disadvantages ✔ Pretty flexible ✔ No type safety within associations anymore ✔ Maybe some performance impact
  • 60.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 60 Lab Implement Business Keys (not more than 15 min.)
  • 61.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 61 Module Adding some data dynamically
  • 62.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 62 Why? ✔ Sometimes there might be the need to enhance the datamodel at runtime (and not at compile- and deploy-time) ✔ JPA provides a lot of support, e.g. ➢ Generation of tables and constraints at deploy-time ➢ Dynamic data model due to @ElementCollection ➢ Embedded objects due to @Embeddable ➢ Criteria API for runtime queries ✔ Unfortunately sometimes even this isn't enough
  • 63.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 63 Let's take a walk @ElementCollection ✔ Presumed a person has several email addresses: Unfortunately of just one data type @ElementCollection private List<String> emails; { emails = new ArrayList<String>(); }
  • 64.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 64 Let's take a walk @Embedded ✔ Weapon of choice when designing compositions ✔ Embedded class will not have any primary key on it's own @Embeddable public class Address implements Serializable { private String city; private String country; private String street; private String zipCode; private String houseNo; public String getCity() { return city; } public void setCity(String city) { this.city = city; } ...
  • 65.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 65 Let's take a walk @Embedded public class Person extends BaseEntity { ... @Embedded private Address address;
  • 66.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 66 Let's take a walk Collection of embeddable objects ✔ Similar to a @OneToMany except the target objects are embeddables and have no Id. ✔ This allows for a @OneToMany to be defined without a inverse @ManyToOne, as the parent is responsible for storing the foreign key in the target object's table. ✔ JPA 2.0 does support collections of embeddable objects through the @ElementCollection mapping.
  • 67.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 67 Let's take a walk Querying ✔ Embeddable objects cannot be queried directly, but they can be queried in the context of their parent. ✔ Typically it is best to select the parent, and access the embeddable from the parent. SELECT employee.period FROM Employee employee WHERE employee.period.endDate = :param
  • 68.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 68 But what if ... ✔ Some sketch taken from ISA-95 specification for Manufacturing Execution Systems (I'm sure you can find similar in your domain)
  • 69.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 69 But what if ... The description of these PersonProperties according to ISA-95 ✔ Several datatypes ✔ Ranges and lists of Values
  • 70.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 70 But what if ...
  • 71.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 71 But what if ... ✔ Example provided within the solutions ✔ This approach leads to records with lot's of null values in it ✔ Experimental!
  • 72.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 72 Presentation Dynamic data model
  • 73.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 73 Module Tips and tricks
  • 74.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 74 Not patterns ✔ … just hints and best practices: ➢ Names of named queries ➢ Key generation ➢ Wrappers for numbers ➢ SerialVersionUID ➢ hashCode and equals
  • 75.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 75 Names of NamedQueries ✔ Using a NamedQuery sometimes look like trial and error if you're not using a consistent naming strategy: ✔ ClassName.QueryName might be an option (but still you have to guess the name of the query) ✔ Using constants might be a better option @Entity @NamedQueries({ @NamedQuery(name = "User.findByCredentials", query = " FROM User AS u WHERE u.user = :user AND password = :pwd" ) } ) public class User extends BaseEntity { private static final long serialVersionUID = 4616273573516105734L; public static final String FIND_BY_CREDENTIALS = "User.findByCredentials";
  • 76.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 76 Names of NamedQueries ✔ Invocation public User findUserByCredentials(String user, String pwd) { TypedQuery<User> q = this.em.createNamedQuery(User.FIND_BY_CREDENTIALS, User.class); q.setParameter("user", user); q.setParameter("pwd", pwd); return q.getSingleResult(); }
  • 77.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 77 hashCode and equals ✔ Normally, most Java objects provide a built-in equals() and hashCode() based on the object's identity; so each new() object will be different from all others. ✔ But what in case of JPA: the id will be set once the object is persisted for the first time. ✔ What in the case, you put these objects to a map prior to saving it? ✔ To avoid this problem it is recommended using the "semi"-unique attributes of your persistent class to implement equals() and hashCode().
  • 78.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 78 hashCode and equals Using Apache BeanUtils make things easier: ✔ Overwrite hashCode() in BaseEntity: @Override public int hashCode() { HashCodeBuilder hcb = new HashCodeBuilder(); hcb.append(this.key); return hcb.toHashCode(); }
  • 79.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 79 hashCode and equals ✔ Overwrite equals() in Base Entity @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof BaseEntity)) { return false; } BaseEntity that = (BaseEntity) obj; EqualsBuilder eb = new EqualsBuilder(); eb.append(this.getKey(), that.getKey()); return eb.isEquals(); }
  • 80.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 80 hashCode and equals ✔ For completeness overwrite toString() as well at BaseEntity: at subclass: @Override public String toString() { ToStringBuilder tsb = new ToStringBuilder(this); tsb.append("key", this.key); return tsb.toString(); } @Override public String toString() { ToStringBuilder builder = new ToStringBuilder(this); builder.appendSuper(super.toString()); builder.append(this.user); return builder.toString(); } de.brockhaus.userMgmt.entity.User@9a9b65[id=5,key=64d75dd7-3960-4e20-8279- 95f4a4e88eae,user=peterp]
  • 81.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 81 SerialVersionUID … for Persistent Entities ✔ Not mandated by spec but recommended for every class implementing java.io.Serializable. ✔ From spec: If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID. ✔ Once you make use of it, change it everytime you change the class!
  • 82.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 82 Key generation ✔ JPA supports several strategies, not all are the same (by meanings of portability): ➢ Table -the persistence provider must assign primary keys for the entity using an underlying database table to ensure uniqueness ➢ Sequence - specify the use of a database sequence to ensure uniqueness ➢ Identity - specify the use of a database identity column ➢ Auto - the persistence provider should pick an appropriate strategy for the particular database ✔ If it comes to portability (e.g. if you are about to develop a product running on several databases), Table seems to be the best option. ✔ If it comes to performance, Identity and sequence might be better.
  • 83.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 83 Generating keys Automatic ID Generation: ✔ provider will use whatever strategy it wants to generate identifiers ✔ generation strategy for development or prototyping only ✔ getting you up'n' running more quickly when the database schema is generated ✔ Default strategy! @Id @GeneratedValue(strategy = GenerationType.AUTO) public long getId() { return id; }
  • 84.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 84 Generating keys Generation using a table / table generator ✔ Using a table to store key values ✔ Portable amongs vendors @Id @TableGenerator( name="PersonId_Gen", table="GEN_ID", pkColumnName="GEN_OBJECT", pkColumnValue="Person", valueColumnName="GEN_ID", initialValue=10, allocationSize=1) @GeneratedValue(strategy=GenerationType.TABLE,generator="PersonId_Gen") // more simple //@GeneratedValue(strategy=GenerationType.TABLE) public long getId() { return id; }
  • 85.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 85 Generating keys Generation using a Database Sequence ✔ Not supported by every database vendor! ✔ If not supported, choose Table strategy @Id @GeneratedValue(strategy=GenerationType.SEQUENCE) public long getId() { return id; }
  • 86.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 86 Generating keys Generation using Database Identity ✔ Adds an identity column to the table ✔ Not supported by all database vendors @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public long getId() { return id; }
  • 87.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 87 Wrappers for numbers ✔ If you use a primitive on a nullable field JPA (at least using Hibernate in JBoss) will throw an error when it reads a null value from the database and attempts to put that value into a primitive field. ✔ You can search for days to find this error!
  • 88.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 88 Lab Implement some hints (not more than 15 min.)
  • 89.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 89 Review Session Review: ✔ Can you name the principles behind DAO, Generic DAO and Domain-specific DAO? ✔ How does pagination help? ✔ Why do we need to have DTOs?
  • 90.
    Copyright by BrockhausGmbH, alle Rechte reserviert, unautorisierte Vervielfältigung untersagt 90 Recommeded reading ✔ http://java.sun.com/blueprints/corej2eepatterns/ ✔ http://www.corej2eepatterns.com/Patterns2ndEd/ ✔ Adam Bien, J2EE Patterns, Addison Wesley 2002, ISBN: 3-8273-1903-X ✔ Floyd Marinescu, Ed Roman: Ejb Design Patterns: Advanced Patterns, Processes, and Idioms; Wiley & Sons, ISBN-10: 0471208310 ✔ And other ... Photo: Bundesarchiv

Editor's Notes

  • #5 You can see that there is no tight coupling between the classes. Both can be changed independently without affecting each other. Of course, if there is any change in the public methods of Class Callee, Class Caller needs to change as well. But how Object &amp;quot;c&amp;quot; is created and managed is not decided in the implementation of Object &amp;quot;a&amp;quot;. Instead, the IoC framework uses the setB() method in Object &amp;quot;a&amp;quot; to inject Object &amp;quot;c&amp;quot;.
  • #10 Soem statement which makes some sense as well: I don&amp;apos;t think the DAO is dead yet. A JPA graph is still pretty much directly tied to the schema of the underlying data source. A DAO can potentially be decoupled from that schema and might represent a denormalized view or something like that. I can see such high level DAOs being implemented using code that makes use of JPA. A DAO is a higher level construct, not so tightly coupled with the underlying schema as JPA entities will be. – Billy Newport DAOs Aren&amp;apos;t Dead - But They Either Collapsed Or Disappeared What if: 1. The vendor of your database changes? 2. You will have to replace your relational database with LDAP, flat files or object oriented storage? 3. You will have to replace JPA with iBatis or even plain JDBC? 4. You will have to replace your local storage with remote service calls? The questions above are interesting and valid, but how likely is such a case? The architecture (even real live) is all about probability. If something is likely to happen, we react to it. If something is rather unlikely, we tend to ignore it. In my past projects, only in (very) few cases we had to switch the database vendor.We never switched from a relational database to a flat file or LDAP. I guess it is unlikely in the future as well. Interestingly the real problem during the migration from one relational DB to another was not the leaky encapsulation of SQL statements or hiding classes behind interfaces, rather than different locking behavior, which just cannot be hidden or abstracted with Java-means. Most projects are concerned about the answers for the questions above and introduce DAOs, which are especially leaky by nature. Locking behavior is one thing, semantic behavior is even harder to abstract. A typical DAOs operates &amp;quot;per Value&amp;quot;, whereby OR-tools work with managed / attached objects. If you start to emulate such a behavior for e.g. flat files, you will either fail, or eventually implement Hibernate 5.0. My post &amp;quot;JPA/EJB 3 Killed The DAO&amp;quot; was not precise enough. In some situations even the classic DAOs are still a good solution, but for the vast majority of all cases and projects are absolutely not. If you are developing a product, like e.g. a CMS software, it is essential to be as flexible as possible to survive in a heterogenous market. A DAO could help you to abstract from the particular data source, but such abstractions are leaky by nature. The variations of different data sources is already predefined by the system requirements of your product. You have to protect your business logic from being dependent on the particular data store implementation. DAO can help you to abstract from the variations. Even so, in most commercial products a particular database tend to be better supported, than the other. Just look at the Hibernate, Toplink or openJPA support for a particular database. In a usual projects there is no need to introduce a DAO as as standalone component. It is enough to rely on your common sense and try to remain DRY. Then you could easily use the EntityManager directly in your Service layer and if you notice some repetition or duplication just to refactor the code into one place. This can happens without any ceremony - you either delegate the calls to a class which encapsulates common queries, or you could even inherit such capabilities from a common class. You could call both strategies a &amp;quot;DAO&amp;quot; - in J2EE, however, you would start with a DAO in own layer, in Java EE a DAO can just evolve but is optional...
  • #36 See: http://www.adam-bien.com/roller/abien/entry/mapping_jpa_entities_on_view
  • #83 Check here: http://blog.eyallupu.com/2011/01/hibernatejpa-identity-generators.html http://www.developerscrappad.com/408/java/java-ee/ejb3-jpa-3-ways-of-generating-primary-key-through-generatedvalue/