Až Vám zčerná obrazovka, přejděte na Linux!

Proč používat Linux

středa 30. dubna 2008

Jak na JBossí WebServisy v IDEA

Po několika dnech Googlování a pokusů a omylů se mi konečně podařilo rozchodit první WebServisí komunikaci klient-servisa na zákeřné kombinaci: Windows XP, Sun J2SE 1.6.0_5, JBoss 4.2.2GA, IntelliJ IDEA 7.0.3

Co je třeba udělat:

  1. nainstalovat ony zmíněné produkty :-)
  2. nepoužívat implicitní JAVA_HOME/jre/lib/endorsed adresář, protože se buď nepodaří zkompilovat vygenerované stuby nebo začne řvát JBoss
  3. stáhnout si a nainstalovat jbossws patch:

    1. rozbalit (ideálně hned vedle jboss-4.2.2GA, ať to máte pohromadě)
    2. přejmenovat JBOSSWS_HOME/ant.properties.template na JBOSSWS_HOME/ant.properties
    3. v JBOSSWS_HOME/ant.properties nastavit propertu jboss422.home na JBOSS_HOME (např ../jboss-4.2.2GA)
    4. v JBOSSWS_HOME/build/build-deploy.xml odstranit závislost targetu deploy-jboss422 na undeploy-jboss422 (jinak na Vás zařve, že nemůže smazat soubory v JBOSS_HOME)
    5. pokud není ant v cestě, tak je třeba nastavit
      set "ANT_HOME=JBOSSWS_HOME\tools\ant"
      set "PATH=%ANT_HOME%\bin;%PATH%"

    6. v JBOSSWS_HOME spustit ant deploy-jboss422 - tím se do JBOSS_HOME/lib/endorsed nahrají patřičné jary JAXBčka


  4. napsat si servisu (Web a WebService (JAXB2.1, nikoli Axis))
  5. nadeployit servisu do JBossu
  6. založit projekt pro klienta (WebService client, JAXB2.1, nikoli Axis)
  7. vygenerovat stuby z WSDLka WebServisy
  8. upravit example.HelloWorldClient tak, aby zavolal onu servisu
  9. vytvořit Run Configuration pro klienta (typ Application)
  10. do VM Parameters dát "-Djava.endorsed.dirs=C:\Documents and Settings\tapik\.IntelliJIdea70 \system\webservices\jaxws-ri-2.1\"
  11. spustit a doufat, že funguje

Pokud funguje, je vymalováno.

pondělí 28. dubna 2008

Naše první keška

Zapojili jsme s rodinkou do celosvětové braně-orientační hry Geocaching a toto je náš první úlovek. Keška v Přílepském zámku.
 
Posted by Picasa

pátek 25. dubna 2008

IDEA WebService plugin a JDK 1.6

Po šesti letech zkušeností s WASPem (alias Systinet Server for Java) jsem se vrhl do implementace WebServisy, kterou lze nadeployit do JBossu bez nutnosti jakékoli další knihovny. Tak jsem zvolil JavaWS.
Ninstaloval jsem si IDEA WebService Plugin, juknu se letmo na tutorial, zkusim si spustit example webservisu a bac ho:
The exception com.sun.xml.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class example.jaxws.SayHelloWorldFrom is not found. Have you run APT to generate them?
Tak to jsem teda čuměl jak puk. Řeknu si No nic, ask Google. Googlil jsem hodinu, prošel jsem si dokumentaci k JavaWS, JBoss WS, Idea Webservice Plugin. Jediné, co jsem našel, že všem fungovalo, bylo nastavit java.endorsed.dirs na adresář s javaws dodávaný k IntelliJ IDEA. Furt nic. Zkoušel jsem už různé obskurní řešení typu @WebServiceProvider, ale furt nic. Nakonec jsem našel toto naprosto triviální řešení.
By default generuje JavaWS ve formátu WRAPPED, ale já po něm požadoval chování BARE. Stačí tedy nastavit:
@SOAPBinding(parameterStyle=ParameterStyle.BARE) a je po ptákách.

čtvrtek 24. dubna 2008

SMTP-AUTH Postfixem na OpenSuSE

