internetove technologie na platforme java

79
ˇ Cesk´ e vysok´ e uˇ cen´ ı technick´ e v Praze Fakulta elektrotechnick´ a C ˇ VUT FEL katedra poc ˇı ´tac ˇu ˚ Bakal´aˇ rsk´apr´ ace Internetov´ e technologie na platformˇ e JAVA Miroslav Hr´ uz Vedouc´ ı pr´ ace: Ing. Andrej Zachar Studijn´ ı program: Elektrotechnika a informatika strukturovan´ e bakal´ rsk´ e Obor: Informatika a v´ ypoˇ cetn´ ı technika srpen 2007

Upload: miroslav-hruz

Post on 16-Jul-2015

1.928 views

Category:

Education


0 download

TRANSCRIPT

Page 1: Internetove technologie na platforme Java

Ceske vysoke ucenı technicke v PrazeFakulta elektrotechnicka

CVUT FEL katedra pocıtacu

Bakalarska prace

Internetove technologie na platforme JAVA

Miroslav Hruz

Vedoucı prace: Ing. Andrej Zachar

Studijnı program: Elektrotechnika a informatika strukturovane bakalarske

Obor: Informatika a vypocetnı technika

srpen 2007

Page 2: Internetove technologie na platforme Java

ii

Page 3: Internetove technologie na platforme Java

Podekovanı

Chtel bych podekovat firme SimpleWay s.r.o., kde jsem mel tu moznost seznamit se s techno-logiemi, ktere popisuji ve svojı bakalarske praci.

iii

Page 4: Internetove technologie na platforme Java

iv

Page 5: Internetove technologie na platforme Java

Prohlasenı

Prohlasuji, ze jsem svou bakalarskou praci vypracoval samostatne a pouzil jsem pouze podkladyuvedene v prilozenem seznamu.Nemam zavazny duvod proti uzitı tohoto skolnıho dıla ve smyslu §60 Zakona c. 121/2000 Sb.,o pravu autorskem, o pravech souvisejıcıch s pravem autorskym a o zmene nekterych zakonu(autorsky zakon).

V Praze dne 21.8. 2007 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

v

Page 6: Internetove technologie na platforme Java

vi

Page 7: Internetove technologie na platforme Java

Abstract

The goal of this bachalor thesis is to show possibilities of the Java platform for building webapplications. Content of this paper is from on piece a recherche and from other piece an im-plementation. In the beginning I make the reader acquainted with technologies like Java EE,Spring framework and Hibernate ORM. In the next section I show the principles of Extremeprogramming and Test-Driven development. In the last section I apply knowledges of foregoingparts to the practical project, to the portal for seeking roommates. I show illuminating applyof Extreme programming in the real life.

Abstrakt

Cılem teto bakalarske prace je ukazat moznosti JAVA platformy pro tvorbu webovych aplikacı.Obsah dıla je z casti resersnı, z casti implementacnı. V uvodu seznamuji ctenare s techno-logiemi jako Java EE, Spring framework a Hibernate ORM. V dalsı casti ukazuji principyExtremnıho programovanı a Testem rızeneho vyvoje. V poslednı casti aplikuji teoreticke zna-losti z predchozıho textu na praktickem projektu, portalu pro hledanı spolubydlıcıch. Ukazujinazornou aplikaci Extremnıho programovanı v kazdodennım zivote.

vii

Page 8: Internetove technologie na platforme Java

viii

Page 9: Internetove technologie na platforme Java

Obsah

Seznam obrazku xiii

1 Uvod 11.1 Naroky a technicka obtıznost textu . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Typograficka uprava a clenenı textu . . . . . . . . . . . . . . . . . . . . . . . . 1

2 Reserse 32.1 Java EE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.1.1 Vıcevrstva architektura (N-tier architecture) . . . . . . . . . . . . . . . 32.1.2 Koncept kontejneru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.1.3 Aplikacnı servery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.1.3.1 Servletove kontejnery . . . . . . . . . . . . . . . . . . . . . . . 42.1.3.2 Java EE aplikacnı servery . . . . . . . . . . . . . . . . . . . . . 4

2.1.4 Vyber technologiı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2 Spring framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.2.1 Aplikacnı framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2.2 Historie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2.3 Hlavnı prednosti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2.4 Moduly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2.5 Inversion of Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.2.5.1 Dependecy lookup . . . . . . . . . . . . . . . . . . . . . . . . . 72.2.5.2 Dependecy injection . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2.6 Rozhranı BeanFactory a ApplicationContext . . . . . . . . . . . . . . . 82.2.6.1 BeanFactory . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.2.6.2 Zivotnost beany . . . . . . . . . . . . . . . . . . . . . . . . . . 92.2.6.3 Typove konverze . . . . . . . . . . . . . . . . . . . . . . . . . . 112.2.6.4 Autowiring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.2.6.5 ApplicationContext . . . . . . . . . . . . . . . . . . . . . . . . 12

2.2.7 Spring Web MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.2.7.1 Navrhovy vzor MVC . . . . . . . . . . . . . . . . . . . . . . . 122.2.7.2 Rozdelenı webovych frameworku . . . . . . . . . . . . . . . . . 142.2.7.3 Architektura . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.2.7.4 Dispacher servlet . . . . . . . . . . . . . . . . . . . . . . . . . . 162.2.7.5 Webove scopy . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.2.8 Spring Web Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.2.8.1 Struktura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.2.8.2 Stavy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.2.8.3 Vyhody . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.2.8.4 Nevyhody . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.2.8.5 Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.2.8.6 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202.2.8.7 Konfigurace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.3 Hibernate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.3.1 ORM framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.3.2 JPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.3.3 Mapovanı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.3.4 Anotace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242.3.5 Prace s objekty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

ix

Page 10: Internetove technologie na platforme Java

2.3.6 Dotazy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.3.6.1 HQL API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.3.6.2 Criteria API . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

2.3.7 Lazy, Eager loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262.3.8 Integrace se Springem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

2.3.8.1 Deklarativnı transakce . . . . . . . . . . . . . . . . . . . . . . . 262.4 Extremnı programovanı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

2.4.1 Historie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.4.2 Role . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.4.3 Zakladnı postupy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

2.4.3.1 Planovacı hra . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.4.3.2 Male iterace . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.4.3.3 Metafora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.4.3.4 Testovanı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292.4.3.5 Jednoduchy navrh . . . . . . . . . . . . . . . . . . . . . . . . . 292.4.3.6 Refaktorovanı . . . . . . . . . . . . . . . . . . . . . . . . . . . 292.4.3.7 Parove programovanı . . . . . . . . . . . . . . . . . . . . . . . 292.4.3.8 Kolektivnı vlastnictvı kodu . . . . . . . . . . . . . . . . . . . . 292.4.3.9 40-ti hodinovy pracovnı tyden . . . . . . . . . . . . . . . . . . 292.4.3.10 Zakaznık na spravnem mıste (On-site customer) . . . . . . . . 302.4.3.11 Standardnı podoba kodu . . . . . . . . . . . . . . . . . . . . . 302.4.3.12 Sjednocene pracovnı prostredı . . . . . . . . . . . . . . . . . . 30

2.5 Testovacı framework JUnit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302.5.1 JUnit 3.x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

2.5.1.1 Architektura . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302.5.1.2 Assert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302.5.1.3 Integrace s IDE . . . . . . . . . . . . . . . . . . . . . . . . . . 31

2.5.2 JUnit 4.x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312.5.2.1 Hlavnı zmeny oproti 3.x . . . . . . . . . . . . . . . . . . . . . . 312.5.2.2 assertThat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312.5.2.3 Predpoklady a teorie . . . . . . . . . . . . . . . . . . . . . . . 32

2.6 Testovacı framework JMock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322.6.1 Mockovanı, Mock objekty . . . . . . . . . . . . . . . . . . . . . . . . . . 322.6.2 Architektura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332.6.3 Prıklad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3 Implementace 353.1 Zadanı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353.2 Analyza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.2.1 Co uz je naimplementovano? . . . . . . . . . . . . . . . . . . . . . . . . 353.2.2 Pruzkum trhu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353.2.3 Prototypy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

3.3 Implementace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.3.1 Iterace 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.3.2 Iterace 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443.3.3 Iterace 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443.3.4 Iterace 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

4 Zhodnocenı 594.1 Shrnutı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594.2 Moznosti rozsırenı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

x

Page 11: Internetove technologie na platforme Java

4.3 Osobnı zkusenosti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

5 Obsah prilozeneho CD 61

6 Literatura 63

7 Seznam pouzitych zkratek 65

xi

Page 12: Internetove technologie na platforme Java

xii

Page 13: Internetove technologie na platforme Java

Seznam obrazku

2.1 Kontext Java EE technologiı, zdroj: [6] . . . . . . . . . . . . . . . . . . . . . . . 32.2 Spring framework, zdroj: [13] . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 Princip IoC, zdroj: [13] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.4 Navrhovy vzor MVC, zdroj: [15] . . . . . . . . . . . . . . . . . . . . . . . . . . 132.5 MVC implementace JSP Model 2, zdroj: [1] . . . . . . . . . . . . . . . . . . . . 132.6 Architektura aplikace ve Spring MVC, zdroj: [20] . . . . . . . . . . . . . . . . . 142.7 Stavy objektu a prechody pomocı metod persistent manageru, zdroj: [17] . . . 252.8 Prubeh vyvoje v XP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3.1 Zakladnı UI prototyp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.2 Vkladanı noveho inzeratu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.3 Validace polozky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433.4 Novy inzerat vıce lokalit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453.5 Hledanı v poptavkach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

xiii

Page 14: Internetove technologie na platforme Java

xiv

Page 15: Internetove technologie na platforme Java

KAPITOLA 1. UVOD 1

1 Uvod

Internet se v dnesnı dobe stal nepostradatelnou zalezitostı, muzeme ho vyuzıvatruznymi zpusoby a vydolovanych informacı je vıce nez dost. Je to v dnesnı dobe, stale, nejper-spektivnejsı reklamnı medium na svete. Zakaznıku, prejıcıch si mıt na internetu svoji prezentacistale pribyva. Nenı proto od veci se seznamit s technologiemi pouzitymi pro vyvoj internetovychaplikacı.

Tato prace pojednava o tvorbe rozsahlejsıch aplikacı na platforme JAVA. JAVA spolus technologiemi .NET a Ruby on rails vede zebrıcky statistik pouzitych platforem [12] apokud si zvolıme vhodnou metodiku vyvoje, aplikace nam roste pod rukama velice rychle.

1.1 Naroky a technicka obtıznost textu

Prace by mela slouzit jako studijnı material vsem, kterı majı zajem vyvıjet internetoveaplikace na platforme Java. Predpokladam proto patricnou znalost tohoto jazyka. Je dobre, po-kud ma ctenar znalost vyvoje webovych aplikacı na jine platforme (naprıklad s PHP). Na skodunejsou zkusenosti s vyvojem pro Java EE, znalost tvorby JSP stranek nebo JPA, plne postacujeabsolvovanı predmetu X36TJV - Technologie programovanı v jazyku Java, vyucovaneho u nasna fakulte.

1.2 Typograficka uprava a clenenı textu

Veskery text je psan pomocı nastroje LATEX, s pouzitım pripravene sablony, kterouposkytuje katedra. Text je clenen hierarchicky do kapitol, sekcı a podsekcı. Pro lepsı citelnosta orientaci v textu budu veskery kod psat takto, pokud budu v textu hovorit o rozhranıch,zapisuji je takto. Trıdy a metody zapisuji takto. Prace je psana v cestine, ackoliv je IT odvetvıcharakteristicke vsemoznymi anglickymi termıny, tam, kde to lze, jsem pouzil jejich cesky ekvi-valent s originalnım znenım v zavorkach.

Page 16: Internetove technologie na platforme Java

2 KAPITOLA 1. UVOD

Page 17: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 3

2 Reserse

2.1 Java EE

Java Enterprice Edition je platforma urcena pro vyvoj byznys aplikacı. Stavajıcı spe-cifikace Java EE 5 definuje radu technologiı a API potrebnych pro vyvoj rozsahlych systemu.Drıve se platforma oznacovala zkratkou J2EE, z marketingovych duvodu, stejne jako JRE 1.5se oznacuje Java 5, se prejmenovala na Java EE. Aktualne je cele JVM opensourceovano a Javenic nestojı v ceste stat se nejpouzıvanejsı platformou od mobilnıch telefonu po velke byznys apli-kace. Krome standardnıch API jsou k dispozici stovky opensourceovych knihoven, frameworkua projektu. Nejdrıve se seznamıme se zaklady.

Obrazek 2.1: Kontext Java EE technologiı, zdroj: [6]

2.1.1 Vıcevrstva architektura (N-tier architecture)

Architektura byznys aplikace v Java EE se typicky sklada z castı, jez ukazuje obrazek2.1. Vzdy se jedna o model klient/server [2], resp. request/response, serverova cast se skladaz weboveho kontejneru, doplneneho v prıpade pouzitı specifikace EJB o EJB kontejner, dalejakehokoliv perzistentnıho datoveho uloziste (predstavme si naprıklad klasickou relacnı da-tabazi) a nejakeho klienta, v nasem prıpade weboveho prohlızece.

2.1.2 Koncept kontejneru

Kontejner je takovy softwarovy objekt, ktery je alokovan uvnitr daneho aplikacnıhoserveru nebo aplikacnıho frameworku.

• Zodpovıda za pridelovanı zdroju danym komponentam.

• Rıdı zivotnı cyklus objektu.

Nekdy se pojmy jako framework a kontejner zamerne zamenujı, napr. EJB a EJB kon-tejner, Spring a Spring kontejner.

2.1.3 Aplikacnı servery

Aplikacnı server je jadrem Java EE technologie. Podle poctu implementovanych speci-fikacı je muzeme rozdelit do dvou skupin

Page 18: Internetove technologie na platforme Java

4 KAPITOLA 2. RESERSE

2.1.3.1 Servletove kontejnery

Implementujı pouze webovy kontejner a technologie v nem dostupne, viz 2.1. Jehonasazenı je vhodne obecne pro mensı a strednı aplikace. Cılem mojı prace je ukazat, ze i beztezkotonaznıho kanonu jmenem EJB jsme schopni vytvorit robustnı aplikaci presne podle nasichpredstav. Mezi zastupce teto kategorie patrı

• Apache Tomcat - opensource projekt vydany pod Apache licencı, nejbeznejsı a nejdo-stupnejsı vubec.

• Jetty - opensource, webovy server pro staticky a dynamicky obsah, optimalizace provykon.

2.1.3.2 Java EE aplikacnı servery

Narozdıl od predchozı kategorie, Java EE AS implementujı plnou specifikaci z Java EEstacku.

• GlassFish (Sun Java AS) - opensource resenı od Sun Microsystems, referencnı implemen-tace

• JBoss AS - opensource

• IBM Websphere AS - komercnı, vlastnı implementace JVM

• BEA WebLogic AS - komercnı

2.1.4 Vyber technologiı

Pri vyberu aplikacnıho serveru musıme zvazit, co dany projekt opravdu potrebuje,jaky pouzıvame aplikacnı framework, jaky ORM nastroj nebo jake dalsı API jsou nezbytne,poprıpade jake pouzıvame IDE. V zasade bychom meli zvolit jednoho dodavatele resenı a ne-kombinovat dodavatele JVM, AS, frameworku a dalsıch API a knihoven nebo zvolit takovoukombinaci, ktera je odzkousena a bezproblemova; naprıklad Sun JVM, Glassfish AS, JSF, EJB,Toplink Essentials a NetBeans IDE, vse pekne standardnı nebo v nasem prıpade Sun JVM,Apache Tomcat, Spring framework, Spring Web MVC a WebFlow, Hibernate a Eclipse IDE.

2.2 Spring framework

2.2.1 Aplikacnı framework

Aplikace se dnes netvorı cele od zakladu, spıse se podobajı stavebnicım. Proc bychommeli znovu objevovat kolo, kdyz uz ho nekdo pred nami vymyslel a funguje dobre. Frameworkje softwarovy system, ktery nam pomaha resit nejcastejsı problemy pri implementaci, melby zrychlovat a usnadnovat vlastnı vyvoj, rıdit zivotnı cyklus aplikace a pomahat oddelitnızkourovnovy kod od vlastnı aplikacnı logiky daneho zadanı.

2.2.2 Historie

Odlehceny J2EE framework Spring vznikl puvodne jako demo aplikace knihy RodaJohnsonna: Expert One-to-One: J2EE design and development z roku 2002, ktera ukazala vdobe EJB 2.0, ze lze v J2EE programovat take jednoduse. Pozdeji, roku 2003 byl zalozenopensource projekt na portalu sourceforge.net, ktery vychazel z puvodnıho kodu a postupne sestal mezi vyvojari velmi popularnı. Dnes je Spring ve stabilnı verzi 2.0, cas ukazal, ze koncept,

Page 19: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 5

ktery Rod Johnsonn navrhl je spravny. Stavajıcı Java EE 5 se velmi Springem inspirovala abudoucı specifikace Java EE 6 se planuje Springu priblızit jeste vıce.

2.2.3 Hlavnı prednosti

• Snazsı a prıjemnejsı prace s J2EE,

• neinvazivnost, nenutı pouzıvat nic, co prave nepotrebujeme,

• objektove orientovany navrh je dulezitejsı nez jakakoliv implementacnı technologie,

• JavaBeans jako silny konfiguracnı nastroj,

• testovanı je zasadnı, Spring dela kod snadneji testovatelny,

• modularita, umoznuje zvolit jen ty komponenty, ktere potrebujeme,

• usnadnuje praci s dalsımi frameworky, pouzitı jako sjednocujıcı prıstup rozlicnych tech-nologiı a implementacı,

• usnadnuje praci s vyjımkami, kdy je zaobaluje do lepe citelnych.

Obrazek 2.2: Spring framework, zdroj: [13]

2.2.4 Moduly

