75
Not your Father’s Java EE @mobileLarson @_openKnowledge Lars Röwekamp | CIO New Technologies

Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

  • Upload
    others

  • View
    5

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Not your Father’sJava EE

@mobileLarson @_openKnowledge

Lars Röwekamp | CIO New Technologies

Page 2: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

„May I submit my billing info to your merchant account via your payment

gateway?“

Page 3: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer
Page 4: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Wo liegt das Problem ...

„Too many times application

architects focus on the

technical problems instead of

designing for the problem

domain.“

Page 5: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Wo liegt das Problem ...

App

Service

Data

User Interface

CDI Managed Bean

Session EJB Session EJB

EntityManager Entity

TX

UI

Page 6: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Es wäre doch viel schöner, wenn ...

App

User Interface

UseCase Controller

TX

UI

Business Object

Business Object

Business Object

Domain

Page 7: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

App

User Interface

UseCase Controller

TXUI

Business Object

Business Object

Business Object

Domain

Es wäre doch viel schöner, wenn ... Business

Page 8: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Es wäre doch viel schöner, wenn ...

Domain Model

ApplicationA

dapter

Ad

apter

Page 9: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Es wäre doch viel schöner, wenn ...

Domain Model

ApplicationA

dapter

Ad

apter

App Core mit Business TX

Page 10: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Es könnte alles so einfach sein ...

Page 11: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Das kleine 1x1 des DDD …

Eric Evans says

„For most software projects, the primary focus should be on the domain and domain logic.“

„Complex domain design should be based on a model.“

Page 12: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

End User

Domain Expert

TechnicalExpert

fachliche Domäne

Die gemeinsame fachliche Welt

in der wir „leben“.

Das kleine 1x1 des DDD …

Page 13: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Das kleine 1x1 des DDD …

End User

Domain Expert

TechnicalExpert

Ubiquitous Language

Fachsprache als Basisfür ein gemeinsames

Domain Model

Page 14: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Das kleine 1x1 des DDD …

„Produce Software that makes perfectly sense to business,

not only to coder“

End User

Domain Expert

TechnicalExpert

Rich Domain Model

Page 15: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Das kleine 1x1 des DDD …

„Produce Software that is always

in a correct state, not only partially“Domain

ExpertTechnical

Expert

Rich Domain ModelAccess Layer

Business Layer

DB Layer

Page 16: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Das kleine 1x1 des DDD …

Factories

encapsulate with encapsulate with

encapsulate with

Model-Driven Design

Services

express model with Entities

express model with

Value Objects express model with

Smart UI

mutually exclusive choices

X

Aggregates

maintain integrity with

act as root of

encapsulate with

Repositories access with

access with

Layered Architecture

isolate domain with

Page 17: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Das kleine 1x1 des DDD …

Bounded Context

Ubiquitous Language

names enter

Continous Integration

keep model unified by

Context Map assess/overview relationships with

Shared Kernel

Overlap allied contexts through Customer Supplier Teams relate allied contexts as

Conformist overlap unilaterally as

Open Host Service

support multiple clients through

Published Language

formalize as

Separate Ways

free teams to go

Anticorruption Layer

translate and insulate unilaterally with

Page 18: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Passt das zu Java EE?

Page 19: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Passt das zu Java EE? Klar …

Java EE Next Generation BluePrint

a.k.a.

Java EE meets DDD

Page 20: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Passt das zu Java EE? Klar …

Page 21: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

You must follow the „Chuck-Norris“ Rules!

Passt das zu Java EE? Klar, aber …

Page 22: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

RULE #1 Design a Rich not an Anemic Domain Model

Always follow the Rules …

Page 23: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer is „sui juris“ and a valid address * that may change after a relocation. */ public class Customer {

private String firstName; private String lastName;

private Date birthDate; private Address address;

public void setFirstName(String aFirstName) { ... } public String getFirstName() { return firstName; }

public void setLastName(String aLastName) { ... } public String getLastName() { return lastName; }

public void setBirthDate(Date birthDate) { ... } public Date getBirthDate() { return birthDate; }

public void setAddress(Address address) { ... } public Address getAddress() { return address; }

}