Nějakou dobu jsem se odhodlával k rozchození kryptovaného SMTP-AUTH na mém (lépe řečeno našem společném s Maťkou a Michalem) serveru. Při představě rekompilace a rekonfigurace postfixu, který tam bez potíží běží už pár let a je to poměrně důležité místo, navíc bez možnosti ho otestovat jinde v ostrém provozu, mě celkem šimralo v okolí žaludku.
Chystal jsem se postupovat podle HOWTO od Patricka Ben Koettera. Všechno jsem si nachystal, když tu mne osvítil já nevím kdo a napadlo mě ještě chvilku Googlit. A vygooglil jsem pravou perlu: OpenSuSE 10.2 Perfect Setup od falka.
Tato stránka krok za krokem přesně popisuje co dělat, když chcete rozchodit OpenSuSE 10.2 box jako ISP/hosting server. Sqělé počteníčko! Dík, falko!

středa 23. dubna 2008

Krátké oRESTování

O RESTu se všude vedou dalekosáhlé debaty. Například zde se Vlasta Vávrů snaží přijít oné věci na kloub.
Nejsem sice kdovíjaký REST-guru, ale svoje si k tomu řeknu:
* REST je o zdrojích (resourcech). Každý zdroj má svou jednoznačnou identifikaci - URI. Po dobu jeho životnosti pod tímto URI vždy a za každých okolností najdete tento zdroj (jestli je to URLčko nebo URN do repozitáře je buřt). Každý zdroj JE STAVOVÝ. Minimální sada stavů je jsem - budu - byl jsem. Představíme-li si jako zdroj seznam členů CZLUGu, je jasné, že se bude v čase měnit. Ale pokaždé dostanete logicky totéž, aktuální seznam členů. No, aktuální, RESTózní architektura umožňuje plnohodnotné interceptory, kde například může stát cache, která vrátí seznam klidně včerejší. I o tom REST je. Data nemusí být vždy aktuální.
* důležitou vlastností RESTózních aplikací je omezená množina operací, které lze s daným zdrojem provádět. Proto je HTTP RESTózní, má čtyři hlavní operace GET, POST, PUT a DELETE.
* komunikace MUSÍ BÝT BEZESTAVOVÁ, tedy komunikace nesmí zahrnovat stav klienta. To ale neznamená, že sezení jako takové je v RESTu nesmysl. Pouze jeho řešení pomocí sušenek je nepřípustné. Mám-li sezení zakomponováno do URL, jsme v pohodě. Samo sezení se stává zdrojem. Dostávám se tak do situace, kdy logická operace přidej produkt s URI:XY do košíku patřící sezení s URI:SSS (třeba HTTP POST SSS produkt=XY) bude mít za následek vždy to totéž a o to právě v RESTu jde. Dalším problémem pro bezestavovost komunikace jsou <INPUT TYPE="HIDDEN">. Tyto jsou v HTML zavedeny právě pro udržení stavovosti komunikace, čili typická antiRESTóznost.
Doufám,že si někdy najdu čas a všechno, co o RESTu vím, sem napráskám.

Fotomapy alá seznam.cz

Na Ilblogu jsem zaznamenal spuštění nové služby - foto.mapy.cz. Nemá smysl komentovat funkcionalitu, to se musí vidět. paráda.
Už si žhavím foťák...

pondělí 21. dubna 2008

Tak to ještě se mnou není tak hrozné

O víkendu za mnou přišel bratranec s prosbou, jestli bych mu nepomohl s řešením domácího úkolu z geometrie pro jeho dceru, studentku druhého ročníku ekonomky. Danou úlohu neměli v učebnici, neprobírali ji a jejich kantor prohlásil, že to mají udělat selskou úvahou. No zkrátka nedali to.
Zadání je vcelku triviální. Zkonstruujte trojúhelník, pro který platí: |AB|=4cm, v(c)=3cm, úhel ACB=60 stupňů.
Uznávám, že je to trivka. Ale sám jsem byl přeqapen, že jsem to vypotil bez dlouhého přemýšlení a bez nutnosti použít literaturu, i přes propast 16let od maturity, kdy jsem naposled rýsoval.
Ti z vás, kterým se nechce nad řešením přemýšlet, najdou postup řešení v komentářích.

