31. března 2009

Spring MVC: GET kontroler

Dlouho jsem neuváděl žádný můj zdrojový kód, tak to dnes zkusím napravit. Spring MVC nabízí pro zpracování požadavku GET dva základní kontrolery:

  • ParameterizableViewController - jednoduchý kontroler, který pouze vyžaduje zadání cílového view, které se následně zobrazí.

  • BaseCommandController - kontroler, který pracuje s parametry requestu přes commandy. Tedy kontroler automaticky mapuje parametry requestu do atributů objektu (commandu), je možné využívat validace, bindery apod.

V každé aplikace resp. projektu se hodí mít nějaké své předky-kontrolery, které mohou zprvu být prázdné, ale vždy se časem ukáže, že je potřeba mít nějakou společnou funkcionalitu nebo společná data pro většinu nebo všechny kontrolery. My jsme se na projektu rozhodli mít dva předky-kontrolery, jeden pro práci s formuláři (zpracování POSTu) a jeden pro práci s GETem. A právě u GETu jsem narazil na to, že bych rád měl možnost výběru - jednou mi stačí si vytáhnout parametr přímo z requestu a jindy využiji command s validací. Takže z tohoto důvodu jsem udělal následující mix dvou výše uvedených kontrolerů. Pro úplnost ještě musím zmínit použití rozhraní IDataModelProvider, které slouží k předávání modelu resp. dat společných jak pro GET, tak pro POST kontrolery.


/**
* Zakladni implementace kontroleru pro zobrazovani stranek pres GET metodu, tj. zobrazeni
* JSP stranky, pripadne predani promennych na stranku.
*
* <p>Kontroler muze pracovat ve dvou "rezimech" - s commandem a bez nej.
* Pokud chceme pracovat s commandy a tedy mapovat parametry requestu do commandu, tak pak
* je vhodne v podtride implementovat metodu
* {@link #handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, Object, org.springframework.validation.BindException)}
* a nastavit tridu commandu {@link #commandClass}.
*
* <p>Pokud nam staci pristup k parametrum requestu (bez commandu), tak pak je vhodne implementovat
* v podtride metodu {@link #handleRequestInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}.
* Toto chovani je defaultni.
*
* @see BaseFormController
*/
public class BaseGetController extends AbstractCommandController {
private static final Logger logger = Logger.getLogger(BaseGetController.class);

private IDataModelProvider dataModelProvider;
private String viewName;
private boolean supressBinding = false;
private boolean supressValidation = false;

protected void initApplicationContext() {
if (this.viewName == null) {
throw new IllegalArgumentException("Property 'viewName' is required");
}
}

/**
* Metoda resi, zda se bude pracovat s commandem (a tedy request parametry se budou
* napojovat na command) a nebo zda se bude pracovat bez commandu (a tedy je nutne pracovat samostatne
* primo s parametry requestu).
*
* <p><b>Tato metoda je vhodna k implementaci v podtridach, pokud nepracujeme s commandem
* a staci nam pristup k requestu.</b>
*/
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (getCommandClass() == null) {
//pracujeme bez commandu
this.supressBinding = true;
this.supressValidation = true;
return this.handle(request, response, null, null);
}
else {
//pracujeme s commandem
return super.handleRequestInternal(request, response);
}
}

/**
* Metoda vklada spolecna data do vysledneho modelu.
*
* <p><b>Tato metoda je vhodna k implementaci v podtridach, pokud pracujeme s commandem</b>.
* Pokud neni {@link #commandClass} definovano, tak pak vstupni parametry <i>command</i> a <i>errors</i> jsou null.
*/
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object command,
BindException errors) throws Exception {
ModelAndView mav = new ModelAndView(getViewName());

mav.addAllObjects(dataModelProvider.getModelData());

if (logger.isDebugEnabled()) {
logger.debug("BaseGetController returns: " + mav);
}

return mav;
}

protected boolean suppressBinding(HttpServletRequest request) {
return this.supressBinding || super.suppressBinding(request);
}

protected boolean suppressValidation(HttpServletRequest request, Object command) {
return this.supressValidation || super.suppressValidation(request, command);
}

public void setDataModelProvider(IDataModelProvider dataModelProvider) {
this.dataModelProvider = dataModelProvider;
}

/**
* Set the name of the view to delegate to.
*/
public void setViewName(String viewName) {
this.viewName = viewName;
}