Fachlichkeit?

Page 24: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** * Represents a customer data access object to * encapsulate all db relevant activities */ public class CustomerDao {

... public List<Customer> findByZipCodeOrCity( String zipCode, String city) { return ...; }

public List<Customer> findByZipCodeOrCityOrCityLimit( String zipCode, String city, int order) { return ...; } }

sprechend?

Page 25: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model

Zur Erinnerung

„Wir möchten ein sprechendes Domain Model, mit einem sprechenden API, welches wir in sich konsistent erzeugen und im weiteren Verlauf konsequent konsistent erhalten.“

Page 26: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Anforderungen

‣ sprechendes Modell ‣ sprechendes API

‣ konsistent erzeugen ‣ konsistent erhalten

‣ Fachlichkeit, Validierung, Konvertierung, Normalisierung und Konsistenzprüfung!

Rule #1: Rich not Anemic Domain Model

Page 27: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Mut zur Fachlichkeit

Page 28: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Anforderungen

‣ sprechendes Modell ‣ sprechendes API

‣ konsistent erzeugen ‣ konsistent erhalten

Rule #1: Rich not Anemic Domain Model

Page 29: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model// (JPA) Entity with Value Objects public class Customer extends HumanBeing { private FirstName firstName; private LastName lastName; private FamilyStatus familyStatus; private Customer partner; private Address postalAddress; private Map<PhoneNumberType, PhoneNumber> phoneNumbers; ... public void marry(Partner partner,LastName newLastName) { lastName = notNull(newLastName) familyStatus = FamilyStatus.MARRIED; // Ensure bidirectional integrity for partner entity! ... } public boolean isMarried() { return (familyStatus == FamilyStatus.MARRIED); } }

sprechend

Page 30: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model// (JPA) Entity with Value Objects public class Customer extends HumanBeing { ... private Map<PhoneNumberType, PhoneNumber> phoneNumbers; ... public void changeHomePhoneNumber( PhoneNumber changedHomePhoneNumber) { ... } public void disconnectHomePhone() { ...}

public void changeMobilePhoneNumber( PhoneNumber changedHomePhoneNumber) { ... } public void disconnectMobilePhone() { ... } ...

}

sprechend

Page 31: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** * Represents a customer data access object to * encapsulate all db relevant activities */ public class CustomerDao {

... public List<Customer> findByZipCodeOrCityOrStreet( String street, String city, String zipCode) { return ...; }

public List<Customer> findByAnyOf( ZipCode zipCode, City city, Street order) { return ...; } }

sprechend

Page 32: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Hmm, passt das wirklich zu Java EE?

Page 33: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** * Simple value object for first name using the * common base <code>SimpleValueObject</code> */ public class FirstName extends SimpleValueObject<String> {

public FirstName(String aValue) { super(aValue); }

public String getText() { return super.getValue(); }

}

Common Base

‣ Passt das wirklich: Value Objects?

Page 34: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** Abstract value object as a common base */ public abstract class SimpleValueObject<T extends Comparable> implements Serializable, Comparable<SimpleValueObject<T>> {

private T value;

public SimpleValueObject(T aValue) { value = aValue; }

protected T getValue() { return value; }

public boolean equals(Object o) { return ...; }

public int hashCode() { return ...; }

public String toString() { return ...; }

public int compareTo(SimpleValueObject<T> o) { return ...; } }

Common Base

Page 35: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** * Embeddable date of birth for (re)use in value objects */ @Embeddable public class DateOfBirth { private Date dateOfBirth;

... }