pátek 18. dubna 2008

Nepoužívejte CORBU, smrdí, aneb rychlost řešení chyb v Sun JDK

Tušil jsem, že rychlost řešení nebude přílš vysoká vzhledem k množství chyb, ale co je moc, to je někdy opravdu příliš.
V Barcu máme docházkový systém, který je řešený appletem komunikující se systémem přes CORBU. V JDK 1.4.2 fungoval naprosto spolehlivě. Při přechodu na 1.5 mu přestala chodit CORBA. Lidé z ComInfa dodali workaround - soubor java.policy obsahující:

// CORBA error workaround
grant codeBase "http://192.168.11.9/watt/jar/*" {
permission java.lang.RuntimePermission "modifyThread";
permission java.lang.RuntimePermission "modifyThreadGroup";
};

Přišlo mi to strašně divné, protože nutnost povolovat práci s Thready považuji za prasárnu. Tak jsem začal pátrat, co za svinstvo tam můžou vlastně dělat. Odpově byla přeqapující - jsou v tom nevinně!

Chybu má totiž na svědomí com.sun.corba.se.impl.transport.SelectorImpl, který na začátku metody run() udělá naprosto samozřejmou věc - nastaví si jméno. Potíž je v tom, že v Appletu je takováto operace by default zakázána! Aby ji bylo možno provést, je třeba si spustit v Privileged módu. Stačí tedy ono volání zabalit do doPrivileged() a máme vystaráno. Jednoduché, fix na deset minut, který navíc může být potencionálně na více místech, takže za hoďku za dvě může být pořešeno celé JDK.
Jenomže to bychom museli být někde jinde. Buga číslo 6203567 byla reportována v 03-DEC-2004 a podle všeho ještě pořád není fixnutá! A to je u reportu jednoduchý kód na její reprodukci včetně patche. Navíc bylo od Sunu před třemi lety získáno prohlášení, že to bude v tehdy příští verzi opraveno. Nevím, ale fixnutí by zabralo méně času než vydání onoho prohlášení :-)
Schválně si na vašem JREčku vyzkoušejte, jestli vám projde! Já dostal:

tapik@bilbo:~> java -version
java version "1.6.0_05"
Java(TM) SE Runtime Environment (build 1.6.0_05-b13)
Java HotSpot(TM) Server VM (build 10.0-b19, mixed mode)
tapik@bilbo:~> appletviewer CorbaTest.html
Exception in thread "Thread-2" java.security.AccessControlException: access denied (java.lang.RuntimePermission modifyThread)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at sun.applet.AppletSecurity.checkAccess(AppletSecurity.java:214)
at java.lang.Thread.checkAccess(Thread.java:1263)
at java.lang.Thread.setName(Thread.java:1050)
at com.sun.corba.se.impl.transport.SelectorImpl.run(SelectorImpl.java:239)

čtvrtek 17. dubna 2008

Ať žije frameworkování

Jakožto člověk, který začínal s trošku obsáhlejším programováním na Didaktiku Gama a v assembleru se mi zvedá žaludek nad dnešním přeframeworkovaném programování. To by nebylo nic divného a ani bych vás tím neotravoval, proti gustu žádný dišputát. Nebýt včerejšího dotazu na konference@java.cz .
Jeden človíček se ptal, jak číst a zapisovat data do XML, když jich má obrovskou tabulku v DB o hodně sloupcích a ještě více řádcích. Hovořil dokonce o desítkách GB dat.
Pokud jde o čtení, tam je to jasné. Je to XML a on nemůže předpokládat nějakou pevnou textovou strukturu a musí tedy využít XML parser. Co mne ale zarazilo, byl dotaz na zápis.
Osobně nepočítám s tím, že by měl všechna data v paměti a chtěl s nimi nějak zásadně při zápisu manipulovat než je prostě odněkud načíst řádek po řádku, provést nějakou substituci na onom řádku a pak jej uložit jako strukturovaný XML element. V čem vidím problém je to, že chlapce ANI NENAPADLO řešit to otevřením OutputStreamu a cpát tam data v textové podobě! Vždyť přece XML je v prvé řadě textový soubor formátovaný tak, aby byl člověkem jednoduše čitelný!

