effective enterprise java johannes brodwall chief scientist, steria norway

60
Effective Enterprise Java Johannes Brodwall Chief scientist, Steria Norway www.steria.no

Upload: collin-floyd

Post on 30-Dec-2015

222 views

Category:

Documents


0 download

TRANSCRIPT

Effective Enterprise Java

Johannes BrodwallChief scientist, Steria Norway

www.steria.no

What I have prepared

In order to design, develop or maintain an enterprise information system in Java (web, database)

As a senior developer I want to learn how to approach important aspects of

my application

My responsibity as an instructor

To give the best answer I can to the problems you have

To be honest when I’m unsure about a question

To listen to your wishes for topics throughout the tutorial

Your responsibilties as participants

To ask your most pressing questionsTo participate activelyTo let me know if we spend too much

time on a topicTo challenge me when you think I’m

wrong

19.04.23

Konfidensiell - Navn på presentasjon.ppt

4

Contents

ArchitectureCommunicationProcessingState managementPresentationSecurity

Top take-aways Development

▬ Invest in unit and integration level tests

Architecture▬ Isolate each processing event and abort if you can’t complete

Communication▬ Fowler's First Law of Distributed Object Design: Don’t distribute your

objects Processing

▬ Prefer local transactions to distributed ones State management

▬ Understand the underlying relational model before using an ORM tool Presentation

▬ Design your system from the outside in Security

▬ Treat all data from outside as tainted

Agenda

Architectural overview of enterprise applications Sections (a la carte)

▬ Preparated materials▬ Without prepared materials▬ Suggestions from you▬ Things I don’t know

Breaks at ???

Section menu a la carte

Prepared materials▬ Integration testing▬ Unit testing enterprise applications▬ Persistence (ORM basics, ORM advanced)▬ Scalability▬ Distributed applications▬ Security▬ Client options

Without prepared materials▬ Continuous Deployment▬ Putting transactions, state and processing into context▬ A practical approach to system design▬ Machine-enabled interfaces

Suggestions from you Things I don’t know

Participant stories

In order to <solve a problem in my job> As a <job title> I want to learn about <subject>

Disclaimer!

Code is presented as stand-alone as possible – in real systems, refactor to

remove duplication

The world has changed

Enterprise Java Architecture 2009

Every processing is triggered by an event▬ Usually: Timed trigger, incoming http request, incoming message

All triggers can be forged Every processing event should be isolated

▬ Retrieve all data as you need it▬ Update all data at an end▬ Do optimistic locking▬ All objects are short-lived or immortal and stateless

Unexpected errors should rollback everything, log and abort

Any, oh, EJBs are more trouble than they’re worth

10 000 ft architecture

Internet/intranet

Perimeter

Application

Information

Clients

3 000 ft http architecture

What you need to care about

Your applicationYour application

Interpretrequest

Renderresponse

Identify user

Identifyaction and flow

Read and persistinformation

Isolate processing

3 000 ft thick client architecture

What you need to care about

Server moduleServer module

Wire protocol

Identify user

Identifyaction and flow

Read and persistinformation

Server moduleServer module

Present data Manage events

API

Scalability

What are you bottlenecks?

Scalability: Only two solutions, one problem

Solution #1: Add more identical nodes Solution #2: Cache at some level

Problem: Data out of sync

Bottlenecks #1: Make one app server performant

1. Poor SQL performance – trace and optimize SQL

2. Garbage collection screw-up – check with a memory profiler

3. Rendering similar pages repeatedly – page caching

4. Stateful pages get in the way of caching – make saner URLs

5. User-info gets in the way of caching – render with JavaScript and cookies

6. Offload static content

7. Increase hardware

Bottleneck #2: Horizontal app server scaling

More seldom than you’re led to think! (e.g. stackoverflow.com)

In principle simple: mod_whatever in Apache frontend Problems: Session Solutions

▬ No session (authentication in perimeter)▬ Sticky sessions▬ Distributed sessions▬ Cookie-based sessions

Bottleneck #3: Database scalability

Two basic solutions▬ Expensive, poorly-understood distributed RDBMSs▬ Caching

Caching:▬ In application server▬ In read-only database mirrors▬ Seperate read and write-requests to different app servers (on

HTTP verbs or URLs)

