JBoss + Xdoclet + Unknown primary key + CMR relation = ?
Za otazníkem v nadpisu se skrývá nejspíše něco jako “spousta zábavy”. Věc se má následovně:
EJB specifikace nám umožňuje ponechat na kontejneru vytváření primárních klíčů, a říká tomu “Unknown primary key” (bod 10.8.3). Co když se rozhodneme něco takového zkusit v praxi (s aplikačním serverem JBoss 4.0.1)?
Nejprve se popereme s implementací “neznámého” primárního klíče.
Člověk by řekl, že postačí v souladu se specifikací definovat návratový typ příslušé findByPrimaryKey metody jako java.lang.Object, stejný typ dát příslušnému CMP poli a navíc třídu i pole patřičně otagovat Xdocletem (u třídy @jboss.unknown-pk a @ejb.pk class = "java.lang.Object" generate = "false", u get metody pak @ejb:persistent-field, @ejb:pk-field a @ejb:interface-method view-type="local").
A houbeles — JBossův CMP plugin nerozpozná, že deklarovaný “unknown primary key” je totožný s deklarovaným CMP primárním klíčem, a tedy generuje dotazy jako insert into tabulka (pk field, pkfield, ...). Zkrátka vidí dva sloupce, od čehož se odvíjejí rozličná chybová hlášení, od pochopitelné stížnosti relační databáze na zdvojené jméno sloupce v insert dotazu, až po mysteriózní zamyšlení aplikačního serveru na téma nevhodnosti složených primárních klíčů ve scénáři “unknown primary key”.
Co s tím? Zlenivěn Xdocletem přeskakuji studium JBoss-specific deployment descriptoru (možná chyba ;)) a rovnou sahám po manuálu k Xdocletu. Nabízí pouze uvést JBoss specific tagem název databázového sloupce sloužícího jako PK, to pochopitelně dělám, ale JBoss si z toho (vcelku pochopitelně) souvislost neznámého klíče a specifikovaného CMP fieldu odvodit nedokáže. Navíc při generování SQL příkazu INSERT se snaží vkládat primární klíč coby null namísto toho, aby se o něm vůbec nezmiňoval.
Napadá mě CMP field pro primární klíč vypustit, a vida, najednou vše funguje. Primární klíč se stává opravdu doslova neznámým — v důsledku to znamená, že hodnotu klíče musím lovit přes ruku z EntityContextu získaného callback metodou, ale tím se trápit nebudeme.
Nicméně nyní nás čeká úkol číslo 2 — definovat mezi takovýmito entitami relaci.
Napohled nic těžkého, dokud si neuvědomíme, že v descriptoru aplikačního serveru musíme definovat propojovací sloupce — a nyní na nás dopadá důsledek předminulého odstavce: co je vlastně primárním klíčem, když jsme jeho CMP pole zavrhli?
Po marném Googlování a několika naivního pokusech cosi nastřelit nezbývá než využít dostupnosti zdrojových kódů JBosse a ladících možností Eclipse. Po pár breakpointech je situace jasná:
- Vytvoříme-li “unknown primary key” výše popsaným způsobem, JBoss si interně zavede pole s názvem
JménoBeany_upk. - Toto po chvíli úspěšně ověřuju na stránce JBossích odštěpenců z Core Developers Network
Uf.
Stále si říkám, že by nebylo od věci tam pole pro primání klíč zavést. Neustále se ale opakují problémy se zdvojenými poli v dotazu či nadbytečným uvádění primárního klíče v INSERT dotazu.
Takže výsledný kód je:
/**
* @ejb.bean name="Something" type="CMP" cmp-version="2.x" view-type="local"
* @jboss.entity-command name="postgresql-fetch-seq"
* class="org.jboss.ejb.plugins.cmp.jdbc.keygen.JDBCPostgreSQLCreateCommand"
* @jboss.unknown-pk auto-increment = "true" column-name="somethingId"
* jdbc-type="INTEGER" sql-type="INTEGER"
* class="java.lang.Integer"
* @ejb.pk class = "java.lang.Object" generate = "false"
*/
public abstract class SomethingEJB implements EntityBean {
/**
* @ejb.interface-method view-type="local"
* @ejb.relation name="Something_SomethingElse"
* role-name="something-has-somethingelse"
* target-ejb="SomethingElse"
* target-role-name="somethingelse-has-something "
* @jboss.relation related-pk-field="SomethingElse<strong>_upk</strong>"
* fk-column="assignedSomethingElse"
*/
public abstract LocalSomethingElse getSomethingElse ();
// other stuff comes here
}
(Jde o dvě entity beans — Something a SomethingElse, obě mají databází generovaný (a z pohledu EJB specifikace “unknown”) primární klíč. Pro jednoduchost jsem uvedl zdrojový kód pouze jedné z nich, která obsahuje jednosměrnou relaci getSomethingElse().)
EJB 3.0 poprvé odhaleno
Na TheServerSide Symposiu bylo koncem minulého týdne s velkou slávou představeno, co pěkného nám přinese chystaná specifikace EJB 3.0.
Čas od času si neodpustím povzdech nad komplexností EJB, které programátory zahrnuje kvanty rozhraní, výjimek a kontraktů. Protože v tomto nejsem jediný, vzniká spousta "odlehčených" frameworků (Spring, Hibernate), které se snaží dělat věci lépe a radostněji. Jak jsem už avizoval ve zmínce o pražském Sun Tech Day, EJB 3.0 přináší značné odlehčení a přístup založený spíše na používání POJO než implementování či rozšiřování všemožných rozhraní.
Shrnuto jednou větou: EJB 3.0 se soustřeďuje především na usnadnění vývoje. Hodně změn se týká entity bean, rozšíří se možnosti EJB-QL.
EJB 3.0 už samozřejmě počítá s možnostmi Javy 1.5, zejména metadat. Díky bude zdrojový kód jednoduché session beany vypadat následovně:
@Session public class CalculatorBean {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
A šmitec. Rozhraní Calculator vznikne samo od sebe, a deployment descriptoru netřeba (přinejmenším, pokud byste v něm nepotřebovali sdělit nic extra zajímavého).
A uživatele Spring frameworku jistě nepřekvapí "setterová" Dependency Injection, která nahrazuje vyhledávání zdrojů pomocí JNDI. A je-li vám termín "Dependency Injection" cizí, zkuste obsáhlý článek Martina Fowlera.
Vše nasvědčuje tomu, že EJB 3.0 potvrdí vizionářství JBossího týmu a zejména neúnavného a nekompromisního agitátora Marca Fleuryho.
Zdroje a doporučená četba:
- pochopitelně článek na TheServerSide
- nadšené ovace Cedrica Otaku
- méně nadšené komentáře Jasona Carreiry (XWork)
Aktualizace:
K zajímavým zdrojům přidám ještě pár kontroverznějších komentářů od Hani Suleimana — aneb TSSS extrémně kritickým okem:
- TSSS: the zombies arise
- TSSS: AOP still suck
- TSS: EJB 3.0 — cituji: "… EJB 3.0 is basically a bizarre subset of Hibernate…"
- TSSS: AOP Panel — "The trouble is, AOP IS SO GODDDAM BORING. These bastards have been saying all this crap for over a year now."
- TSSS: EJB to Hibernate to EJB3 — "Gavin also frequently mixes ‘I’ and ‘we’ (as in the expert group). What’s funny about this is that he’s pretty much screwed either way. If he says I, the EJB whiners will complain of him hijacking the spec. If he says we, Hibernate users become defensive at losing their fearless leader."
- TSSS: Fleury keynote (co čekat, když se v jednom příspěvku střetnou dva "jokeři" dle TMC’s Who Is Who, zvláště je-li jeden z nich autor)
- TSSS: Day 3 and Aftermath
- a celým TSSS inspirované závěrečné provolání Fuck thought leaders!