Hodina angličtiny od Elánov

Dneska jsem poslouchal $SUBJ a nevěřil jsem vlastním uším. Dvakrát jsem si vracel onu pasáž. A pak jsem se rozchechtal...
Většina písně je složená z výkladu anglických slov a frází. Tady je první sloka:
Yes je áno a no je nie,
a one je jedna a two je dve,
a hovoriť je speak a dobre je well,
a you've got what you wanted značí, máš, čo si chcel.
a know je vedieť a how je ako,
a watch the Czechs, je pozor na Slovákov,
a go je ísť a out je von,
bože Lendl ten má prachov, chcem byť ako on!

Pro ty málo vnímavé jsem onu pasáž zvýraznil :-)

středa 16. dubna 2008

Java prý prohrává boj o Web

Po delší době jsem zase brouzdal The ServerSide a musel jsem se opravdu zasmát. Přečetl jsem si "Java is losing the battle for the modern web"..., reakci Josepha Ottingera na Java is losing the battle for the modern Web. Can the JVM save the vendors? od Andiho Gutmana. Lidi, číst si některé blog2blog flameware, to je vám fakt někdy švanda. První něco ne zrovna inteligentního vymyslí pro podporu svého tvrzení, druhý to navíc špatně pochopí a polemizuje s tím. No nic.
Přesto je dobré si ona dvě zamyšlení přečíst. Andi se snaží přijít na to, proč je LAMP tak úspěšný a prosazuje se oproti Java EE řešení.
Zaujala mne myšlenka o větší RESTovosti LAMP řešení oproti klasice v Javě, která je podle něj navržena více na Enterprise aplikace a Webový Xicht je tam přidán tak nějak jako navíc. S tou historickou skutečností má dozajisté pravdu. EJB, gró J2EE, vznikaly nezávisle a odděleně od JSDK. JServ jsme používali a EJBoss byl ve stavu nepoužitelném.
Co se týká RESTovosti, tak tady je to dáno geneticky. Spustit CGIčko bylo velice rychlé, obzvláště když byl skript nakešován. Navíc CGI nemohlo být stavové a tak se všechna data předávala v INPUT HIDDEN tazích. Oproti tomu spouštět JVM pro každý request by znamenalo si vyrvat vlasy. Je celkem pochopitelné, že chtěl-li Sun dostat Javu i na serverovou stranu, musel JVM pověsit na ServerSocket. Ono to mělo zase spoustu výhod. Najednou přibyla stavovost a všichni tvůrci Webových aplikací (no, moc nás tehdy nebylo) jásali, protože si mohli data držet v HttpSession. A ano, zde se ztratil REST.
Časem ale došlo k velkému sblížení. PHP dostalo session (ó, jaká to výhoda oproti Perlu, máme podporu session přímo v systému!), J2EE patterny tvrdí něco o bezstavovosti a držení si stavu v DB, což je momentálně jediný způsob, jak si ho drží Perl či Python.
Takže o větší RESTovosti LAMPu to není. Aplikace je tak RESTová, jak se napíše.
Další zajímavý poznatek je o multiprocess versus multithread. Dozajista pád skriptu nemusí nutně znamenat pád celého systému. Ale řekněme si to jinak - od dob mod_php či mod_perl je schopen vzít s sebou skript celý apache. Deadlocky nechrozí jenom zdánlivě - maximální počet spojení na MySQL se při tuhnutí skriptu velice brzo vyčerpá, to mi věřte.
Já si myslím, že hlavní rozdíl je v nasazení. V rámci komunity se vyvíjí především na LAMP ve stylu komunita sobě, komerčnímu světu zase vládne spíše J2EE, protože platící zákazník požaduje záruku stability a pro většinu z nich není ani PHP ani MySQL dostatečnou zárukou. Proto je možno z Webu stáhnout LAMP OpenSource aplikace a vrznout je na svůj LAMP server, kdežto málokdy stáhnete OpenSource .ear .

