Když jsem přemýšlel jaký zvolím framework pro webovou aplikaci,
naskytly se mi v podstatě dvě možnosti. Buď JSF či Struts. Osobně jsem
raději hned sáhnul po JSF. Komponentový framework, navíc tolik dotovaný
samotným Sunem.
Po vyzkoušení pár příkladů jsem ihned přešel do vývoje. Zde ovšem
nastaly potíže. Psaní stejného kódu stále dokola. Stálá definice přes
XML, neexistence použitelného scope pro komponenty. Navíc jsem na vývoj sám
a přijde mi příliš těžkopádné vše striktně oddělovat.
Našel jsem Seam. Jedná se o webový framework od JBosse, který tvoří
ono lepidlo mezi JSF a EJB3. Samotná definice komponent je plně řízena
anotacemi, čímž odpadají mnohé XML definice. Seam navíc obsahuje dosah
komponenty „conversation“. Taková komponenta poté existuje od doby vzniku
konverzace až do jejího zániku. Odpadá tak potřeba definovat komponenty
jako „session“. Další věcí, která mě zaujala byla podpora Hibernate
Validatoru. Pokud použiji Hibernate, mám možnost nechat Seam, ať mi
jednotlivé hodnoty entit validuje podle definice z Hibernate.
Já se zde nechci zabývat podrobnostmi, jak daný Seam funguje, k tomu
slouži referenční příručka. Mimochodem skutečně výtečně napsaná.
Spíše se zaměřím na to, jak nainstalovat Seam 2.0 na Glassfish V2.
Seam je primárně určen pro aplikační server Jboss. Pravdou ovšem je,
že ho lze použít i na jiném serveru či přímo bez EJB kontejneru (viz.
Tomcat). Samotná konfigurace se liší jen nepatrných věcech. Mě ovšem dali
pekelně zabrat :)
Takže, nejprve je nutné stáhnout samotný Seam 2.0 a Hibernate. Již
přímo v examplech existuje ukázková aplikace s názvem booking
(v adresáři jee5). Jedná se o web. aplikaci pro hotel, kde si můžete
zamluvit vlastní aparmá. Na aplikaci je vysvětlené jak funguje komunikace
mezi Seamem, JSF a JPA.
Při tvorbě vlastní aplikace si musím nejprve zaregistovat dané knihovny.
Pro webovou vstvu to je:
- el-api.jar
- el-ri.jar
- jsf-facelets.jar
- jboss-seam-ui.jar
Pro EJB modul:
- jboss-seam.jar
- jboss-seam-debug.jar
- hibernate-all.jar
- thirdparty-all.jar
EJB Modul dále musí obsahovat conf/seam.properties, který může být
klidně prázdný. Definice persistence.xml, kde je třeba, aby byla správně
nastavena transakce:
<?xml version=„1.0“ encoding=„UTF-8“?>
<persistence version=„1.0“ xmlns=„http://java.sun.com/xml/ns/persistence“ xmlns:xsi=„http://www.w3.org/2001/XMLSchema-instance“ xsi:schemaLocation=„http://java.sun.com/xml/ns/persistence http://java.sun.com/…1_0.xsd">
<persistence-unit name=“default">
<provider>org.hibernate.ejb.HibernatePersistence
</provider>
<jta-data-source>my/db
</jta-data-source>
<properties>
<property name=„hibernate.dialect“ value=„org.hibernate.dialect.MySQLInnoDBDialect“/>
<property name=„hibernate.transaction.manager_lookup_class“ value=„org.hibernate.transaction.SunONETransactionManagerLookup“/>
<property name=„hibernate.cache.provider_class“
value=„org.hibernate.cache.HashtableCacheProvider“/>
<property name=„hibernate.transaction.flush_before_completion“
value=„true“/>
<!-- ONLY FOR
DEVELOPMENT -->
<!--<property
name=„hibernate.show_sql“ value=„true“/>
-->
<!--<property
name=„hibernate.format_sql“ value=„true“/>
-->
</properties>
</persistence-unit>
</persistence>
Webový modul: Jednak obsahuje web.xml, kde je třeba dodefinovat Seam:
<!-- START JBoss Seam -->
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/</url-pattern>
</servlet-mapping>
<!-- END JBoss
Seam -->
A jednak reference na EJB Beany.
<ejb-local-ref>
<description>For Transaction from EJB3 Container</description>
<ejb-ref-name>Irminsul/EjbSynchronizations/local</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>org.jboss.seam.transaction.LocalEjbSynchronizations</local>
<ejb-link>EjbSynchronizations</ejb-link>
</ejb-local-ref>
<ejb-local-ref>
<ejb-ref-name>MyEARName/MyBean/local</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>ejb.seam.app.MyLocal</local>
<ejb-link>MyBean</ejb-link>
</ejb-local-ref>
Je to trochu nevýhoda oproti použití samotného Jbosse, kde reference jsou
dohledany automaticky.
Dalšími konfiguračními soubory jsou:
- components.xml
- exceptions.xml
- pages.xml
- security.drl
V components.xml se definují jednotlivé vlastnosti Seamu jako
jndi-pattern, security, atd.
<!-- DEBUG=true ONLY FOR DEVELOPMENT -->
<core:init jndi-pattern=„java:comp/env/MyEARName/#{ejbName}/local“ debug=„false“/>
<transaction:ejb-transaction/>
<core:manager conversation-timeout=„120000“
concurrent-request-timeout=„10000“
conversation-id-parameter=„cid“/>
<security:identity authenticate-method=„#{authenticator.authenticate}“/>
<!-- security events
-->
<event type=„org.jboss.seam.notLoggedIn“>
<action execute=„#{redirect.captureCurrentView}“/>
</event>
<event type=„org.jboss.seam.postAuthenticate“>
<action execute=„#{redirect.execute}“/>
</event>
<!-- mapping security roles
-->
<drools:rule-base name=„securityRules“>
<drools:rule-files>
<value>/WEB-INF/security.drl</value>
</drools:rule-files>
</drools:rule-base>
Zaregistrování JNDI patternu je potřebné pro referencování EJB Bean.
Dále nastavím, že transakce je řízena přes EJB kontejner, kde si Seam
dokáže odchytit i exeptions při rollbacku. Dále se jedná o nastavení
časové platnosti konverzace. Poslední věcí je authentifikace a
nadefinovaní pravidel pro práci s rolemi a celkovými pravami nad
aplikací.
V exceptions.xml se definuje ruční správa nad výjimkami. Jinymi slovy,
pokud dojde k výjimce, mohu nechat aplikaci automaticky někam přesměrovat,
odeslat příslušnou správu, atd. Samotná konfigurace může vypadat
následovně:
V pages.xml se definuje page-flow. Zde je možnost využít klasický
přistup přes navigation-rule v JSF nebo Seam přístup. Osobně se mi více
zalíbíl tento přístup, jelikož povyšuje definici mnohem dál než
v případě JSF.
V security.drl mám možnost definovat, nastavovat, odebírat, upravovat
práva jednotlivých rolí. Jedná se o jakýsi konfigurační skript nad
správou rolí. Pokud například chci, aby role admin mohla to samé co role
obchodnik, žádný problém takovou věc nastavit.
Pro samotný běh enterprise aplikace je ještě zapotřebí nadefinovat
jboss-seam.jar jako ejb modul. Definice se provádí v application.xml.
Pro práci s hibernate je zapotřebí nahrát všechny požadované knihovny
do $GLASSFISH_HOME/lib a restartovat server.
Každý, kdo to s webovými aplikacemi v Jave myslí vážně, měl by se
na Seam podívat. Už jen z prostého důvodu, že Gavin King se stal hlavním
vývojářem pro novou specifikaci WebBeans, která by měla být v Java EE
6. Jak je patrné, tak WebBeans vycházejí právě z konceptu Seamu.