Dulezitym aspektem je, ze Spring lze pouzıt i na servletovem kontejneru, dokonce iciste s Java SE. Modularnost je take docılena tım, ze se sklada z vıce .jar archivu, zakladnıchi volitelnych, pricemz si vybereme, co z nej chceme pouzıt.

• Spring Core - hlavnı jadro frameworku, jediny povinny modul, metodika Inversion ofControl, rozhranı BeanFactory

• Spring DAO - abstrakce a zjednodusenı prace s JDBC

Page 20: Internetove technologie na platforme Java

6 KAPITOLA 2. RESERSE

• Spring ORM - integrace s ORM frameworky, vlastnı implementace perzistentnıho API ina JRE 1.4 bez JPA

• Spring Web - integrace s webovymi frameworky jako JSF, Struts2, Velocity, vlastnı im-plementace weboveho frameworku Spring Web MVC

• Spring AOP - podpora aspektove orientovaneho programovanı

• Spring J2EE - podpora pro EJB, JMX, JMS, web service

2.2.5 Inversion of Control

Navrhovy vzor IoC je zalozen na tzv. Hollywoodskem principu: “Nevolejte mi, ja za-volam vam.”[5]. Aplikace se vzdava odpovednosti za vytvarenı a nastavenı instancı ve prospechframeworku, resp. jeho IoC kontejneru. Jedna se o stezejnı vlastnost, proto ji ukazu na prıkladu.

Obrazek 2.3: Princip IoC, zdroj: [13]

Zapıseme trıdu SampleContoller dvema zpusoby, jednak klasicky a jednak s vyuzitımtechniky IoC.SampleContollerWithoutIoC.java

public class SampleContollerWithoutIoC implementsorg.springframework.web.servlet.mvc.Controller {

public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {

Connection connection = DatabaseUtils.getConnection();UserDAO dao = DAOFactory.createUserDAO("hibernate", connection);List users = dao.getUsers();DatabaseUtils.closeConnection(conn);return new ModelAndView("userList", "users", users);

}}

SampleContollerWithIoC.java

public class SampleContollerWithIoC implementsorg.springframework.web.servlet.mvc.Controller {

private UserDAO dao = null;public void setUserDAO(UserDAO userDAO) {

this.dao = userDAO;}public ModelAndView handleRequest(HttpServletRequest request,

HttpServletResponse response) throws Exception {List users = dao.getUsers();

Page 21: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 7

return new ModelAndView("userList", "users", users);}

}

action-servlet.xml

<?xml version="1.0" encoding="UTF-8"?><beans>

<bean id="sampleController" class="SampleContollerWithIoC"><property name="userDAO" ref="userDAO"/>

</bean></beans>

Ve trıde SampleContollerWithoutIoC jsme rucne nastavovali komponentu dao. Ve trıdeSampleContollerWithIoC jsme ji dostali jiz nakonfigurovanou. Predstavme si prıklad v kon-textu realneho zivota, komponentu dao vyuzıvajı desıtky trıd. Co by se stalo, kdybychom bylinuceni zmenit rozhranı tovarnı metody createUserDAO? Museli bychom zmenit i implementaciv desıtkach trıd, ktere dao pouzıvajı, coz odporuje prvnı zasade OOP: “Pridavej vlastnost jenna jednom mıste!”.1

Ucel souboru action-servlet.xml a vlastnı konfigurace bean, jak vidıme v prıkladu,resım v kapitole 2.2.6.

2.2.5.1 Dependecy lookup

Navrhovy vzor IoC muzeme rozdelit do dvou technik, prvnı z nich je dependecy lookup.Je to navrhovy vzor, pomocı nehoz objekt zada kontejner o beanu. Toto resenı bylo pouzitov EJB 2.X v technologii JNDI, kdy pozadovana beana musela implementovat API specifickepro dany kontejner. Evoluce ukazala, ze toto nenı nejvhodnejsı resenı. Spring jej pouzıva prozıskanı beany “z ruky”.

XmlBeanFactory beanFactory = new XmlBeanFactory("action-servlet.xml");DemandService demandService = (DemandService) beanFactory.getBean("demandService");

2.2.5.2 Dependecy injection

Druhou technikou IoC je navrhovy vzor dependecy injection, ktery resı samotne na-stavenı a nainjektovanı potrebnych objektu a jejich zavislostı. Vlastnı vlozenı zavislostı muzeprobıhat pomocı

Setter injection - Nainjektovanı zavislostı pomocı JavaBeans setteru. Prıklad je uveden vkapitole 2.2.5.

Constructor injection - Nainjektovanı zavislostı pomocı konstruktoru.

public class SampleContollerWithIoC implements Controller {private UserDAO dao = null;public SampleContollerWithIoC(UserDAO userDAO) {

this.dao = userDAO;}public ModelAndView handleRequest(HttpServletRequest request,

HttpServletResponse response) throws Exception {

1V takto jednoduchem prıkladu to samozrejme lze obejıt, vyvojar komponenty dao by byl nucen provestzmenu s ohledem na kompatibilitu, kazdopadne je to problem, do ktereho se nemusıme dostat.

Page 22: Internetove technologie na platforme Java

8 KAPITOLA 2. RESERSE

List users = dao.getUsers();return new ModelAndView("userList", "users", users);

}}

action-servlet.xml

<bean id="sampleController" class="SampleContollerWithIoC"><constructor-arg ref="userDAO"/>

</bean>

Method injection - Pouzitı pro specialnı prıpady, pro netrivialnost zde neuvedu prıklad.2

Mezi dalsı typ dependecy injection, ktery Spring avsak nepodporuje, patrı Interfaceinjection, na kterem je zalozen kontejner frameworku Avalon. Nejpouzıvanejsı je metoda Setterinjection, nejcasteji z techto duvodu:

• je jednodussı pracovat s defaultnımi hodnotami properties daneho objektu,

• pomocı getteru zıskame okamzite hodnotu dane property,

• settery mohou byt v prıpade potreby volany vıcekrat, coz konstruktor byt nemuze,

• gettery/settery jsou zdedeny na rozdıl od konstruktoru jako klasicke metody.

2.2.6 Rozhranı BeanFactory a ApplicationContext

2.2.6.1 BeanFactory

BeanFactory je ustrednı castı celeho frameworku, rıdı zivotnı cyklus, konfiguraci avlastnı injektaci vsech bean. Kontejner startuje podle nasazenı aplikace, napr. na aplikacnımserveru pomocı definice v deployment deskriptoru web.xml nebo v JUnit testovacı sade pomocıpripravenych startovacıch API, muzeme ho take samozrejme nainicializovat rucne, jak jsmevideli v kapitole 2.2.5.1.

Manageovany objekt muze byt jakykoliv, v teto souvislosti se mluvı o tzv. POJO, coz vprekladu znamena stary dobry java objekt. Je to jakykoliv objekt, ktery nenı nucen dodrzovatimplementacnı omezenı dane platformy. Vlastnı konfigurace vzajemnych vztahu bean muzemedefinovat pomocı:

• XML - nejcastejsı a nejprehlednejsı zapis, oddeluje konfiguraci od vlastnıho pouzitı,

• anotacı - podobne jako EJB, je konfigurace zapsana v POJO,

• JavaBean properties,

• Jakarta Commons atributes.

Pokud vyuzıvame XML konfigurace, mame minimalne jeden korenovy konfiguracnı sou-bor, nazveme jej napr. applicationContext.xml, na ktery ve webovem nasazenı ukazuje de-poloyment descriptor.web.xml

2Pokud chceme nainjektovat beany s ruznymi scopy (viz. 2.2.6.2), nevystacıme si s setter injection, ctenareodkazuji na referencnı dokumentaci Springu [13].

Page 23: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 9

<?xml version="1.0" encoding="UTF-8"?><web-app><!-- Context Configuration locations for Spring XML files --><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/applicationContext.xml</param-value>

</context-param>

<!-- Base dispacher’s servlet mapping --><servlet><servlet-name>action</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/action-servlet*.xml</param-value>

</init-param><load-on-startup>1</load-on-startup>

</servlet><servlet-mapping><servlet-name>action</servlet-name><url-pattern>*.html</url-pattern>

</servlet-mapping></web-app>

Krome korenoveho aplikacnıho kontextu3 nadefinujeme servlet, ktery se vzdy stara o je-den typ pozadavku (v nasem prıpade o vse s prıponou .html), ktere zpracovava DispacherServlet.Podrobneji je tomu venovana kapitola 2.2.7.4. Jelikoz budu mluvit o jedne jedine konfiguraci,budu ApplicationContext.xml a action-servlet.xml vedome zamenovat.

Vıme, kam zapsat XML konfigurace, aby se automaticky nacetly, podıvame se ted’ nazakladnı syntaxi. Hodnotu do property dane beany muzeme zapsat bud’to rovnou,

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="

http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean id="bean" class="SampleBean"><property name="property" value="value"/>

</bean></beans>

nebo odkazem na jinou beanu.

<bean id="bean" class="SampleBean"><property name="property" ref="bean2"/>

</bean>

<bean id="bean2" class="SampleBean2" />

2.2.6.2 Zivotnost beany

3Nic nam nebranı mıt korenovych konfiguracnıch souboru vıce, v tagu <param-value/> muze byt regularnıvyraz.

Page 24: Internetove technologie na platforme Java

10 KAPITOLA 2. RESERSE

Kazda beana ma z hlediska konverze IoC kontejneru s klientem svoji zivotnost (oborviditelnosti), ktere rıkame scope. Krome definice zavislostı beany, Spring jednoduse dovoluje sizvolit i jejı scope. Od verze 2.0 muzeme vytvaret beany 5ti (resp. 6ti) scopu.

• sigleton - existuje jen jedna instance, ktera se vytvorı pri prvnı injekci, u dalsıch seinjektuje tato,

• prototype - pro kazdou injektaci se vytvorı nova instance,

• request - beana platı po dobu HTTP requestu,4

• session - beana platı po dobu HTTP session,

• global session - beana platı po dobu HTTP global session,

• custom - pokud potrebujeme nestandardnı resenı, Spring dovoluje definovat vlastnı.

prototype

Defaultne se vzdy pouzije singleton. Je to logicke, ve vetsine prıpadu nas stav beany ne-zajıma a plne si s tım vystacıme, pokud ale potrebujeme vytvaret pokazde nove instance,tj. chceme zohlednovat stav beany, musıme uvest explicitne parametr scope.

<bean id="bean3" class="SampleBean3" scope="prototype" />

web scopes

Jako prıklad uvedu nasledujıcı beany:

<bean id="loginAction" class="LoginAction" scope="request"/><bean id="userPreferences" class="UserPreferences" scope="session"/><bean id="userPreferences" class="UserPreferences" scope="globalSession"/>

Po kazdem HTTP requestu se vytvorı nova instance beany loginAction, zatımco intuitivnebeana userPreferences ma mıt platnost po celou dobu relace.

Ve vetsıne prıpadu ve webove aplikaci si pri definici bean vystacıme pouze s prvnımidvema standardnımi scopy. Pokud potrebujeme nainjektovat beanu s webovym (nebocustom) scopem do beany se standardnım scopem, musıme k tomu pozıt chytreho objektu- proxy, ktery nainjektovanou beanu zastupuje. Pri volanı metody beany proxy zıskaobjekt ze scopu a deleguje jejı volanı.

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"><aop:scoped-proxy/>

</bean>

<bean id="userService" class="com.foo.SimpleUserService"><property name="userPreferences" ref="userPreferences"/>

</bean>

K webovym scopum vsak nejcasteji pristupujeme jako ke kontejnerum, do kterychukladame objekty (a z nich vybırame) programove. Tuto praktiku ukazuji spolu s SWFscopy v kapitolach 2.2.7.5, 2.2.8.5.

4Tyto 3 tzv. webove scopy majı smysl pouze ve webove aplikaci s pouzitım webove implementaceApplicationContextu - s XmlWebApplicationContext.

Page 25: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 11

2.2.6.3 Typove konverze

Typova konverze je zpusob prevodu hodnot zapsanych v XML deskriptoru na realneobjekty. Chteli bychom naprıklad zapsat neco jako

<bean id="bean" class="SampleBean"><property name="measure" value="90/60/90"/>

</bean>

public Class SampleBean {private Measure measure;public Measure getMeasure() { return measure;}public void setMeasure(Measure measure) {this.measure=measure;}

}

Spring nam nabızı moznost implementace Property editoru, na ktery se kontejner obratıv prıpade, ze v setteru narazı na dany typ, ktery neumı automaticky dosadit.

public class MeasurePropertyEditor extends java.beans.PropertyEditorSupport {@Overridepublic void setAsText(String measure) throws IllegalArgumentException {

try {//set data from String to valuesetValue(value);

} catch (NumberFormatException e) {throw new IllegalArgumentException();

}}

}

Implementaci metody setAsText nechavam na ctenari. Krome nı existuje inverznı metodagetAsText(). Property editor zaregistrujeme naprıklad do beany customEditorConfigurer, kte-rou umıstıme na viditelne mısto z ApplicationContextu.

<bean id="customEditorConfigurer"class="org.springframework.beans.factory.config.CustomEditorConfigurer">

<property name="customEditors"><map><entry key="Measure">

<bean class="MeasurePropertyEditor" /></entry>

</map></property>

</bean>

2.2.6.4 Autowiring

Ohledne Spring IoC kontejneru stojı za to zmınit jeste jednu zajımavou vlastnost -autowiring.

<bean id="bean" class="SampleBean" autowire="byName" />

Tım rekneme Sprigu, aby se pokusil automaticky vyresit zavislosti injektovanych beansam, bez nutnosti je explicitne uvadet. Hodnota v parametru autowire muze nabyvat nejcastejinasledujıcıch hodnot:

• no - zadny autowiring,

Page 26: Internetove technologie na platforme Java

12 KAPITOLA 2. RESERSE

• byName - Spring hleda ve svem ApplicationContextu beanu, podle jmena JavaBean pro-perty,

• byType - Spring hleda beanu podle typu JavaBean property, funguje pouze pokud se vbeane nevyskytuje vıce properties stejneho druhu.

2.2.6.5 ApplicationContext

Rozhranı ApplicationContext obaluje BeanFactory a rozsiruje jejı funkcionalitu o inter-nacionalizaci, publikovanı udalostı nebo nahravanı zdroju. Ukazi na prıkladu internacionalizaci,resp. pouzitı souboru .properties, kde uvadıme k danemu klıci jeho hodnotu.Sample.properties

bean.value = someOtherValue

Kdekoliv v nası XML konfiguraci tyto promenne muzeme pomocı Expression Language5

pouzıt, naprıklad takto.

<bean id="bean" class="SampleBean"><property name="property" value="${bean.value}"/>

</bean>

Vse bude fungovat, pokud doplnıme ApplicationContext o beanu

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="locations"><list><value>classpath:Sample.properties</value>

</list></property>

</bean>

2.2.7 Spring Web MVC

V teto kapitole predstavım webove frameworky, vysvetlım cestu, jak jsme se k nimdostali a ukazu Springovskou implementaci weboveho frameworku Spring Web MVC. Jakovsechny modernı webove frameworky je Spring MVC, jak uz jeho nazev napovıda, zalozen nanavrhovem vzoru Model View Controller.

2.2.7.1 Navrhovy vzor MVC

Z historickeho pohledu se pred nastupem JSP pouzıvaly pouze servlety, s nimiz sevysledny HTML vystup generoval obtızne. Z dnesnıho pohledu je tento zpusob vhodny jen pronejjednodussı prıpady.

Pri prıchodu specifikace JSP 1.0 byla zvolena architektura tzv. Model 1, kdy je HTTPpozadavek delegovan prımo na prıslusnou JSP stranku, v nız je umısten veskery kod pomocıskriptletu.6 Tento prıstup se dnes oznacuje termınem “spagetovy kod”, postradame tu jakekoliv

5EL se primarne pouzıva pro vyhodnocovanı vyrazu na JSP strankach, pro prıstup k hodnotam z CommandObjektu a podobne.

6Skriptlet je specialnı tag, v nemz je umısten prımo Java kod <% /*java code here*/ %>.

Page 27: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 13

Obrazek 2.4: Navrhovy vzor MVC, zdroj: [15]

rozdelenı do vrstev, centralizovany prıstup HTTP pozadavku a potencialnı moznost rozsırenıaplikace.

Specifikace JSP 1.1, krome prıstupu psanı logiky aplikace pomocı tagu, prinesla imple-mentaci navrhoveho vzoru MVC (obrazek 2.4), kterou oznacujeme jako Model 2.

Obrazek 2.5: MVC implementace JSP Model 2, zdroj: [1]

MVC slouzı k oddelenı aplikacnı, prezentacnı logiky a datoveho modelu. Nenı pouzitjen ve webovych frameworcıch, ale naprıklad v desktopovych aplikacıch u knihoven Swing aSWT. Jeho koreny muzeme najıt ve Smalltalku, kdy byl puvodne pouzit pro zakomponovanıklasickeho postupu vstup-zpracovanı-vystup do GUI programu.

• Controller - prostrednık mezi vrstvami Model a View

• Model - predstavuje vlastnı data zobrazovana ve View

• View - transformuje Model do prezentacnı podoby

Jelikoz HTTP protokol je typu request/response, tedy bezestavovy, nemuzeme zde apli-kovat typicky MVC pattern. Model 2 je upravene MVC schema, kdy jediny rozdıl spocıva vtom, ze View nemuze volat Controller.

Vzajemnou interakci si muzeme predstavit tak, ze klient posle pozadavek na webovyserver, ten je vzapetı delegovan na servlet, ktery predstavuje controller, servlet zavola aplikacnı

Page 28: Internetove technologie na platforme Java

14 KAPITOLA 2. RESERSE

logiku, ze ktere zıska model, ten zaregistruje do scopu viditelneho z JSP, ktere predstavuje view.Nasledne provede presmerovanı na View a posleze na JSP, ktere si vyzvedne data ze scopu aten vysledek zobrazı.[15]