Tradeoff: How often should users see stale data? Should they ever see own stale data?

Integration testing web applications

Live demo

Integration testing web applications

@Testpublic void shouldFindSavedPeople() throws Exception { org.mortbay.jetty.Server server = new org.mortbay.jetty.Server(0); server.addHandler(new WebAppContext("src/main/webapp", "/")); server.start();

String rootUrl = "http://localhost:" + server.getConnectors()[0].getLocalPort() + "/";

org.openqa.selenium.WebDriver browser = new org.openqa.selenium.htmlunit.HtmlUnitDriver(); browser.get(rootUrl);

browser.findElement(By.linkText("Create a new person")).click(); browser.findElement(By.name("full_name")).sendKeys("Johannes Brodwall"); browser.findElement(By.name("create")).click();

browser.findElement(By.name("name_query")).sendKeys("johannes"); browser.findElement(By.name("search")).click(); browser.findElement(By.xpath(".//*[text() = 'Johannes Brodwall']"));}

Unit testing enterprise applications

Live demo: Servlet testing Live demo: Hibernate testing

Unit testing servlets with Mockito

@Testpublic void shouldSearchForPerson() throws Exception { HttpServletRequest req = org.mockito.Mockito.mock(HttpServletRequest.class); HttpServletResponse resp = mock(HttpServletResponse.class);

StringWriter pageSource = new StringWriter(); when(resp.getWriter()).thenReturn(new PrintWriter(pageSource));

when(req.getMethod()).thenReturn("GET"); when(req.getPathInfo()).thenReturn("/find.html"); when(req.getParameter("name_query")).thenReturn("foobar");

PersonDao personDao = mock(PersonDao.class); PersonServlet servlet = new PersonServlet(); servlet.setPersonDao(personDao);

servlet.service(req, resp);

verify(personDao).find("foobar"); DocumentHelper.parseText(pageSource.toString()); org.fest.assertions.Assertions.assertThat(pageSource.toString()) .contains("<input type='text' name='name_query' value='foobar'");}

Unit testing Hibernate

@Testpublic void shouldFindPeopleByName() { AnnotationConfiguration configuration = new AnnotationConfiguration(); Properties properties = configuration.getProperties(); properties.setProperty(Environment.URL, "jdbc:h2:mem:person-dao-test;MVCC=true"); properties.setProperty(Environment.DRIVER, Driver.class.getName()); properties.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, ManagedSessionContext.class.getName()); properties.setProperty(Environment.HBM2DDL_AUTO, "update"); configuration.addAnnotatedClass(Person.class); SessionFactory sessionFactory = configuration.buildSessionFactory();

ManagedSessionContext.bind(sessionFactory.openSession());

HibernatePersonDao personDao = new HibernatePersonDao(sessionFactory);

personDao.create(Person.withName("Aye Bee Cee"), Person.withName("Aye Cee")); sessionFactory.getCurrentSession().flush(); sessionFactory.getCurrentSession().clear(); assertThat(personDao.find("Bee")) .contains(Person.withName("Aye Bee Cee")) .excludes(Person.withName("Aye Cee"));

ManagedSessionContext.unbind(sessionFactory).close();}

Persistence – the ORM

Why?

In order to reduce the amount of dedious work and error prone SQL/jdbc code I write

As a developer who already understands SQL well, I want to use an ORM to manage my persistence

Basics

@Entitypublic class Person {

@Id @GeneratedValue(strategy=GenerationType.SEQUENCE) private Long id;

private String name;

@Override public boolean equals(Object obj) { }

@Override public int hashCode() { }

}

Advanced ORM-JPA-Hibernate

Advanced: Hacked polymorphic joins