/** * Customer entity making use of date of birth embeddable */ @Entity public class Customer {

@Embedded @AttributeOverride(name=„dateOfBirth", column=@Column(name=“CUST_BIRTHDATE“)) private DateOfBirth dateOfBirth;

... }

VO, Entities & JPA

Page 36: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** * Using JPA-QL and ValueObjects */ @Entity @Table(name = "TAB_USER", ...) @NamedQueries({ @NamedQuery(name = "User.findByEmail", query = "select u from User u where u.email = :email"), @NamedQuery(name = "User.findByEmailString", query = "select u from User u " + " where u.email.value = :emailString“) }) public class User extends AbstractEntity {

protected static final String EMAIL_COLUMN = "EMAIL";

@AttributeOverride(name = "value", column = @Column(name = EMAIL_COLUMN, unique = true, nullable = false)) private Email email;

...

}

VO & JPA Queries

Page 37: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model/** CDI based JSF Controller managing user related input */ @Named("customerController") @RequestScoped public class CustomerController { private DateOfBirth dateOfBirth; private ZipCode zipCode; ...; public DateOfBirth getDateOfBirth() { return dateOfBirth; }

public void setDateOfBirth(DateOfBirth newDateOfBirth) { dateOfBirth = newDateOfBirth; } public ZipCode getZipCode() { return zipCode; }

public void setZipCode(ZipCode newZipCode) { zipCode = newZipCode; } ... }

VO & JSF

Page 38: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model<!-- Value Object binding in JSF xhtml page via Unified Expression Language & JSF Faces Converter -->

<!-- using JSF converter for Value Object of type ZipCode (read) —> <h:outputText value=“#{customerController.zipCode}“ />

<!-- using JSF converter for Value Object of type ZipCode (write) —> <h:inputText value=“#{customerController.zipCode}“ ... />

VO & JSF

@FacesConverter(forClass = ZipCode.class) public class ZipCodeConverter extends SimpleValueObjectConverter <ZipCode> { }

Page 39: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Anforderungen

‣ sprechendes Modell ‣ sprechendes API

‣ konsistent erzeugen ‣ konsistent erhalten

Rule #1: Rich not Anemic Domain Model

Page 40: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model// JPA entity @ValidPaymentMethod // cross-field constraint @Entity public class Customer { @Name // common constraint for type Name private FirstName firstName;

@Name // common constraint for type Name private LastName lastName; @Valid // delegate validation to Class private CreditCard creditCard;

@Valid // delegate validation to Class private BankAccount bankAccount;

@Address(area = AddressArea.GERMANY) // special constraint private Address postalAddress; ... }

konsistent?

Page 41: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model// Builder Pattern - IN ACTION (easy version)

// create AddressBuilder AddressBuilder builder = new AddressBuilder();

// set all known values // BTW: could be also used in JSF and other frameworks builder.setStreet(...); builder.setStreetNumber(...); builder.setZipCode(...); builder.setCity(...); builder.setState(...); builder.setCountry(...);

// build valid and immutable Address object Address address = builder.build();

konsistent

Page 42: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model// Builder Pattern - IN ACTION (extended version)

// create AddressBuilder Address address = newAddress()

// set values // BTW: could be also used in JSF with own EL Resolver .forStreetNumber(...).ofStreet(...) .inCity(...).withZipCode(...) .lyingInState(...).ofCountry(...)

// build Address object .build(...);

konsistent

Page 43: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #1: Rich not Anemic Domain Model// Class with Builder - extended version public class Address {

public static Builder newAddress() { return new Builder(); } ...

public static class Builder {

private Address address = new Address();

public Builder ofStreet(String initialStreet) { address.street = validateStreet(initialStreet); return this; }

public Address build() { validate(); Address validAddress = address; address = new Address(); return validAddress; } } }

konsistent

Page 44: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

RULE #2 Inject Business not Infrastructure

Always follow the Rules …

Page 45: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure// JSF UI [email protected]@javax.inject.Named(“createCustomerController“)public class CreateCustomerController {

// inject CustomerService and MailService via @Inject

@Inject // CDI managed controller layer bean (SessionScoped) private AuthenticationController authController; private Customer customer;

public String createCustomer() { currentCallCenterAgent = authController.getLoggedInCca();

customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED;}

// getter / setter for customer...

}

Page 46: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure// JSF UI [email protected]@javax.inject.Named(“createCustomerController“)public class CreateCustomerController {

// inject CustomerService and MailService via @Inject

@Inject @Current private CallCenterAgent currentCallCenterAgent; private Customer customer;

public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED;}