pondělí 14. dubna 2008

getClass() versus instanceof v equals()

Jak píše Dagi, použití if (getClass() != o.getClass()) return false; generuje chyby při použití Beanových frameworků (Hibernate, EntityBeans,...). Josh Bloch například zde doporučuje instanceof i s tím, že napsat equals() bude mnohem těžší. Otázka zní: jak ji vlastně správně napsat? Je potřeba zaručit symetričnost, takže
if (!(o instanceof this.getClass())) return false;
nic neřeší.
if (!(o instanceof this.getClass())
&& !(this instanceof o.getClass())) return false;

vypadá na první pohled lépe, ale pořád to neřeší vůbec nic.
Lze vůbec genericky prohlásit, že je možné v jakémkoli případě napsat equals() podle obecného algoritmu tak, aby odpovídala všem požadavkům na ni kladených? V případě Hibernate je bez debaty nutné použít instanceof. Co ale v případě, kdy potomek se liší od předka v přidání jednoho podstatného atributu? Pro příklad uvedu třídu popisující N rozměrný Euklidovský prostor. Jako potomka pak navrhnete třídu popisující Lobačevkého hyperbolický prostor, která pouze zavede patřičnou transformaci, která ovšem nemůže nikdy vrátit identitu na jiný prvek prostoru než bod. A v žádném případě nemůžete položit rovnítko mezi libovolnou instancí hyperbolického prostoru a euklidovského prostoru! Totéž by platilo pro systémy, které odpovídají Peanovské algebře a jejich potomky připravené o axiom indukce.
Uznávám, že se nejedná o zrovna zářné příklady. Uvedu jiný, učebnicový. V mnoha učebnicích je pro vysvětlení principů OOP použita hierarchie objektů: Bod->Obdélník->Kvádr. I zde je jasné, že nelze v žádném případě použít instanceof. Nebo dokážete pro Obdélník takovou smysluplnou symetrickou metodu equals() napsat? Čekám na vaše názory.
Mně teda jedno příšerné řešení napadlo. Použít Cimrmanova úkroku stranou a udělat z toho PNJ, tedy je-li to můj potomek, nechť to zařídí on. Ale nejsem si jist, zda jej lze použít v každém případě.

Nefunkční oracle-xa-ds.xml z JBoss docs

Kdo z Vás se bude snažit rozchodit konexi na Oracle z JBossu, asi v první chvíli sáhne po JBossí dokumentaci. V kapitole Other Databases mají přímo ukázkový deployment descriptor pro oráklovký datový zdroj. Leč je v něm ašíbka (alespoň pro verzi 4.2.2), a to konkrétně v definici MBeany pro formátovač chyb z Oracle plynoucích.

<mbean code="org.jboss.resource.adapter.jdbc.xa.oracle.
OracleXAExceptionFormatter"
name="jboss.jca:service=OracleXAExceptionFormatter">
<depends optional-attribute-name="TransactionManagerService">
jboss:service=TransactionManager
</depends>
</mbean>

Jenomže OracleXAExceptionFormatter není v balíku org.jboss.resource.adapter.jdbc.xa.oracle, alébrž v org.jboss.resource.adapter.jdbc.vendor. A pak se můžete divit, že vám z toho lítají CNFE: ClassLoaderNotFound.

Sláva našim výrobkům