V prostredı webu existuje nekolik implementacı, ktere odpovıdajı navrhovym vzorum:

• Front Controller (Service to worker) - frameworky Struts, Spring Web MVC, WebWork,Ruby on Rails

• Dispacher view (View helper) - frameworky JSF-based (JSF, Seam, Shale), Tapestry,Wicket, Echo2

Rozdıl mezi prıstupy je v okamziku volanı aplikacnı logiky. V prıpade Front Controlleruse aplikacnı logika vola pred predanım zpracovanı do View, zatımco u Dispacher View se volaaplikacnı logika uvnitr View pomocı View Helperu[3].

2.2.7.2 Rozdelenı webovych frameworku

Nejdulezitejsı roli hraje uroven abstrakce nad protokolem HTTP. Cım vetsı je uroven abstrakce,tım mene se musı jednotlive vrstvy starat o samotny protokol. Takto delıme webove frameworkydo dvou skupin

• Pozadavkove orientovane (Request based) - zalozene na Front Controlleru,

• Komponentove orientovane (UI component based, event-based) - zalozene na View Hel-peru.

Budoucnost patrı komponentove orientovanym webovym frameworkum. Ty umoznujıvyvojari pracovat na urovni UI komponent a udalostı, tedy stejne jednoduse jako s dalsıminapr. s desktopovymi frameworky (Swing, SWT). Snadno naprıklad vytvorıme RAD nastrojpro WYSIWYG editaci webove aplikace.

2.2.7.3 Architektura

Obrazek 2.6: Architektura aplikace ve Spring MVC, zdroj: [20]

Architektura aplikace ve Spring Web MVC je rozdelena do navzajem nezavislych vrstev,jak vidıme na obrazku 2.6.

User Interface - prezentacnı vrstva, stara se o generovanı vystupu k uzivateli (nejcastejiXHTML), vetsinou pouzito JSP, ke kteremu existujı implementace rozhranı View

Page 29: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 15

org.springframework.web.servlet.view.JstlView. Jako prıklad si uvedeme jednodu-chou JSP stranku.7

SampleJSP.jsp

<?xml version="1.0" encoding="UTF-8" ?><html><body>

<c:choose><c:when test="${1 + 1 == 10}">

we count in binary base</c:when><c:otherwise>

we don’t count in binary base</c:otherwise>

<c:choose></body></html>

Web - webova vrstva resı prechody mezi strankami a odstinuje servisnı vrstvu od vlastnıimplementace. Hlavnı rozhranı v teto vrstve je Controller.

• AbstractController - zakladnı abstraktnı kontroler

• BaseCommandController,AbstractCommandController - pracuje s Command Ob-jectem, tj. objekt, do ktereho namapujeme vstupnı hodnoty z hodnot zıskanychHTTP requestu, ten pak pouzıvame ve View vrstve

• SimpleFormController,AbstractSearchController - umoznuje naprıklad prechodymezi jednotlivymi obrazovkami pomocı reakce na vysledek metody

• MultiActionController - umoznuje reagovat na vıce typu HTTP requestu, de-faultne se metoda obsluhujıcı danou namapovanou stranku jmenuje stejne jak tatostranka

• UrlFilenameViewController - pomocı namapovane stranky zobrazı JSP se stejnymjmenem

Prıklad na takovy jednoduchy kontroler je uveden hned v kapitole 2.2.5.

Service - V teto vrstve se nachazı implementace danych byznys requirementu, jako jedina maprıstup k perzistentnı vrstve. Jelikoz je tato vrstva obvykle v kazde aplikaci jina, Springk nı nenabızı zadne rozhranı. Jako prıklad ukazu rozhranı IUserService

public interface IUserService {public boolean isLoginFree(String login);public AbstractUser getUser(String login);public boolean saveUser(AbstractUser user);

}

Persistence - Perzistentnı vrstva implementuje ukladanı,nahravanı a praci s objekty datovehomodelu z databaze. Nejcasteji implementuje metody CRUD (create,retrieve,update,delete).Spring ve svem ORM modulu dovoluje pouzıt deklarativnı transakce imlementovane po-mocı AOP nebo zaobaluje mene citelne vyjımky do citelnejsıch. Spoluprace s Hibernateframeworkem je hlavne docılena pomocı trıd

• HibernateTemplate

7Uvedene tagy zacınajıcı XML namespacem c nebo ftm jsou soucastı knihovny JSTL, kde jsou definovanyzakladnı tagy pro vetvenı kodu, zobrazovanı, iterace, definovanı a pouzıvanı promennych nebo pro formatovanıtextu.

Page 30: Internetove technologie na platforme Java

16 KAPITOLA 2. RESERSE

• HibernateDaoSupport

Jako prıklad zde uvedu rozhranı IOfferDao. Ukazku deklarativnıch transakcı spolu s im-plementaci rozhranı IOfferDao si ukazeme v kapitole 2.3.8.1.

public interface IOfferDao {void saveOrUpdate(Offer offer);Offer getOfferById(long id);Offer getOfferBy(Inzerent inzerent);void delete(Offer offer);List<Offer> getTopItems(int maxResult);

}

Domain model - datovy model, soubor tzv. Bussiness Object u, ktere abstrahujı entity zdomenoveho modelu do programu, ktery s nimi pracuje, nakonfigurovanych pro O/Rmapovanı danym perzistentnım nastrojem. Ukazeme si jednoduchy prıklad se zapisempomocı JPA anotacı.

Inzerent.java

@Entitypublic class Inzerent extends AbstractUser {

private String firstName = "";private String lastName = "";private String telephone = "";//appropriate getters and setters

}

Podrobneji se teto problematice venuji v kapitole 2.3.

2.2.7.4 Dispacher servlet

DispacherServlet je Front Controller, jak jsem ukazal v kapitole 2.2.7.1. Nynı si ukazemejednoduchy prıklad, kde dame vse probrane v teto kapitole do kontextu. V deployment deskrip-toru jsme nadefinovali pro vsechny prıstupy na *.html obsluhu servletu action, jemuz odpovıdakonfigurace action-servlet.xml8, jak je uvedeno v kapitole 2.2.6. V action-servlet.xml nadefinu-jeme:

<bean id="urlMapping"class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="alwaysUseFullPath" value="true" /><property name="mappings">

<props><prop key="/sample-web-page.html">sampleController2</prop>

</props></property>

</bean>

<bean id="sampleController2" class="SampleController2"><property name="view" value="sampleJSP" />

</bean>

8Podle jmena servletu “action” se prida automaticky “-servlet”.

Page 31: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 17

Tedy kazdy pozadavek o sample-web-page.html bude zpracovavat beana sampleCont-roller2, ta ma “nasetovanu” JSP stranku9, ktera se ve vysledku zobrazı. Implementace trıdySampleController2 bude velmi podobna prıkladu SampleContollerWithIoC u kapitoly 2.2.5.

public class SampleContoller2 implementsorg.springframework.web.servlet.mvc.Controller {

private String view;public void setView(String view) {

this.view = view;}public ModelAndView handleRequest(HttpServletRequest request,

HttpServletResponse response) throws Exception {return new ModelAndView(view);

}}

Pokud potrebujeme jen jednoduse podle pozadavku na sample-web-page.html zobrazitjen JSP stranku a nic jineho, tak k tomu pouzijeme kontroler UrlFilenameViewController,ktery hleda View a posleze JSP se stejnym jmenem jako je html pozadavek. V prıkladu bystacilo zmenit odpovıdajıcı kontroler.

<bean id="urlFilenameViewController"class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />

2.2.7.5 Webove scopy

Jak jsem zmınil v kapitole 2.2.6.2, casteji k webovym scopum pristupujeme jako kekontejnerum pro data, jez majı byt viditelna v ramci nami definovaneho scopu.

• Request - platnost jen v prubehu jednoho HTTP pozadavku, v requestu prichazı para-metry z HTTP GETu,

• Session - platnost v prubehu HTTP session,

• Global session - platnost v prubehu HTTP global session,

Zakladnı moznosti prace uvadım v nasledujıcım prıkladu, naprıklad s pomocı trıdyorg.springframework.web.context.request.DispatcherServletWebRequest.

HttpServletRequest request; //gets as method parameterHttpSession session = request.getSession();DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request);

Integer id = (Integer) request.getParameter("id");id = (Integer) webRequest.getAttribute("id", RequestAttributes.SCOPE_REQUEST);

session.setAttribute("string", id.toString());webRequest.setAttribute("string", id.toString(),

RequestAttributes.SCOPE_SESSION);

webRequest.setAttribute("string", id.toString(),RequestAttributes.SCOPE_GLOBAL_SESSION);

9V tomto jednoduchem kontextu si muzeme predstavit naprıklad tu, jez jsem ukazal v kapitole 2.2.7.3.

Page 32: Internetove technologie na platforme Java

18 KAPITOLA 2. RESERSE

2.2.8 Spring Web Flow

Spring Web Flow je mocny nastroj pro definici toku obrazovek ve webove aplikaci.Snadno resı problemy, ktere konvencnı prıstup resı velmi neefektivne. Hlavnı idea spocıva vklıcove abstrakci konverzace mezi uzivatelem a serverem - ve flow. Flow je neco vıce nez jed-notlivy pozadavek, neco mene nez cela session. Jedine flow rıdı celou konverzaci, kdyz se oduzivatele ocekava nejaky vstup, flow je pozastaveno a ceka na uzivateluv vstup. Klient ovladakonverzaci pomocı udalostı, podle kterych se flow rozhoduje, co udelat dal.

2.2.8.1 Struktura

Definice flow nenı nic jineho nez konecny automat s pocatecnım stavem, mnozinoustavu, ve kterych se muze nachazet, mnozinou konecnych stavu a vlastnımi prechody do dalsıchstavu. Takovyto zapis provadıme bud’to do XML souboru nebo do java kodu (pouzitı prispecialnıch prıpadech a napojenıch na dalsı systemy). Pro zacatek zde uvedu uvodnı zapis,ve kterem flow konfigurujeme.sample-flow.xml

<?xml version="1.0" encoding="UTF-8"?><flow xmlns="http://www.springframework.org/schema/webflow"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/webflowhttp://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">

</flow>

2.2.8.2 Stavy

Start State - Pocatecnı stav, jako u kazdeho automatu je prave jeden. Parametr idref odkazujena jiny stav.

<start-state idref="actionState" />

End State - Koncovy stav, pokud je ve flow na nejvyssı urovni, ukoncı se jeho provadenı,zresetujı se vsechny promenne.

<end-state id="endState" />

View State - Stav, ve kterem dochazı k vykreslenı zadaneho obsahu.

<view-state id="viewState"><transition to="actionState" />

</view-state>

Action State - Stav, ve kterem dochazı k nejake akci, tj. zavolanı metody dane beany aobvykle podle navratu nasleduje prechod do jineho stavu.

<action-state id="actionState" ><action bean="actionBean" method="sampleAction" /><transition to="decisionState" />

</action-state>

Decision State - Stav, urceny k vetvenı logiky, testuje podmınku, podle ktere prejde dodalsıho stavu.

Page 33: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 19

<decision-state id="decisionState" ><if test="requestParameters.id gt 0" then="viewState" else="subflowState"/>

</decision-state>

SubFlow State - Do flow muzeme vnorit jine flow jako subflow a pomocı koncoveho stavudaneho subflow reagovat a prejıt dle logiky aplikace. Vhodne pokud se urcite sekvencestavu a prechodu opakujı ve vıce flow.

<subflow-state id="subflowState" flow="inner-flow"><transition on="ok" to="viewState" /><transition on="cancel" to="endState"/>

</subflow-state>

2.2.8.3 Vyhody

Za hlavnı vyhody SWF muzeme bezpochyby oznacit:

• oddelenı navigace od vlastnıho kodu,

• automaticke rızenı stavu aplikace,

• vyssı uroven abstrakce,

• dovoluje volat metody strednı vrstvy bez nutnosti pouzitı kontroleru.

2.2.8.4 Nevyhody

Spring Web Flow nemuzeme pouzıt tam, kde kvuli velke praci, nez se zprovoznı jenjedna jedina obrazovka, se nam jej nevyplatı nasadit. Avsak po urcite velikosti a slozitostiprechodu mezi strankami v aplikaci tato nevyhoda pada.

2.2.8.5 Scope

Stejne jako webove scopy ve Spring Web MVC, existujı ve SWF podobne kontejnery proulozenı jakychkoliv kratkodobych dat. Pristupuje se k nim pres rozhranı Map pomocı instancetrıdy RequestContext.SampleFormAction.java

public org.springframework.webflow.EventsampleAction(org.springframework.web.servlet.support.

RequestContext context) {

Object object = context.getXXXScope().get("key");context.getXXXScope().put("key",object);

context.getExternalContext().getRequestMap().put("key",object);Object object = context.getExternalContext().getSessionMap().get("key");context.getExternalContext().getGlobalSessionMap().put("key",object);context.getExternalContext().getApplicationMap().put("key",object);

return success();}

kde za XXX dosadıme jeden za 4 scopu pouzitelnych ve SWF:

• request - majı platnost pouze pro dany pozadavek,

Page 34: Internetove technologie na platforme Java

20 KAPITOLA 2. RESERSE

• flash - platı dokud uzivatel neopustı aktualnı stav,

• flow - platı pro cele flow,

• conversation - platı po dobu zivotnosti materskeho flow.

Na prıkladu vidıme, ze pomocı trıdy RequestContext mame prıstup i ke klasickymwebovym scopum predstavenym v kapitole 2.2.7.5, s tım rozdılem, ze k nim pristupujeme jakok mape. Poslednı dosud nepredstaveny je application scope, ktery platı v prubehu chodu celeaplikace.

Nutno poznamenat, ze data v jakemkoliv scopu, krome singletonu, nejsou viditelnavsemi uzivateli dohromady.

2.2.8.6 Syntax

<transition/> - Definujeme prechod do jineho stavu, parametry on, to, on-exception. Pa-rametr to je povinny. Pokud provadıme ve stavu vıce akcı, prechod muzeme podmınitvysledkem prave jedne metody.

<action-state id="actionState" ><action bean="actionBean" method="sampleAction" /><action bean="actionBean" method="sampleAction2" /><transition on="sampleAction.success" to="decisionState" /><transition on-exception="exception" to="endState" />

</action-state>

<global-transitions/> - Vhodne pouzıt, pokud se prechody v kazdem stavu z flow opakujı.

<global-transitions><transition on="globalEvent1" to="state1"/><transition on="globalEvent2" to="state2"/>

</global-transitions>

<xxx-actions/> - Pomocı tagu definujeme akce:

• <start-actions/> - akce se provedou po vstupu do flow,

• <end-actions/> - akce se provedou pred koncem flow,

• <entry-actions/> - akce se provedou po vstupu do stavu,

• <exit-actions/> - akce se provedou pred koncem stavu,

• <renderer-actions/> - akce se provedou pred vlastnım renderovanım ve viewState.

<xxx-mapper/> - Tagem definujeme mapovanı do flow/z subflow:

• <input-mapper/> - vstupnı mapovanı,

• <output-mapper/> - vystupnı mapovanı.

Pokud chceme v subflow pristoupit k datum z nadrazeneho flow, mame 2moznosti, jak toho dosahnout. Prvnı moznostı je pouzıt conversation scope, ktery je vsubflow viditelny. Tımto ale dana data zviditelnıme i pro vsechny ostatnı subflow. Dalsımoznostı je pouzıt mapovanı atributu. V hlavnım flow definujeme:

Page 35: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 21

<subflow-state id="sampleSubflow" flow="sample-flow"><attribute-mapper>

<input-mapper><mapping source="flowScope.number" target="number"/>

</input-mapper><output-mapper>

<output-attribute name="result"/></output-mapper>

</attribute-mapper><transition to="decisionState"/>

</subflow-state>

Zapisem <mapping source="flowScope.number" target="number"/> vezmemepromennou number ulozenou ve flow scope a predame jı pomocı input-mapperu dosubflow. Zapisem <output-attribute name="result"/> zıskame promennou result zoutput-mapperu a predame jı do flow scope tohoto flow. V subflow je ovsem musımedefinovat take:

<flow><input-mapper>

<input-attribute name="number"/></input-mapper>

... some logic

<end-state id="finish"><output-mapper>

<output-attribute name="result"/></output-mapper>

</end-state></flow>

Zapisem <input-attribute name="number"/> zıskame pomocı input-mapperupromennou number do flow scope, zapisem <output-attribute name="result"/> umıstenymv koncovem stavu mapujeme promennou result z flow scope do output-mapperu.

redirect - Pokud chceme nasilne presmerovat tok aplikace, prevazne pouzijeme jeden ze dvouhlavnıch prıstupu:

• flowRedirect - presmerovanı na jine flow,

• externalRedirect - presmerovanı na kompletne jiny HTTP pozadavek10.

<end-state id="finish" view="flowRedirect:sampleFlow"/><end-state id="finish" view="externalRedirect:sample-web-page.html"/>

Pro kompletnı prehled syntaxe a praci s SWF odkazuji ctenare na referencnı dokumen-taci SWF. [14]

10Rozdıl je samozrejme ten, ze ve druhem prıpade se postupuje k dispacher servletu, zatımco prvnı prıpadzustava ve flowControlleru.

Page 36: Internetove technologie na platforme Java

22 KAPITOLA 2. RESERSE

2.2.8.7 Konfigurace

SWF zapojıme do nası aplikace tım, ze pridame nasledujıcı beany do XML deskriptoruSpringu.action-servlet.java

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:flow="http://www.springframework.org/schema/webflow-config"xsi:schemaLocation="

http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/webflow-confighttp://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd">

<bean name="/sample-web-page.html"class="org.springframework.webflow.executor.mvc.FlowController"><property name="flowExecutor" ref="flowExecutor" />

</bean>

<!-- Launches new flow executions and resumes existing executions. --><flow:executor id="flowExecutor" registry-ref="flowRegistry"/>

