Rád bych vám představili nový občasník s volným pokračováním, který bude představovat nejrůznější JBoss technologie v praxi. Každý díl tohoto občasníku si vymezí určitý cíl, který pokryje několik Java a JBoss technologií, a ukáže jak tohoto cíle dosáhnout.
Začneme tím, že napíšeme (přesněji vygenerujeme) JEE aplikaci, která poskytne webové rozhraní pro úpravu databázových entit - uživatelů. Dál bude umožňovat shodný přístup (tedy CRUD - Create, Read, Update, Delete) přes REST rozhraní. Aplikace bude běžet na aplikačním serveru JBoss AS 7 a pro veřejný přístup bude nasazena na cloudu OpenShift. Pokud by to nebylo z předchozí věty zřejmé - ano, bude to Java aplikace, která bude běžet na veřejně přístupné IP adrese a nebude nás to stát ani korunu.
Začneme tím, že si založíme účet na portálu OpenShift. OpenShift je bezplatné řešení tzv. PaaS (Platform as a Service). To je technologie obvykle postavená na cloudu, která nám poskytuje kompletní řešení pro určitou platformu ve formě služby. Čili jdeme ještě o krok dále za Amazon EC2 a daná služba není jen virtuální stroj s nainstalovaným operačním systémem, ale plně nakonfigurované a odladěné prostředí pro poskytnutí nějaké služby. V případě OpenShift je takovou službou aplikační server, na který vystavíme svoji aplikaci.
Pro registraci na OpenShift musíme zadat pouze email a heslo. Následně potvrdit ověřovací email, který obdržíme. Po přihlášení si na záložce My Applications vytvoříme novou aplikace tlačítkem ADD APPLICATION. Jako typ aplikace zvolíme JBoss Application Server 7.1. Na další stránce vyplníme jméno aplikace, které se zároveň stane součástí URL. V našem příkladu si vytvoříme registr zaměstnanců, proto aplikaci nazveme staff. Pro vaši aplikaci můžete použít stejný název, protože součástí URL je i takzvaná doména. Výchozí doména je jméno vašeho účtu. Doména neslouží na nic jiného, než na vytvoření jmenného prostoru pro skupinu aplikací.
Vytvoření aplikace může chvilku trvat, protože se při něm alokuje virtuální stroj právě v Amazon cloudu. Na výsledné stránce máme instrukce pro přístup k nově vytvořené aplikaci. OpenShift nám poskytuje Git repozitář, do kterého naši aplikaci nahrajeme. Abychom mohli k repozitáři přistupovat, musíme ještě správně nastavit SSH klíče. Na záložce My Account vidíte v pravém sloupci registrované veřejné klíče. Místo výchozího klíče můžete přidat váš existující veřejný klíč. Jedná se o obsah souboru ~/.ssh/{jméno klíče}.pub. Další možností je vytvoření nového klíče určeného výhradně pro použití s OpenShift. Klíč vygenerujete následujícím příkazem:
# ssh-keygen -t rsa -b 2048 -f libra_id_rsa
Dojde k vytvoření souborů ~/.ssh/libra_id_rsa a ~/.ssh/libra_id_rsa.pub. Obsah souboru s koncovkou .pub vložte do rozhraní OpenShift. Aby byl klíč funkční, musíte jej ještě instalovat do bežící instance SSH agenta na vašem počítači pomocí příkazu:
# ssh-add ~/.ssh/libra_id_rsa
Pokud by se stalo, že se nemůžete k serveru přihlásit pomocí SSH ani stáhnout/nahrát projekt z/do Git repozitáře, zkuste znovu přidat klíč do SSH agenta.
Následně si můžeme stáhnout připravené zdrojové kódy aplikace pomocí příkazu, který jsme viděli na závěrečné stránce při vytváření aplikace (jméno repozitáře si můžete znovu zobrazit kliknutím na záložku My Applications a pak na jméno aplikace). Například:
# git clone ssh://3c1146543138763a31e654c631e654f64d@staff-mvecera.rhcloud.com/~/git/staff.git/
Na server se můžete i přihlásit pomocí:
# ssh 3c1146543138763a31e654c631e654f64d@staff-mvecera.rhcloud.com
Pokud nyní nahrajete zdrojový kód aplikace zpět na server příkazem # git push origin master, dojde k automatickému zkompilování aplikace a jejímu nasazení.
Další variantou jak pracovat s OpenShift je pomocí nástrojů na příkazové řádce. Tyto nástroje můžete nainstalovat podle instrukcí v úvodním manuálu na OpenShift. Je zde popsán způsob i pro ostatní operační systémy kromě Fedory. My tyto příkazy nevyužijeme, ukážeme si však jeden, který vám může pomoci zjistit příčinu chyby v nastavení OpenShift, kdyby něco nefungovalo.
# rhc-domain status -l {váš login}
Poslední věc, kterou musíme udělat ve webovém rozhraní OpenShift je přidání PostgreSQL databáze. Na záložce My Applications klikněte na jméno aplikace, následně na Add Cartridge a vyberte PostgreSQL Database 8.4. Přidání musíme ještě potvrdit na další stránce. Tato operace může opět chvíli trvat. Poté se zobrazí přístupové údaje k databázi. Vše je už nakonfigurované, takže je nebudete potřebovat nikam ručně zadávat. Ve webovém rozhraní je však už není možné znovu zobrazit.
Nyní se budeme věnovat vývoji samotné aplikace. Přesněji řečeno, vyvíjet zase tak moc nebudeme, protože můžeme aplikaci nechat téměř celou vygenerovat. Na to budeme potřebovat nástroj JBoss Forge, který jednoduše stáhneme, rozbalíme do libovolného adresáře (např. /opt) a nastavíme systémovou proměnnou FORGE_HOME, aby odkazovala na tento adresář. Pro snadnější spouštění můžeme přidat také cestu do adresáře $FORGE_HOME/bin do systémové proměnné PATH. Aktuální verze nástroje Forge v době psaní toho článku je 1.0.5.Final. Pokud budete používat novější verzi, můžete narazit na drobné odlišnosti.
Výchozí podobu aplikace, kterou jsme si stáhli z Git repozitáře na virtuálním stroji, budeme muset trochu upravit, aby nástroj Forge správně fungoval. V souboru src/main/webapp/WEB-INF/web.xml odstraníme definice servletu a mapování. Zůstane nám jen prázdný soubor s kořenovým elementem web-app. Poté smažeme všechny soubory, které nebudeme v naší aplikaci potřebovat. Jsou to všechny soubory v adresáři src/main/webapp a jeho podadresáře kromě WEB-INF.
Nyní se přesuneme do kořenového adresáře projektu a upravíme pom.xml. V něm za uzavírací tag </dependencies> vložíme:
<build>
<finalName>${project.name}</finalName>
</build>
Dále upravíme závislost na JavaEE specifikaci následujícím způsobem (změny jsou vyznačeny tučně):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>2.0.0.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>2.0.0.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.faces</groupId>
<artifactId>jboss-jsf-api_2.0_spec</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Tyto úpravy a úprava souboru web.xml jsou potřebné, aby nástroj Forge správně fungoval a abychom mohli aplikaci zkompilovat. V souboru pom.xml si ještě můžeme všimnout definice profilu se jménem openshift. Ten musíme v projektu ponechat, protože se používá při automatickém nasazení aplikace po jejím uložení na server příkazem # git push origin master.
Před dalšími úpravami si ještě ověříme nastavení nástroje Maven, který bude kompilovat a sestavovat projekt. Do souboru s nastavením (typicky ~/.m2/settings.xml) musíme doplnit odkaz na JBoss repozitář. Jeho definici najdete na komunitní wiki stránce v části Configuring Maven to use the JBoss Repository. Můžete si vytvořit celý nový profil:
<settings>
<profiles>
<profile>
<id>jboss-public-repo</id>
… zde vložte konfiguraci z wiki
</profile>
</profiles>
<activeProfiles>
<activeProfile>jboss-public-repo</activeProfile>
</activeProfiles>
</settings>
Teď už nám nic nebrání abychom spustili nástroj Forge. Jeho spuštění chvíli trvá, protože analyzuje projekt.
14:42:23 [mvecera@oa:os/staff]$ forge
_____
| ___|__ _ __ __ _ ___
| |_ / _ \| `__/ _` |/ _ \ \\
| _| (_) | | | (_| | __/ //
|_| \___/|_| \__, |\___|
|___/
[staff] staff $
A budeme v podstatě následovat kurz s návodem na vygenerování základní Java EE aplikace.
Jako první věc provedeme instalaci komponent uživatelského rozhraní (Java Server Faces) následujícím příkazem. Všechny volby ponecháme na výchozích hodnotách.
[staff] staff $ scaffold setup
? No scaffold type was selected, use default [JavaServer Faces]? [Y/n]
? Scaffold provider [faces] is not installed. Install it? [Y/n]
***SUCCESS*** Installed [forge.spec.jpa] successfully.
***SUCCESS*** Installed [forge.spec.cdi] successfully.
***SUCCESS*** Installed [faces] successfully.
? Create scaffold in which sub-directory of web-root? (e.g. http://localhost:8080/${project.name}/DIR) [/]
Wrote /home/mvecera/work/os/staff/src/main/resources/META-INF/persistence.xml
Wrote /home/mvecera/work/os/staff/src/main/webapp/WEB-INF/beans.xml
Wrote /home/mvecera/work/os/staff/src/main/webapp/favicon.ico
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/scaffold/paginator.xhtml
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/scaffold/pageTemplate.xhtml
Wrote /home/mvecera/work/os/staff/src/main/webapp/index.html
Wrote /home/mvecera/work/os/staff/src/main/webapp/index.xhtml
Wrote /home/mvecera/work/os/staff/src/main/webapp/error.xhtml
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/add.png
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/background.gif
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/false.png
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/favicon.ico
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/forge-logo.png
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/forge-style.css
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/jboss-community.png
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/remove.png
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/search.png
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/true.png
Wrote /home/mvecera/work/os/staff/src/main/webapp/WEB-INF/web.xml
[staff] staff $
Dalším krokem bude konfigurace perzistence příkazem # persistence setup. Jako poskytovatele implementace použijeme Hibernate a budeme instalovat na aplikační server JBoss verze 7.
[staff] staff $ persistence setup
? [provider=ARG (of type org.jboss.forge.spec.javaee.jpa.api.JPAProvider)]:
HIBERNATE OPENJPA ECLIPSELINK INFINISPAN
? [provider=ARG (of type org.jboss.forge.spec.javaee.jpa.api.JPAProvider)]: HIBERNATE
? [container=ARG (of type org.jboss.forge.spec.javaee.jpa.api.JPAContainer)]:
JBOSS_AS6 JBOSS_AS7 GLASSFISH_3 CUSTOM_JDBC CUSTOM_JTA CUSTOM_NON_JTA
? [container=ARG (of type org.jboss.forge.spec.javaee.jpa.api.JPAContainer)]: JBOSS_AS7
***INFO*** Setting transaction-type="JTA"
***INFO*** Using example data source [java:jboss/datasources/ExampleDS]
? The JPA provider [HIBERNATE], also supplies extended APIs. Install these as well? [y/N]
***SUCCESS*** Persistence (JPA) is installed.
Wrote /home/mvecera/work/os/staff/src/main/resources/META-INF/persistence.xml
[staff] staff $
Soubor src/main/resources/META-INF/persistence.xml musíme ještě upravit, aby použil PostgreSQL databázi, kterou jsme si nainstalovali na virtuálním stroji. Musíme změnit jméno datového zdroje a přidat definici databázového dialektu (změny jsou opět vyznačeny tučně).
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="forge-default" transaction-type="JTA">
<description>Forge Persistence Unit</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/PostgreSQLDS</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.transaction.flush_before_completion" value="true"/>
</properties>
</persistence-unit>
</persistence>
Pokud nechcete, aby se databáze při aktualizaci aplikace na virtuálním stroji smazala, můžete změnit hodnotu proměnné hibernate.hbm2dd.auto na update.
V dalším kroku si vytvoříme entitu zaměstnance se jménem Employee a dvěmi jednoduchými vlastnostmi - jméno a hash kód hesla.
[staff] staff $ entity --named Employee
? In which package you'd like to create this @Entity, or enter for default [staff.model]
Created @Entity [staff.model.Employee]
Picked up type <JavaResource>: staff.model.Employee
Wrote /home/mvecera/work/os/staff/src/main/java/staff/model/Employee.java
[staff] Employee.java $ field string --named userName
Added field to staff.model.Employee: @Column private String userName;
Wrote /home/mvecera/work/os/staff/src/main/java/staff/model/Employee.java
[staff] Employee.java $ field string --named passwordHash
Added field to staff.model.Employee: @Column private String passwordHash;
Wrote /home/mvecera/work/os/staff/src/main/java/staff/model/Employee.java
[staff] Employee.java $
Pro novou entitu si necháme vygenerovat stránky pro základní CRUD operace.
[staff] Employee.java $ scaffold from-entity
***INFO*** Using currently installed scaffold [faces]
? [/home/mvecera/work/os/staff/src/main/webapp/resources/scaffold/pageTemplate.xhtml] File exists, overwrite? [Y/n]
***SUCCESS*** Generated UI for [staff.model.Employee]
Wrote /home/mvecera/work/os/staff/src/main/java/staff/view/EmployeeBean.java
Wrote /home/mvecera/work/os/staff/src/main/webapp/employee/create.xhtml
Wrote /home/mvecera/work/os/staff/src/main/webapp/employee/view.xhtml
Wrote /home/mvecera/work/os/staff/src/main/webapp/employee/search.xhtml
Wrote /home/mvecera/work/os/staff/src/main/webapp/resources/scaffold/pageTemplate.xhtml
Wrote /home/mvecera/work/os/staff/src/main/java/staff/view/ViewUtils.java
Wrote /home/mvecera/work/os/staff/src/main/webapp/WEB-INF/classes/META-INF/forge.taglib.xml
Wrote /home/mvecera/work/os/staff/src/main/java/staff/model/Employee.java
[staff] Employee.java $
Nyní si doinstalujeme podporu pro REST a vygenerujeme rozhraní pro entitu zaměstnance.
[staff] Employee.java $ rest setup
? What root path do you want to use for your resources? [/rest]
***SUCCESS*** Installed [forge.spec.jaxrs.webxml] successfully.
***SUCCESS*** Rest Web Services (JAX-RS) is installed.
Wrote /home/mvecera/work/os/staff/src/main/webapp/WEB-INF/web.xml
[staff] Employee.java $ rest endpoint-from-entity
***SUCCESS*** Generated REST endpoint for [staff.model.Employee]
Wrote /home/mvecera/work/os/staff/src/main/java/staff/model/Employee.java
Wrote /home/mvecera/work/os/staff/src/main/java/staff/rest/EmployeeEndpoint.java
[staff] Employee.java $
Tím máme vygenerovaný základ aplikace a můžeme nástroj Forge ukončit příkazem exit nebo dvojím stisknutím Ctrl+D (na Linuxu).
Protože nechceme, aby kdokoliv mohl upravovat záznamy v naší databázi, zabezpečíme přístup k webovému rozhraní a k REST operacím pro zápis pomocí HTTP Basic autentizace.
Pro náš jednoduchý příklad nebudeme vytvářet vlastní bezpečnostní doménu, která by musela být součástí archívu (OpenShift totiž neumožňuje zápis do hlavního konfiguračního souboru serveru). Místo toho využijeme již existující doménu messaging. Vytvoříme soubor src/main/webapp/WEB-INF/jboss-web.xml a vložíme do něj odkaz na security-domain.
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 5.0//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd">
<jboss-web>
<security-domain>java:/jaas/messaging</security-domain>
</jboss-web>
Na konec souboru src/main/webapp/WEB-INF/web.xml doplníme příslušnou konfiguraci pro použití této bezpečnostní domény.
<security-constraint>
<web-resource-collection>
<web-resource-name>SecuredWeb</web-resource-name>
<url-pattern>/faces/*</url-pattern>
</web-resource-collection>
<web-resource-collection>
<web-resource-name>SecuredREST</web-resource-name>
<url-pattern>/rest/*</url-pattern>
<http-method>POST</http-method>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>AdminRole</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Declare yourself</realm-name>
</login-config>
Poslední drobnost, která nám schází, je vytvoření konfiguračního souboru pro Java Server Faces. V podstatě je to prázdný soubor, který serveru jen oznámí přítomnost JSF v archívu. Do souboru src/main/webapp/WEB-INF/faces-config.xml vložíme následující obsah.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
</faces-config>
Nyní si můžeme aplikaci zkusit zkompilovat a zabalit do .war souboru.
# mvn package
Pokud vše proběhlo v pořádku, nahrajeme aplikaci do Git repozitáře na našem virtuálním stroji. Označíme nové a změněné soubory pro vložení do repozitáře, odstraníme smazané soubory z repozitáře, změny potvrdíme a nahrajeme na server.
# git add .
# git rm src/main/webapp/health.jsp src/main/webapp/images/jbosscorp_logo.png src/main/webapp/snoop.jsp
# git commit -a -m “First version of the application”
# git push origin master
Během nahrávání na server můžeme vidět průběh kompilace a nasazení aplikace na serveru. Aplikace nyní běží, ale neznáme k ní heslo. Příhlásíme se proto na server a trochu se porozhlédneme.
[staff-qe.rhcloud.com ~]\> ls
git postgresql-8.4 staff
[staff-qe.rhcloud.com ~]\> cd staff/
[staff-qe.rhcloud.com staff]\> ls
ci data jbossas-7 logs repo run runtime staff_ctl.sh tmp
V home adresáři máme podadresář s repozitářem, instalovanými rozšířeními (PosgreSQL) a podadresář se jménem aplikace, ve kterém jsou důležité dvě věci - aplikační server a podadresář s logy o běhu aplikace. Upravíme soubory s přístupovými údaji pomocí editoru vim.
[staff-qe.rhcloud.com staff]\> cd jbossas-7/standalone/configuration/
[staff-qe.rhcloud.com configuration]\> ls
application-roles.properties application-users.properties logging.properties mgmt-users.properties modules standalone.xml standalone_xml_history
[staff-qe.rhcloud.com configuration]\> vim application-roles.properties
[staff-qe.rhcloud.com configuration]\> vim application-users.properties
Do souboru application-roles.properties doplníme definici
admin=AdminRole
Tím zařadíme uživatele admin do role AdminRole, kterou vyžaduje naše aplikace.
Do souboru application-users.properties doplníme řádek
admin=topsecretpassword
Vytvořili jsme tak uživatele admin se zvoleným heslem.
Teď se již můžeme přihlásit na adrese staff-{naše doména}.rhcloud.com.
OpenShift má samozřejmě také podporu v JBoss Developer Studiu (JBDS). Nedávno vyšla pátá verze, kterou si můžete zdarma stáhnout. Oproti předchozím verzím obsahuje tzv. JBoss Central, což je takový rozcestník pro snadné vytvoření nejrůznějších typů aplikací. Vzhledem k tomu, že jsme v našem příkladě neupravovali žádný Java kód, ponecháme ukázku používání OpenShift v JBDS někdy na příště.