Musím se přiznat, že článek (Ne)Qalita v běžném životě jsem napsal hlavně qůli článku tomto jako kontrast.
V sobotu jsem byl nakupovat. Nejdřív jsem si koupil stálici na trhu obuvi, české boty Prestige (tzv. prestižky). Už jsou to moje čtvrté. A nedám na ně dopustit. Lehoučké, pohodlé, kožené, na běžné nošení i na sport, do lesa a klidně i do bláta, dobře se v nich řídí, prostě úžasné boty. Navíc vyráběné v mém rodném Zlíně, bývalém městě obuvi. 889,- za takové boty opravdu není moc.
Rozradostněn touto koupí mne do malého obchůdku v Holešově se sportovním, převážně turistickým sortimentem, zavedla touha pořídit si nové gatě. A mám je. Manželka tam objevila pro mne krásné tričko (jak jinak než s tučňákem :-D ). Pěkně vypadá, perfektní materiál, kvalitní vypracování, větrací vsuvka v podpaží, prostě něco pro mě. Když jsem ho platil, nečekal jsem, že s ním doma zažiju milé překvapení.
Doma jsme totiž začali studovat visačku. Jenom mimochodem uvádím, že byla k tričku přivázaná špagátkem. První, co mne zarazilo, byl název firmy: Bemaniax. Ano, má to znamenat Be maniacs :-) . Pak jsme četli dál. Dozvěděli jsme se, že tato česká firma dělá limitované edice triček, takže málokdo bude chodit ve stejném jako já. Dále jsme se dozvěděli, že tričko bylo vyrobeno tak, aby nezatížilo životní prostředí.
Největší pecku jsem si schoval nakonec. Cituji: Tento výrobek nevyrobila čínská holčička.

(Ne)Qalita v bežném životě