<!-- Creates the registry of flow definitions for this application --><flow:registry id="flowRegistry">

<flow:location path="/WEB-INF/sample-flow.xml"/></flow:registry>

<!-- All formActions in application --><bean id="formAction" class="SampleFormAction" />

</beans>

Uvedena konfigurace je opravdu zakladnı, pro vetsı pocet stranek a flow se nehodı. Lepsıkonfigurace je uvedena v implementaci portalu www.chcispolubydlici.cz, jehoz zdrojove kodyjsou obsazeny na prilozenem CD.

2.3 Hibernate

Tato cast by mela ctenari osvetlit pouzitı perzistentnı vrstvy ve webove aplikaci.Vysvetlım cestu k ORM frameworkum, jejich dnesnı standard JPA a blıze se podıvame najednu z implementacı - JBoss Hibernate framework.

2.3.1 ORM framework

Z historickeho pohledu existuje vıce prıstupu, jak resit problem s napojenım perzis-tentnı vrtsvy k javovske aplikaci. Problem spocıva v tom, ze zde mame dva prıstupy - OOPprıstup pouzıvany v Jave a relacnı prıstup pouzıvany v relacnıch databazıch.

JDBC - vlastnı implementace perzistentnı vrstvy pomocı JDBC API, zapis SQL dotazu ametod DAO trıd, ktere volajı prıslusne procedury - prılis zdlouhave, dnes v podstateprezitek

Serializace - ukladanı/nacıtanı serializovatelnych hierarchiı objektu do/z souboru nebo DB -pracuje se jen s celymi hierarchiemi - nevhodne

Page 37: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 23

Objektova DB - pouzitı objektoveho databazoveho stroje, neexistuje jedine resenı, ktere byse prosadilo v praxi

EJB 2.x Entity Beany - starsı EJB 2.x specifikace, v 3.0 se preslo k ORM-based JPA

Dlouhou dobu prevladal prvnı zpusob, az do doby, kdy se objevily prvnı ORM nastrojejako Castor a Hibernate. ORM je mapovacı nastroj mezi OOP svetem, kde zakladnı nosic dat jetrıda, vztah mezi objekty je definovan kompozicı a je vzdy jednosmerny, a mezi svetem relacnıDB, kde nosicem dat je tabulka, sloupce definujı atributy entity a vztah (relace) mezi tabulkamije definovan pomocı cizıch klıcu nebo vztahove tabulky a je vzdy obousmerny. ORM mapujetrıdy na tabulky, jejich instance na jednotlive radky tabulky.

2.3.2 JPA

Java Persistence API je dnesnı standard, ktery popisuje zakladnı myslenky ORM. Hibernate3.x byl prepsan, aby odpovıdal tomuto standardu. Jako referencnı implementace byl zvolenframework Oracle Toplink Essentinals. Mezi dalsı hlavnı ORM resenı patrı:

• Oracle Toplink - komercnı

• Apache iBATIS - opensource

• JBoss Hibernate - opensource

Resenı pouzıvajıcı JPA jej berou jako zakladnı balık vlastnostı, budeme-li pouzıvat cistesamotne JPA, teoreticky bychom mohli vymenit jeden ORM framework za jiny bez zmeny jedineradky kodu. JPA bohuzel neresı vsechny problemy a tak jsou frameworky nuceny pouzıvatvlastnı nestandardnı resenı.

2.3.3 Mapovanı

Vlastnı mapovanı z objektu na tabulky zapisujeme v JPA pomocı anotacı. U Hiber-nate se take muzeme setkat se zapisem metadat pomocı XML nebo XDoclet. Zde ukazu jenprvnı zpusob, protoze se jedna o standard. Anotace zapisujeme bud’to pred atribut trıdy, kdeframework pouzıva pro prıstup k polozkam Java Reflection API (gettery/settery nemusı bytvubec implementovany), nebo do getteru JavaBean trıdy, kdy framework pro prıstup pouzıvavolanı getteru/setteru[19]. JavaBeans prıstup je nejcastejsı.

@Entitypublic class Customer implements Serializable {

private Integer id;private String name;@Id@GeneratedValuepublic Integer getId() {return id;}public void setId(Integer id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name;}

}

@Entitypublic class Producer implements Serializable {

private Integer id;private String name;private List<Customer> customers;

Page 38: Internetove technologie na platforme Java

24 KAPITOLA 2. RESERSE

@OneToManypublic List<Customer> getCustomers() {return customers;}public void setCustomers(List<Customer> customers) {this.customers = customers;}@Id@GeneratedValuepublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}

}

2.3.4 Anotace

Mezi zakladnı anotace patrı:

@Entity - vlastnı oznacenı objektu, ktery chceme mapovat

@Id - oznacenı primarnıho klıce

@OneToOne - vyjadrenı vztahu 1 : 1

@OneToMany - vztah 1 : N

@ManyToOne - vztah N : 1

@ManyToMany - vztah M : N

@Transient - metoda (polozka) nebude nijak mapovana

@MappedSuperClass - pro danou trıdu se nevytvarı tabulka, pouzito u abstraktnıch trıd,kdy potomci dedı jejich anotace

@Emeddable - pro danou trıdu se nevytvarı tabulka, polozky trıdy se pripojı k jine jiz exisujıcıtabulce, pomocı nasledujıcı anotace ve vztahu 1 : 1 nebo N : 1 (JPA neumı vztah 1 : N s@Emeddable entitou)11

@Embedded - polozky trıdy @Emeddable se pripojı ke trıde

@Version - oznacenı atributu k optimistickemu zamykanı

Uvedene anotace majı mnoho nepovinnych parametru, ktere zde v uvodu nebudu popi-sovat. Vedle JPA anotacı podporuje Hibernate sve vlastnı @org.hibernate.anotations.xxx,ktere pouzijeme, pokud potrebujeme cokoliv nestandardnıho.

2.3.5 Prace s objekty

JPA pro praci s objekty pouzıva rozhranı EntityManager, s Hibernatem vsak castejipracujeme starsım zpusobem a to pomocı Session.

Jak vidıme na obrazku 2.7, nove vytvoreny objekt, ktery jeste nema v databazi repre-zentaci, je tranzientnı, jeho ID je zatım = 0. Pokud ho ulozıme, prejde objekt do perzistentnıhostavu, tj. stavu, kde se reprezentace objektu v pameti a v databazi shodujı. Pokud objektmenıme v te same session, zmeny se okamzite promıtnou do databaze. Pokud se sessiona zavre,prejdeme do Detached stavu, kdy se obe reprezentace neshodujı. Po ulozenı Detached objektuse stane znovu perzistentnı. Perzistentnı objekt muzeme vymazat, Detached objekt po uzavrenısession putuje do garbage collectoru.

11Hibernate ma pro tento specialnı prıpad anotaci @org.hibernate.annotations.CollectionOfElements

Page 39: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 25

Obrazek 2.7: Stavy objektu a prechody pomocı metod persistent manageru, zdroj: [17]

2.3.6 Dotazy

Velkou vyhodou ORM je, ze dotazy pıseme vuci objektove reprezentaci. Vlastnı relacnıreprezentace nas ve vetsine prıpadu dokonce nezajıma.

2.3.6.1 HQL API

HQL je podobne jako standardnı JPQL urcen k dotazum do databaze. Syntax je po-dobna klasickemu SQL s tım rozdılem, ze se ptame na objekty. Jako prıklad uvedu jednoduchyHQL dotaz.

SessionFactory factory = new Configuration().buildSessionFactory();Session session = factory.openSession();Transaction tx = session.beginTransaction();

Query cutomerQuery = session.find("SELECT Customer FROM Producer AS p " +"WHERE p.customer.name = :customerName", "mira");List<Customer> customers = customerQuery.list();

tx.commit();session.close();

Takovyto kus kodu muzeme pouzıt kdekoliv v aplikaci s nakonfigurovanym Hibernatem.Vsimneme si, jak zıskavame instanci Session a ze sami rıdıme transakce. Takovyto zpusobse oznacuje jako programovy (programmatic). Existuje jeste jiny prıstup k transakcım - dekla-rativnı, ktery ukazuji v kapitole 2.3.8.1.

2.3.6.2 Criteria API

Hibernate vsak podporuje jeste jiny zpusob dotazovanı - Criteria API. Dotazy zapi-sujeme pomocı pridavanı restrikcı k danemu kriteriu. Nasledujıcı prıklad vracı stejny vysledekjako HQL dotaz v minulem odstavci.

SessionFactory factory = new Configuration().buildSessionFactory();

Page 40: Internetove technologie na platforme Java

26 KAPITOLA 2. RESERSE

Session session = factory.openSession();Transaction tx = session.beginTransaction();

