Obsah
Seznam obrázků
Seznam příkladů
Obsah
Předmět PA165 Vývoj programových systémů v jazyce Java je magisterským předmětem určeným pro zájemce o hlubší proniknutí do principů výstavby rozsáhlejších programových systémů na platformě Java.
Cílem je seznámit s principy:
kvalitního návrhu rozsáhlých systémů (jak navrhnout architekturu, jakou zvolit infrastrukturu/rámec...),
jejich tvorby (jaké zásady, nástroje,...)
testování (při vývoji, zavádění a v provozu),
refaktoringu (=zlepšování kódu bez změny funkcionality),
ladění výkonu (optimalizace)
Výuka probíhá jako:
Dvouhodinová přednáška - Po od 14.00 v A107
Dvouhodinová cvičení v nové učebně B130 (v přízemí "za halou")
Nedílnou součástí je řešení projektu - ve cvičení s možností konzultací nebo ve volném čase
Těžištěm předmětu je samostatná práce na projektech. Společně zadávaných úloh je proto minimum.
Projekty jsou koncipovány jako týmové (4členné týmy).
Tematicky vždy pokrývají netriviální část z celkového obsahového záběru předmětu a musí tomu být i technologicky přizpůsobeny.
Zadání projektu stanovuje nebo schvaluje cvičící.
Zkouška bude ústní.
Student při ní musí prokázat dobrý přehled ve studované problematice s tím, že principy a technologie, které aplikoval při řešení projektu musí zvládnout do větší hloubky.
Hodnocení předmětu je stanoveno podle celkového součtu bodů z jednotlivých kritérií:
Úlohy - 15 bodů
Projekt - 50 bodů
Ústní zkouška - 35 bodů
Obecné, známé principy OO jazyků:
možnost (a nutnost) zapouzdření dat a metod ned nimi pracujících do podoby objektu,
dědičnost (inheritance) - odvozování nových typů s děděním vlastností typů rodičovských,
polymorfizmus (mnohotvarost) - využitelnost objektů poděděných typů v roli předků
Na obecných principech OOP není mezi teoretiky a vývojáři (v různých jazycích) až taková shoda, jak by se mohlo zdát:
bezespornou charakteristikou OOP je zapouzdření,
další char. jako dědičnost (inheritance) je už v různých jazycích pojímána různě, příp. chybí - a přesto můžeme ještě hovořit o OO jazyku,
polymorfizmus (mnohotvarost)
Výhody OOP (za předpokladu kvalitního návrhu) jsou dobře známy:
dobrá čitelnost a udržovatelnost kódu,
rozšiřitelnost,
určitá vnitřní nahraditelnost částí - např. třídu lze nahradit potomkem
aspoň teoreticky - využitelnost i jako "black-box"/černá skříňka - bez znalosti zdrojového kódu
Ale tak skvělé to zase není:
bez zdrojového kódu lze dobře znovupoužít jen kvalitní objektový kód,
kód je znovupoužitelný většinou jen na mikroúrovni - jednotlivé třídy
k znovupoužití je třeba detailní znalosti celého prostředí programu, rozhraní větších programů bývá většinou komplikované - i proto, že komponenty (objekty) jsou příliš malé, jemné
V zásadě vychází z objektového, ale:
komponenty jsou VELKÉ (coarse-grained) objekty zapouzdřující ucelený kus aplikační logiky nebo dat,
komponenty jsou nezřídka přístupné i vzdáleně (tj. po síti, často i z jiných platforem/jazyků),
komponenty mohou (za podpory middleware) existovat relativně samostatně
vazby k ostatním jsou dobře kontrolovatelné a obecně spíše volné
jako protokoly, datové formáty atd. jsou přednostně použity standardní, byť třeba ne tak efektivní
Komponenta musí být:
dobře dokumentovaná, s jasně definovaným API, nejlépe i formálně
důkladně testovaná
robustní a odolná vůči chybám uživatele (validace vstupů)
musí mít podrobné hlášení chyb
musí se chovat defenzivně - být odolná vůči nesprávnému použití - je nutné s ním počítat
Přestože komponenty jsou ve většině případů realizovány jako objekty - a tedy komponentní programování je v zásadě pokračováním objektového - je tu jeden zásadní rozdíl.
Při návrhu objektů v podstatě přímočaře reprezentujeme strukturu a chování výseku reality.
Předpokládá se soulad chápání koncového uživatele (zákazníka) a návrháře ohledně této reprezentace.
Návrh komponent naproti tomu zcela podřizujeme účelu, proč komponenta existuje, a znovupoužitelnosti.
Vnitřní struktura uživatele (zákazníka) nezajímá.
Oproti OOP to umožňuje:
daleko lepší znovupoužitelnost - slabší vazby, vyšší autonomie
vyšší robustnost komponentních systémů
snazší vyměnitelnost (nefunkční, zastaralé) komponenty
možnost souběžného použití různých verzí komponent
lepší testovatelnost komponent vzhledem ke slabším vazbám
vývoj mohou dělat nezávislejší mikro-týmy
V javovém světě jsou minimálně tyto trendy a možnosti odpovídající KP:
pro výstavbu velkých systémů (aplikací) se používají Enterprise JavaBeans,
existují tzv. aplikační servery, které pro ně zajišťují middleware,
Komponentní principy nejsou užívány jen při tvorbě SW, ale i návrh struktur dokumentů:
Obecný příklon k chápání IT jako poskytovatele služby - servisu - nikoli jen technologie.
Stejně se začíná přistupovat i k vazbě mezi SW komponentami.
Orientace na služby se ve vývoji SW stává vůdčím směrem.
Architektury orientované na služby (Service-oriented Architectures - SOA) představují princip budování softwarových architektur založený na:
komponentách umístěných v uzlech sítě
nabízející své služby ostatním prostřednictvím dobře definovaného protokolu
služby jsou bezestavové
vnitřní realizace klienta obvykle nezajímá - standardy zajišťují interoperabilitu služeb
SOA v zásadě neváže na žádnou SW platformu, OS, pg. jazyk ani konkrétní standard.
V úzkém slova smyslu se za SOA dnes někdy považují architektury budované na tzv. Web Services (webových službách, WS) kolem množiny standardů:
XML - data reprezentovaná značkovanými dokumenty
HTTP jako základní webový protokol
SOAP - jako std. protokol WS
WSDL - popisovač webových aplikací
UDDI - služby registrace a vyhledávání webových služeb
Orientace na služby přináší:
Nahraditelnost služeb
Interoperabilitu
Možnost nezávislého ladění služeb
Usnadňuje integraci systémů třetích stran.
Oboje jsou moderní až módní záležitosti, vztah lze definovat takto:
Komponenta je často entitou realizující určitou službu.
Koncový uživatel nahlíží více na služby, zatímco vývojáře zajímají rovněž komponenty, které je realizují.
Kromě základního odkazu na Wikipedii lze navštívit/pročíst:
Obsah
Agilní programování (Agile Programming, AP) je relativně novým přístupem k vývoji software.
Není to jedna metodika, přesný návod, jak systém navrhnout a realizovat.
Je to spíše přístup, "filozofie", do které je třeba dodat konkrétní postupy pro jednotlivé úkony vývoje.
Označení Agilní programování bylo poprvé zavedeno skupinou autoritativních odborníků (praktiků) na SW metodiky.
Zastánci AP se sdružili při sestavení manifestu AP, formulující jeho hlavní zásady.
„We are uncovering better ways of developing software by doing it and helping others do it. Through this work we have come to value: “
„Individuals and interactions over processes and tools“
„Working software over comprehensive documentation“
„Customer collaboration over contract negotiation“
„Responding to change over following a plan “
„That is, while there is value in the items on the right, we value the items on the left more.“
Motivací pro AP byla především řada neúspěchů při budování rozsáhlých softwarových děl a řízení realizačních projektů.
Projekty trvaly déle, než se předpokládalo.
Stály více peněz.
Objevovala se negativa typu "hraní na úspěch/výsledek" a nikoli výsledek sám.
K cíli se nešlo přímočaře, produkovaly se dále nevyužité (nevyužitelné) artefakty, věci do zásoby.
Mezi zadavatelem (zákazníkem) a tvůrcem byla propast (formalizmus místo spolupráce).
Vytvořené produkty pak často neodpovídaly aktuální potřebě...
Realizovat věci nejjednodušším možným způsobem.
Tak se předejde nadměrné složitosti vytvářeného artefaktu.
Je větší šance, že produkt bude bez chyb.
Vynakládání prostředků lze při dodržení této zásady lépe kontrolovat.
Namísto jednorázového (obvykle složitého) jednání o smlouvách s přesnou (a v podstatě statickou) specifikací zadání:
Zákazník (budoucí uživatel) je ve stálém, nejlépe denním a osobním kontaktu s vývojářem.
Takové dynamické týmy musejí být dobře motivované, nehrát si na úspěch, ale musejí o něj stát.
Zákazník často dostává nové verze (měsíčně, ještě lépe týdně), ihned konfrontuje stav s požadavky, hledá chyby...
Technická kvalita je základem. Neváhá se kvůli tomu podstoupit i radikální refaktoring kódu.
Na vývoj software má vliv mnoho faktorů, které se neustále mění (zadání, návrh, technologie, trh, složení týmu apod.). Obecně lze říci, že změna je jedinou konstantou vývoje software. Problémem vývoje softwaru je schopnost úspěšného zvládnutí těchto změn za přijatelné náklady.
Toto je východisko pro řadu moderních metodik programování (řízení SW projektů), které se souhrnně označují jako agile programming.
Mezi ně patří i Extreme Programming (XP).
Viz J. Ministr, IT pro praxi, 2004:
Extrémní programování (XP) je metodika vývoje softwaru, která je postavena na tvorbě zdrojového textu v týmech, jež tvoří dva až deset programátorů. XP používá obecně známé principy a postupy vývoje softwaru, tyto však dotahuje do extrémů.
Od ostatních metodik se XP odlišuje v následujících vlastnostech:
testy jsou tvořeny před samotnou tvorbou zdrojového textu za účelem následného ověření skutečného pokroku ve vývoji softwaru z hlediska jeho požadované funkcionality (testy navrhuje zákazník) a architektury programového modulu (testy navrhuje programátor).
společně s testy a zdrojovým textem slouží ke sdělování systémové struktury a záměru projektu.
Postupy, které podporují intuici programátorů a dlouhodobé zájmy projektu (testování, refaktorizace, integrace apod.).
Udržení řádných komunikačních toků ovlivňuje kvalitu jednotlivých postupů XP (testování modulů, párové programování, stanovení metrik apod.).
Vývoj software je řízen zásadou, že je lepší udělat jednoduchou věc dnes, s vědomím, že zítra bude možná nutné provést další změnu, spíše než udělat složitější změnu dnes, která nemusí být uživatelem využita. Jednoduchost a komunikace jsou spolu komplementární. Čím více tým komunikuje, tím je mu jasnější co přesně má dělat. Naopak čím je jednodušší systém, tím méně potřebujeme komunikovat.
Členové týmu jsou ochotni experimentovat s vyšším rizikem a ziskem.
představuje fixní proměnnou ze čtyř proměnných pro posouzení projektu (šíře zadání, náklady, čas a kvalita) s hodnotou vynikající, při horší hodnotě členy týmu práce nebude bavit a projekt může skončit neúspěchem.
představuje soustředění práce týmu na kvalitu vyvíjeného produktu, nikoli na zbytečné alibistické činnosti, kdy tým pracuje „podle předpisů“ (mnoho papírů a porad), aby se tzv. „neprohrálo“.
kdy všechna abstraktní rozhodnutí by měla být převedena do řady experimentů, které jsou následně otestovány.
a nikoli proti nim představuje práci s krátkodobými zájmy lidí, kteří se rádi učí, vyhrávají, komunikují s ostatními apod.
představuje hodnotné a účinné nástroje vývoje softwaru, které tvoří především testy a zdrojový text.
Plánovací hra stanoví šíři zadání následující verze software pomocí kombinace obchodních priorit a technických odhadů.
Malá verze představuje rychlé uvedení jednoduchého systému do provozu. Následně jsou uvolňovány malé přírůstky systému ve velmi krátkých cyklech.
Metafora pomáhá všem v projektu pochopit základní prvky systému a vztahy mezi nimi na základě jednoduchého přirovnání.
Jednoduchý návrh u něhož je nadbytečná složitost ihned odstraněna v okamžiku jejího zjištění z návrhu.
Testování představuje činnost programátorů a zákazníků, kdy programátoři testují zdrojový text z hlediska jeho programových vlastností, aby mohli pokračovat v jeho dalším psaní, a kdy uživatelé otestují funkcionalitu modulu, která je úspěšným provedením testu dokončena.
Refaktorizace představuje restrukturalizaci systému s cílem zdokonalení jeho nefunkčních kvalit (pružnost, zjednodušení) bez vlivu na jeho chování.
Párové programování představuje vývoj zdrojového textu dvěma programátory na jednom počítači.
Společné vlastnictví
Nepřetržitá integrace - okamžitá integrace dokončeného otestovaného přírůstku do systému.
40 hodinový týden plus se nepracuje nikdy přesčas dva týdny za sebou.
Zákazník na pracovišti - odpovídá na otázky programátorů při vývoji software.
Standardy pro psaní zdrojového textu
představuje stanovení termínu programátory společně se zákazníky na základě postupu plánovací hry. Do uvolnění první verze by mělo trvat mezi dvěma až šesti měsíci.
představuje stav systému, kdy je software neschopen své existence z důvodu neekonomického rozšíření jeho funkcionality, entropie (tendence k většímu počtu chyb). Zákazníci i manažeři by měli souhlasit s ukončením údržby systému s tím, že se snaží identifikovat příčiny zániku systému.
Netýká se jen programování, je to obecný princip vývoje či realizace čehokoli.
Snahou je produkovat co nejjednodušeji, bez zbytečností, bez nadbytečností, s minimem chyb.
KISS přístup patří do základního arzenálu Agilního programování.
Ideovými předchůdci principu jsou např.:
tzv. Occamova břitva (Occam's Razor)
Realizovat věci nejjednodušším možným způsobem.
Tak se předejde nadměrné složitosti vytvářeného artefaktu.
Je větší šance, že produkt bude bez chyb.
Vynakládání prostředků lze při dodržení této zásady lépe kontrolovat.
Aplikace se vyvíjejí často překotně, pak je třeba "předělávat".
Refaktoring je právě takové "předělávání":
přepis beze změny (vnějšího) chování/rozhraní
směřuje ke zpřehlednění,
optimalizaci,
lepší rozšiřitelnosti
robustnosti atd.
Hlavní metody:
manipulace na úrovni návrhu: přesuny tříd mezi balíky, přejmenování tříd
přesuny metod mezi třídami
vysunutí metody do nadtřídy
"vytknutí" (do) rozhraní
zapouzření datového prvku (proměnné) přístupovými metodami
...
Klasický způsobe vývoje SW předpokládá testování jako následnou fázi - testy se píší a spouštějí až po návrhu software
To je však paradoxní, protože návrh testů vychází - stejně jako návrh vlastního kódu - ze specifikace a to dokonce přímočařeji. Test je přímý odraz specifikace, protože programovým kódem hlídá chování, které je specifikací očekáváno.
Programování řízené testy proto předřazuje návrh a implementaci testů před vývoj vlastního SW.
Jde o metodiku vývoje samotného SW, ne testů.
Nejprve sestavit test, pak psát kód.
Stejný cíl jako Návrh dle kontraktu (Design by Contract), ale separuje testy od kódu, testuje "zvenčí".
Výhody: včasná (okamžitá) detekce chyb v kódu
Nevýhody: nelze použít tam, kde je obtížné automatizovaně testovat
... resp. teoreticky lze, prakticky však chybí přijatelné nástroje a metodiky:
distribuovaná prostředí (částečně již lze: např. Cactus pro webové aplikace)
grafická uživatelská rozhraní (i tam částečně lze: pomocí "robotů" na obsluhu GUI - na simulaci klikání a ovládání klávesnice)
Napsat test - na základě specifikace (požadavků) reprezentovaných např. případy užití (usecases).
Test bude používat samotný kód prostřednictvím rozhraní.
Napsat kód - aby splnil specifikaci a komunikoval se světem pomocí rozhraní (API).
Spustit automatizované testy.
V případě chyb kód přeprogramovat (refactoring) a
spustit testy znovu.
některé převzaty z Wikipedie, hesla Test-driven Development:
Systémy pro správu verzí jsou nezbytností pro
Pouhý sdílený, vzdáleně přístupný souborový systém nestačí.
RCS je klasický, původně na UNIXech existující systém navržený pro sledování více verzí souborů.
Prvotním cílem bylo zefektivnit ukládání více verzí
(podobné jsou v CVS, SVN)
Syst. správy verzí nabízejí
server existuje jako samostatná aplikace, standardní použití je však s webových serverem Apache
Klient pro Win 2k, XP i 98... vč. integrace do GUI
Řízení sestavování Antem postupuje podle popisu v souboru build.xml.
Ten obsahuje následující prvky:
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
![]() | Varování |
---|---|
Pozor na cyklické závislosti! |
Pro sestavování, správu a údržbu SW projektů menšího a středního rozsahu se delší dobu úspěšně využíval systém Ant.
Oproti klasickým nástrojům typu unixového make poskytoval Ant platformově nezávislou možnost popsat i složité postupy sestavení, testování a nasazení výsledků SW projektu.
Ant měl však i nevýhody:
pro každý projekt (i když už jsme podobný řešili) musíme znovu
sestavit - poměrně velmi technický - popisovač
(build.xml)
popisovač je vždy téměř stejný a tudíž
neříká nic o obsahu vlastního projektu, je jen o procesu sestavení, nasazení...
neumožňoval zachytit metadata nezbytná pro zařazení projektu do širšího kontextu, mezi související projekty, atd.
nástroj řízení SW projektů
open-source, součást skupiny nástrojů kolem Apache
dostupný a popsaný na http://maven.apache.org
momentálně (září 2004) již jako použitelná, ostrá, verze 1.0
projekt řízený Mavenem je popsán tzv. POM
(Project Object Model), obvykle
project.xml
POM nepopisuje postup sestavení, ale obsah projektu, jeho název, autora, umístění, licenci...
postup sestavení je "zadrátován" v Mavenu, protože je pro většinu projektů stejný
programátor není frustrován opakováním psaní popisovačů
build.xml, návrhem adresářové
struktury...
nicméně, Maven je založen na Ant, jeho
build.xml popisovače lze znovupoužít
Základní filozofie projektu v Mavenu:
jeden projekt => jeden tzv. artefakt
Artefaktem může být typicky:
.jar - obyčejná aplikace nebo knihovna (javové třídy, soubory .properties, obrázky...)
.war - webová aplikace (servlety, JSP, HTML, další zdroje, popisovače)
.ear - enterprise (EJB) aplikace (vše výše uvedené pro EJB, popisovače)
základním organizačním nástrojem pro správu vytvořených (nebo používaných) artefaktů je repository
artefakt, tj. výstup projektu, se může v repository vyskytovat ve více verzích
repository je:
slouží k centralizovanému umisťování jak vytvořených, tak používaných artefaktů
dosažitelná pro čtení pomocí HTTP: je to de-facto běžné webové místo
slouží k ozrcadlení používaných artefaktů ze vzdálené repository
typicky zvlášt každému uživateli - v jeho domovském adresáři
slouží též k vystavení vytvořených artefaktů "pro vlastní potřebu"
Maven má nástroje (pluginy) pro vystavování artefaktů do repository
Maven lze stáhnout z http://maven.apache.org v binární i zdrojové distribuci.
Binární distribuce je buďto čistě "java-based" nebo ve formě
windowsového .exe.
Pak se nainstaluje do Program Files
Po instalace je třeba nastavit proměnnou prostředí
MAVEN_HOME na adresář, kam se nainstaloval.
Kromě toho ještě přidat adresář
%MAVEN_HOME%\bin do
PATH
.
Příklad minimálního popisovače
project.xml:
<project>
<pomVersion>3</pomVersion><!-- verze POM - zatím vždy 3 -->
<id>RunningCalculator</id><!-- jednoznačné id projektu -->
<name>RunningCalculator</name><!-- (krátké) jméno/nemusí být jednoznačné -->
<currentVersion>0.1</currentVersion><!-- momentální verze -->
<organization><!-- organizace vytvářející projekt -->
<name>Object Computing, Inc.</name>
</organization>
<inceptionYear>2004</inceptionYear><!-- rok zahájení projektu -->
<shortDescription>calculates running pace</shortDescription><!-- stručný popis -->
<developers/>
Příklad minimálního popisovače
project.xml:
<dependencies><!-- závislosti -->
<dependency><!-- závislost -->
<groupId>junit</groupId><!-- skupina artefaktu -->
<artifactId>junit</artifactId><!-- označení artefaktu -->
<version>3.8.1</version><!-- verze artefaktu -->
</dependency>
</dependencies>
<build><!-- odkud se co a jak sestavuje... -->
<sourceDirectory>src/java</sourceDirectory><!-- adresář zdrojů -->
<unitTestSourceDirectory>src/test</unitTestSourceDirectory><!-- adresář zdrojů testů -->
<unitTest><!-- které soubory jsou třídy testů -->
<includes>
<include>**/*Test.java</include>
</includes>
</unitTest>
</build>
</project>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="MAVEN_HOME/maven-project.xsd">
<pomVersion>3</pomVersion>
<id>unique-project-id</id>
<name>project-name</name>
<groupId>repository-directory-name</groupId>
<currentVersion>version</currentVersion>
<!-- Management Section -->
<!-- Dependency Section -->
<!-- Build Section -->
<!-- Reports Section -->
</project>
Jsou podobně jako u Antu definovatelné a využitelné
(odkazovatelné) v popisovači, zde
project.xml.
Vyskytne-li se zavedení určité vlastnosti (property) vícekrát, uplatní se poslední.
Vlastnosti jsou vyhledávány v pořadí:
vlastnosti specifikované na příkazové řádce -Dkey=value
Na vlastnost se lze odvolat pomocí ${property-name}
Týká se jak vzdálené, tak lokální repository.
Obecně je relativní cesta v rámci repository k hledanému artefaktu: repository/resource-directory/jars/jar-file
konkrétní např.: repository/junit/jars/junit-3.8.1.jar
Cíle (goals) v Mavenu odpovídají zhruba antovým cílům (target).
Spouštění Mavenu vlastně odpovídá příkazu k dosažení cíle ("attaining the goal"):
Zásuvné moduly (plugins) obsahují předdefinované cíle (goals) a jsou taktéž uloženy v repository.
Většinou jsou jednoúčelové, slouží/směřují k jednomu typu artefaktu, např.:
checkstyle, clean, clover, cruisecontrol, dist, ear, eclipse, ejb, fo, genapp, jalopy, jar, java, javadoc, jboss, jcoverage, maven-junit-report-plugin, pom, site, test, war, xdoc
smaže vygenerované soubory (podstrom
target)
přeloží všechny javové zdroje
spustí všechny testy
vygeneruje webové sídlo projektu
vygeneruje kompletní distribuci
vytvořit prázdný adresář pro vytvářený projekt
spustit maven genapp (Zeptá se na id
projektu, jeho jméno a hlavní balík. V něm předgeneruje jednu
třídu.)
tím se vytvoří následující soubory:
project.xml, project.properties
src/conf/app.properties
src/java/package-dirs/App.java
src/test/package-dirs/AbstractTestCase.java
src/test/package-dirs/AppTest.java
src/test/package-dirs/NaughtyTest.java
Generování reportů (zpráv) je jednou se základních funkcí Mavenu.
Které reporty se generují, je regulováno v project.xml v sekci reports:
<reports>
<report>maven-checkstyle-plugin</report>
<report>maven-javadoc-plugin</report>
<report>maven-junit-report-plugin</report>
</reports>
Cílů (goals) je sice v Mavenu řada, ale přesto nemusejí stačit anebo je třeba měnit jejich implicitní chování.
Potom lze před nebo po určitý cíl připojit další cíl pomocí preGoal a postGoal.
Ty se specifikují buďto v nebo.
maven.xml ve stejném adresáři jako
project.xml
nebo
v zásuvném modulu (pluginu)
Zcela nové cíle je možné napsat ve skriptovacím jazyku jelly (s XML syntaxí).
Obsah
Seznam obrázků
Seznam příkladů
Technologie JSP a Java Servlety jsou jedny ze základních technologií Java™ 2 Platform, Enterprise Edition (J2EE).
Servlet je program v Javě, který rozšiřuje funkcionalitu webového serveru, generuje dynamický obsah a komunikuje s webovými klienty pomocí request-response paradigmatu.
JavaServer Pages™ (JSP) je abstrakce servletového modelu. JSP stránky jsou rozšiřující webovou technologií, využívající značkovací šablony, specifikovatelné elementy, skriptovací jazyky a server-side Java objekty pro zpřístupnění dynamického obsahu klientovi. Nejčastěji se jako šablony používají HTML či XML elementy a ve většině případů je klientem webový browser.
Specifikace servletu a JSP je dostupná na: http://java.sun.com/products/servlet a http://java.sun.com/products/jsp.
Servlety jsou reakcí Javy na CGI scripty. Jedná se o programy v Javě, které běží na webovém serveru a odpovídají na požadavky ze stany klientů. Servlety nejsou spjaty s žádným konkrétním client-server protokolem, nicméně nejširší využití servletů je s HTTP protokolem. Označením „Servlet“ je tedy často míněn „HTTP Servlet“.
Servlety jsou implementací tříd v balíku
javax.servlet (základní Servlet framework) a
javax.servlet.http
(rozšíření Servlet frameworku
pro servlety odpovídají na HTTP požadavky). Jelikož jsou servlety
napsáný ve vysoce portabilním jazyku a s splňují požadavky na framework,
umožňují vytváření sofistikovaných serverových aplikací nezávisle na
operačním systému.
Servlety se používají zejména pro:
Tradiční způsob přidávání další funkcionality webovému serveru je pomocí Common Gateway Interface (CGI), jedná se o jazykově nezávislý interface, který umožňuje serveru spouštět externí procesy. Každý požadavek je zodpovězen separátní instancí CGI scriptu.
Servlety mají nad CGI několik výhod:
Servlet neběží v separátním procesu. Což odstraňuje zátěž s vytvářením nového procesu pro každý požadavek.
Servlet zůstává v paměti mezi požadavky. CGI script je nutné nahrávat a spouštět pro každý požadavek.
Existuje pouze jediná instance servletu, která souběžně obsluhuje všechny požadavky. Tímto se ušetří paměť a zároveň může servlet jednoduše obsluhovat všechna data.
Servlet může běžet v sandboxu a mít tak pevně definované bezpečnostní omezení.
Na obrázku 1 je zobrazen jeden z nejčastějších využití servletů. Uživatel (1) vyplní formulář, který se odkazuje na servlet a kliknutím na submit tlačítko vyšle požadavek na informaci (2). Server (3) lokalizuje požadovaný servlet (4). A teď vyhodnotí a vrátí požadované informace ve formě web stránky (5). Ta je poté zobrazena v uživatelově prohlížeči (6).
Servlet ve své nejobecnější formě je instance třídy, která
implementuje javax.servlet.Servlet interface.
Většina servletů je potomkem jednoho ze standardních implementací
tohoto interfacu, jmenovitě
javax.servlet.GenericServlet
a
javax.servlet.http.HttpServlet
.
Při inicializaci servletu načte server třídu servletu (a ostatní
odkazované třídy) a vytvoří instanci voláním bezparametrového
konstruktoru. Následně zavolá metodu servletu
init(ServletConfig config). Servlet při
vykonávání této metody uloží ServletConfig
objekt, který bude dostupný metodou
getServletConfig(). Toto vše je obstaráno
GenericServletem. Servlety, které jsou potomky
GenericServletu
(nebo jeho podtřídy
HttpServlet
) by měli volat
super.init(config) na začátku metody
init. Vzniklý objekt
ServletConfig
obsahuje parametry servletu a
odkaz na ServletContext
obsahující runtime
environment informace. Metoda init je v životním
cyklu servletu volána pouze jednou.
Poté co je servlet inicializován, je jeho metoda service(ServletRequest req, ServletResponse res) volána pro každý požadavek na servlet. Tato metoda je volána souběžně (např. multiple threads mohou volat tuto metodu ve stejný okamžik) a tudíž je nutné, aby byla implementována jako thread-safe.
V případě potřeby odstranění servletu z paměti (např. z důvodu nahrání nové verze nebo vypínaní serveru) je volána metoda destroy().
Ještě před tím, než se pustíme do psaní našeho prvního servletu, musíme znát několik základních rysů HTTP protokolu.
HTTP je request-response orientovaný protokol. HTTP požadavek se skládá z metody request , URI, hlaviček a těla dotazu. HTTP odpověď obsahuje kód odpovědi, hlavičky a tělo.
Metoda service HttpServletu rozděluje
požadavek vstupním metodám servletu podle typu HTTP požadavku. Jsou
rozeznávaný standardní HTTP/1.1 metody: GET, HEAD, PUT, POST, DELETE,
OPTIONS a TRACE. Ostatní metody jsou vráceny jako: Bad Request HTTP
error. HTTP metoda XXX je přiřazena metoda servletu
doXxx, (GET -> doGet()).
Všechny tyto metody očekávají parametry
„(HttpServletRequest req,
HttpServletResponse
res)“. Metody
doOptions() a doTrace() mají
dostatečnou defaultní implementaci a obvykle je nepředefinovávají.
Metoda HEAD (která vrací pouze hlavičky) je řešena voláním
doGet() a ignorací výstupu této metody. Tím nám
zůstávají metody doGet, doPut, doPost a doDelete, jejich výchozí
implementace v HttpServletu vrací: Bad Request HTTP error. Podtřída
HttpServletu předefinovává jednu či více těchto metod smysluplnou
implementací.
Data požadavku vstupují do servletu přes první argument typu
HttpServletRequest (který je podtřídou
obecnější třídy ServletRequest
). Odpověď může
být vytvořena skrz druhou proměnou, která je typu
HttpServletResponse
(podtřída
ServletResponse
).
V okamžiku, kdy v našem prohlížeči zadáme požadavek na URL, je použita metoda GET. Odpověď se bude skládat z těla odpovědi a hlaviček popisující tělo (obzvláště Content-Type a Content-Encoding). Pokud posíláme HTML formulář, můžeme použít metodu GET nebo POST. S GET požadavkem jsou parametry zakódovaný v URL a s POST požadavkem jsou přeneseny v těle požadavku.
Začneme obvyklým „Hello World“ příkladem
Příklad 31..1. HelloClientServlet.java
1: import java.io.*;
2: import javax.servlet.*;
3: import javax.servlet.http.*;
4:
5: public class HelloClientServlet extends HttpServlet
6: {
7: protected void doGet(HttpServletRequest req,
8: HttpServletResponse res)
9: throws ServletException, IOException
10: {
11: res.setContentType("text/html");
12: PrintWriter out = res.getWriter();
13: out.println("<HTML><HEAD><TITLE>Hello Client!</TITLE>"+
14: "</HEAD><BODY>Hello Client!</BODY></HTML>");
15: out.close();
16: }
17: }
Podívejme se jak daný servlet funguje.
Řádky 1 až 3 importují balíky potřebné pro běh servletu.
1: import java.io.*;
2: import javax.servlet.*;
3: import javax.servlet.http.*;
Třída servletu je deklarovaná na řádku 5. Servlet dědí třídu javax.servlet.http.HttpServlet, standardní třída pro HTTP servlety.
5: public class HelloClientServlet extends HttpServlet
Na řádcích 7 až 16 je předefinovaná metoda doGet() HttpServletu.
7: protected void doGet(HttpServletRequest req,
8: HttpServletResponse res)
9: throws ServletException, IOException
10: {
...
16: }
Na řádku 11 je pro nastavení content type odpovědi použita
metoda třídy HttpServletResponse. Všechny
hlavičky odpovědi musí být nastaveny před tím než je zavolán
PrintWriter
nebo
ServletOutputStream
pro výpis dat.
11: res.setContentType("text/html");
Řádek 12: pomocí třídy PrintWriter je
zapsán text do odpovědi.
12: PrintWriter out = res.getWriter();
13 až 14 no comment ...
13: out.println("<HTML><HEAD><TITLE>Hello Client!</TITLE>"+
14: "</HEAD><BODY>Hello Client!</BODY></HTML>");
Po ukončení zápisu zavíráme na řádku 15
PrintWriter.
15: out.close();
Tento řádek je uveden pro úplnost. Není striktně vyžadován. Web
server zavírá PrintWriter nebo
ServletOutputStream
automaticky po návratu
metody service.
Obsah
Servlet/JSP container umožňuje používání JSP souborů. Container dostane (od webového serveru) JSP soubor, ke zpracování, přeloží ho do java-byte kódu, provede a výstup předá zpátky (webovému serveru).
Jedním z nejpoužívanějších Servlet/JSP containerů je Apache Jakarta Tomcat. http://jakarta.apache.org/tomcat
Tomcat verze 5.5 implementuje Servlet 2.4 a JavaServer Pages 2.0 specifikaci a obsahuje mnoho dalších vlastností, které z něj činní vhodnou platformu pro vývoj a provoz webových aplikací a webových služeb.
bin - startovací scripty
common - adresář pro třídy a balíky sdílené všemi aplikacemi i serverem
conf - soubory s konfigurací serveru
logs - výstup a logy serveru
server - knihovny nezbytné pro běh serveru
shared - adresář pro třídy a balíky sdílené všemi aplikacemi
webapps - úložiště pro aplikace
work - pracovní adresář pro běžící aplikace
temp - adresář používaný JVM pro dočasné soubory (java.io.tmpdir)
Tomcat se spouští pomocí příkazu startup.sh,
poté je server dostupný na portu 8080 na daném serveru http://localhost:8080
Ukončení běhu serveru se provádí příkazem
shutdown.sh
Top-level adresář ve struktuře aplikací je i kořenovým adresářem naší aplikace. Po nahrání aplikace na server bude dostupná právě pod jménem aplikace: např soubor index.html v aplikaci catalog, bude odkazovaná jako http://server/catalog/index.html
Vnitřní struktura aplikace odpovídá formátu WAR souboru
*.html, *.jsp, atd. - HTML a JSP stránky musí být spolu s ostatními soubory viditelné pro prohlížeče klientů (to platí i pro JavaScript, CSS a obrázky). V rozsáhlejších aplikacích se přistupuje do rozdělení těchto souborů do jednotlivých podadresářů
/WEB-INF/web.xml - (Web Application Deployment Descriptor) je XML soubor pro naši aplikaci popisující servlety a ostatní komponenty v aplikaci. Dále obsahuje případné definice inicializačních parametrů a bezpečnostních omezen.
/META-INF/context.xml (Tomcat Context Descriptor) je soubor, který může být použit pro specifické definice Tomcatu jako: loggers, data sources, session manager configuration a další.
/WEB-INF/classes/ - Adresář obsahující zkompilované soubory servletů a ostatních tříd, které nejsou zabalené v JAR archívu. Pokud máme třídy organizované v balíčcích, musíme respektovat tuto adresářovou strukturu i v /WEB-INF/classes/ např. třída com.mycompany.mypackage.MyServlet musí být uložena v souboru /WEB-INF/classes/com/mycompany/mypackage/MyServlet.class.
/WEB-INF/lib/ - Adresář obsahující JAR soubory.
Základní myšlenka strukturu naší aplikace je oddělení zdrojových kódu od binárních. Takovéto rozděleni přináší následující výhody:
Obsah zdrojových adresářů lze jednoduše spravovat, přesouvat a zálohovat.
Správa zdrojových kódů je jednodušší pokud adresáře obsahují pouze zdrojové soubory.
Distribuční soubory jsou hierarchicky oddělené od zdrojových.
Později uvidíme, že vytváření hierarchické struktury adresářů za pomocí antu je velmi snadné.
Doporučená struktura adresářů:
docs/ - Dokumentace.
src/ - Java zdrojové kódy pro servlety, beany a další třídy. Pokud jsou zdrojové soubory organizovány do balíčků (což je vřele doporučováno), musí struktura balíčku odpovídat struktuře adresářů.
web/ - statické stránky (HTML, JSP, JavaScript, CSS a obrázky). Tento adresář bude kořenovým adresářem webové aplikace. Veškerá podadresářová struktura bude zachována.
web/WEB-INF/ - konfigurační soubory pro aplikaci (web.xml), taglibs a jiné. Soubory v tomto adresáři nebudou přístupné klientům. Z tohoto důvodu je právě toto místo vhodné pro ukládaní konfiguračních souboru s citlivými informacemi (hesla k přístupu do databáze).
V průběhu kompilace dojde k vytvoření dvou adresářů:
build/ - po spuštění antu obsahuje tento adresář kompletní obraz přeložené aplikace.
dist/ - do toho adresáře umístí ant war soubor s aplikací
Není vhodné do aplikace začleňovat JAR soubory běžných aplikací.
Ty je vhodnější umístit na server do sdílených složek common nebo shared
.
Taktéž není příliš vhodné umisťovat přiložené třídy do SVN repozitory.
V souboru web.xml je uveden popis
aplikace, použití různých filtrů, taglibs, servletů atd. V následují
ukázce je uvedeno na jaký odkaz má Tomcat přemapovat servlet
HelloWorldExampleServlet
, který je spouštěn
třídou mypackage.HelloWorldExample
.
Příklad 32..1. web.xml
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Hello, World Application</display-name>
<description>
This is a simple web application with a source code organization
based on the recommendations of the Application Developer's Guide.
</description>
<servlet>
<servlet-name>HelloWorldExampleServlet</servlet-name>
<servlet-class>mypackage.HelloWorldExample</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldExampleServlet</servlet-name>
<url-pattern>/HelloWorldExample</url-pattern>
</servlet-mapping>
</web-app>
Existují dva hlavní způsoby jak svou aplikaci do Tomcatu nainstalovat:
Použít webovou nástavbu tomcat manageru, což je nástroj
který umožňuje instalovat do Tomcatu aplikace. Buď můžeme použít
jeho grafickou nástavbu: a aplikaci zabalenou do war jím
nainstalovat http://kore.fi.muni.cz:8080
a nebo, což je úplně nejjednodušší, použít
Ant, který za nás aplikaci do waru
sestaví a managerem nainstaluje. K tomu abychom mohli manažer
používat, je nutné buď znát heslo managera nebo jako uživatel
mít roli managera. Jelikož uživatel v roli managera může
odstraňovat veškeré aplikace, dávejte si pozor, aby jste
neodstranili aplikaci i někomu jinému!
Použít antový target, který používá třídy z balíku
catalina-ant.jar. Balík obsahuje i další
targety, které umožňují plně využít veškeré schopnosti tomcat
managera.
Použití Antu je snadná věc, kterou zvládne opravdu každý a
ušetří si tak spoustu práce. Pro instalaci do tomcat manageru je
potřeba nakopírovat soubor catalina-ant.jar z
tomcatu do $ANT_HOME/lib
. Ant v
modulech již uvedený soubor obsahuje a tak není potřeba nic kopírovat.
Stačí přidat Ant:
Ant používá jako konfigurační Makefile soubor
buil.xml v kterém jsou uvedeny jednotlivé
targets a parametry. Pro základní použití není
potřeba konfiguračnímu souboru příliš rozumět, navíc je možné
parametry includovat z externího souboru většinou nazvaném
buil.properties
, takže když potřebujeme něco
změnit v konfiguraci stačí změnit několik údajů v tomto souboru a do
buil.xml
vůbec nezasahovat.
Příklad 32..2. build.properties
app.name=pokus12
catalina.home=/packages/share/tomcat
manager.url=http://kore.fi.muni.cz:8080/manager
manager.username=manager
manager.password=manager
Nyní již stačí aplikaci zkompilovat a nainstalovat.
aplikaci pouze zkompiluje a výsledný
war soubor uloží do adresáře /dist
aplikaci zkompiluje a nainstaluje do adresáře
/webapps/${app.name}, která
bude dostupná jako http://kore.fi.muni.cz:8080/${app.name}.
přenese war soubor aplikace do tomcatu a nainstaluje
do adresáře /webapps/${app.name}, aplikace bude
dostupná jako http://kore.fi.muni.cz:8080/${app.name}.
T[Aento cíl umožňuje také použití vlastní konfigurací kontextu
aplikace, které uvedeme v souboru context.xml
.
Aplikace bude jednak v tomcatu nainstalována a navíc bude do tomcatu
přenesen i distribuční war soubor.
odstraní deploynutou aplikaci i war soubor.
aplikaci pozastaví (nebude dostupná z webu).
aplikaci spustí pozastavenou aplikaci.
zastaví aplikaci a provede její znovu načtení.
![]() | Poznámka |
---|---|
konfigurace aplikace uložená v souboru
/WEB-INF/web.xml |
Nejlepší je se inspirovat již nějakou hotovou aplikací: http://www.fi.muni.cz/~xpavlov/tomcat/app1.tar.gz. K dispozici je i originální ukázková aplikace z distribuce tomcatu http://jakarta.apache.org/tomcat-5.0/tomcat-docs/appdev.
V případě, že se do apache zkompiluje
mod_jk2, není nutné pro použití
JSP souboru specifikovat port, na kterém tomcat
běží. Apache pak sám pozná, který soubor má předat tomcatu ke
zpracování a který soubor má zpracovat sám.
Obsah
Postup práce s JDBC je následující:
Koncepce je podobná jako ODBC (Microsoft Windows).
import java.sql.*;
public class TestJDBCMySQL {
public static void main(String[] args) {
String url = "jdbc:mysql://idealab.cs.uiowa.edu/WorksOn";
String uid = "user";
String pw = "testpw";
try { // Load driver class
Class.forName("com.mysql.jdbc.Driver");
} catch (java.lang.ClassNotFoundException e) {
System.err.println("ClassNotFoundException: " +e);
}
...
...
Connection con = null;
try {
con = DriverManager.getConnection(url, uid, pw);
Statement stmt = con.createStatement();
ResultSet rst = stmt.executeQuery("SELECT ename,salary FROM Emp");
System.out.println("Employee Name,Salary");
while (rst.next()) {
System.out.println(rst.getString("ename")+","+rst.getDouble("salary"));
}
con.close();
} catch (SQLException ex) {
System.err.println("SQLException: " + ex); }
}
}
JDBC je velmi obecné rozhraní pro přístup k relačním databázím. Proto:
je "slabě typované", nemá např. speciální metody pro jednotlivé typy SQL dotazů, vše se spouští executeQuery.
totéž platí pro přístup k výsledkům dotazů: ResultSet je jednoduchý iterátor (přesněji kurzor), kde lze z aktuální pozice číst a případně na ní modifikovat.
vše podstatné je ponecháno na uživateli - formulaci SQL dotazů uvnitř execute, executeQuery apod. - rozhraní nezkontroluje ani syntaktickou správnost, to až samotný DB stroj.
taktéž výjimky jsou téměř vždy pouze SQLException s textovým popisem uvnitř
JDBC je rozloženo do balíků:
základní rozhraní a třídy
rozšiřující rozhraní a třídy
závisejí na použitém DBMS, např. balík org.hsqldb
Klasickým způsobem práce s JDBC je tento postup:
získáme spojení typicky oslovením
DriverManageru s uvedením url zdroje, jména a
hesla uživatele:
na získaném spojení vytváříme příkazy
(Statement):
na příkazu spustíme SQL dotaz:
ResultSet rst = stmt.executeQuery("SELECT
ename,salary FROM Emp");
výsledky dotazu projdeme iterací výsledného
ResultSetu:
while (rst.next()) {
System.out.println(rst.getString("ename")+","+rst.getDouble("salary"));
}
spojení "po použití" uzavřeme.
![]() | Varování |
---|---|
Nesmíme uzavřít, dokud nedočteme ResultSet - jeho zbytek by se ztratil. |
![]() | Poznámka |
---|---|
Také se obecně nelze v ResultSetu vracet. |
![]() | Poznámka |
---|---|
Je nutné počítat s tím, že ResultSet neexistuje v jednu chvíli v paměti celý; je to virtuální přístupový bod k výsledkům, které se obecně postupně načítají/generují. |
Implicitně se pro zřízené spojení nastaví režim "auto-commit", každý dotaz je uzavřen do samostatné transakce.
Chceme-li toto změnit (což je vzhledem k výkonu i vhodné),
nastavíme con.setAutoCommit(false) a řídíme si
transakce sami.
Řízení transakcí provádíme na daném spojení pomocí:
potvrdí a trvale uloží změny provedené od posledního commit/rollback
"zahodí" změny provedené od posledního commit/rollback, tj. vrátí databázi do stavu po posledním commit/rollback
vrátí databázi do stavu p
Příklad kódu s řízením transakce: první změna je potvrzena (commit), druhá zamítnuta (rollback):
con.setAutoCommit(false);
// inserts first two messages
for (int i = 0; i < messages.length-1; i++) {
stmt.executeUpdate(
"INSERT INTO MESSAGES VALUES (" ... ")");
con.commit();
// inserts last message ?
stmt.executeUpdate(
"INSERT INTO MESSAGES VALUES (" ... ")");
// no. last message will not be inserted!
con.rollback();
Na rychlé a nenáročné vyzkoušení databázových věcí v Javě můžeme použít volně dostupný javový systém řízení báze dat HSQLDB (dříve HypersonicSQL), http://hsqldb.sf.net.
Všechny demoprogramy dostupné ve zdrojové podobě jsou bez úprav učené pro HSQLDB.
HSQLDB může pracovat ve třech režimech:
běží v rámci procesu klientského programu, není nutné spouštět zvlášť, pouze v programu přistoupíme k databázi pomocí zvláštního URL - viz manuál HSQLDB nebo příklady
DB server běží zvlášť, tudíž je přístupný více klienty, tabulky se ukládají na disk
dtto, přístupné přes HTTP přes mini HTTP-server
Předpřipravené příkazy (Prepared Statements) jsou prostředkem, jak efektivně provádět často opakované SQL dotazy, např.:
více vložení do stejné tabulky
dotazy, kde mění jen jeden parametr, např. hledaný klíč
Technicky předpřipravený dotaz vypadá tak, že na místě dosazovaného parametru je znak ?.
Pomocí set-metod se daný formální parametr ("otazník") nahradí skutečnou hodnotou a pak se příkaz spustí.
Příklad:
// příprava příkazu
PreparedStatement pstmt = con.prepareStatement(
"SELECT E.FIRSTNAME, E.SURNAME, M.CREATED, M.TEXT " +
"FROM EMPLOYEES AS E, MESSAGES AS M " +
"WHERE E.SURNAME = ?"
+" AND E.ID = M.TO " +
"ORDER BY M.CREATED DESC");
// naplnění parametrů
pstmt.setString(1, "Novak");
// vlastní provedení
ResultSet result = pstmt.executeQuery();
Uložené procedury - Stored Procedures - jsou vzdáleně podobné předpřípraveným příkazům, jsou však zcela v server-side režii.
Běží tedy vzdáleně přímo na serveru.
Jsou výhodné nejen z hlediska výkonu, ale i údržby - jsou centralizovaně uložené, lze je lépe měnit při změnách datového modelu, konfigurace DB atd.
Podporuje-li to daný DBMS, můžeme řádky vrácených tabulek modifikovat:
ResultSet result = stmt.executeQuery(
"SELECT TEXT " +
"FROM MESSAGES " +
"WHERE ID > 10");
// posuň se na pátý řádek výsledku
result.absolute(5);
// změň hodnotu atributu/pole
result.updateString("TEXT", "Zmeneny text zpravy");
// proveď změny
result.updateRow();
DBMS poskytne základní informace o
svých schopnostech (dostupných funkcích) a
údaje o příslušně databázi (metadata)
voláními, jako jsou:
DatabaseMetaData dbmd = con.getMetaData();
// základní údaje o DBMS
System.out.println(
"DBMS: " +
dbmd.getDatabaseProductName() + ", " +
dbmd.getDatabaseProductVersion() );
// údaje o driveru
System.out.println(
"Driver: " +
dbmd.getDriverName() + ", " +
dbmd.getDriverVersion() );
// dostupné funkce DBMS
System.out.println("String functions: "+dbmd.getStringFunctions());
System.out.println("TimeDate functions: "+dbmd.getTimeDateFunctions());
System.out.println("Numeric functions: "+dbmd.getNumericFunctions());
System.out.println("System functions: "+dbmd.getSystemFunctions());
Moderní přístup k datovým zdrojům je založen na přidání další úrovně adresovací abstrakce:
místo URL databáze, jména a hesla se
prostřednictvím jmenné a adresářové služby (JNDI) najde datový zdroj - aplikační programátor ani předem neví, kde je zdroj fyzicky uložen, jaký DBMS se o něj stará
datový zdroj se zpřístupní nikoli jako Connection, ale ponovu
jako javax.sql.DataSource
teprve z něj se získá spojení.
![]() | Poznámka |
---|---|
JNDI služba je obvykle ve správě aplikačního (webového) serveru (Tomcat, jboss...) |
JDO je Java-centrická alternativa k tradičním způsobům zajištění perzistence dat:
JDBC (přístup z Javy k relačním datům)
serializace (základní technika převodu objektů - potenciálně libovolných - do binární, uložitelné, podoby)
JDO je specifikace, která prochází tzv. Java Community Process (JCP) Program, blíže viz http://jcp.org.
Mají na ni tedy vliv i nezávislí vývojáři.
Její aktuální platná verze je 1.0.1, připravuje se 2.0.
Specifikace JDO 1.0.1 má 200 stran.
Motivací pro JDO bylo dát pohodlnější techniku (než JDBC a serializace) pro zachycení stavu běžných javových objektů v programu a možnost jeho obnovy.
Existuje několik open-source i komerčních implementací JDO:
komerční implementace JDO, dostupná na http://www.solarmetric.com/
Popis: Kodo JDO is SolarMetric's robust, high-performing, feature-rich implementation of the Java™ Data Objects specification for transparent persistence. Unlike many proprietary object/relational mapping tools, Kodo JDO provides access to relational databases through the JDO standard, enabling Java developers to use existing relational database technology from Java without needing to know SQL or be an expert in relational database design. It can be used with existing database schemas, or can automatically generate its own schema.
open-source, free (BSD-like licence), dostupný na http://www.castor.org/jdo.html
open-source, free implementace, dostupná na http://tjdo.sourceforge.net/. Charakteristika:
Supports JDO 1.0.1. Implements the entire JDOQL query language, including several useful method enhancements. Auto-creates all necessary schema elements (tables, foreign keys, indexes) according to your app's classes and JDO metadata. Auto-validates expected schema structure at runtime, reducing failures from schema evolution. Can map Java classes to SQL views, and allows for direct SQL queries, to leverage SQL capabilities not normally accessible through JDO. Designed to be lightweight and fast.
Java Data Objects - informace na stránkách Sun
JDO Central.com - hlavní portál o JDO
Alternativou pro pohodlnou serializaci mnoha typů objektů do XML je např. open-source balík XStream, viz dále.
Javová třída může implementovat rozhraní
java.io.Serializable, které
nepředepisuje žádné metody, ale zajistí, že
objekty dané třídy lze serializovat, tj. převést jejich obsah (proměnné) na binární (vnější) podobu zapsatelnou např. do souboru
inverzně lze zase objekty z této binární podoby deserializovat
Při serializaci se standardně
převádějí do binární podoby všechny instanční proměnné
vyjma těch označených klíčovým slovem transient
Tak lze zajistit serializaci skutečně jen potřebných složek stavu objektu, zbytek se po deserializaci může "dopočítat".
![]() | Poznámka |
---|---|
Typický příklad: symetrickou matici (např. podle hlavní diagonály) neukládáme celou, ale jen "jednu polovinu". |
Požadujeme-li speciální chování (např. kvůli serializaci návazných/odkazovaných objektů), můžeme v objektu poskytnout metody:
realizuje zápis objektu do výstupního proudu - metodu si napíšeme sami
realizuje čtení objektu ze vstupního proudu - metodu si napíšeme sami
Serializační mechanizmus zajistí vytvoření "prázdného" objektu, ten pak naplníme metodou readObject.
Potřebujeme-li serializaci javových objektů jen na prosté účely typu
uložení a opětovné načtení konfigurace do/ze XML souboru
přenesení objektů jinému procesu, programu, na jiný stroj
pak je XStream pravděpodobně nejlepší volbou, pokud nám nevadí nepodpora non-ASCII znaků...
XStream je extrémně jednoduše a přímočaře použitelné API pro serializaci jakýchkoli objektů do XML.
Není třeba psát žádné popisovače, stačí vybrat objekt a poslat ho
metodě toXML objektu serializátoru
org.codehaus.xstream.XStream.
Vytvoříme pole se zadaným počtem prvků, postupně do něj vřadíme nově vytvořené objekty Person a toto pole serializujeme.
public static int LEN = 10000;
public static void main(String[] args) {
Person[] people = new Person[LEN];
XStream xs = new XStream();
xs.alias("person", Person.class);
for(int i = 0; i < LEN; i++) {
people[i] = new Person("Clovek "+i, i, i * 10);
}
// serialize
String xml = xs.toXML(people);
System.out.println(xml);
// uncomment the following code to test deserialization
/*
Person[] secondPeople = (Person[])xs.fromXML(xml);
for(int i = 0; i < secondPeople.length; i++) {
increaseSalary(secondPeople[i], 20);
}
*/
}
Vytvořený soubor vypadá takto:
<person-array>
<person>
<name>Clovek 0</name>
<age>0</age>
<salary>0.0</salary>
</person>
<person>
<name>Clovek 1</name>
<age>1</age>
<salary>10.0</salary>
</person>
<person>
<name>Clovek 2</name>
<age>2</age>
<salary>20.0</salary>
</person>
...
Obsah
Nejde o nic jiného, než o zajištění, aby výsledný navržený program splňoval specifikaci, tj.:
aby pro každý atomický, zvenčí viditelný/volatelný kus kódu (typicky metoda) byly specifikovány vstupní a výstupní podmínky
a aby jejich platnost byla za běhu zaručena
mezi zadavatelem (tj. analytikem, příp. zákazníkem) a návrhářem tak vzniká
dohoda (contract), že specifikace bude dodržena
K dosažení tohoto ideálního stavu vede budto čistě formální cesta:
specifikace zmíněných podmínek matematickými prostředky a
formální dokazování korektnosti
Dále zmiňované nástroje však toto nedokážou; omezují se na běhovou kontrolu platnosti předpsaných podmínek
jass je preprocesor javového zdrojového textu. Umožňuje ve zdrojovém textu programu vyznačit podmínky, jejichž splnění je za běhu kontrolováno.
Podmínkami se rozumí:
pre- a postconditions u metod (vstupní a výstupní podmínky metod)
invarianty objektů - podmínky, které zůstávají pro objekt v platnosti mezi jednotlivými operacemi nad objektem
Postup práce s jass:
stažení a instalace balíku z http://csd.informatik.uni-oldenburg.de/~jass/
vytvoření zdrojového textu s příponou
.jass, javovou syntaxí s použitím speciálních
komentářových značek
takový zdrojový text je přeložitelný i normálním překladačem
javac, ale v takovém případě ztrácíme možnosti
jass
proto nejprve .jass souboru převedeme
preprocesorem jass na javový (.java
)
soubor
ten již přeložíme javac a spustíme
java
, tedy jako každý jiný zdrojový soubor v
Javě
z .jass zdrojů je možné vytvořit také
dokumentaci API obsahující jass značky, tj. informace, co kde musí
platit za podmínky atd. - vynikající možnost!
úvodní materiálek k použití junit (v němčině, jako PDF)
Uvádíme pragmaticky jen to, co je potřeba zde (pro potřeby IoC), nechápat jako komplexní terminologii.
objekt poskytující navenek ucelenou funkcionalitu (část aplikační nebo pomocné logiky)
komponenta je obvykle chápána jako "velký objekt" nebo graf více objektů s vnějším rozhraním ("fasádou")
komponenta je sice do jisté míry samostatná, ale většinou nežije nezávisle; za běhu potřebuje návaznosti na další komponenty nebo hostující rámec (kontejner)
objekt, v němž jsou za běhu aplikace uloženy a spravovány komponenty (objekty)
kontejner dokáže většinou komponenty i vytvářet a poskytovat odkazy na ně (vyhledávat je)
V komponentních systémech bývá tradičním problémem zajistit správnou inicializaci a provoz komponent závislých na ostatních.
jak závislosti popsat
jak získat objekty (komponenty), na nichž vytvářená komponenta závisí
jak tuto komponentu vytvořit
jak závislosti předat ("injektovat") do ní
Co je třeba udělat při nasazení jedné nové komponenty
Připravit komponenty, na nichž "ta moje" závisí
Vytvořit "noji komponentu"
Nastavit závislosti
Postup vypadá přímočaře, ale je bohužel rekurentní... v bodě 1 (připravit komponenty...) se opakuje rekurentně celý postup
V Inversion of Control obracíme tento (pro komponentního programátora) nepraktický, obtížný postup.
O řešení závislostí se postará rámec (kontejner), komponenta pouze deklaruje na čem závisí.
Historicky se postupně vyvinuly tři přístupy k "injektáži" potřebných závislostí; tedy k IoC:
Interface Injection
Setter Injection
Constructor Injection
Blíže viz popis k IoC v systému (rámci) vraptor a následující slidy.
Komponenta MUSÍ IMPLEMENTOVAT určité, rámcem/kontejnerem dané rozhraní (příklad z článku Intro. to AOP):
import org.apache.avalon.framework.*;
public class JDBCDataManger implements Serviceable {
DataSource dataSource;
public void service (ServiceManager sm)
throws ServiceException {
dataSource = (DataSource)sm.lookup("dataSource");
}
public void getData() {
//use dataSource for something
}
}
Nevýhoda: musí implementovat dané rozhraní, nelze vyvíjet zcela nezávisle.
Komponenta je jako objekt JavaBean, má setXXX metody:
public class JDBCDataManger {
private DataSource dataSource;
public void setDataManager(DataSource dataSource {
this.dataSource = dataSource;
}
public void getData() {
//use dataSource for something
}
}
Rámec (kontejner), např. Spring musí vědět, jak komponentu vytvořit a na čem závisí:
<bean id="myDataSource"
class="org.apache.commons.dbcp.BasicDataSource" >
<property name="driverClassName">
<value>com.mydb.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mydb://server:port/mydb</value>
</property>
<property name="username">
<value>root</value>
</property>
</bean>
a druhá komponenta:
<bean id="dataManager"
class="example.JDBCDataManger">
<property name="dataSource">
<ref bean="myDataSource"/>
</property>
</bean>
Oproti Interface Injection: netřeba implementovat rozhraní
Je ale nezřetelné, které setXXX metody jsou pro účely nastavení závislostí přes Setter Injection a které ne.
Odpovídá přístupu "Good Citizen" (označení zavedl J. Bloch ze Sun):
objekt je po vytvoření (a aplikaci konstruktoru) plnohodnotný, plně inicializovaný, platí pro něj všechny invarianty, lze jej použít
public class JDBCDataManger {
private DataSource dataSource;
public JDBCDataManger(DataSource dataSource) {
this.dataSource = dataSource;
}
public void getData() {
//use dataSource for something
}
}
Existují jednoduché (lightweight) kontejnery pro nasazení a provoz komponent s využitím IoC.
Tyto kontejnery mnohdy neumí nic navíc, jde jen o základní správu komponent.
Příkladem je PicoContainer a Spring, který je však komplexnější (a složitější).
Programový kód rozsáhlejších soudobých systémů je složitý, nepřehledný, nesnadno udržovatelný.
U systémů jsou často implementovány mimofunkční požadavky: protokolování, zabezpečení, optimalizace.
Pokrytí těchto požadavků jde napříč s požadavky funkčními - současné splnění vede nezřídka ke kombinatorické explozi a (téměř) exponenciálnímu nárůstu velikosti kódu.
Kód je nečitelný a ještě obtížněji udržovatelný.
I rozšiřování nelze většinou provést lokálně, nezřídka je jím zasaženo více částí kódu.
Příklad převzatý z weblogu Jablok Pavla Kolesnikova (typický kód aplikační logiky):
public class KusAplikacniLogiky extends ObecnejsiKus {
// data tridy;
// jina pomocna data;
// pretizeni rodicovskych metod
public void provedNecoPodstatneho () {
// autentizace
// autorizace
// dalsi nezajimavy kod
// logovani zacatku operace
// vlastni aplikacni logika — konecne!
// logovani ukonceni operace
// treba jeste neco
}
}
stále se opakující úkony na začátku před vlastní realizací "užitečné práce" a po ní
aplikační logika tvoří jen zlomek rozsahu kódu
Překlad článku Graham O'Regana Introduction to Aspect-Oriented Programming na onjava.com nastiňuje hlavní principy:
AOP umožňuje přidat do statického OO modelu programu (třídy) dynamické aspekty - např. ovlivňovat (vstupovat do) volání metod.
Např. servlet očekává vstup z webového formuláře, naváže data z formuláře do vytvořeného datového objektu, ten zpracuje aplikační logikou a výsledek prezentuje.
Kromě toho ale musí řešit:
ošetření výjimek
zabezpečení přístupu
protokolování
Přes JMX se řídí:
Vhodnými kandidáty na JMX (MBeans) jsou takové komponenty, které:
Model systému řízeného JMX zahrnuje:
Přes JMX se může řídit prakticky cokoli v javovém systému:
JMX ovládá zdroje prostřednictvím tzv. _rapperu_ který:
Jaké podoby může wrapper nabývat?
Komponenta koncipovaná jako MBean je často vytvářena takto:
FibonacciCounter.java - původní komponenta
CounterMBean.java - rozhraní
Counter.java - třída implementující rozhraní
Co odlišuje skriptování od "ostatních" pg. jazyků?
Kdy obvykle (nejen v Javě) cítíme potřebu skriptovat?
Proč je potřeba skriptovat silná právě dnes, když je tolik dokonalých programovacích jazyků s rychlými překladači?
![]() | Poznámka |
---|---|
Takové rychlovýtvory nezřídka mívají delší životnost než složitě a dlouho budované "pořádné" aplikace - přicházejí rychle a v pravý čas! |
Bean Scripting Framework (BSF) je projektem jakarta.apache.org, původně však vytvořený v IBM T.J.Watson Laboratories (jako produkt "alphaWorks").
Jedná se o rámec umožňující:
![]() | Poznámka |
---|---|
To mj. dovoluje "save of investment" do stávajících skriptů - i z plnohodnotného prostředí (Java) je lze volat! |
BSF obsahuje dvě hlavní komponenty:
Tři základní způsoby:
Iterace přes všechna celá čísla 1 až 10 s jejich výpisem:
for (i in 1..10) {
println "Hello ${i}"
}
Definice mapy (asociativního pole) a přístup k prvku:
map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map['name'] == "Gromit"
Řízení toku pomocí switch s velmi bohatými možnostmi:
x = 1.23
result = ""
switch (x) {
case "foo":
result = "found foo"
// lets fall through
case "bar":
result += "bar"
case [4, 5, 6, 'inList']:
result = "list"
break
case 12..30:
result = "range"
break
case Integer:
result = "integer"
break
case Number:
result = "number"
break default:
result = "default"
}
assert result == "number"
Protokolování je základní činností sledující běh software v
testovacím i
ostrém nasazení.
Protokolování má oproti klasickým přístupům
System.out.println nebo o něco lepším
System.err.println
jasné výhody:
snadná konfigurovatelnost
nezaměnitelnost s jinými (neladicími) výstupy programu
možnost vazby na zasílání zpráv mailem, ukládání do souborů, databáze
V zásadě dva možné přístupy:
použít standardní API
použít API daného aplikačního prostředí (ap. serveru)
Standardní API je však často ap. serverem také podporováno a má jasné výhody:
je známé, existuje široká komunita se zkušenostmi
obsluhu obvykle již sami známe
Existuje několik "standardních" protokolovacích API:
od Java 1.4: balík java.util.logging
již dříve nezávislé open-source řešení
log4j
Obě řešení jsou srovnatelná, log4j je o něco elegantnější a propracovanější. Nejlépe (pokud to stačí) je použít zastřešujícího API:
balík Apache Commons Logging
Existuje několik "standardních" protokolovacích API:
od Java 1.4: balík java.util.logging
již dříve nezávislé open-source řešení
log4j
Obě řešení jsou srovnatelná, log4j je o něco elegantnější a propracovanější. Nejlépe (pokud to stačí) je použít zastřešujícího API:
balík Apache Commons Logging
Obsah
Rozšíření webových aplikací na úkor desktopových má své důvody:
Snadnější údržba (opravy či aktualizace verzí pocítíme jako uživatelé, ne jako správci).
Většinou snadnější vývoj díky platformové nezávislosti kombinací HTTP, HTML, grafických formátů (a příp. JavaScriptu).
Vše dobře ladí s centralizací dat a jejich zpracování na serveru.
I starosti se zabezpečením (safety & security) jsou centralizovány.
Tradiční webové aplikace trpěly typickými nedostatky oproti klasickým desktopovým aplikacím:
komunikace klient-server byla vždy inicována ze strany klienta a to většinou akcí uživatele - klikem na odkaz, stiknem tlačítka...
většina operací (aplikační logiky) musela být na serveru (s drobnými výjimkami - validace vstupu, drobné změny v GUI...)
zvyšovalo to zátěž sítě a hlavně ztěžovalo práci
jsou starosti s nekompatibilitou interpretace HTML a zejména skriptů (i JavaScriptu) na různých platformách i prohlížečích.
Koncepce AJAX je vybudována na principech webových aplikací, které generují a používají na straně klienta (tj. v prohlížeči) speciální javascriptové techniky, jež:
asynchronně komunikují se stranou serveru a
vyměňují si XML data
na straně klienta je skriptem modifikován DOM model dokumentu
Uživatel nemusí stále klikat, aby získal odezvu na své akce: výběry ze seznamů, vpisování do textových polí, pohyby po obrázcích (např. mapách) atd.
Není nutné při sebemenší aktualizaci generovat na straně serveru a následně načítat a zobrazovat celou stránku.
Nejznámnějšími místy intenzivně využívajícími principy AJAX jsou služby Google:
Google Suggest (FAQ)- při vyhledávání jsou uživateli nabízeny tipy (klíčová slova), na co se může ptát
Google Gmail (popis)- jsou nabízeny adresy příjemců zpráv, automaticky je aktualizován obsah mailboxu...
Google Maps - při pohybu v mapě se automaticky objevují nové části mapy.
To ale nejsou aplikace jediné, mezi další patří i české:
slovnik.seznam.cz - při vkládání slova pro překlad se objevují tipy, co zadat.
Manuel Kiessling’s open-source ARSC (A Really Simple Chat) - chat založený na HTTP komunikaci
KnowNow’s SpeedReader
AJAX není jednou technologií, ale spočívá v použití kombinace (známých a zavedených) technologií a standardů:
HTML / XHTML a CSS pro prezentaci informací
JavaScript pro modifikaci Document Object Modelu (DOM) na klientovi
XMLHttpRequest pro (asynchronní) výměnu dat se serverem.
Server dev.java.net nabízí v rámci Java BluePrints Solutions Catalog sekci:
Obsah
Webový rámec a jeho architektura
Funkcionalita webových rámců
Výstavba aplikací nad webovými rámci
Více či méně ucelené prostředí pro tvorbu (případně i nasazení) webových aplikací středního rozsahu
Není to knihovna!
Využívá "The Hollywood Principle": Do Not Call Us, We Will Call You!
Rámec "funguje sám", my jej modifikujeme a doplňujeme
Budeme diskutovat javové rámce
Vrstvy "od uživatele dolů":
prezentační vrstva - ve webových aplikacích HTML, CSS, JavaScript,... na klientovi (prohlížeči): JSP, servlety, XSLT, JSTL, JSF, šablony...
aplikační logika - javové objekty, JavaBeans, EJB...
databázová vrstva - DBMS dostupný přes JDBC
Model - objekty/data a jejich obslužné metody realizující vlastní aplikační logiku
View - pohled na data - prezentace, vstup od uživatele
Controller - řídí tok zpracování - kdy se aktivuje jaká metoda modelu, jaký pohled se uplatní na výsledek,...
Základem je Java Servlet API
specifikuje Servlety, stránky JSP, knihovny značek, filtry, popisovače...
Jeho implementace jsou volně dostupné a dobře prozkoumané
Java Servlety:
javové třídy rozšiřující typicky abstraktního předka javax.servlet.http.HttpServlet
stránky JSP:
podobný princip jako ASP, PHP
při požadavku se přeloží do servletu
knihovny značek (Tag Libraries): pro JSP lze zadefinovat vlastní XML značky obsluhované javovým kódem a ty na stránkách JSP používat
filtry: než je HTTP požadavek předán servletu (JSP), může být filtrován, filtr je podobný servletu, lze filtrovat i vygenerovanou odpověď
Oddělení prezentační vrstvy - většinou prostřednictvím jazyka šablon (template language) jako jsou:
Velocity, WebMacro, FreeMarker, RIFE ...
nebo JSTL (std. knihovna značek)
moderně přes JSF (Java Server Faces)
napodobují klasické "desktopové" GUI v prostředí webové aplikace
případně transformace XSLT
Oddělení prezentační vrstvy
Šablona Velocity - stránka jednoduchého weblogu
<html><head>
<title>#showWebsiteTitle()</title>
<style type="text/css">#includePage("_css")</style>
#showRSSAutodiscoveryLink()
</head>
<body><div id="Content">
<center>
<h1>#showWebsiteTitle()</h1>
<p class="descrip">#showWebsiteDescription()</p>
#showWeblogCategoryChooser()<br>
</center>
#showWeblogEntries("_day" 15)
<hr />
#showReferers( 40 25 )
</div></body></html>
Stránka využívající JSF
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-faces"
prefix="s" %>
<f:use_faces>
<s:form action="/listFlights">
<h:input_text id="fromCity"
valueRef="FlightSearchForm.fromCity"/>
<h:input_text id="toCity"
valueRef="FlightSearchForm.toCity"/>
<h:command_button id="submit" action="success" label="Submit" commandName="submit" />
<h:command_button id="reset" action="reset" label="Reset"
commandName="reset" />
<s:errors/>
</s:form>
</f:use_faces>
Správa zabezpečení - např. deklarativní nařízení přihlašování
použití nastavení Java Security Manageru
pak lze na serveru hostovat i nedůvěryhodný "zákaznický" kód
lze také použít filtry (jakási vnitřní "autentizační proxy")
Vše směřuje k deklarativní specifikaci zabezpečení - snadněji se udržuje
Příklad konfigurace Java Security Manageru (Apache Tomcat 5):
The permission granted to your JDBC driver
grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/driver.jar!/-" {
permission java.net.SocketPermission "dbhost.mycompany.com:5432", connect";
};...
// These permissions apply to the container's core code, plus any additional libraries installed in the "server" directory
grant codeBase "file:${catalina.home}/server/-" {
permission java.security.AllPermission;
};
Řada rámců podporuje deklarativní specifikaci uživatelských vstupů
datový typ, formát, přípustné rozmezí hodnot...
a jejich dekódování
znakové sady, různé národní zvyklosti
Pokročilé rámce:
řízení toku při vyplňování formulářů (průvodci jako u desktopových GUI)
automatické generování fyz. podoby form.
Příklad specifikace zpracování uživ. vstupů - rámec Struts
<form-validation>
<formset>
<form name="addSubjectForm">
<field property="subjID"
depends="required" page="1">
<arg0 key="admin.subject.missing.ID"/>
</field>
<field property="subjName"
depends="required" page="1">
<arg0 key="admin.subject.missing.name"/>
</field>
<field property="groupID"
depends="required" page="2">
<arg0 key="admin.subject.missing.groupID"/>
</field>
</form>
<form name="addTaskForm">...
Mezi jednotlivými interakcemi s uživatelem je uchován stav dané relace -
Překlenuje bezestavovost HTTP
V javových aplikacích pomocí objektů javax.servlet.http.HttpSession
Rozsáhlejší aplikace mívají složitou navigační strukturu
v MVC modelu řídí navigaci Controller
navigace bývá v rámcích popisována deklarativně
<!-- Action Mapping Definition -->
<action-mappings>
<!-- List Flights action -->
<action path="/listFlights"
type="foo.bar.FlightSearchAction"
name="FlightSearchForm"
scope="request"
input="/faces/FlightSearch.jsp">
<forward name="success" path="/faces/FlightList.jsp"/>
</action>
</action-mappings>
Opět deklarativně bývá popsáno řízení toku po vzniku chybového stavu (výjimky)
Umožňuje bezpečně pokrýt i neočekávané chyby a zaznamenat je, poslat informaci správci...
Cíl:
S minimálním "obtěžováním" programátora zajistit kontrolu nad chodem aplikace ve fázi tvorby, ladění i ostrého provozu
Java nabízí několik "logging API":
od Java 1.4: balík java.util.logging
kdekoli: balíky log4j
zastřešující: Jakarta Commons Logging
Pomocí Aspect-oriented Programming lze logování řešit ještě méně invazivně
Rozlišujeme:
Internationalization (i18n)
Localization (l10n)
Co znamenají národní zvyklosti:
texty v nabídkách, ovládacích prvcích,...
formáty výpisu data, času, měny, vícemístných a desetinných čísel
lexikografické řazení
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<c:if test="${lang==null}">
<fmt:setBundle basename="com.heaton.bundles.Forum"
var="lang" scope="session"/>
</c:if>
<c:if test="${param.lang!=null}">
<fmt:setLocale value="${param.lang}"/>
<fmt:setBundle basename="com.heaton.informit.I18NBundle"
var="lang" scope="session"/>
<c:redirect url="index.jsp"/>
</c:if>
<html><head><title>I18N Example</title></head>
<body>
<h1><fmt:message key="login.pleaselogin" bundle="${lang}"/></h1>
<form method=post action=main.jsp>
<fmt:message key="login.uid" bundle="${lang}"/><input name=uid><br/>
<fmt:message key="login.pwd" bundle="${lang}"/><input name=pwd><br/>
<input type="submit" name="action" value="<fmt:message
key="login.title" bundle="${login}"/>">
</form>
<h1><fmt:message key="login.language" bundle="${lang}"/></h1>
<ul>
<li><a href="index.jsp*lang=en">
<fmt:message key="login.english" bundle="${lang}"/>(English)</li>
<li><a href="index.jsp*lang=es">
<fmt:message key="login.spanish" bundle="${lang}"/>(Spanish)</li>
</ul>
</body></html>
Objektový model v paměti vs. data na discích (v databázi)
Rámce do jisté míry vzájemné převody automatizují
Většinou používají osvědčený produkt třetí strany - např. Hibernate, POJO
Výkon aplikace nelze zvyšovat pouze hardwarovými prostředky nebo optimalizací
Zejména dnes je levnějším řešením použít svazek (cluster) "běžně výkonných" počítačů namísto jednoho supervýkonného
Více zatížená aplikace musí být schopna výkon škálovat
Řešením jsou tzv. aplikační servery
poskytují middleware: komplexní prostředí pro běh rozsáhlých (podnikových) aplikací
míří nad schopnosti běžných webových rámců - ty ale většinou podporují/využívají
Eclipse (+Struts Studio) volně dostupný
Borland JBuilder (+InternetBeans Express)
Web Application Framework Research project - http://www.waferproject.org.
Obsah
Svět podnikových (ale i jiných) IS často vyžaduje integrovat stávající systémy.
Možností, jak integrovat je více, liší se např. v míře/těsnosti vazby mezi jednotlivými systémy. Extrémy jsou:
těsná vazba (tight coupling) - systémy "o sobě ví všechno" (API), jsou na sobě závislé, často se musí výrazně modifikovat, aby mohly spolupracovat
volná vazba (loose coupling) - systémy "o sobě neví skoro nic", jsou nezávislé
Typickým příkladem a jedním směrem moderních integrujících technologií jsou systémy řízení zpráv.
Oproti jiným integračním technologiím mají tyto přednosti:
nevyžadují přiliš přebudovávat stávající aplikace proto, aby mohly spolupracovat;
nezpůsobují úzkou vazbu integrovaných systémů (systémy jsou tzv. loosely coupled);
jako odesílatelé zprávy nemusíme vůbec tušit, jak ji příjemce zpracuje, stačí dohodnout:
dohodnout formát
znát cílovou adresu zprávy
Systémy řízení zpráv slouží ke správě výměny zpráv mezi softwarovými systémy nebo komponentami.
komunikace je peer-to-peer, systém řízení zpráv zajišťuje infrastrukturu
komponenty (systémy), které chtějí zasílat/přijímat zprávy, k tomu využívají služeb agentů (kteří jsou součástí API systémů řízení zpráv)
Javovou podobou rozhraní k systému řízení zpráv je Java Messaging Service (JMS) API, jehož historie sahá do roku 1998, současná verze je 1.1. (z r. 2002).
JMS je poměrně malé rozhraní, které nenutí programátora studovat příliš mnoho konceptů - je jednoduché.
JMS umožňuje komunikaci, která je:
zpráva je odeslána konzumentovi, který nemusí být stále "on-line"; vybere si zprávu, až se připojí
systém zajistí perzistentní ukládání zpráv do doby, než jsou příjemcem přečteny; zajistí, že jsou přečteny právě jednou
Možné důvody, proč JMS:
chceme propojovat komponenty bez znalostí jejich API
chceme robustní systém: je možný nezávislý souběžný provoz komponent
zasílání zpráv a čekání na odpověď je asynchronní - proces čekat nemusí (není to tedy request/response výměna)
Současná verze JMS nabízí:
rozhraní pro tvorbu klientů k (i jiným) systémům řízení zpráv
rozhraní Message-driven Beans
Aplikace JMS sestává z těchto relevantních entit:
poskytovatel infrastruktury zasílání zpráv vč. administrace
klienti produkující nebo konzumující zprávy
objekty - zprávy
typickými reprezentanty jsou předkonfigurované tovární objekty (factories) na vytváření objektů destinations a connections.
Vyhledání a zpřístupnění těchto servisních objektů je zajištěno přes JNDI.
Většina implementací JMS umožňuje:
zasílání zpráv od jednoho odesílatele k jednomu příjemci
více odesílatelů může zprávu "vystavit" na místo, kam se odběratel ("předplatitel") může zapsat a zprávy odebírat
Proces P-to-P zasílání zpráv zahrnuje tři základní participující objekty:
vytvoří a pošle zprávu do fronty zpráv
zprávu přijme a zajistí její "přežítí" než je zkonzumována nebo zastará (time-out)
odebírá zprávy z fronty
Vztah producent:konzument je 1:1.
Producent adresuje zprávu tzv. tématu (topic).
Konzument se může přihlásit k odběru zpráv k tomuto tématu.
Vztah producent:konzument tak není obecně 1:1.
Systém zabezpečí uchování zprávy na tak dlouho, dokud ji všichni odběratelé nepřečtou.
Komponenty (třídy, rozhraní):
Administered objects
Connections
Sessions
Message Producers
Message Consumers
Messages
Sun nabízí podrobný tutoriál k použití jeho implementace systému řízení zasílání zpráv: Sun Java System Message Queue
Součástí tutoriálu je Quick Start Tutorial s praktickým návodem jak nainstalovat, přeložit a spustit server a jednoduchého klienta.
Pro překlad klienta musíme mít v CLASSPATH tyto soubory:
jms.jar imq.jar
jndi.jar
(u Javy 1.4 je to automaticky, není
třeba přidávat do CLASSPATH)
Provedeme spustitelným souborem z
IMQ_HOME/bin/
Server SJS MQ se rozběhne s hláškami:
Zda MQ běží v pořádku lze zjistit dotazem:
MQ odpoví:
Demo HelloWorldMessage z adresáře
IMQ_HOME/demo/helloworld/helloworldmessage má tyto
hlavní prvky (viz tutoriál):
Import the interfaces and Message Queue implementation classes for the JMS API.
The javax.jms package defines all the JMS interfaces necessary to develop a JMS client.
import javax.jms.*;
Instantiate a Message Queue QueueConnectionFactory administered object. A QueueConnectionFactory object encapsulates all the Message Queue-specific configuration properties for creating QueueConnection connections to a Message Queue server.
QueueConnectionFactory myQConnFactory = new com.sun.messaging.QueueConnectionFactory();
ConnectionFactory administered objects can also be accessed through a JNDI lookup (see Looking Up ConnectionFactory Objects). This approach makes the client code JMS-provider independent and also allows for a centrally administered messaging system.
Create a connection to the message server. A QueueConnection object is the active connection to the message server in the Point-To-Point programming domain.
QueueConnection myQConn =
myQConnFactory.createQueueConnection();
Create a session within the connection. A QueueSession object is a single-threaded context for producing and consuming messages. It enables clients to create producers and consumers of messages for a queue destination.
QueueSession myQSess = myQConn.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
The myQSess object created above is non-transacted and automatically acknowledges messages upon consumption by a consumer.
Instantiate a Message Queue queue administered object that corresponds to a queue destination in the message server. Destination administered objects encapsulate provider-specific destination naming syntax and behavior. The code below instantiates a queue administered object for a physical queue destination named “world”.
Queue myQueue = new.com.sun.messaging.Queue("world");
Destination administered objects can also be accessed through a JNDI lookup (see Looking Up Destination Objects). This approach makes the client code JMS-provider independent and also allows for a centrally administered messaging system.
Create a QueueSender message producer. This message producer, associated with myQueue, is used to send messages to the queue destination named “world”.
QueueSender myQueueSender = myQSess.createSender(myQueue);
Create and send a message to the queue. You create a TextMessage object using the QueueSession object and populate it with a string representing the data of the message. Then you use the QueueSender object to send the message to the “world” queue destination.
TextMessage myTextMsg = myQSess.createTextMessage();
myTextMsg.setText("Hello World");
System.out.println(“Sending Message: “ + myTextMsg.getText());
myQueueSender.send(myTextMsg);
Create a QueueReceiver message consumer. This message consumer, associated with myQueue, is used to receive messages from the queue destination named “world”.
QueueReceiver myQueueReceiver =
myQSess.createReceiver(myQueue);
Start the QueueConnection you created in Step 3. Messages for consumption by a client can only be delivered over a connection that has been started (while messages produced by a client can be delivered to a destination without starting a connection, as in Step 7.
myQConn.start();
Receive a message from the queue. You receive a message from the “world” queue destination using the QueueReceiver object. The code, below, is an example of a synchronous consumption of messages (see Message Consumption: Synchronous and Asynchronous).
Message msg = myQueueReceiver.receive();
Retrieve the contents of the message. Once the message is received successfully, its contents can be retrieved.
if (msg instanceof TextMessage) { TextMessage txtMsg = (TextMessage) msg; System.out.println("Read Message: " + txtMsg.getText()); }
Close the session and connection resources.
myQSess.close();
myQConn.close();
Obsah
"Klasické" webové služby jsou v poslední době kritizovány z několika důvodů:
režie služeb je velká
flexibilita často zbytečně velká, protokoly mají více vrstev, než je prakticky nutné (SOAP)
psaní služeb zahrnuje vytváření řady složitých (XML) popisovačů - nelze psát bez spec. nástrojů
nasazení služeb má poměrně velkou vstupní bariéru: vyžaduje aplikační server a speciální klientský SW
interoperabilita mezi platformami (a jazyky) není vzhledem ke složitosti standardů stoprocentní
Webové služby typu REST (Representational State Transfer) jsou "lehkou" (lightweight) alternativou k SOAP službám.
REST je tzv. architekturní styl (architectural style), tj. soustava architekturních omezení (architectural constraints), definujích, jak budovat webové služby (aplikace). Není to tedy standard, technologie, nástroj, ani API...
REST vychází z úspěšných postupů používaných na webu od samého počátku.
Autorem REST je Roy Fielding, jenž principy poprvé představil ve své disertaci Architectural Styles and the Design of Network-based Software Architectures. Jeho definice říká: „Representational State Transfer is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through an application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.“
Podrobnější objasnění principů najdeme např. na serveru O'Reilly webservices.xml.com.
REST je metodika (architekturní styl), jak psát webové služby, či spíše, jak webové služby vystupují vůči klientovi.
REST používá některé pojmy:
typicky odpovídá nějaké (datové) entitě, předmětu zájmu; něčemu, co lze číst, ale obvykle i vytvářet a měnit.
zdroj je identifikován svým URI (např. URL)
to, co je na požadavek posláno klientovi, tj. např. XML soubor, HTML stránka, obrázek...
REST sám o sobě není standardem, REST aplikace jsou ale na standardech přísně založeny - a to na běžných a zavedených jednoduchých standardech:
HTTP (přístup ke zdrojům)
URL (identifikace zdrojů)
XML/HTML/GIF/JPEG/atd. (reprezentace zdrojů)
text/xml, text/html, image/gif, image/jpeg, etc (MIME typy zdrojů)
klient "si řekne" o zdroj (princip "pull")
(bezestavový) každý klientský dotaz obsahuje veškeré informace potřebné pro vyřízení dotazu na serveru (server neuchovává stav)
zdroje musejí být označeny, zda podporují kešování
rozhraní přístupu ke zdrojům (čtení, vytvoření, smazání, modifikace) je jednotné (HTTP GET, PUT, DELETE, POST)
zdroje jsou identifikovány pomocí URI (typicky URL)
reprezentace zdrojů jsou propojeny pomocí URI (URL) a klient tedy může přecházet mezi stavy
mezi klienta a server se službou lze umisťovat proxy, keše, brány...
Co jsou URI (tj. zdroje)?
Jaký formát?
Jaké metody každé URI podporuje?
Jaké návratové kódy jsou vraceny?
Identifikovat zdroje.
Vytvořit pro ně systém pojmenování (URI).
Určit, jaké metody bude každý zdroj (URI) podporovat (GET, POST, PUT, DELETE?).
Čtení zdroje (GET) nesmí mít vedlejší efekt (nesmí nic modifikovat).
Reprezentace (např. vrácená stránka) by měla umožnit klientovi pokračovat dále, mít odkazy na další zdroje.
Zdroje nemusí (neměly by být) obrovské - lze vždy zpřístupnit jen část a přes odkazy nechat klienta dotaz upřesnit.
Specifikovat schéma pro reprezentaci zdroje (DTD, XML Schema, RelaxNG, Schematron). Rovněž pro vytvoření a modifikace zdroje je dobré schéma zveřejnit.
Popsat službu pomocí WSDL nebo aspoň HTML.