Během víkendu jsem měl několik zajímavých postřehů ohledně kvality výrobků běžně potřeby.
Na prvním místě je autíčko mého syna, imitace klasického vojenského jeepu. Předpokládám, že uhodnete zemi původu. Ano, je to tak. Autíčko Made in China. Jako již poněkolikáté jsem vzal modelářské lepidlo na plasty a zalepil upadávající přední sklo (sklo tam samozřejmě není, jenom prázdný rám). Čínské plasty jsou pěkná fušeřina, trošku zatlačíte a křus. Tentokrát ale krom onoho rámu jsem zjistil, že je zadní náprava nějak podezřele posunutá jedním směrem.
Tak jsem vzal šroubovák, povolil jediný šroubek, co tam je, oddělal podvozek a čuměl jsem jak puk. V autíčku byl z mně neznámých důvodů osazený motorek spřevodovaný se zadní nápravou. A oba vstupy byly ustřižené! Pokud to mělo sloužit jako brzda nebo jako doraz (jiný význam nevidím), je to totální kravina. Holt, čínský výrobek, u něj se asi nemáme čemu divit.
Druhá hračka, která mne pěkně nadzvedla, byl silniční kužel v rozšiřující sadě (čtyři kužely, jeřáb, parní válec a nákla´dák) k vláčkodráze (ta kompatibilní s Maxim Wooden Toys), bohužel si už nepamatuju na výrobce, krabičku jsme už vyhodili. Každopádně jsme u této sestavy za pět kilo kvalitu jaksi očekával. Bohužel.
Buď máme doma takového ničitele, nebo prostě jenom ty hračky tak qalitní nejsou, ale dvě části kužele, vlastní kužel a podstava, byly k sobě jenom přilepeny a to něčím méně trvanlivým. Stačilo se o něj malinko opřít mimo osu kužele a podstava upadla. Musel jsem to k sobě přišroubovat.
Další "srandu" jsem si užil, když jsem koupil náhradní trafo k halogenovým bodovkám. Když jsem chtěl do svorkovnice přišroubovat měděné lanko, nešlo to. Důvod? Ve svorkovnici vypadající jak jednostranná "čokoládka" byl pod každým šroubem plech. Na tom by nebylo nic divného, kdyby ten plíšek nebyl napevno ukotvený z vnější strany. Přitahováním jsem tudíž lanko vytláčel a stačilo po dotažení za něj mírně zatáhnout a bylo venku :-(
Poslední zápich jsem zažil se satelitem od Koskomu. Po spadeném stropu, kdy jsme barák 7+2 muslei sestěhovat do dětského pokoje, který se zabednil, a do mojí nové pracovny o rozměrech 7x3m, ve které jsme museli měsíc vegetovat (čtyřčlenná rodina a naše hovawartí slečna, fakt legrace), byl satelit odpojený od sítě a pěkně zabalený před prachem. Po měsíci jsme ho vytáhli. Přívodní kabel jsme museli přecvaknout, protože se musela bourat příčka, kterou byl protažen a jíž konektor neprolezl. Po zapojení jsme ho museli zase nacvaknout. Byl šroubovací a tak jsem si na to troufl jenom se štípačkama a kombinačkama. Jenomže nám od té doby po televizi občas přeběhly pruhy. Napotřetí jsem k nám dostal ogaru, který nás zasatelitnil. Ten přišel a řekl, že je to pouhým nastavením video výstupu. Po dvou dnech odpojení prý koskom ztrácí konfiguraci!
No prostě hrůza a běs. Pokud mají nízké ceny přinést takové šmejdy, tak to ať se s cenovými závody honem přestane.

pátek 11. dubna 2008

IDEA a setter/getter generátor

IntelliJ IDEA umí generovat ohromné množství jednotlivých kusů kódu. Například toString() plugin generuje opravdu velice přehledně a inteligentně to, o co by se člověk musel starat. Navíc si můžete napsat několik vlastních šablon a ty potom podle potřeby generátoru vyměňovat.
Opačný extrém ale platí pro gettery a settery. IDEA je umí vygenerovat pro specifikované atributy, ale neumožňuje použít žádnou šablonu ani nakonfigurovat žádnou inteligenci.
Tak jsme hledal, jak toto opravit. A vygoogloval jsem feature request, který přesně o tomto mluví. takže doufám, že se toho brzo dočkáme. Ideálně v podobě pluginu či opravy stávajícího kódu.

Slovenčina je nádherná

Včera jsem se díval na ST 2. V reklamní přestávce v kriminálce Miami šel reklamní spot známý i u nás, na "konečně přípravek na hebké podpaží od nejmenované firmy", kde se děvče ptá svého milého, kterou část jejího těla má nejraději.
A reklama byla ve slovenštině. Na jejím konci jsem se musel smát, až jsem se za břicho popadal. Víte, jak se řekne slovensky podpaží? Podpazuší!
No řekněte, není ta slovečina úchvatný jazyk?

středa 9. dubna 2008

Hibernate a tabulky bez primárních klíčů

Jsou lidi, kteří tvrdí, že mít tabulku bez primárního klíče je nesmysl. A proto se bez něj Hibernate neumí pohnout. Já s nimi nesouhlasím.
Mějmež jednoduchý příklad: chceme uložit přichodivší fakturu do databáze. Faktura obsahuje hlavičku (kdo, kdy,...) a několik položek. Každá položka faktury má pevně danou strukturu. Z hlediska databázisty jednoduchý případ jak facka. Jedna tabulka pro fakturu (ID faktury, hlavička a stav), druhá pro položky (id faktury jako cizí klíč a atributy položky (cena, množství,...).
No jo, ale zkuste toto udělat v Hibernate! Jediná cesta, kterou jsem vygoogloval, je vytvořit fake_id pro každou položku každé faktury! FUJ! řeknou kování DBáci. A já s nimi.
Možná, že znáte jinou cestu. Rád se ji dozvím.

Hibernate a Primary Foreign Key

Tak jsem si dneska pořádně naběhl. Chtěl jsem si dvě tabulky provázat přes sdílený klíč, který byl v první Primary Key (tam záznam jako první vzniká) a po zpracování dat uložit do jiné tabulky řádek, jehož ID odpovídá tomu prvnímu, tedy bude hrít roli Primary a Foreign Key zároveň. Principiálně nic složitého.
Nechal jsem si v Idei vygenerovat příslušné anotace:

public class DataBindingEntity {
private long recordId;

@Id
@Column(name = "RECORD_ID", nullable = false)
public long getRecordId() {
return recordId;
}

public void setRecordId(long recordId) {
this.recordId = recordId;
}


private HibertestEntity hibertestByRecordId;

@OneToOne
@JoinColumn(name = "RECORD_ID", referencedColumnName = "ID", nullable = false)
public HibertestEntity getHibertestByRecordId() {
return hibertestByRecordId;
}

public void setHibertestByRecordId(HibertestEntity hibertestByRecordId) {
this.hibertestByRecordId = hibertestByRecordId;
}
...
}

public class HibertestEntity {
private long id;

@Id
@GeneratedValue(generator="triggerAssigned")
@GenericGenerator(name = "triggerAssigned",
strategy = "jpl.hibernate.util.TriggerAssignedIdentityGenerator")
@Column(name = "ID", nullable = false, length = 22)
public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}
private DataBindingEntity dataBindingById;

@OneToOne(mappedBy = "hibertestByRecordId")
public DataBindingEntity getDataBindingById() {
return dataBindingById;
}

public void setDataBindingById(DataBindingEntity dataBindingById) {
this.dataBindingById = dataBindingById;
}
...
}


Jenže jsem si parádně naběhl. Během inicializace sezení jsem chytil NPE:

13:04:59,125 ERROR [[acceptor]] Allocate exception for servlet acceptor
java.lang.NullPointerException
at org.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:135)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1130)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:296)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1286)