// getter / setter for customer...

}

Page 47: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure// Authentication Controller@SessionScoped@Named(“authenticationController“)public class AuthenticationController implements Serializable {

private CallCenterAgent loggedInCca;

public String authenticate() {...}

@Produces @Current public CallCenterAgent getLoggedInCca() {

return loggedInCca;}

...}

@RequestScoped

@Inject @Current CallCenterAgent

Page 48: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructurepackage de.openknowldege.qualifier

import ...

// self-made qualifier to indicate current instance of something

@Qualifier@Target({TYPE, METHOD, PARAMETER, FIELD})@Retention(RUNTIME)public @interface Current{ }

Page 49: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure// JSF UI [email protected]@javax.inject.Named(“createCustomerController“)public class CreateCustomerController {

// inject CustomerService and MailService via @Inject

@Inject @Current private CallCenterAgent currentCallCenterAgent; private Customer customer;

public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED;}

// getter / setter for customer...

}

Page 50: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure// JSF UI [email protected]@javax.inject.Named(“createCustomerController“)public class CreateCustomerController {

// inject CustomerService and MailService via @Inject

@Inject @Current // still „bounded“ to controller layer? private CallCenterAgent currentCallCenterAgent; private Customer customer;

public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED;}

// getter / setter for customer...

}

Page 51: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure// JSF UI [email protected]@javax.inject.Named(“createCustomerController“)public class CreateCustomerController {

// inject CustomerService and MailService via @Inject

@Inject @Current // still „bounded“ to controller layer? NO! private CallCenterAgent currentCallCenterAgent; private Customer customer;

public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED;}

// getter / setter for customer...

}

Page 52: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure// Customer Service EJB@Statelesspublic class CustomerService {

@Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em;

// transactional by default public void createCustomer(Customer customer) {

customer.setAuditInformation(currentCallCenterAgent); em.persist(customer);}

...}

Page 53: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure

<html ...> <h:body> <h:form>

Vorname: <h:inputText value=“#{createCustomerController.customer.firstname}"/> Name: <h:inputText value=“#{createCustomerController.customer.lastname}"/>

</h:form> </h:body></html>

Aber was ist mit der View?

Page 54: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure

<html ...> <h:body> <h:form>

Vorname: <h:inputText value=“#{customerToCreate.firstname}"/> Name: <h:inputText value=“#{customerToCreate.lastname}"/>

</h:form> </h:body></html>

Fachlichkeit auch in der View?

Page 55: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure

// JSF UI [email protected]@javax.inject.Named(“createCustomerController“)public class CreateCustomerController {

@Inject private CustomerService customerService;

private Customer customer;

// getter for [email protected]@javax.inject.Named(“customerToCreate“) public Customer getCustomer { return customer; }...

}

#{customerToCreate … }

Page 56: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure

// EJB based Service @Named(“shoppingCartService“) @ApplicationScopedpublic class ShoppingCartService {

...

// call from JSF via #{shoppingCartService.add(...)}public void add( ShoppingCart shoppingCart, Article article) {

...

}...

}

BTW: Service Access via EL

Page 57: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #2: Inject Business not Infrastructure

// JPA Repositorypublic class CustomerRepository {

@InjectEntityManager em;

// CDI producer method for „current“ Customer@Produces@Current@Named(“currentCustomer“) public Customer findCustomer ( @Parameter(“customerId“) Integer customerId) { return em.find(Customer.class, customerId) }...

}

BTW: Repository als Producer

Page 58: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

RULE #3 Business drives TX not Technology

Always follow the Rules …