/**
* Return the name of the view to delegate to.
*/
public String getViewName() {
return this.viewName;
}
}

21. března 2009

JavaRebel - vývoj bez restartu serveru

O nástroji JavaRebel se již psalo před nějakým časem na Jirablogu. Přesto bych rád o tomto super nástroji napsal znovu a podělil se s vámi o mé zkušenosti.

Pokud tento nástroj ještě neznáte, tak se jedná o JVM plugin, který umožňuje za běhu aplikace upravovat Java kód tak, že se změny hned promítnou do běžící aplikace. To zní hodně podobně jako standardní JVM HotSwap, ale JavaRebel toho umí mnohem více, např. přidání nové proměnné do třídy, metody, změna anotace apod. Více o možnostech zde.

Vždy jsem si při vývoji vystačil s lightweight servery (Tomcat, Jetty) a tam nebyl problém server často restartovat z důvodu promítnutí změn v Java kódu. Nyní dělám na projektu, kde máme OC4J server a plně jsem pochopil, proč ty servery jsou tak heavyweight. Člověk si musí při psání kódu dávat opravdu pozor, protože náběh serveru je v řádu desítek sekund až minuty. A pro tyto případy se hodí JavaRebel.

Moje zkušenost je nyní celkem pozitivní. Používám poslední verzi 2.0-RC2 spolu s OC4J verze 10.1.3.4, k tomu IntelliJ IDEA verze 7.0.4. Intalace je velice jednoduchá - JavaRebel knihovnu se nahraje do classpath aplikace nebo serveru, upraví se spouštěcí soubor serveru a pro IDEU se ještě doinstaluje plugin, aby hezky fungovalo debuggování. Vše je popsáno zde.

S JavaRebel pracuji již přibližně měsíc a chvíli trvalo, než jsem si to vyladil. Měl jsem problémy s během aplikace, někdy mi dokonce spadnul z ničeho nic celý server. To se hodně zlepšilo s uvedením nové verze 2.0-RC2 (před tím jsem používal 2.0-M2). Také jsem musel vyloučit generované Java třídy z JSP stránek (přidal jsem při spouštění tento parametr -Drebel.packages_exclude=_oracle._jsp._tag). Teď mám pocit, že to opravdu funguje, jak bych si představoval.

Součástí JavaRebelu je i plugin pro Spring (pozn. pluginy jsou součástí JavaRebelu od verze 2.0-RC1, před tím bylo nutné si stáhnout pluginy odděleně). Ten by měl umět promítnout změny v konfiguraci Spring kontejneru v průběhu běžící aplikace. Tento plugin jsem krátce používal, ale měl jsem podezření, že mi kvůli tomu padá server, tak jsem ho zatím vypnul. Ale určitě se k němu ještě vrátím, až budu mít více času.

Díky udělátku JavaRebel se i s OC4J dá vyvíjet efektivně. Nástroj není sice zadarmo, ale cena 59 dolarů mi přijde velice příjemná, zejména když vezmu o kolik se mi zvýšila produktivita práce. JavaRebel je možné vyzkoušet po dobu 30 dní.

17. března 2009

Dynamické jazyky nejsou zase tak špatné

Pokud jste v minulosti četli mé názory na dynamické jazyky, tak jste museli cítit, že je zrovna "moc nemusím". Jak to dost často bývá, člověk je omezený díky své neznalosti.

Když jsem se vždy někoho zeptal, k čemu jsou dobré dynamické jazyky, tak jsem vždy dostal hodně podobnou odpověď - DSL, tvorba GUI, customizace. Jenže můj problém byl vždy v tom, že jsem si nedokázal sám sobě říci, kde konkrétně to můžu využít - DSL jazyky obvykle nevytvářím, pro GUI používám JSP nebo JSF (a obecně s tím nemám problém) a customizace je pěkná věc, ale také jsem ji nikdy moc nepotřeboval, protože spíše pracuji na jednorázových projektech než na produktech.

Můj názor se celkem radikálně změnil poté, co jsem si přečetl články o integraci Springu a Groovy a také po vašich komentářích v mém posledním článku o dynamických jazycích.