Criteria customerCriteria = session.createCriteria(Producer.class);customerCriteria.add(Restrictions.eq("customer.name","mira");List<Customer> customers = customerCriteria.list();

tx.commit();session.close();

Criteria se rozhodne nehodı na vsechno. Jsou dotazy, ktere pomocı kriteriı zapsatnejdou. Na druhou stranu jsou dotazy, ktere pomocı HQL vypadajı slozite, a s kriterii jdouzapsat velmi snadno.

2.3.7 Lazy, Eager loading

Hibernate podporuje vyznamnou optimalizaci databazovych dotazu tım, ze mısto ob-jektu samotneho vracı tzv. dynamickou proxy. Proxy je potomek dane trıdy, ktery je vytvarenv runtimu pomocı frameworku CGLIB. Proxy realizuje odlozene nahravanı polozek v objektu,od ktereho dedı. Pokud objekt obsahuje reference na dalsı objekt, tato data se v dotazu nevratı.Defaultne je vybrana prave tato strategie. Problem nastava v prıpade, ze chceme pristoupit kproperties proxy v dobe, kdy se uz zavrela hibernate Session.

Opakem teto strategie je Eager loading, pomocı ktere se nahrajı property do objektuvraceneho v dotazu. Strategii zapisujeme pro kazdou property v entite pomocı parametru kanotaci fetch = FetchType.EAGER. Tohoto se da vyuzıt jen v jednoduchych dotazech, kterevracı prımo databazove sloupce (polozky).

Dalsı moznostı jak “doloadovat” property k proxy je znovu tento objekt nahrat doaktualnı session pomocı metody refresh(). Existuje jeste jiny zpusob, ktery by se nemelzneuzıvat, pouzıt statickou metodu Hibernate.initialize(proxy), kterou zavolame bez-prostredne po dotazu v te same session.

2.3.8 Integrace se Springem

Spring nabızı velke kvalitativnı zlepsenı prace s Hibernatem. Jak jsem psal v kapitole2.2.7.3, jsou k tomu urceny trıdy

• org.springframework.orm.hibernate.HibernateTemplate

• org.springframework.orm.hibernate.support.HibernateDaoSupport

2.3.8.1 Deklarativnı transakce

V programovem prıstupu k transakcım se stale opakuje ten samy kod - zıskatsession, otevrıt session, vytvorit transakci...potvrdit transakci, uzavrıt session. Vse resı trıdaHibernateDaoSupport, kdy tento kod provadı pred a po jakekoliv metode v jeho potomkovipomocı Spring AOP.

Pri pouzitı Hibernatu v prostredı webu se nejcasteji vyuzıva navrhoveho vzoru OpenSession in View, kdy je Hibernate session otevrena po celou dobu HTTP requestu. Jiny prıstupje, ze v kazde volane metode se otevıra session nova. Open Session in View resı problem s lazyloadingem, kdy se tyto properties do proxy doloadovavajı pri renderovanı view.12

Nynı mame dostatecne znalosti k tomu napsat implementaci rozhranı IOfferDao.12Avsak pokud nacteme objekt z databaze pri jednom requestu, ale pouzijeme ho v jinem requestu (v jine

session), musıme ho rucne do aktualnı session nahrat.

Page 41: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 27

public class OfferHibernateDao extends HibernateDaoSupport implements IOfferDao {public void saveOrUpdate(Offer offer) {

getHibernateTemplate().saveOrUpdate(offer);}public Offer getOfferById(long id) {

return (Offer) getHibernateTemplate().get(Offer.class, id);}public Offer getOfferBy(Inzerent inzerent) {

List offers = getHibernateTemplate().findByNamedParam("from Offer as offer" +"where offer.inzerent.id = :userId ", "userId", inzerent.getId());

return (Offer) offers.get(0);}public void delete(Offer offer) {

getHibernateTemplate().delete(offer);}public List<Offer> getTopItems(int maxResults) {

DetachedCriteria criteria = DetachedCriteria.forClass(Offer.class);criteria.addOrder(Order.desc("updated"));return getHibernateTemplate().findByCriteria(criteria, 0, maxResults);

}}

2.4 Extremnı programovanı

Extremnı programovanı nebo zkracene XP je odlehcena disciplına vyvoje softwaru.Jako jednu z agilnıch metodik jı muzeme popsat manifestem agilnıho prıstupu[10], kdy

• ma fungujıcı software prednost pred obsahlou dokumentacı,

• majı individuality a interakce prednost pred procesy a nastroji,

• ma spoluprace se zakaznıkem prednost pred sjednavanım smluv,

• a nakonec reakce na zmenu ma prednost pred plnenım planu.

XP se navrhuje nasadit na projektove tymy o mensı az strednı velikosti, ktere potrebujıvyvıjet software rychle a v prostredı, kde se casto menı zakaznıkovy pozadavky.

2.4.1 Historie

XP vytvoril roku 1996 v prubehu sveho projektu pro firmu Chrysler Kent Beck, poprvevec publikoval spolu s Erichem Gammou v knize Extreme Programming Explained roku 1999.Kvuli tomu, ze obracelo sw vyvoj “naruby”, se XP stalo velmi popularnı.

2.4.2 Role

Z hlediska XP rozdelujeme vsechny zainteresovane osoby do jedne ze trı zakladnıchrolı[9], ktere mohou (ale nemusı) odpovıdat prımo jednotlivym osobam.

• Zakaznık - Pıse, vyklada uzivatelske prıbehy, muze a nemusı byt koncovy uzivatel.

• Programator - Odhaduje cas potrebny na implementaci uzivatelskych prıbehu, implemen-tuje testy a produkcnı kod.

• Tester - Implementuje funkcnı, integracnı testy.

Page 42: Internetove technologie na platforme Java

28 KAPITOLA 2. RESERSE

Obrazek 2.8: Prubeh vyvoje v XP

2.4.3 Zakladnı postupy

Celou metodiku muzeme v podstate shrnout do nasledujıcıch 12ti extremnıch prıstupu.Cast z nich klidne uplatnıme i pokud pracujeme sami.

2.4.3.1 Planovacı hra

Zakaznık pripravuje uzivatelske prıbehy (user stories, podobny vyznam jako use case),ktere zakaznık po konzultaci s programatory rozdelı do jednotlivych iteracı (release planning).Casto jsou k tomu pouzity CRC karty (CRC cards, story cards), coz jsou papırove kartickytak o velikosti vizitky, kde na kazde z nich je jeden uzivatelsky prıbeh. Programatori pomocınich odhadnou pribliznou casovou slozitost implementace uzivatelskeho prıbehu (lepsı pouzıvatsofistikovanejsı sw nastroj - tracker). Zakaznık rozhodne, ktere prıbehy majı pro nej vetsı byznyshodnotu a tak rozhoduje, ve ktere iteraci je chce videt.

2.4.3.2 Male iterace

Jak vidıme na obrazku 2.8, zakladnı motto muze znıt: “Uvolnuj rychle, uvolnuj casto!”.Behem jedne iterace, ktera trva nejcasteji 1-4 tydny, se uvolnuje produkcnı verze sw s novymivlastnostmi, ktera muze byt okamzite nasazena. Zakaznık tak nejrychleji dostane pozadovanoufunkcionalitu. Pokud zakaznık nevidı pokrok, muze projekt zrusit. Takovyto vyvoj se nekdyoznacuje jako Rapid Application Development nebo zkracene RAD.

2.4.3.3 Metafora

Vyvojari casto definujı vystizne prirovnanı, metaforu, jak dany system ma vypadata co ma delat. Soubor trıd a navrhovych vzoru, ktere odpovıdajı danemu byznys problemu aresenı, pomaha clenum tymu v komunikaci o systemu.

Page 43: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 29

2.4.3.4 Testovanı

V XP se rıdıme metodikou programovanı rızene testy (test-driven development, test-first design). Za prve, test pıseme pred vlastnı implementacı. Metodikou TDD pridavame novouvlastnost do systemu v 5ti fazıch:

1. Rychle pridat test.

2. Spustit vsechny testy, at’ vidıme, jestli test dopadne spatne. Pokud novy test nepada, jenapsan spatne.

3. Provest drobnou zmenu.

4. Spustit vsechny testy, at’ vidıme, jak vse dopadne dobre.

5. Refaktorovanım odstranit duplicitu.

Jednotkove a funkcnı testy nahrazujı specifikaci. Pokud testy neprochazı, musı se kodopravit. Vıce o programovanı rızenem testy nalezneme v [16].

2.4.3.5 Jednoduchy navrh

Software vyvıjeny pomocı XP ma zpravidla nejjednodussı design, ktery zaroven splnujezakaznıkovy pozadavky. Pomocı TDD a refaktorovanı je implementovano opravdu jen to, coje treba. Jednoduchy design je zakladem snadneho pridavanı dalsıch vlastnostı a udrzovanısystemu.

2.4.3.6 Refaktorovanı

Pomocı refaktorovanı dokazeme udrzet architekturu systemu cistou, jednoduchou, kteravzdy odpovıda pozadavkum na system. Refaktorovanım restrukturalizujeme kod bez zmenyjeho funkcionality, delame kod citelnejsı, prehlednejsı, lepe odpovıdajıcı aktualnımu chapanısystemu. Pred refaktorovanım spustıme vsechny testy, refaktorujeme po malych krocıch a poteznovu spustıme vsechny testy, abychom se ujistili, ze system funguje stejne. Vıce o refaktorovanınalezneme v [18].

2.4.3.7 Parove programovanı

Parove programovanı znamena dva lidi u jednoho pocıtace s jednou klavesnicı. Pro-dukuje lepsı kod nez pri praci kazdeho zvlast’, probıha neustala revize kodu, lepsı porozumenıco system dela. Vsechen produkcnı kod by mel byt tvoren parovanım. Take vhodne pro vyuku(slabsı se ucı od zdatnejsıch a naopak).

2.4.3.8 Kolektivnı vlastnictvı kodu

Veskery kod patrı vsem vyvojarum. Minimalizuje prodlevy v resenı problemu. Kdokolivpotrebuje zmenu v kodu, ktery nenapsal, tak jednoduse udela.

2.4.3.9 40-ti hodinovy pracovnı tyden

Unaveny vyvojar pıse mizerny kod, dela vıce chyb.

Page 44: Internetove technologie na platforme Java

30 KAPITOLA 2. RESERSE

2.4.3.10 Zakaznık na spravnem mıste (On-site customer)

Zakaznık by mel aktivne prispıvat do vyvoje. Vyklada uzivatelske prıbehy, ovlivnujepozadavky, nastavuje priority, zodpovıda otazky od vyvojaru. Dokumentace je mene v tistenepodobe, je spıse sdılena vsemi cleny tymu.

2.4.3.11 Standardnı podoba kodu

Jelikoz kazdy muze editovat cokoliv, je dulezite zavest urcity standard v psanı kodu,ktery by meli vsichni clenove tymu dodrzovat.

2.4.3.12 Sjednocene pracovnı prostredı

Usnadnuje praci v paru. Jsou nastaveny jednotne klavesove zkratky a podobne.

2.5 Testovacı framework JUnit

JUnit je nastroj pro jednotkove (unit) testovanı v Jave, jehoz autori jsou Kent Beck aErich Gamma. Vychazı z puvodnıho nastroje SUnit pro Smalltalk napsaneho Kentem Beckempri predstavenı XP. Je stezejnım prostredkem TDD.

Dnes prevladajı 2 major verze tohoto testovacıho frameworku, a to JUnit 3.x (3.8.1) aJUnit 4.x (4.4). Predstavım zde obe verze, zacneme stale nejrozsırenejsı verzı 3.x.

2.5.1 JUnit 3.x

2.5.1.1 Architektura

• Soubor testu se sklada ze souboru testovacıch sad, tj. trıd, ktere dedı od predkajunit.framework.TestCase. Testovacı sada obsahuje testy.

• Testy jsou metody public void, pokud je oznacıme pocatecnım slovem test, napr. publicvoid testAddTwoIntegers(), test se spustı automaticky.

Kazdy test by mel byt spusten nezavisle na ostatnıch a neovlivnovat je.

• private void setUp() - provede se pred kazdym testem, nastavuje stejne prostredı,stejna testovacı data

• private void tearDown() - provede se bezprostredne po skoncenı kazdeho testu, uklızıpro dalsı test, zavıra datove proudy

2.5.1.2 Assert

Pomocı predpokladu (assertu) definujeme jak se ma testovany kod zachovat. Jsouimplementovany ve trıde junit.framework.Assert, vsechny majı hlavicku public staticvoid. V testovacı sade je pıseme bez prıstupu ke trıde.

• assertTrue(boolean expression) - ocekava true,

• assertFalse(boolean expression) - ocekava false,

• assertNotNull(Object object) - ocekava nenullovou instanci,

• assertNull(Object object) - ocekava nullovou instanci,

• assertEquals(Object x, Object y) - ocekava rovnost na equals() objektu x a y,

Page 45: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 31

• assertSame(Object x, Object y) - ocekava, ze majı objekty x a y stejnou pamet’ovoureferenci,

• assertNotSame(Object x, Object y) - ocekava, ze nemajı objekty x a y stejnoupamet’ovou referenci,

• fail() - skoncı test chybou,

Vsechny uvedene metody majı jeste jeden nepovinny parametr String message, kteryse zobrazı pokud assert selze.

2.5.1.3 Integrace s IDE

Pri TDD je dulezite, abychom testy pousteli casto a byly co nejvıce automatizovane.K tomu nam pomaha integrace s vyvojovym prostredım. JUnit je standardnı soucastı beznychnastroju jako Eclipse, Netbeans a IntelliJ Idea.

2.5.2 JUnit 4.x

Tento odstavec by mel pokryt pocatecnı uvod do nove rady JUnitu, ktery se hodneinspiroval frameworky TestNG, Popper a JMock. Predstavım hlavnı zmeny oproti minule verzia vse ukazu na prıkladu, ktery jsem prevzal z [8].

2.5.2.1 Hlavnı zmeny oproti 3.x

• Testovacı sada nemusı dedit od junit.framework.TestCase.

• Testy nemusı zacınat prefixem “test”, mısto toho jsou oznaceny anotacı @Test.

• Mısto metod setUp() a tearDown() se pred a po kazdem testu volajı metody oznaceneanotacemi @Before a @After.

• Pokud potrebujeme spustit metodu v ramci testovacı sady jen jednou pri startu a jednouna konci, oznacıme metodu anotacemi @BeforeClass a @AfterClass.

• Anotace @Test muze mıt parameter Timeout, ktery kdyz provadenı testu prekrocı, testselze.

• Spustitelne jen od JDK 5.

2.5.2.2 assertThat

Konstrukt assertThat() doplnuje a rozsiruje pouzitı predpokladu z 3.x, doslovnypreklad muze znıt “ocekavam ze” a takto se i zapisuje. Prvnı argument je objekt, na kteryprovadıme predpoklad. Druhy parametr je tzv. matcher, tj. funkce, kterou formulujemepredpoklad.

assertThat(something, eq("Hello"));assertThat(something, isA(Color.class));assertThat(something, contains("World"));assertThat(myList, hasItem("3"));assertThat(something, not(contains("Cheese")));assertThat(responseString, either(containsString("color"))

.or(containsString("colour")))

Page 46: Internetove technologie na platforme Java

32 KAPITOLA 2. RESERSE

2.5.2.3 Predpoklady a teorie

Predpoklady slouzı k explicitnımu vyjadrenı podmınek, za kterych musı test projıt,obecne zavislostı mimo rozsah vlastnıho testu. Teorie se sklada ze vstupnıch testovacı dat,predpokladu, za ktereho je schopen test s daty pracovat a vlastnıho testu. Dıky teorii muzemerıci, za predpokladu techto vstupnıch podmınek se testovany kod musı chovat takto. Dıkypodmınkam je mozne nechat JUnit generovat vstupnı data, ktera jdou za rozsah toho, jakbychom ocekavali nebo toho, co by bylo pracne vyjadrit klasicky.

@RunWith(Theories.class)public class UserTest {@DataPoint public static String GOOD_USERNAME = "optimus";@DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";

@Theory public void filenameIncludesUsername(String username) {assumeThat(username, not(containsString("/")));assertThat(new User(username).configFileName(), containsString(username));

}}

Anotace @DataPoint definuje vstupnı data teorie. Spoustec testu sam zadava do tes-tovacı metody filenameIncludesUsername vsechny kompatibilnı verejne promenne oznaceneanotacı @DataPoint (shodujı se typy promenne a parametru). Predpoklad je vyjadreny pomocıassertThat. Tato teorie by se dala prelozit do cestiny asi takto:“Za predpokladu, ze usernameneobsahuje /, musı platit, ze jmeno konfiguracnıho souboru uzivatele obsahuje jeho jmeno.”

2.6 Testovacı framework JMock

V teto kapitole predstavım duvody, kdy je vhodne pouzıt mockovanı, predstavım jeden znejpouzıvanejsıch mockovacıch frameworku v Jave. Zakladnı syntaxi a pouzitı ukazu na kratkemprıkladu.

2.6.1 Mockovanı, Mock objekty

Vsude tam, kde je klasicke unit testovanı obtızne, pomale nebo se jedna o takrkaneresitelny problem, si musıme poradit, jak danou vec otestovat. Naprıklad, pokud testovanatrıda:

• produkuje nedeterministicke vysledky (aktualnı cas, aktualnı teplota),

• ma stavy, ktere je tezke vytvorit nebo reprodukovat (sıt’ova chyba),

• ma pomalou odezvu (inicializace kompletnıho DB spojenı),

• jeste neexistuje nebo bude menit chovanı,

• bude muset obsahovat rozdılne informace pro testy a pro realne nasazenı. [11]

Mock objekt je falesny zastupce, ktery se navenek chova stejne jako jeho realnyprotejsek. Mame na vyber z vıce implementacı:

• implementovat falesnou trıdu (fake) s ocekavanou vlastnı implementacı,

• pouzıt predem vytvorene falesne implementace znamych trıd (napr. HttpServletRequest),Spring nabızı mock implementace k beznym komponentam systemu (MockHttpServletRequest),

Page 47: Internetove technologie na platforme Java

KAPITOLA 2. RESERSE 33

• pouzıt staticky mock creator, napr. MockCreator, ktery vytvorı kostru trıdy implemen-tujıcı testovane rozhranı,

• pouzıt dynamicky mock creator, ktery za behu v testu vytvorı objekt implementujıcıtestovane rozhranı. Predstaviteli teto kategorie jsou JMock, EasyMock a rMock.

2.6.2 Architektura

Spoustenı JMock testu se lisı podle pouzite verze JUnitu. Predstavım pouzıvanejsı verzis JUnit 3.x.

• Testovacı sada dedı od abstraktnı trıdy MockTestCase.

• Mock objekt vytvarıme pomocı metody mock(Clazz.class).

• K objektu, ktery napodobuje, se dostaneme vzdy pomocı mockObject.proxy().

2.6.3 Prıklad

Predstavme si jednoduchy prıklad [7]. Vyvıjıme software pro nejakou bankovnı spolecnost.Budeme potrebovat rozhranı Account, ktere zaobaluje informace o uctech a rozhranı Ac-countManager, ktere nad nimi provadı operace.

public interface AccountManager {void transfer(Account from, Account to, double amount)

throws OutOfMoneyException;}public interface Account {

void charge(double amount) throws OutOfMoneyException;void deposit(double amount);

}

Banka je chamtiva. Kdykoliv je proveden prevod z jednoho uctu na druhy, strhne se10 Kc + 10% z prevadene castky. Tyto penıze se pripısou na bonusovy ucet banky, kde sije bankovnı manazeri rozdelı. Naimplementujeme chovanı trıdy AccountManagerImpl pomocıTDD, tedy napıseme test pred vlastnı implementacı.

public class AccountManagerImplTest extends MockObjectTestCase {public void testTransferWithoutOvercharging()

throws Exception {Mock mockAccount1 = mock(Account.class);mockAccount1

.expects(once())

.method("charge")

.with(eq(100.0 * 1.10 + 10.0));

Vytvorili jsme novy Mock objekt pomocı JMock, ktery bude pozdeji pouzit jako zdrojovy ucet.Ve drude radce jsme pridali predpoklad. Ocekavame, ze AccountManagerImpl zavola jednoumetodu charge() s argumentem rovnym 100*1.1 + 10 = 120.

Mock mockAccount2 = mock(Account.class);mockAccount2

.expects(once())

.method("deposit")

.with(eq(100.0))

.after(mockAccount1, "charge");

Page 48: Internetove technologie na platforme Java

34 KAPITOLA 2. RESERSE

Vytvorili jsme Mock objekt, ktery bude pouzit jako cılovy ucet. Predpokladame, ze AccountMa-nagerImpl bude volat metodu deposit() s argumentem rovnym 100. Poslednı radka rıka, ze budemetoda volana az po volanı metody mockAccount1.charge(), cımz nepripıseme penıze na cılovyucet, pokud se predtım neodepsaly ze zdrojoveho.

Mock mockBonusAccount = mock(Account.class);mockBonusAccount

.expects(once())

.method("deposit")

.with(eq(100.0 * 0.10 + 10.0))

.after(mockAccount1, "charge");

Nakonec jsme vytvorili Mock objekt pro bonusovy ucet. AccountManagerImpl na nej pripısepenıze pomocı metody deposit() s argumentem 100*0.1+10=20, kterou zavola az po uspesnemodepsanı penez ze zdrojoveho uctu.

Account account1 = (Account) mockAccount1.proxy();Account account2 = (Account) mockAccount2.proxy();Account bonusAccount = (Account) mockBonusAccount.proxy();

Nynı jednoduse z Mock objektu vytvorıme ucty

AccountManagerImpl man = new AccountManagerImpl(bonusAccount);man.transfer(account1, account2, 100.0);

}}

a nakonec vytvorıme AccountManagerImpl, na kterem zavolame metodu transfer().V prubehu celeho testu jsme nikde nevolali JUnit asserty. Az test skoncı, predek

MockObjectTestCase prekontruje zda vsechny zadane predpoklady na Mock objekty bylysplneny. Pokud nebyly, pokud byla metoda volana v jinem poradı nebo s jinym typem ar-gumentu, test skoncı s fail() vyjımkou AssertionFailedError.

Page 49: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 35

3 Implementace

V resersnı casti jsem ukazal zaklady technologiı tvorby webovych aplikacı na platformeJava, v teto casti ukazu prakticke aplikovanı nabytych znalostı implementacı casti portalu prohledanı spolubydlıcıch.

3.1 Zadanı

Vylepsit stavajıcı portal pro hledanı spolubydlenı www.chcispolubydlici.cz o moznostinzerovat poptavku. Pomocı teto nove funkcionality pujde v inzeratech vyhledavat. Pridat au-tomaticke mazanı inzeratu a umoznit export inzeratu do formatu RSS.

3.2 Analyza

Uzivatele v ankete vyplnili nejpalcivejsı veci, ktere na portalu postradajı. Kromeprelozenı do anglictiny je inzerovanı poptavky na druhem mıste. Neimplementovanı inzerovanıpoptavky melo svuj duvod, lide nabızejıcı spolubydlenı vetsinou tuto kategorii inzeratu prılisnevyhledavajı. Avsak nicemu neuskodı, pokud tato funkcionalita bude a sami si statistickyoverıme, jestli se nas nazor potvrdil ci vyvratil.

3.2.1 Co uz je naimplementovano?

Portal se neustale vyvıjı. Kdyz jsem poprve prisel do firmy Simple Way s.r.o., portal uzbyl nasazen a meli jsme pulrocnı zkusenosti s provozem. Vyvoj aplikace do teto doby a nesazenıje v podstate obsahem bakalarske prace studenta Lubose Racanskeho.

3.2.2 Pruzkum trhu

Na internetovem trhu se spolubydlenım vynikajı prevazne servery www.spolubydlici.cz,www.espolubydleni.cz a www.bydlim.com.

Server www.spolubydlici.cz umoznuje inzerovat nabıdku i poptavku, inzerat nenı de-tailnı a tak i vyhledavanı inzeratu postrada vyber parametru, ktere uzivatele zajımajı. Hledanımjde omezit vyber jen v Praze, Morave a Slezsku a ve zbytku CR, pomocı maximalnı ceny apohlavı. Evidentne je to nedostacujıcı a uzivatel musı hledanım stravit zbytecne vıce casu.Navzdory tomu je nejpouzıvanejsım portalem v teto kategorii.

Server www.espolubydleni.cz je na tom o poznanı lepe. Umoznuje inzerovat nabıdku ipoptavku, inzerat je vıce detailnı, jelikoz se server objevil po uspesnem nasazenı spolubydlıcıch,muzeme predpokladat, ze se jım nechal inspirovat. Adresa se zadava pomocı okresu z htmlselectu a mesta, ktere je v html text area. Hledanım lze omezit vyber podle druhu domu, okresua ceny najemneho od/do, coz opet nedostacuje. Zajımava funkce je naprıklad sumarizovanaprumerna cena najmu v Praze, v Brne a ve zbytku CR.

Poslednı zmıneny server www.bydlim.com je sponzorovan medialnımy partnery jakoatlas.cz, Sıp, Annonce, 24hodin. Nasadil dokonce letakovou kampan po Praze. Adresa je jenmesto a navıc jen velke (cca. 11 krajskych mest). Vybrat lze druh bytu, jestli je dotycny studentnebo kurak. Inzerat je mene detailnı nez v predchozım prıpade.

Co jsem nikde nenasel? Ohledne lokalit, kde by chtel uzivatel bydlet, jsem nikde nevidelmoznost zapsat lokalit vıce. Student CVUT naprıklad hleda bydlenı poblız Dejvic, cili P6Dejvice, P6 Bubenec nebo P6 Stresovice. Muze nastat dalsı prıpad, uzivatel chce bydlet na

Page 50: Internetove technologie na platforme Java

36 KAPITOLA 3. IMPLEMENTACE

Praze 1, ale je mu jedno v jake ctvrti a mimo to by se spokojil s Prahou 2 Nove Mesto. Nenınic jednodussıho nez zadat neco jako P1 nezalezı a P2 Nove Mesto. S podobnou logikou vecibychom mohli zadat celou Prahu, popr. cely kraj.

3.2.3 Prototypy

Po prozkoumanı trhu jsem vytvoril zakladnı prototyp vkladanı noveho inzeratu. UIprototypy pomahajı s ujasnenım pozadavku a k vyjasnenı pojmu se zakaznıkem.

Obrazek 3.1: Zakladnı UI prototyp

V novem inzeratu nas zajıma krome pozadovanych lokalit take maximalnı prijatelnacena za bydlenı, datum odkdy se chce uzivatel nastehovat a na jak dlouho, jestli je student,kurak, jestli ma zvıre, velikost bytu, druh domu. Dale pak pozadovane vybavenı bytu (internet,kabelova televize, telefon,..) a dalsı vybavenı v domu (lednicka, pracka, mikrovlnka,...).

3.3 Implementace

V ramci release planovanı jsem rozdelil vsechny uzivatelske prıbehy do requirementu a tydo jednotlivych iteracı. Jak jsem psal v kapitole 2.4.3.2, iterace by mela probıhat 1-4 tydny. Tam,kde to bylo mozne, jsem psal testy nejdrıve. Nektere casti vznikaly parovym programovanıms vedoucım mojı prace Ing. Andrejem Zacharem a studentem Lubosem Racanskym. Veskerykod, ktery uvadım v teto casti, je v rozsahu nutnem pro pochopenı daneho resenı. Cely projektje k dispozici na prilozenem CD.

3.3.1 Iterace 1

Do prvnı iterace jsem naplanoval implementaci zakladnıho requirementu.

• Umoznit vkladanı noveho inzeratu.

Page 51: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 37

Podle zvyklosti pouzıvane u vkladanı nabıdky jsem ukon rozdelil na nekolik obrazovek.Na prvnı obrazovce se zadavajı stezejnı parametry inzeratu, na druhe obrazovce pozadovanelokality, na tretı obrazovce potom prihlasovacı udaje na server. Poslednı obrazovka slouzı prorekapitulaci zadanych udaju.

Obrazek 3.2: Vkladanı noveho inzeratu

V prvnı rade potrebujeme databazovou reprezentaci inzeratu a uzivatele, definujemeproto BO Demand a HomelessInzerent.Demand.java

@Entitypublic class Demand extends AbstractBo {

private static final long serialVersionUID = -4713748752937686298L;private HomelessInzerent homelessInzerent;private Set<FlatSizeType> flatSizeTypeSet = new HashSet<FlatSizeType>();//and many other properties with appropriate getters and setters

@OneToOne(cascade = { CascadeType.ALL })public HomelessInzerent getHomelessInzerent() {

return homelessInzerent;}public void setHomelessInzerent(HomelessInzerent homelessInzerent) {

this.homelessInzerent = homelessInzerent;}@ManyToMany(fetch = FetchType.EAGER)public Set<FlatSizeType> getFlatSizeTypeSet() {

return flatSizeTypeSet;}public void setFlatSizeTypeSet(Set<FlatSizeType> flatSizeType) {

this.flatSizeTypeSet = flatSizeType;

Page 52: Internetove technologie na platforme Java

38 KAPITOLA 3. IMPLEMENTACE

}}

HomelessInzerent.java

@Entitypublic class HomelessInzerent extends Inzerent {

private static final long serialVersionUID = -546574687654564L;}

Vytvorili jsme BO, dale musıme dat Hibernatu vedet, aby s nimi mohl pracovat.Pridame je beane sessionFactory do property annotatedClasses.core-service.java

<bean id="sessionFactory"class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">...<property name="annotatedClasses">

<list><value>cz.sw.getroommate.bo.HomelessInzerent</value><value>cz.sw.getroommate.bo.Demand</value>

</list></property>...</bean>

Podle obrazku 2.6 se webova aplikace sklada z vıce vrstev. Datovy model jiz mamenaimplementovany, kde budeme pokracovat? Zacneme od servisnı vrstvy, respektive od jejıhotestu.DemandServiceTest.java

public class DemandServiceTest extends TestCase {DemandService demandService;Demand demand;

// OVERRIDEprotected void setUp() throws Exception {

super.setUp();demandService = SpringTestUtil.getDemandService();setupDemand();

}public void setupDemand() {

demand = new Demand();//and set all properties

}public void testSaveAndLoad() {

try {demandService.saveOrUpdate(demand);

} catch (Exception e) {fail(e.getMessage());

}long id = demand.getId();Demand loadeDemand = demandService.getDemand(id);assertEquals(demand, loadeDemand);assertNotNull(loadeDemand.getHomelessInzerent());

}}