Page 59: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #3: Business drives TX not Technology// Customer Service EJB @Statelesspublic class CustomerService {

@Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em;

// transactional by default public void createCustomer(Customer customer) {

customer.setAuditInformation(currentCallCenterAgent); em.persist(customer);}

...}

Page 60: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #3: Business drives TX not Technology// Customer Service EJB - no EJB annotation required!@ApplicationScoped @Statelesspublic class CustomerService implements Serializable {

@Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em;

// transactional by default public void createCustomer(Customer customer) {

customer.setAuditInformation(currentCallCenterAgent); em.persist(customer);}

...}

Page 61: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #3: Business drives TX not Technology// Customer Service@ApplicationScoped public class CustomerService implements Serializable {

@Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em;

@Transactional public void createCustomer(Customer customer) {

customer.setAuditInformation(currentCallCenterAgent); em.persist(customer);}

...}

Java EE 7, DeltaSpike or „home brewn“

Page 62: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #3: Business drives TX not Technology

@Transactional @Interceptorpublic class TransactionAdvice {

@Inject private UserTransaction utx;

@AroundInvoke public Object applyTransaction( InvocationContext ic) throws Throwable {

... // 1. implement utx.begin() ic.proceed(); // 2. call original method ... // 3. implement utx.commit()

}

*XML registration omitted

Page 63: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #3: Business drives TX not Technology// Customer Service - no annotation required!@ApplicationScoped public class CustomerService implements Serializable {

@Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em;

@Transactional public void createCustomer(Customer customer) {

customer.setAuditInformation(currentCallCenterAgent); em.persist(customer);}

...}

Page 64: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

App

User Interface

UseCase Controller

TX

UI

Business Object

Business Object

Business Object

Domain

Rule #3: Business drives TX not Technology

Page 65: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

App

User Interface

UseCase Controller

TXUI

Business Object

Business Object

Business Object

Domain

Business

Rule #3: Business drives TX not Technology

Page 66: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Rule #3: Business drives TX not Technology// JSF UI [email protected]@javax.inject.Named(“createCustomerController“)public class CreateCustomerController {

@Inject private CustomerService customerService;

private Customer customer;

@Transactional public String createCustomer() {

customerService.create(customer); ... // some additional use case “tx“ related work return CUSTOMER_CREATED;}

// getter / setter for customer...

}

Page 67: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

App

User Interface

UseCase Controller

TX

Business Object

Business Object

Business Object

Domain

Business

Rule #3: Business drives TX not Technology

Danger: LIE!

Page 68: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Lazy Initialization Problem besteht nach wie vor!

‣ EntityManager ist an Transaktion gebunden ‣ Probleme bei lesenden Zugriffen ohne TX

‣ Varianten ‣ EXTENDED EM (@Stateful CM) ‣ EXTENDED EM (@RequestScoped AM) ‣ Fachliche Queries via EntityGraph (seit JPA 2.1)

Rule #3: Business drives TX not Technology

Page 69: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

… and You are my (wo)man!

Always follow the Rules …

Page 70: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

App

User Interface

UseCase Controller

TXUI

Business Object

Business Object

Business Object

Domain

Business

Always follow the Rules …

Page 71: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Es wäre doch viel schöner, wenn ...

Domain Model

ApplicationA

dapter

Ad

apter

App Core mit Business TX

Page 72: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Erkenntnis des Tages - bitte mitnehmen!

„The Design is the Code, the Code is the Design.“

Page 73: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Erkenntnis des Tages - bitte mitnehmen!

„Muss ich denn jedes Mal den Code ändern, wenn

sich die Fachlichkeit ändert?“

Page 74: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Erkenntnis des Tages - bitte mitnehmen!

„Zur Hölle, ja! Wann denn bitte sonst?“

Page 75: Not your Father’s Larson · Rule #1: Rich not Anemic Domain Model /** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer

Not your Father’sJava EE

@mobileLarson @_openKnowledge

Lars Röwekamp | CIO New Technologies