Díky tomu se mi moc začala líbit ta myšlenka, že pomocí Javy si vytvořím kostru aplikace (pomocí rozhraní) a ty části, které se mění resp. je potřeba upravovat per instalace, tak ty můžu implementovat pomocí Groovy (a hezky měnit za běhu aplikace bez restartu serveru). Toto není nijak obecně převratná myšlenka, ale pro mě je převratná v tom, že jsem ji dokázal aplikovat na konkrétní aplikaci s konkrétními problémy. Holt někomu to trvá trochu déle... :)

21. února 2009

IDEA vs. Eclipse - je někdo vůbec lepší?

Tento článek bude dalším příspěvkem do nekonečné diskuze, které to IDE je vlastně nejlepší. Nedělám si nároky, že by se mi to podařilo nějak vyřešit, ale cítím potřebu o tom napsat, hlavně abych si to sám srovnal.

Hlavním důvodem k napsání tohoto článku byla skutečnost, že jsem nyní po přibližně 4 letech přešel z Eclipse na IntelliJ IDEA. S Ideou jsem před tím již dělal, bylo to moje vůbec první IDE v Javě, tehdy ve verzi 4 (možná 3, teď již přesně nevím). Pamatuji si, že jsem tehdy za žádnou cenu nechtěl přejít na Eclipse, byl jsem s Ideou maximálně spokojený. Teď jsem změnu z Eclipse na Ideu celkem uvítal, byl jsem zvědavý si vyzkoušet zase něco jiného.

Zde jsou mé osobní pocity a postřehy z obou IDE.

Eclipse 3.3 (resp. MyEclipse 6.5)

  • + automatická kompilace kódu při uložení včetně stálého přehledu chyb a varování v celém projektu mi přišlo něco tak samozřejmého, že jsem byl překvapen, že to tak Idea třeba nemá. Auto-kompilaci při uložení jsem si nastavil, s těmi chybami nevím - ukazují se mi jen v rámci daného souboru a nebo při překladu celého projektu, pokud chci znát všechny problémy.
  • + pluginy, pluginy a pluginy - není žádné IDE, které by mělo takovou komunitu a takové množství pluginů. Ve srovnání s Ideou to může být ale i trochu nevýhoda - spoustu věcí si člověk musí doinstalovat sám, nejsou automaticky součástí. Toto už dneska asi moc problém není - já využívám MyEclipse (obsahuje cca 200 předinstalovaných pluginů) a nebo samotný Eclipse vychází v různých edicích, např. edice pro webový vývoj apod.
  • + Eclipse platforma se často používá jako základ pro vývoj dalších IDE, jako např. Websphere nástroje. Pak člověk ocení, že se nemusí učit od základu nové IDE, ale že to základní už vlastně zná.
  • - nejednotný přístup v různých typech souborů. Když chci vybrat slovo, tak bych očekával, že se to stejně bude chovat v Java, HTML, JSP, TXT souborech. Bohužel ne - někde se vyznačí celý výraz, někde jen slovo. Není to prostě jednotné jako třeba v Idee. Asi je to tím, že různé formáty souborů jsou podporovány různými pluginy, mezi kterými není úplná jednotnost.
  • - slabší podpora webových stránek. Dost často jsem psal JSP nebo JSF stránky a nebylo to úplně špatné, ale při přechodu na Ideu jsem zjistil, že to slabší bylo.


IntelliJ IDEA 7

    + klávesové zkratky - pokud někdo v oblibě klávesové zkratky, tak Idea je jasná volba. Myslím, že to mají "vychytaný" :).
  • + podpora Springu - SpringSource snad oficiálně vytváří plugin jen pro Eclipse, ale i přes to je v Idee podpora o dost dále (propojení beanů s Java kódem je prostě super).
  • + all-in-one - nainstaluji a můžu fungovat na 100%. Někdo namítá, že Idea už toho obsahuje až moc - je pravda, že většinu nevyužívám a již dříve ve verzi 4 jsem měl pocit, že to IDE nic více umět ani nemůže.
  • + podpora Java kódování - již ve 4. verzi Idei jsem byl nadšený z možností refactoringu, nápovědy a podobných věcí, které člověk využije, když programuje čistou Javu. Od té doby Eclipse hodně zamakal a dohnal náskok Idei, ale prostě pořád mi přijde, že Idea je v tomto směru nejdále - takové možnosti refactoringu, takové možnosti analýzy kódu, takové možnosti debuggingu prostě v Eclipse nejsou. Jeden příklad za všechny: provedu analýzu kódu na duplicity. Hned s ukázkou duplicitních částí mám možnost refactorovat - extrahovat duplicitu do jedné metody.
  • + kombinace s TeamCity a verzovacím systémem nemá chybu. Moc jsem si oblíbil tzv. Remote run - místo samotného "comitu" se nejdříve provede spuštění na TeamCity a pokud vše projde (kompilace, testy), tak pak se teprve provede commit.
  • - cena. Co k tomu napsat více? Eclipse nestojí nic, MyEclipse začíná na 32 dolarech za rok a Idea začíná na 225 eurech.