Zakomentování OneToOne propert na obou stranách problém vyřešilo. No, vyřešilo ... :-(

takže si to musím řešit ručně. Nedá se nic dělat.

pondělí 7. dubna 2008

IDEA 7, Hibernate a DB generovaná ID

Musím uznat, že ač je práce s Javím perzistorem Hibernate v IntelliJ IDEA celkem přímočará, dostanete se do stejných potíží, jaké u Hibernate mají i ostatní uživatelé. IDEA je přeci jenom vývojový nástroj, ikdyž geniální. Nic míň, ale také nic víc.
Potřeboval jsem qůli klastrovatelnosti nechat databázi generovat IDčka záznamů. V Oracle je to jednoduché, jde to naklikat v Oracle XE konzoli. ve výsledku asi nejkratší možný SQL záznam vypadá:

CREATE TABLE "HIBERTEST"
( "ID" NUMBER,
"DATA" BLOB,
CONSTRAINT "HIBERTEST_PK" PRIMARY KEY ("ID") ENABLE
)

CREATE OR REPLACE TRIGGER "BI_HIBERTEST"
before insert on "HIBERTEST"
for each row
begin
select "HIBERTEST_SEQ".nextval into :NEW.ID from dual;
end;


Pro pouhé uložení záznamu vám stačí nastavit IDčku hodnotu -1 (pro zachování nullable=false) a Oracle to přeplácne za Vás. Potíž nastane v okamžiku, kdy chcete s onou zaperzistentněnou beanou dál pracovat a mít v ní ono ID. Naštěstí bratr Google opět pomohl.
Jean-Pol Landrain napsal velice triviální a nádherný PostInsertGenerator, který to řeší velice elegantně. Podívejte se sami.
Pak stačí entitě v IDEA přidat anotaci

@GeneratedValue(generator="triggerAssigned")
@GenericGenerator(name="triggerAssigned",
strategy = "jpl.hibernate.util.TriggerAssignedIdentityGenerator")

a je vymalováno.

IDEA 7 aneb Tak dlouho jsem se bránil hibernate, až se ucho utrhlo

Nastoupil jsem do nového zaměstnání - do hradišťské firmy BARCO a začal psát J2EE aplikaci postavenou nad SQL. O hibernate jsem nechtěl ani slysšet, protože když jsem naposledy viděl jeho konfiguraci, jímala mne hrůza a běs.
Ale nainstaloval jsem si novou IntelliJ IDEA, IMHO nejlepší nástroj na vývoj aplikací v Javě, která podporu Hibernate v sobě obsahuje. Tak jsem to zkusil. V Oracle XE konzoli jsem si nadefinoval tabulku, dal do ní cvičně jeden řádek a zkoušel jsem, co s tím IDEA dokáže za kouzla. A byl jsem mile přeqapen.
Postup je velice jednoduchý. Ze všeho nejdřív si v projektu nadefinujte DataSource ukazující na onu tabulku (Menu->Tools->Data Sources..., nezapomeňte na Refresh Tables jako já :-) ). Pak vytvoříte v projektu nový modul typu Hibernate, zasociujete jej s Data Sources, přidáte Deskriptor (IDEA sama nabídne jediný možný ;-) ) a potvrdíte. Pro modul víc nepotřebujete.
Poté se už jenom v projektovém navigátoru přepnete do pohledu Java EE: Structure, kliknete na nový Hibernate projekt a v kontextovém menu vyberete Generate Persistence Mapping->By Database Schema a pak jen zíráte.