Page 53: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 39

Test nam spadne kvuli tomu, ze jsme zatım nenapsali metody demandService.getDemand()a demandService.saveOrUpdate(Demand demand). Ted’ je ta spravna chvıle je doplnit.DemandService.java

public class DemandService extends AbstractService<IDemandDao> {public void saveOrUpdate(Demand demand) throws Exception {

assert (demand != null);Date now = new Date();if (demand.getCreated() == null) {

demand.setCreated(now);}demand.setUpdated(now);demand.setCancellingEmailSent(null);dao.saveOrUpdate(demand);

}public Demand getDemand(long id) {

return dao.getDemandById(id);}

}

Dale zbyva zapsat beanu, kterou bude Spring IoC kontejner injektovat.core-service.xml

<bean id="demandService"class="cz.sw.getroommate.service.DemandService"><property name="dao" ref="demandHibernateDao" />

</bean>

Test porad neprochazı, jeste je treba napsat DAO vrstvu, rozhranı IDemandDao re-spektive jeho implementaci DemandHibernateDao.DemandHibernateDao.java

public class DemandHibernateDao extends SimpleCrudHibernateDao<Demand>implements IDemandDao {

public Demand getDemandById(long id) {return get(Demand.class, id);

}public void saveOrUpdate(Demand demand) {

getHibernateTemplate().saveOrUpdate(demand);}

}

Opet je potreba zapsat beanu do xml deskriptoru Springu, za zmınku stojı beana abs-tractHibernateDao, pomocı ktere dosahneme deklarativnıch transakcı, viz. kapilota 2.3.8.1.core-service.xml

<bean id="demandHibernateDao" parent="abstractHibernateDao"><property name="target">

<beanclass="cz.sw.getroommate.dao.hibernate.DemandHibernateDao"parent="abstracDao" />

</property></bean>

<bean id="abstractHibernateDao"

Page 54: Internetove technologie na platforme Java

40 KAPITOLA 3. IMPLEMENTACE

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"abstract="true">

<property name="transactionManager" ref="hibernateTransactionManager" /><property name="transactionAttributes">

<props><prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><prop key="save*">PROPAGATION_REQUIRED</prop><prop key="delete*">PROPAGATION_REQUIRED</prop><prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

</props></property></bean>

Naimplementovali jsme tedy servisnı, perzistentnı vrstvu a datovy model. Vsechnufunkcnost mame overenou testy. Vrhneme se tedy na UI a webovou vrstvu. Jelikoz budememıt vıce obrazovek, kterymi budeme navigovat na dalsı a na predchozı obrazovku, v uvahupripada implementace pomocı Spring Web MVC a jeho kontroleruAbstractWizardFormController nebo pomocı SWF. Kvuli uzivatelske prıvetivosti SWF atake proto, ze nabıdkova cast je delana prave takto, jsem zvolil SWF.

Zacneme od definice URL mapovanı, pomocı ktereho budeme pristupovat k vkladanıinzeratu, pridame property do beany urlMapping do property mappings,action-servlet.java

<bean id="urlMapping"class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="alwaysUseFullPath" value="true" /><property name="mappings">

<props><prop key="/hledam-bydleni.html">flowController</prop>

</props></property></bean>

ktera ukazuje na beanu flowController. SWF je nakonfigurovano podobne jako jsemukazoval v kapitole 2.2.8.7, s tım rozdılem, ze pro vazbu URL na flow je pouzita trıdaFlowIdExtractor, ktera nam dovoluje zapsat do mapy property mappings klıc celou URL(bez koncoveho .html) a jako hodnotu flow, ktere se spustı.action-servlet.java

<!-- Launches new flow executions and resumes existing executions. --><flow:executor id="flowExecutor" registry-ref="flowRegistry" />

<!-- Creates the registry of flow definitions for this application --><flow:registry id="flowRegistry">

<flow:location path="/WEB-INF/flows/**/*-flow.xml" /></flow:registry>

<bean id="flowController"class="org.springframework.webflow.executor.mvc.FlowController"><property name="flowExecutor" ref="flowExecutor" /><property name="argumentHandler"><bean class="cz.sw.getroommate.web.custom.FlowIdExtractor">

<property name="mappings"><map>

<entry key="hledam-bydleni" value="new-demand-flow" /></map>

Page 55: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 41

</property></bean></property></bean>

Na Dispacher servlet (viz. kapitola 2.2.7.4) prijde URL, kterou se odkazeme do flow-Controlleru, ktery spustı new-demand-flow.xml.new-demand-flow.xml

<?xml version="1.0" encoding="UTF-8"?><flow><start-state idref="newDemand" /><action-state id="newDemand"><action bean="demandAction" method="createDemand" /><action bean="userAction" method="createHomelessInzerent" name="userAction" /><transition on="userAction.success" to="demandDetails" />

</action-state><subflow-state id="demandDetails" flow="demand-details-flow"><transition to="demandLocation" />

</subflow-state>...<action-state id="saveDemand"><action bean="demandAction" method="saveDemand" /><action bean="loginAction" method="setCurrentUser" name="setCurrentUser" /><transition on="setCurrentUser.homelessInzerent" to="finish" /><transition on="error" to="summary" />

</action-state><end-state id="finish" view="externalRedirect:spolubydlici.html" />

</flow>

Ve stavu newDemand vytvorım nove BO Demand a HomelessInzerent, ktere ulozım doSWF Conversation scope (viz. kapitola 2.2.8.5) a pri uspechu prechazım do subflow demandDe-tails, kde bude definovana prvnı obrazovka. Po skoncenı subflow (pokud uzivatel klikne na but-ton dalsı) prechazım na druhou, tretı obrazovku... Na konci ve stavu saveDemand volam metodudemandAction.saveDemand(), ktera inzerat ulozı do DB a loginAction.setCurrentUser(),ktera zaloguje uzivatele tım, ze jej ulozı do HTTP session (viz. kapitola 2.2.7.5).

Podıvejme se naprıklad na metodu demandAction.createDemand()action-servlet.java

<bean id="demandAction"class="cz.sw.getroommate.web.action.flow.DemandFormAction"parent="abstractFormAction">

<property name="validator" ref="demandValidator" /><property name="propertyEditorRegistrar"

ref="enumsEditorRegistrar" /></bean>

DemandFormAction.java