Závěr

Po přečtení možná budete mít pocit, že jsem velký fanda Idee. Tak to úplně není, dnes už tak netrvám na tom, že musím dělat v tom daném IDE a v ničem jiném. Nadšení z Idei je také určitě dané změnou - dělal jsem dlouho s Eclipsem a teď jsem nadšený z každé nové "fíčurky", kterou objevím.

Sám jsem přemýšlel, zda mohu napsat, že nějaké IDE je lepší než jiné - napsat to nemohu, protože každé má svoje a záleží na každém, co přesně preferuje. Já sám za sebe mám radši Ideu, ale koupil jsem si MyEclipse ...

10. února 2009

Proč pořád webové služby?

K dnešnímu článku mě inspiroval můj bývalý kolega, který se jednou naučil webové služby a od té doby je používal úplně všude - bez ohledu na to, že by se mnohdy dalo použít lepší (rozuměj jednodušší, efektivnější) řešení.

Napadá mě zde analogie s EJB. Mnoho lidí se naučí EJB a od té doby je používají bez ohledu na to, zda skutečně EJB kontejner v aplikaci potřebují. Podobné je to i s webovými službami. Webové služby jsou nezastupitelné v komunikaci mezi různými platformami. Jinak řečeno, pokud nemáme všechny komunikující systémy pod kontrolou, tak vždy bude asi nejlepší používat webové služby. Existují i jiné "multiplatformí" protokoly jako např. binární Hessian nebo textový Burlap, ale určitě nejsou tak rozšířené jako webové služby. Co se ale týče jednoduchosti použití a hlavně rychlosti komunikace, tak zde webové služby hodně ztrácejí oproti jiným řešením.

Pokud ovšem máme komunikující systémy pod kontrolou a navíc se jedná o Java aplikace, tak bych webové služby nevolil. V těchto případech většinou nejde o vystavení nějaké trvalé služby, ale o vzdálené volání metod. Pro tyto případy nejvíce ocením jednoduchost použití (tj. jednoduchost při nastavení řešení plus pracnost spojená s úpravou objektů pro přenos) a rychlost komunikace.

Pro tyto případy mám výborné zkušenosti s řešením od Springu - Spring remoting. Osobní zkušenosti mám s použitím HttpInvokeru - víceméně řešení postavené na Java serializaci s přenosem po HTTP. S tímto řešením jsem neměl jediné problémy, fungovalo suprově. Jen jsem musel dořešit jednu věc - kromě vlastních objektů se přenášely i objekty knihoven třetích stran, které občas obsahovaly neserializované objekty (většinou se jednalo o výjimky). V tomto případě jsem si pomohl AOP - vytvořil jsem si AOP vrstvu nad vzdálenými službami, která kontrolovala, zda všechny přenášená data jsou opravdu serializovatelná.

Na posledním projektu používáme Hessian z důvodu požadavku na co největší výkon resp. na přenos co nejmenšího množství dat. Tuto volbu jsme provedli (lépe řečeno mojí kolegové) na základě vlastních měření a ze zkušeností uvedených v tomto článku. S Hessianem pracuji zatím velice krátce, ale již se mi podařilo narazit na problémy s přenosem dat (až budu znát přesné příčiny a řešení, tak to uvedu v komentáři k tomuto článku).

U Spring remotingu se mi také libí, že je to postavené nad DispatcherServletem (stejně jako třeba Spring MVC), takže mohu využívat spoustu společných věcí, zejména Spring security pro zabezpečení.

Pokud nevíte, který protokol vybrat pro vaše řešení, tak si přečtěte výše uvedený článek (zejména závěrečné shrnutí) a nebo doporučení uvedené v dokumentaci Springu.