@Entity @Table(name="XX_KONTO")public class Konto implements Serializable {

@EmbeddedId private KontoPk id = new KontoPk();

@Column(name="TREKKPST") private Integer trekkprosent;

@ManyToOne(optional=true) @NotFound(action=NotFoundAction.IGNORE) @JoinColumn(name="fodselsnr", referencedColumnName="fodselsnr") private Person person;

@ManyToOne(optional=true) @NotFound(action=NotFoundAction.IGNORE) @JoinColumn(name="orgnr", referencedColumnName="orgnr")

private Foretak foretak;

public KontoEier getEier() { return person != null ? person : foretak; }

Advanced: Composite foreign keys as part of primary key

@ManyToOne @JoinColumns({ @JoinColumn(name="fylkenr", referencedColumnName="fylkenr", insertable=false, updatable=false), @JoinColumn(name="komnr2", referencedColumnName="komnr2", insertable=false, updatable=false), @JoinColumn(name="ktotype", referencedColumnName="ktotype", insertable=false, updatable=false), @JoinColumn(name="ktonr", referencedColumnName="ktonr", insertable=false, updatable=false)}) private Konto konto;

Advanced: Composite foreign keys as part of primary key

@ManyToOne @JoinColumns({ @JoinColumn(name="fylkenr", referencedColumnName="fylkenr", insertable=false, updatable=false), @JoinColumn(name="komnr2", referencedColumnName="komnr2", insertable=false, updatable=false), @JoinColumn(name="ktotype", referencedColumnName="ktotype", insertable=false, updatable=false), @JoinColumn(name="ktonr", referencedColumnName="ktonr", insertable=false, updatable=false)}) private Konto konto;

Advanced: Fetch strategies

public enum FetchType {/** * Defines that data must be lazily fetched */LAZY,/** * Defines that data must be eagerly fetched */EAGER};

Always understand what the ORM does

Fetching strategies:▬ Left outer join▬ Lazy loading

Inheritance▬ Table-per-concrete class (union subclass)▬ Table-per-class (join subclass)▬ Table-per-class-hierarchy ()

Relationships▬ @OneToMany @ManyToOne▬ Cascading (broken)▬ Ownership, mapped-by

When in doubt – make sure to unit test!

Distributed applications

Distributed applications

Fowler’s first law of distributed objects:▬ Don’t distribute your objects

As the server:▬ Treat your clients as you would a human client: Designed

interface, test at the outside, have a ”designer” take a look

As the client:▬ Each service you use will decrease your understanding,

reliability and performance

Why?

In order to get access to data or a service owned by another entity As a complex application I want to integrate with the third party service

In order to profit on a valuable service or dataset that I control As a service provider I want to provide a remote API to my services

In order to create a rich client interface As a the client side of a rich internet application I want to communicate remotely with the server

Bad reasons!

In order to reuse functionality As a complex application I want to call a third party internal service (Seldom worth the saving)

In order to don’t communicate with some other developer

As an introvert loner I want to hide myself behind a service interface (How will you be able to assess total complexity?)

How

REST vs SOAP vs ORB▬ REST is good when you want to use HTTP as an application

protocol and not just a transport protocol▬ ORBs are good when you control both endpoints▬ SOAP is good when ORBs would be better▬ Hessian is a binary ORB-protocol over HTTP

Distributed transactions versus idempotent writes▬ Very few organizations have been able to master distributed

transactions▬ Understand the semantics of HTTP PUT

Security – Little Bobby Tables

Security

Security thread #1: Injection

Problem: Client tricks the application to treat data as instructions

▬ SQL commands▬ HTML code▬ (In C: return pointer in memory)

Solution: Treat all outside data as tainted▬ Outside: Request (obviously), files (usually), database (yes!)

Always, alway, always escape tainted data▬ SQL parameters – Use PreparedStatement▬ Hibernate parameters – Use parameters or Criteria▬ HTML snippet – escape

Security threat #2: Client-only validation

Attack: A malicious user looks at a form and changes the parameters en-route (Firefox plugin)

Weakness: The server expects incoming data to be valid

Solution (again): Treat all incoming data as tainted

Security threat #3: Request forgery

Problem: A malicious site tricks the user into submitting a rogue post-request to you

Problem: A malicious email tricks the user into clicking a rogue link to your application

Solution (again): Treat all incoming data as tainted

Client options

HTML

GWT

Flex (or Silverlight :-P)

JavaFX

Swing

Things to consider

Power of expression▬ Flex, JavaFX, GWT

Testing round-trip▬ HTML, Swing, (JavaFX?)

Easy to layout good Uis?▬ Flex, JavaFX(?)

Simplicity of language▬ Swing, GWT

Client pervasiveness/perceived ease of installation▬ HTML, GWT, (Flex)

Client performance requirements▬ HTML, (GWT)

Things that aren’t issues any more

Communication between client and server▬ Basically, all use http-based async ORBs▬ With Swing: Make your own async http ORB a la GWT with

SwingWorker and Hessian

Distribution of client▬ Swing and JavaFX use JavaWebStart

Retrospective

What new thing have I learned? Which problems at work will I apply this to? What is my most urgent question remaining?

Keep everything as simple as possible, if not simpler.

Johannes BrodwallChief ScientistSteria, Norway

[email protected]://johannesbrodwall.com@jhannes

Thank you for participating

Chapter 2. Architecture

Item 1: Prefer components as the key element of development, deployment, and reuse Item 2: Prefer loose coupling across component boundaries Item 3: Differentiate layers from tiers Item 4: Keep data and processors close together Item 5: Remember that identity breeds contention Item 6: Use hook points to inject optimizations, customizations, or new functionality Item 7: Be robust in the face of failure Item 8: Define your performance and scalability goals Item 9: Restrict EJB to transactional processing Item 10: Never optimize without profiling first Item 11: Recognize the cost of vendor neutrality Item 12: Build in monitoring support Item 13: Build in administration support Item 14: Make deployment as simple as possible

Chapter 3. Communication

Item 15: Understand all your communications options Item 16: Consider your lookup carefully Item 17: Recognize the cost of network access Item 18: Prefer context-complete communication styles Item 19: Prefer data-driven communication over behavior-driven

communication Item 20: Avoid waiting for remote service requests to respond Item 21: Consider partitioning components to avoid excessive load on

any one machine Item 22: Consider using Web Services for open integration Item 23: Pass data in bulk Item 24: Consider rolling your own communication proxies

Chapter 4. Processing

Item 25: Keep it simple Item 26: Prefer rules engines for complex state evaluation and execution Item 27: Prefer transactional processing for implicitly nonatomic failure scenarios Item 28: Differentiate user transactions from system transactions Item 29: Minimize lock windows Item 30: Never cede control outside your component while holding locks Item 31: Understand EJB transactional affinity Item 32: Prefer local transactions to distributed ones Item 33: Consider using optimistic concurrency for better scalability Item 34: Consider using pessimistic concurrency for explicit concurrency control Item 35: Consider lower isolation levels for better transactional throughput Item 36: Use savepoints to keep partial work in the face of rollback Item 37: Replicate resources when possible to avoid lock regions Item 38: Favor the immutable, for it needs no locks

Chapter 5. State Management

Item 39: Use HttpSession sparingly Item 40: Use objects-first persistence to preserve your domain model Item 41: Use relational-first persistence to expose the power of the

relational model Item 42: Use procedural-first persistence to create an encapsulation layer Item 43: Recognize the object-hierarchical impedance mismatch Item 44: Use in-process or local storage to avoid the network Item 45: Never assume you own the data or the database Item 46: Lazy-load infrequently used data Item 47: Eager-load frequently used data Item 48: Batch SQL work to avoid round-trips Item 49: Know your JDBC provider Item 50: Tune your SQL

Chapter 6. Presentation

Item 51: Consider rich-client UI technologies Item 52: Keep HTML minimal Item 53: Separate presentation from processing Item 54: Keep style separate from content Item 55: Pregenerate content to minimize processing Item 56: Validate early, validate everything

Chapter 7. Security

Item 57: Security is a process, not a product Item 58: Remember that security is not just prevention Item 59: Establish a threat model Item 60: Assume insecurity Item 61: Always validate user input Item 62: Turn on platform security Item 63: Use role-based authorization Item 64: Use SignedObject to provide integrity of Serialized

objects Item 65: Use SealedObject to provide confidentiality of

Serializable objects Item 66: Use GuardedObject to provide access control on objects

Chapter 8. System

Item 67: Aggressively release resources Item 68: Tune the JVM Item 69: Use independent JREs for side-by-side versioning Item 70: Recognize ClassLoader boundaries Item 71: Understand Java Object Serialization Item 72: Don't fight the garbage collector Item 73: Prefer container-managed resource management Item 74: Use reference objects to augment garbage collection

behavior Item 75: Don't be afraid of JNI code on the server