public class DemandFormAction extends FormActionimplements ApplicationContextAware {

public DemandFormAction() {super(DemandFormObject.class);

}

public Event createDemand(RequestContext context) {

Page 56: Internetove technologie na platforme Java

42 KAPITOLA 3. IMPLEMENTACE

Demand newDemand = new Demand();newDemand.setWantToMoveIn(new Date());context.getConversationScope().put(Constants.DEMAND, newDemand);return success();

}

Vsimneme si konstruktoru DemandFormAction(), jımz volame kostruktor FormActions parametrem, ktery je typ trıdy Form Objectu1. Vytvorili jsme novy inzerat a uzivatele, ted’nas zajıma subflow demandDetails.demand-details-flow.xml

<?xml version="1.0" encoding="UTF-8"?><flow><start-state idref="demandDetails" /><view-state id="demandDetails" view="newDemandForm">

<render-actions><action bean="demandAction" method="setupForm" />

</render-actions><transition on="submit" to="saveDemandDetails">

<action bean="demandAction" method="bindAndValidate" /></transition>

</view-state><action-state id="saveDemandDetails">

<action bean="demandAction" method="saveToScope" /><transition to="finish" />

</action-state><end-state id="finish" /></flow>

Startovnı stav je view state demandDetails, pred vlastnım “vyrenderovanım” JSPstranky volame metodu demandAction.setupForm(), ktera je zdedena od Springovske trıdyFormAction. Pokud nenajde ve svem flow scopu Form Object, tak zavola metodu createFormObject()a ta jej ulozı do scope.DemandFormAction.java

@Overrideprotected Object createFormObject(RequestContext context) throws Exception {

DemandFormObject demandFormObject = (DemandFormObject) super.createFormObject(context);BeanUtils.copyProperties(getDemand(context), demandFormObject);demandFormObject.setAllFlatEquipments(enumService.getAllEquipments());return demandFormObject;

}

V createFormObject() resp. v setupForm() je ta spravna chvıle naplnit vsechny polozkyz Form Objectu urcene pro data html prvku, ze kterych si muzeme vybırat z nejakych hodnotz databaze (html select, checkbox, radio,...). Vsechny takove polozky jsem pro lepsı orientacioznacoval slovy allXXXs.

Dobra, napıseme tedy konecne JSP stranku. Tolik vecı, co jsme museli kvuli jednestrance udelat, se nam zaplatı v prıpade rozsirovanı nebo upravach systemu.NewDemandForm.jsp

<form:form commandName="demandFormObject"><div><label><spring:message code="equipment" />: </label><div class="facilities"><c:forEach items="${demandFormObject.allFlatEquipments}"

1Form Object je jiny nazev pro Command Object, tj. objekt do/z ktereho “bindujeme” data v html formu.

Page 57: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 43

var="equipment"><form:checkbox path="flatEquipmentSet" value="${equipment}" />&nbsp;${equipment.name}</c:forEach>

</div></div><%-- and other attributes--%><input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" /><input type="submit" name="_eventId_submit" value="<spring:message code="next" />" />

</form:form>

Vsimneme si prvnıho tagu <form:form/>, ten definuje do/z ktereho Form Objectuse majı data bindovat. Z kolekce allFlatEquipments vybereme pomocı html checkboxu datado flatEquipmentSet. Dalsı vec, kterou je treba zmınit, jsou pole <input/>, kde v prvnımpredavame flowExecutionKey, ktery urcuje uzivatelovu session s flow a button dalsı, ktery volaevent submit, na ktery reagujeme v demand-details-flow.xml.DemandFormObject.jsp

public class DemandFormObject implements Serializable{private Set<FlatEquipment> flatEquipmentSet = new HashSet<FlatEquipment>();private List<FlatEquipment> allFlatEquipments;//and appropriate getters and setters

}

Vrat’me se do demand-details-flow, jdeme vysetrit, co se stane po kliknutı na buttondalsı, resp. po odpalenı eventu “submit”, volame metodu demandAction.bindAndValidate(),ktera je zdedena od Springovske trıdy FormAction. Data z html formulare se nabindujı doForm Objectu a provede se nad nimi validace. Validator pro demandFormAction uz jsme beanenainjektovali, ukazeme si jeho implementaci pomocı Valangu.

Obrazek 3.3: Validace polozky

Pomocı Valangu snadno napıseme kriteria pro spravne hodnoty zadavanych polozek.Valang ma dost vestavenych funkcı a operatoru, nic nam ale v prıpade potreby nebranı si novefunkce napsat sami. Pro kompletnı specifikaci jazyka odkazuji ctenare na referencnı dokumen-taci.web-core-validators.xml

<bean id="demandValidator" class="org.springmodules.validation.valang.ValangValidator"><property name="valang"><value>

<![CDATA[{ age : ? BETWEEN 15 AND 99 : ’Size must be between <15,99>’ :

’errors.betweenvalues’ : 15, 99 }]]>

</value></property>

Pokud validovacı funkce BETWEEN vracı true, vse probehne uspesne. Pokud vratıfalse, metoda bindAndValidate() vratı error(), neprejde se na dalsı stranu, zobrazı se chybovahlaska a ceka se na opravu, jak vidıme na obrazku 3.3. Chybove hlasenı se hleda pomocı klıce’errors.betweenvalues’, ten se hleda ve vsech souborech .properties, ktere definujeme v beanemessageSource.core-resources.xml

Page 58: Internetove technologie na platforme Java

44 KAPITOLA 3. IMPLEMENTACE

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">

<property name="basenames"><list>

<value>ApplicationResources</value><value>ErrorMessages</value>

</list></property><property name="useCodeAsDefaultMessage" value="true" /></bean>

Hlaska muze byt, jak je videt v teto ukazce, parametrizovana, hodnoty se dosazujıpomocı slozenych zavorek cıslovanych od nuly.ErrorMessages.properties

errors.betweenvalues = Musı byt od {0} do {1}

3.3.2 Iterace 2

Do druhe iterace jsem naplanoval zprovoznit nasledujıcı funkcionalitu:

• Umoznit mazat inzeraty.

• Umoznit editovat inzeraty.

System rozeznava v tuto chvıli 3 typy uzivatelu, vsichni dedı od abstraktnı trıdyAbstractUser:

• Inzerent - uzivatel inzerujıcı nabıdku po bydlenı,

• WatchDog - uzivatel, ktery si zrıdil SMS notifikaci,

• HomelessInzerent - uzivatel inzerujıcı poptavku.

Pro jakoukoliv zmenu inzeratu je nutne prihlasenı. Pro editaci se posıla URL /edit.html,ktery DispacherServlet deleguje na flowController, jez vola edit-flow.xml. V edit-flow.xml sepodle typu uzivatele rozhodne, co chce vlastne editovat. Vytvoril jsem tedy subflow edit-demand-flow.xml, ktere zhruba odpovıda new-demand-flow.xml, jez jsem podrobne rozebralminulou iteraci. Jediny rozdıl je, ze se nevytvarı nove Byznys Objecty, ale podle aktualnıhouzivatele se z databaze nahraje jeho inzerat a data se preklopı do Form Objectu, z ktereho senaloadujı do JSP stranky.

Pro smazanı inzeratu je situace jeste jasnejsı. Posleme request na /delete.html, Dispa-cherServlet jej deleguje na flowController, ktery spustı delete-flow.xml, kde podle typu uzivatelespustıme delete-demand-flow.xml. Zobrazıme potvrzovacı dialog a po potvrzenı nejdrıve podleuzivatele nacteme inzerat z databaze a vzapetı pomocı teto reference jej smazeme.

3.3.3 Iterace 3

Zprovoznil jsem vkladanı, editaci a mazanı noveho inzeratu. Ohledne poptavky zbyvanaimplementovat uz jen tyto uzivatelske pozadavky:

• Umoznit vkladat do inzeratu vıce lokalit.

Page 59: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 45

Obrazek 3.4: Novy inzerat vıce lokalit

• Umoznit vyhledavat v inzeratech.

Zprovoznıme nejdrıve prvnı requirement - vkladanı vıce lokalit, kde castı lokality muzebyt polozka “nezalezı”, jak vidıme na obrazku 3.4.

Jaka bude reprezentace lokalit? V systemu je BO Location oznaceny anotacı @Em-beddable. Resenı, ktere vypalıme “od boku” je, ze BO Demand bude obsahovat mnozinu lokalitve vztahu 1:N. Resenı se zda v poradku, jediny fakt, ktery nam vadı, je, ze Location ne-vytvarı tabulku (viz. kapitola 2.3.4), cili pomuzeme si tak, ze vytvorıme novy BO, reknemeDemandLocation, ktery bude oznacen anotacı @Entity. Obe reprezentace lokalit spojıme ex-trahovanım metod do rozhranı ILocation. Bohuzel resenı vypalene “od boku” jsem kvulipozdejsımu problemu predelal a tak si potom ukazeme refaktorovanı v praxi.

Naimplementujeme BO DemandLocation a pridame jej do BO Demand.DemandLocation.java

@Entitypublic class DemandLocation extends AbstractBo implements ILocation {

private static final long serialVersionUID = -358439507774392169L;private Region region;private District district;private City city;private String street;@ManyToOnepublic City getCity() {return city;}public void setCity(City city) {this.city = city;}@ManyToOnepublic District getDistrict() {return district;}public void setDistrict(District district) {this.district = district;}@ManyToOnepublic Region getRegion() {return region;}public void setRegion(Region region) {this.region = region;}public String getStreet() {return street;}public void setStreet(String street) {this.street = street;}

}

Property street nenı prımo potreba, pokud nechceme spojit obe implementace lokalitrozhranım, coz je prave nas prıpad.ILocation.java

Page 60: Internetove technologie na platforme Java

46 KAPITOLA 3. IMPLEMENTACE

public interface ILocation extends IBO{public City getCity();public void setCity(City city);public District getDistrict();public void setDistrict(District district);public Region getRegion();public void setRegion(Region region);public String getStreet();public void setStreet(String street);

}

Zmenıme take hlavicku BO Location, aby implementoval ILocation, dale pridame doBO Demand mnozinu DemandLocation.Demand.java

@Entitypublic class Demand extends AbstractBo {

private static final long serialVersionUID = -4713748752937686298L;//...private Set<DemandLocation> locations = new HashSet<DemandLocation>();@OneToMany(cascade={CascadeType.ALL})public Set<DemandLocation> getLocations() { return locations;}public void setLocations(Set<DemandLocation> locations) { this.locations=locations;}//...

}

Servisnı ani DAO vrstvu zatım menit nemusıme. Pridame dalsı obrazovku do wizarduvkladanı noveho inzeratu, jinymi slovy pridame dalsı subflow do new-demand-flow.xml.new-demand-flow.xml

<?xml version="1.0" encoding="UTF-8"?><flow>...<subflow-state id="demandDetails" flow="demand-details-flow"><transition to="demandLocation" />

</subflow-state>

<subflow-state id="demandLocation" flow="demand-location-flow"><transition on="back" to="demandDetails" /><transition on="next" to="createUser" />

</subflow-state>...

</flow>

Vytvorıme nove flow, ktere bude zodpovıdat za volbu lokalit. Dobrym zvykem jevytvaret pro ruzne akce ruzne Form Objecty a Form Action. Proto vytvorıme take DemandLo-cationFormObject a DemandLocationFormAction, ktery bude s tımto form objectem pracovat.demand-location-flow.xml

<?xml version="1.0" encoding="UTF-8"?><flow><start-state idref="demandLocation" /><view-state id="demandLocation" view="demandLocationForm"><render-actions><action bean="demandLocationAction" method="setupForm" />

</render-actions>

Page 61: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 47

<transition on="back" to="back" /><transition on="addLocation" to="addLocation" /><transition on="submit" to="saveDemandLocation" /><transition on="delete" to="deleteDemandLocation"/>

</view-state><action-state id="addLocation"><action bean="demandLocationAction" method="bindAndAdd" /><transition to="demandLocation" />

</action-state><action-state id="saveDemandLocation"><action bean="demandLocationAction" method="storeLocation" /><transition to="next" />

</action-state><action-state id="deleteDemandLocation"><action bean="demandLocationAction" method="deleteLocation" /><transition to="demandLocation" />

</action-state><end-state id="back" /><end-state id="next" />

</flow>

Metoda demandLocationAction.setupForm() respektive metoda createFormObject(),kterou zavola, “nasetı” hodnoty ve form objectu bud’ nove nebo ulozene v databazi, jelikoz totoflow bude volano i pri editaci. Jak vidıme na obrazku 3.4 mame zde 4 ruzne akce:

• Akce addLocation prida zvolenou lokalitu do locationListu.

• Akce delete odebere lokalitu z locationListu a prida jı do deletedLocationListu, protozevsechny akce se ukladajı az v poslednı fazi wizardu vkladanı/editace inzeratu. List mıstomnoziny je zvolen proto, ze v HTTP RequestParameters pri akci deleteDemandLocationse predava id polozky, kterou chceme smazat, toto id je poradı v listu, nikoliv id z da-tabaze.

• Akce submit ulozı form object do SWF conversation scope a prejde do koncoveho stavu“next”.

• Akce back jednoduse prejde do koncoveho stavu “back”.

Spolu s form objectem, form action potrebujeme JSP stranku demandLocationForm.jsp.Jejich implementace je na prilozenem CD.

Je cas zprovoznit druhy requirement - hledanı v inzeratech, jak vidıme na obrazku 3.5.Na tuto stranku se dostaneme po zadanı requestu o /hledani-poptavek.html. Jelikoz jedineo co nam jde, je pomocı buttonu “search” zavolat vlastnı vyber inzeratu a pomocı odkazu“detail” prejıt na detail inzeratu, web flow bude v tomto prıpade kanonem na vrabce. Zvoliljsem tedy technologii Spring Web MVC, resp. implementaci pomocı BaseCommandController,resp. jeho potomka AbstractSearchController, ktery je v projektu kvuli hledanı v nabıdkacha MultiActionController pro zobrazenı detailu inzeratu. Zacneme opet od zacatku, pridameURL mapovanı do beany urlMapping.action-servlet.xml

<bean id="urlMapping"class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="alwaysUseFullPath" value="true" /><property name="mappings"><props>

<prop key="/hledani-poptavek.html">searchDemandFormController</prop>

Page 62: Internetove technologie na platforme Java

48 KAPITOLA 3. IMPLEMENTACE

Obrazek 3.5: Hledanı v poptavkach

<prop key="/spolubydleni-detail-zajemce.html">demandMultiActionController</prop></props></property></bean>

Vytvorıme nejdrıve kontroler searchDemandFormController.action-servlet.xml

<bean id="abstractSearchFormController" abstract="true"><property name="valueListHandler" ref="valueListHelper" /><property name="enumService" ref="enumService" /><property name="propertyEditorRegistrar" ref="enumsEditorRegistrar" />

</bean>

<bean id="searchDemandFormController"class="cz.sw.getroommate.web.action.SearchDemandController"parent="abstractSearchFormController"><property name="formView" value="searchDemand" />

</bean>

Jelikoz se na strance vyskytuje formular, budeme potrebovat form object, resp. v ter-minologii Spring MVC command object.2

2Nenı to uplne pravda, mapovat data z formulare muzeme prımo do BO, avsak toto resenı se hodı jen v

Page 63: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 49

SearchDemandCommand.java

public class SearchDemandCommand implements Serializable {private static final long serialVersionUID = 3659969246628625452L;private Region region;AbstractSearchController//and appropriate getters/setters

}

Pro pochopenı SearchDemandController, resp. jeho predka AbstractSearchControllerpotrebujeme znat jeste jeden framework, ktery jsem v resersnı casti nepredstavil - ValueList.Opensource projekt ValueList je implementacı core j2ee paternu ValueList handler. Slouzı propostupne nacıtanı hodnot a strankuje vysledky. Nejcasteji je pouzit s databazı a tabulkou,predana data mohou byt ale jakakoliv, napr. DynaBean, DynaClass, cokoliv z file systemuapod., pokud pro ne existuje adapter. Krome toho se firma Simple Way s.r.o. podılela navyvoji, tak nenı divu, ze je pouzit prave ValueList. Vıce nalezneme na oficialnıch webovychstrankach projektu [4].

Napıseme vlastnı kontroler a podıvame se na pouzitı s ValueListem.SearchDemandController.java

public class SearchDemandController extends AbstractSearchController {private static final Logger logger = Logger.getLogger(SearchDemandController.class);public SearchDemandController() {

setCommandClass(SearchDemandCommand.class);setCommandName(SearchDemandCommand.COMMAND_NAME);

}@Overrideprotected Object formBackingObject(@SuppressWarnings("unused")HttpServletRequest request) throws Exception {

SearchDemandCommand searchDemandCommand = (SearchDemandCommand) createCommand();searchDemandCommand.setAllRegions(EnumService.addEmptyRegion(

enumService.getAllRegions()));searchDemandCommand.setRegion(EnumHelper.

getDefaultEnum(searchDemandCommand.getAllRegions()));//...return searchDemandCommand;

}protected ModelAndView showGrid(HttpServletRequest request, @SuppressWarnings("unused")HttpServletResponse response, Object command, BindException errors) throws Exception {

SearchDemandCommand searchCommand = (SearchDemandCommand) command;fillGrid(request, searchCommand);// Trigger rendering of the specified view, using the final model.return new ModelAndView(getFormView(), errors.getModel());

}@SuppressWarnings("unchecked")private void fillGrid(HttpServletRequest request, SearchDemandCommand

searchDemandCommand) {ValueListInfo info = valueListHandler.getValueListInfo(request);info.getFilters().put(SearchDemandCommand.COMMAND_NAME, searchDemandCommand);ValueList valueList = valueListHandler.

getValueList("searchDemandContentProvider", info);valueListHandler.backupAndSet(request, valueList, "list", "t1");

}}

zakladnıch prıpadech.

Page 64: Internetove technologie na platforme Java

50 KAPITOLA 3. IMPLEMENTACE

Jelikoz je AbstractSearchController potomkem BaseCommandController, hlavnı me-toda, ktera se zavola po delegovanı pozadavku na kontroler, je handleRequestInternal(). Taze session vezme command object.

• Pokud je null, tak zavola metodu showNewForm(), ktera pres getErrorsForNewForm()vola metodu formBackingObject(), kterou jsem prekryl v SearchDemandController,je to obdoba createFormObject() ze SWF, getErrorsForNewForm() pak dal zavolabindAndValidate(), zjistı objekt BindException a ulozı command object do sessionscopu a vola metodu showGrid().

• Pokud byl command object nenullovy, tak opet zavola bindAndValidate(), zjistı objektBindException a vola metodu showGrid().

Nasledujıcı 2 metody jsou nutne ke spolupraci s ValueListem. Metodu showGrid() jsemopet prekryl, ta vezme command object, zavola metodu fillGrid() a vratı novou instanciModelAndView, kterou zobrazıme pozadovany vysledek. Metoda fillGrid() vytvorı instanciValueListInfo, ktera drzı vsechny informace potrebne k vytvorenı vlastnıho ValueListu a vlozıdo mapy Filters command object, vytvorı ValueList a zavola metodu backupAndSet(), kteraulozı ValueList do session, odkud ho na JSP strance zobrazıme.

Command object do mapy Filters v instanci ValueListInfo vkladame kvuli datum, kterema ValueList zobrazit. Pokud chceme naprıklad zobrazit jen inzeraty, ktere majı jako jednu zpolozek region, jez hledame.

Vytvorıme content provider, ktery se krome tohoto bude starat o defaultnı trıdıcı slou-pec, defaultnı smer razenı nebo o pocet vysledku na strance.action-servlet-valuelist.xml

<bean id="valueListHelper" class="net.mlw.vlh.web.mvc.ValueListHandlerHelper"><property name="valueListHandler" ref="valueListHandler" />

</bean>

<bean id="valueListHandler" class="net.mlw.vlh.DefaultValueListHandlerImpl"><property name="config.adapters"><map>

<entry key="searchDemandContentProvider"><bean class="cz.sw.getroommate.web.action.SearchDemandContentProvider">

<property name="sessionFactory" ref="sessionFactory"/><property name="defaultNumberPerPage" value="20" /><property name="defaultSortColumn" value="updated" /><property name="defaultSortDirection" value="desc" />

</bean></entry>

</map></property></bean>

Naimplementujeme jeho zakladnı kostru, ktera bude vracet vsechny polozky BO De-mand z databaze pomocı Hibernate Criteria API.SearchDemandContentProvider.java

public class SearchDemandContentProvider extends AbstractCriteriaContentProvider {protected Criteria getCriteria(ValueListInfo info, Session session) {

return session.createCriteria(Demand.class);}

}

Page 65: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 51

Predek AbstractCriteriaContentProvider zatım nenı v ValueList API, ocividne tamale patrı. Je zodpovedny za celou masinerii nahranı dat a nastavenı ValueListu, vzhledem krozsahu teto prace ho nebudu popisovat.

Zbyva napsat JSP stranku searchDemand.jsp, kterou jsme nainjektovali do beany sear-chDemandFormController.searchDemand.jsp

<title>Seznam poptavek</title><form:form commandName="searchDemandCommand"><div><label>Region:</label>

<form:select path="region" multiple="false" id="region"items="${searchDemandCommand.allRegions}" itemValue="id" itemLabel="name" />

<form:errors path="region" /></div>

<input type="submit" value="search" /></form:form>

<vlh:root value="list" configName="microsoftLook" url="?" includeParameters="#"><table class="microsoftLook" cellspacing="0" cellpadding="0"><vlh:row bean="demand"><vlh:column titleKey="Popis" property="description"><vlh:attribute name="class" value="description" /><tags:shorterDescription value="${demand.description}" maxLength="100" />

</vlh:column><vlh:controls title=""><vlh:action url="spolubydleni-detail-zajemce.html?"><vlh:attribute name="class" value="action" /><vlh:addParam property="id" /><spring:message code="searchForm.detail" arguments="${demand.id}" />

</vlh:action></vlh:controls>

</vlh:row></table><vlh:paging showSummary="true" pages="3" />

</vlh:root>

V tagu <form:form/> nenı nic noveho, mapujeme hodnotu z HTML selectu do propertyregion, jak jsem ukazal v kapitole 3.3.1.

• Tag <vlh:root/> zobrazuje ValueList.

• Pomocı <vlh:row/> iterujeme jednotlive radky tabulky z Listu.

• S <vlh:column/> nadefinujeme sloupce, jejich nazev a hodnotu z iteratoru, kterou v tomtoprıpade reprezentuje tag <tags:shorterDescription/>, ktery jsem pro tento prıpadnapsal.3 Mısto toho bychom jednoduse mohli napsat ${demand.description}.

• Tag <vlh:atribute/> umısteny v <vlh:row/> prıdava atributy do html <tr/> tagu,umısteny v <vlh:column/> pridava atributy do html <td/>.

• Tag <vlh:controls/> je urcen pro akce nad daty, specialne s <vlh:actions/> vytvorımehtml odkaz. Ve <vlh:root/> jsme napsali atribut includeParameters="#", tım jsmerekli, ze vsechno, co prislo ValueListu z requestu, take dosadı do <vlh:actions/>, cili

3Argumentem predam property ${demand.description}, kterou podle delky bud’ vratım celou, nebo zkracenouna 100 znaku plus ..., implementace je v definicnım souboru /WEB-INF/tags/shorterDescription.tag a ve trıdeTagHelper v metode getShorterDescription().

Page 66: Internetove technologie na platforme Java

52 KAPITOLA 3. IMPLEMENTACE

muzeme napsat pozadavek rovnou<vlh:action url="spolubydleni-detail-zajemce.html?">.

• Pomocı <vlh:addParam/> pridame id inzeratu do HTTP ReqestParameters.

• S <vlh:paging/> nastavujeme pocet stranek ze strankovacıho menu.

Napsali jsme zakladnı kostru stranky, vyhledavanı nenı zatım zapojene, stejne jakoodkaz na detail inzeratu. Zprovoznıme nejdrıve vyhledavanı pridanım kriteriı do trıdySearchDemandContentProvider. Tady je vhodna chvıle napsat test, jedna se o ucebnicovyprıpad, kdy zadame nejake hodnoty do databaze a v simulaci hledanı chceme vratit patricnypocet vysledku. Tento test je ve trıde SearchDemandContentProviderTest na prilozenem CD.

Chteli bychom podle zadanych lokalit k vyhledavanı vybrat inzeraty, ktere je obsahujı.Jenomze v tomto prıpade s Criteria API to tak jednoduche nenı. Vyznamne bychom si pomohli,kdyby v BO DemandLocation byla reference na Demand a tak obratili vlastnıka vztahu. Je toduvod k refaktorovanı, tak se do neho pustıme.

Odebereme mnozinu lokalit v BO Demand a pridame referenci do BO DemandLocation.DemandLocation.java

@Entitypublic class DemandLocation extends AbstractBo implements ILocation {

//...private Demand demand;@ManyToOne(optional = false)public Demand getDemand() {return demand;}public void setDemand(Demand demand) {this.demand = demand;}//...

}

Vsude tam, kde jsme pracovali s jednım BO, nynı musıme pracovat s dvema, coz nenıaz tak velka rezie. Horsı je, pokud chceme na JSP k dane instanci Demand zobrazit lokality.JSP nema prostredek k volanı metod s parametrem, pouzıvame pro to TagHelper. Napsaljsem tag <tags:location/>, kteremu predam instanci Demand, helper zavola metodu servisnıvrstvy, ktera vratı vsechny lokality k danemu inzeratu a helper vratı HTML vystup, kteryocekavame. Tento prıstup je na hranici unosnosti, bohuzel me nenapadlo lepsı resenı. Potommuzeme pomocı Criteria API zapsatSearchDemandContentProvider.java

public class SearchDemandContentProvider extends AbstractCriteriaContentProvider {protected Criteria getCriteria(ValueListInfo info, Session session) {

Criteria locationCriteria = session.createCriteria(DemandLocation.class);

addId(locationCriteria, "region.id", searchDemandCommand.getRegion());addId(locationCriteria, "district.id", searchDemandCommand.getDistrict());addId(locationCriteria, "city.id", searchDemandCommand.getCity());

Criteria criteria = locationCriteria.createCriteria("demand",CriteriaSpecification.INNER_JOIN);

if (searchDemandCommand.getMaxPrice() != null)criteria.add(Restrictions.le("maxPrice",

searchDemandCommand.getMaxPrice()));

locationCriteria.setProjection(Projections.distinct(Projections.property("demand")));

return criteria;

Page 67: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 53

}private void addId(Criteria c, String field, IBO bo) {

if (bo != null && bo.getId() != EnumService.EMPTY_ID) {if (bo instanceof District || bo instanceof City) {

Disjunction disjunction = Restrictions.disjunction();disjunction.add(Restrictions.eq(field, bo.getId()));disjunction.add(Restrictions.isNull(field));c.add(disjunction);return;

}c.add(Restrictions.eq(field, bo.getId()));

}}

}

Ze vsech lokalit pomocı metody addId() se vyberou jen ty, ktere uzivatel hledal; (muzouse stat tri prıpady, bud’ je v inzeratu nejaka cast lokality a hledame prave tuto cast, nebo jev inzeratu nejaka cast lokality, ale hledame “nezalezı”, cili nekladame podmınku, nebo je vinzeratu “nezalezı” a my hledame nejakou cast, cili bychom meli vratit i “nezalezı”). Z kriteriıpro lokality vytvorıme pres referenci na BO Demand kriteria, ktera v zaveru vracıme. Nastavımekriteria pro dalsı hledane polozky, v tomto prıkladu je to maximalnı cena. Nakonec vyberemez kartezskeho soucinu projekcı distinct ze sloupce demand a vracıme poptavkova kriteria.

Zbyva uz jen naimplementovat detail vyhledavaneho inzeratu. Budeme potrebovat jed-noduchy kontroler, ktery vezme id z HTTP RequestParameters, naloaduje z databaze inzeratpodle tohoto id a nastavı ho do scopu viditelneho z JSP a prejde na nej. Toho jsem docılilpomocı potomka od Springovskeho kontroleru MultiActionController. Jedna se o trivialnıprıklad a na konec kapitoly se nehodı.

3.3.4 Iterace 4

V minule iteraci jsem dokoncil vse k inzerovanı poptavky, do poslednı iterace jsemnaplanoval zprovoznit poslednı uzivatelske prıbehy:

• Pridat automaticke mazanı inzeratu.

• Pridat export do RSS.

Export do RSS je zajist’ovan pomocı opensource knihovny Informa dostupne na serverusourceforge.net. Vlastnı integrace do systemu je zarızena pomocı helperu RSSUtil, ktery abs-trahuje zakladnı metody tvorby RSS a umoznuje zmenit pouzitou RSS knihovnu (napr. ROME)pomocı zmeny jen tohoto helperu.

Cela aplikacnı logika je umıstena v servisnı trıde RSSService, kde se vytvorı novy RSSfeed, do ktereho z databaze prijdou inzeraty, ktere majı byt v RSS, tento feed se exportuje dosouboru, dostupneho z portalu. Pro vytvarenı popisu polozky RSS feedu je pouzit templatovacıframework Apache Velocity. Feed se updatuje kazde 3 hodiny pomocı tasku BuildRSSTask na-pojeneho na Quarz scheduler. Predstavenı Apache Velocity se neveslo do zaberu teto bakalarskeprace, zajemce odkazuji na referencnı dokumentaci nebo patricnou literaturu. Praci s Quarzschedulerem ukazu na nasledujıcım prıkladu.

Inzeraty se po nejake dobe stanou neaktualnı a v systemu se zacnou postupne hromadit.Cılem je naimplementovat resenı, ktere po x dnech posle uzivateli email, ze by si mel inzeratzaktualizovat, nebo bude po y dnech vymazan. Pokud ho zaktualizuje, cela vec se za x dnıopakuje. Kazdy den se spustı job, ktery posle uzivatelum potvrzovacı emaily a smaze stareinzeraty.

Page 68: Internetove technologie na platforme Java

54 KAPITOLA 3. IMPLEMENTACE

Potrebujeme tedy nejak zjist’ovat, jestli se ma poslat email, jestli ma byt inzerat smazannebo nedelat nic. Dobrym zvykem v OOP je umıst’ovat metody nejblıze k jejich datum, ciliidealne je umıstit do BO Offer a Demand reprezentujıcı nabıdkovy a poptavkovy inzerat. Tentoukol je jako stvoreny pro TDD, nejprve tedy napıseme test.OfferEraseTest.java

public class OfferEraseTest extends TestCase {Calendar calendar;Offer offer;protected void setUp() {

calendar = Calendar.getInstance();}public void testDontDeleteOffersWithoutCancellingMailSent() {

offer = new Offer();offer.setCancellingEmailSent(null);assertFalse(offer.willBeDeletedToday());

}

Pro tuto funkci nam stacı pridat jednu promennou typu Date cancellingEmailSent,pokud je null, jeste nebyl potvrzovacı email poslan, pokud nenı null a casovy rozdıl mezi toutopromennou a dneskem je vetsı nez y, bude oznacen pro smazanı. Tedy pridame dalsı polozkudo BO Offer. Prvnı metoda rıka, ze inzerat nebude smazan, pokud nebyl poslan email. MetodawillBeDeletedToday() je umıstena v BO, ale nechceme aby pro nı Hibernate hledal propertyk mapovanı do databaze, oznacıme jı anotacı @Transient.

public void testDeleteOffersWithCancellingMailSent() {offer = new Offer();calendar.roll(Calendar.DAY_OF_YEAR, -CancelAdvertisementTask.

MAX_DAYS_OFFER_TO_CANCEL);offer.setCancellingEmailSent(calendar.getTime());assertTrue(offer.willBeDeletedToday());

}

Pokud u inzeratu byl poslan potvrzujıcı email prave pred x dny, bude smazan.

public void testNotCancelWithCancellingMailSent() {offer = new Offer();calendar.roll(Calendar.DAY_OF_YEAR, -CancelAdvertisementTask.

MAX_DAYS_OFFER_TO_CANCEL + 1);offer.setCancellingEmailSent(calendar.getTime());assertFalse(offer.willBeDeletedToday());

}

A obracene, pokud byl poslan mail, ale jeste neuplynula doba x dnı, smazan nebude.

public void testSentCancellingMailWithCancellingMailNull() {offer = new Offer();calendar.roll(Calendar.DAY_OF_YEAR, -CancelAdvertisementTask.

MAX_DAYS_OFFER_TO_SEND_CANCEL);offer.setUpdated(calendar.getTime());offer.setCancellingEmailSent(null);assertFalse(offer.willBeDeletedToday());assertTrue(offer.willBeSentCancellingMail());

}

Zacali jsme testovat odesılanı emailu, pokud byl inzerat naposledy editovan pred y dnya potvrzovacı email jeste nebyl poslan, tak se posle.

Page 69: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 55

public void testSentCancellingMailWithCancellingMailNotNull() {offer = new Offer();offer.setUpdated(new Date()); //or something elseoffer.setCancellingEmailSent(new Date());assertFalse(offer.willBeSentCancellingMail());

}

Tady rıkame, ze pokud byl uz email poslan, znovu se neposle, podmınka v metodewillBeSentCancellingMail() testuje cancellingMailSent na ruznost od null, jejı hodnotamuze byt jakekoliv datum, v tomto prıpade nas to nezajıma.

public void testDontSendCancelingMail(){offer = new Offer();calendar.roll(Calendar.DAY_OF_YEAR, -CancelAdvertisementTask.

MAX_DAYS_OFFER_TO_SEND_CANCEL+1);offer.setCancellingEmailSent(null);offer.setUpdated(calendar.getTime());assertFalse(offer.willBeSentCancellingMail());

}}

Poslednı test rıka, ze pokud email nebyl poslan a inzerat byl editovan pred (y - 1)dny, email poslan nebude. Postupnym zprovoznovanım testu jsme naimplementovali tranzientnımetody v BO Offer.Offer.java

@Entitypublic class Offer extends AbstractBo {

//...@Transientpublic boolean willBeDeletedToday() {

if (cancellingEmailSent != null && MultifunctionHelper.getTimeDifferenceBetweenTodayAnd(cancellingEmailSent)>= CancelAdvertisementTask.MAX_DAYS_OFFER_TO_CANCEL) {

return true;}return false;

}@Transientpublic boolean willBeSentCancellingMail() {

Assert.notNull(updated);if (cancellingEmailSent != null) {

return false;} else if (cancellingEmailSent == null &&MultifunctionHelper.getTimeDifferenceBetweenTodayAnd(updated)>= CancelAdvertisementTask.MAX_DAYS_OFFER_TO_SEND_CANCEL) {

return true;}return false;

}}

Metoda MultifunctionHelper.getTimeDifferenceBetweenTodayAnd() vracı rozdıldnu mezi dneskem a predanym argumentem. Instance inzeratu vı, co se ma s nı udelat. Zbyvanaimplementovat vlastnı job, ktery provadı tyto ukony. Nejprve jej nakonfigurujeme. Pro tytoucely slouzı Quartz scheduler, stahl jsem knihovnu, pridal do classpath a nakonfiguroval Spring.core-service.xml

Page 70: Internetove technologie na platforme Java

56 KAPITOLA 3. IMPLEMENTACE

<bean name="cancelAdJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean"><property name="jobClass" value="cz.sw.getroommate.tasks.CancelAdvertisementTask" /><property name="jobDataAsMap">

<map><entry key="offerService" value-ref="offerService" /><entry key="demandService" value-ref="demandService" /><entry key="mimeMailService" value-ref="mailService" /><entry key="mailTemplate" value-ref="cancellingMail" />

</map></property>

</bean>

Vytvorıme job a nainjektujeme mu properties offer a demandService pro praci s inzeraty,mimeMailService pro odesılanı mailu a mailTemplate Velocity sablonu mailu.

<bean id="cancelAdCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"><property name="jobDetail" ref="cancelAdJobDetail" /><!-- run every 02:00 --><property name="cronExpression" value="0 0 2 * * ?" />

</bean><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="triggers">

<list><ref bean="cancelAdCronTrigger" />

</list></property>

</bean>

Nastavıme spoustenı jobu na kazdy den ve 2:00 a pridame trigger do SchedulerFactory-Bean. Nakonfigurovali jsme job, zbyva ho naimplementovat, zacneme opet od testu, ukazemesi zde jen jeho kostru.CancelAdvertisementTask.java

public class CancelAdvertisementTask extends QuartzJobBean implements ICronTask {public static final int MAX_DAYS_OFFER_TO_SEND_CANCEL = 3;public static final int MAX_DAYS_OFFER_TO_CANCEL = 3;public static final int MAX_DAYS_DEMAND_TO_SEND_CANCEL = 7;public static final int MAX_DAYS_DEMAND_TO_CANCEL = 3;

private OfferService offerService;private DemandService demandService;private MimeMailService mimeMailService;private CancellingEmailTemplate mailTemplate;//apropriate getters and setters

@Overrideprotected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {

doTask();}public void doTask() {

//no code (yet)}

}

Metoda executeInternal() je protected a tudız nejde volat jinde nez ve trıde (nebov potomkovi), potrebujeme nejak simulovat spustenı jobu, proto nedela nic jineho, nez ze volapublic metodu doTask(), kterou v testu bez obav volat muzeme.

Page 71: Internetove technologie na platforme Java

KAPITOLA 3. IMPLEMENTACE 57

Test na tento job nalezneme spolu s jeho implementacı v prilozenem CD ve trıdeCancellAdTaskOfferTest a CancelAdvertisementTask. Nedela nic jineho, nez ze nastavı tes-tovacı data a testuje smazanı z databaze nebo odesılanı emailu. Pro testovanı odesılanı emailuje pouzit embedded SMTP server subethamail a emailovy klient wiser.

Page 72: Internetove technologie na platforme Java

58 KAPITOLA 3. IMPLEMENTACE

Page 73: Internetove technologie na platforme Java

KAPITOLA 4. ZHODNOCENI 59

4 Zhodnocenı

4.1 Shrnutı

V resersnı casti jsem predstavil stezejnı technologie pouzıvane pri vyvoji webovych apli-kacı na platforme Java. Popsat jsem praci se Springem, Hibernatem a webovymi frameworkySpring Web MVC a Spring WebFlow. Popsal jsem metodiku Extremnıho programovanı a Pro-gramovanı rızene testy.

V implementacnı casti jsem popsal vyvoj casti aplikace pri zprovoznovanı uzivatelskychprıbehu. Ukazal jsem zakladnı pracovnı postupy a navyky. Prace svym rozsahem nesuplujepatricne dokumentace ani referencnı manualy, duraz jsem kladl na pouzitı vsech technologiı vkontextu a vse popsal na realnem netrivialnım prıkladu.

4.2 Moznosti rozsırenı

Naimplementovala se celkem velka cast nove funkcionality. Nejaky cas se budou zjist’ovatzpetne ohlasy od uzivatelu. Z dalsıch funkcı, ktere na portalu postradam, je ukladanı fotek bytua potencialnıch zajemcu o bydlenı, jez dokoncuji v dobe psanı tohoto odstavce.

4.3 Osobnı zkusenosti

Pevne verım, ze moje prace muze pomoci zacınajıcım vyvojarum webovych aplikacı vJave, ze muze poslouzit jako zakladnı seznamenı a uvod do problematiky.

Spolu s touto pracı jsem zıskal zkusenosti i na dalsım projektu ve firme Simple Ways.r.o., a tak muzu rıci, ze tento zpusob vyvoje aplikacı je zajımavy, snadno se osvojuje a nebranıpremyslet. Pokud jste po prectenı mojı prace zıskali podobny nazor na vec, jsem potesen.

Page 74: Internetove technologie na platforme Java

60 KAPITOLA 4. ZHODNOCENI

Page 75: Internetove technologie na platforme Java

KAPITOLA 5. OBSAH PRILOZENEHO CD 61

5 Obsah prilozeneho CD

/getroommate/src - ve slozce jsou zdrojove kody, adresar je projektem v Eclipse IDE.

/getroommate/war - webovy archiv spustitelny na AS.

/getroommate/readme.txt - podrobny navod pro spustenı aplikace.

/getroommate/bak.zip - zdrojovy text teto prace.

Page 76: Internetove technologie na platforme Java

62 KAPITOLA 5. OBSAH PRILOZENEHO CD

Page 77: Internetove technologie na platforme Java

KAPITOLA 6. LITERATURA 63

6 Literatura

[1] Servlets and jsp pages best practices, 2003.http://java.sun.com/developer/technicalArticles/javaserverpages/.

[2] Client-server - wikipedia, the free encyclopedia, 2007.http://en.wikipedia.org/wiki/Client-server.

[3] Core j2ee patterns, 2007.http://java.sun.com/blueprints/corej2eepatterns/Patterns.

[4] Core j2ee patterns - value list handler, 2007.http://valuelist.sourceforge.net/.

[5] Hollywood principle, 2007.http://en.wikipedia.org/wiki/Hollywood_Principle.

[6] Java ee 5 apis, 2007.http://java.sun.com/javaee/5/docs/tutorial/doc/Overview9.html.

[7] jmock-solid testing, 2007.http://therning.org/niklas/node/3&title=jMock-solid+Testing.

[8] Junit 4.4 kladivo na testy, 2007.http://www.sweb.cz/pichlik/archive/2007_08_05_archive.html.

[9] Key xp roles, 2007.www.softwarereality.com/lifecycle/xp/extreme_programming_roles.jsp.

[10] Manifesto for agile software development, 2007.http://agilemanifesto.org/.

[11] Mock object, 2007.http://en.wikipedia.org/wiki/Mock_object.

[12] Programming language wars, part one, 2007.http://radar.oreilly.com/archives/2007/03/programming_lan.html.

[13] The spring framework - reference documentation, 2007.http://static.springframework.org/spring/docs/2.0.x/reference.

[14] Spring web flow reference documentation, 2007.static.springframework.org/spring-webflow/docs/current/reference.

[15] Web frameworky v jave, 2007.http://www.sweb.cz/pichlik/archive/2006_12_10_archive.html.

[16] K. Beck. Programovanı rızene testy. Grada, 1 edition, 2004.

[17] G. K. Christian Bauer. Java Persistence with Hibernate (Hibernate in action revised).Apress, 2 edition, 2007.

[18] M. Fowler. Refactoring: Improving the Design of Existing Code. 1 edition, 2002.

[19] M. S. Mike Keith. Pro EJB3 Java Persistence API. Apress, 1 edition, 2006.

[20] D. D. Seth Ladd. Expert Spring MVC and Web Flow. Apress, 1 edition, 2006.

Page 78: Internetove technologie na platforme Java

64 KAPITOLA 6. LITERATURA

Page 79: Internetove technologie na platforme Java

KAPITOLA 7. SEZNAM POUZITYCH ZKRATEK 65

7 Seznam pouzitych zkratek

AOP Aspect Oriented Programming

API Application Programming Interface

AS Application Server

BO Bussiness Object

DAO Data Access Object

EJB Enterprise Java Beans

EL Expression language

HQL Hibernate Query Langugage

HTML HyperText Markup Language

HTTP HyperText Transfer Protocol

IoC Inversion of Control

JDBC Java Database Connection

JMS Java Message Service

JMX Java Management Extensions

JNDI Java Naming and Directory Interface

JSF Java Sever Faces

JSTL Java Standard Tag Library

JPA Java Persistence API

JPQL Java Persistence Query Language

ORM Object to relation mapping

OOP Object oriented programming

POJO Plain Old Java Object

RAD Rapid application development

SWF Spring WebFlow

SWT Standard Widget Toolkit

TDD Test-driven development

UI User Interface

WYSIWYG What You See Is What You Get

XML Extensible Markup Language

XP eXtream Programming