EJB 2.x – Entity Beans (BMP – vytvorenie entitnej triedy)
Už viete, že ak sa rozhodnete vo vašich entitných triedach využívať princíp BMP, budete si musieť zabezpečiť obsah volania jednotlivých callback metód vo vlastnej réžii. Vieme tiež, že ak klient zavolá metódu create nachádzajúcu sa v home rozhraní entitnej triedy, kontajner zavolá korešpondujúcu metódu ejbCreate, volanú nad inštanciou požadovanej entitnej triedy.
Inštancia nad ktorou je volaná spomínaná metóda ejbCreate
je inštancia, ktorú kontajner vybral z poolu a asocioval ju s novo vytvoreným entitným objektom. Táto vaša metóda je zodpovedná za inicializáciu atribútov entitnej triedy, za ich vloženie do databázy a za vrátenie hodnoty primárneho kľúča. V článku EJB 2.x – Entity Beans (callback metódy a životný cyklus) som uviedol, že signatúra metódy ejbCreate
musí mať presne ten istý zoznam parametrov, ako odpovedajúca metóda create
home rozhrania entitnej triedy a jej návratový typ musí byť trieda primárneho kľúča.
Vo svete objektového návrhu aplikácií existuje jeden návrhový vzor, ktorý sa nazýva Adapter Pattern. Tento vzor je v našom prípade vhodné využiť na vytvorenie implementácie rozhrania EntityBean
, ktoré bude zabezpečovať iba priradenie objektu EntityContext
a zvyšok bude prázdna implementácia callback metód. Nazvime si túto implementáciu AbstractEntity
. Tu je jej zdrojový kód:
AbstractEntity.java:
/**
* Title: AbstractEntity
* Description: Abstraktná entitná trieda implementujúca
* metódy setEntityContext a unsetEntityContext a
* poskytujúca prázdnu implementáciu ostatných metód
* deklarovaných v EntityBean.
*/
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.RemoveException;
public abstract class AbstractEntity implements EntityBean {
protected EntityContext ctx;
public void ejbActivate() {}
public void ejbLoad() {}
public void ejbPassivate() {}
public void ejbRemove() throws RemoveException {}
public void ejbStore() {}
public void setEntityContext(EntityContext newCtx) {
ctx = newCtx;
}
public void unsetEntityContext() {
ctx = null;
}
}
V nasledujúcom výpise si ukážeme príklad metódy ejbCreateWithData()
, ktorá je náprotivkom metódy createWithData()
definovanej v home rozhraní EnglishAuctionHome
. Ako si môžete všimnúť nižšie, naša entitná trieda EnglishAuctionBean
rozširuje vyššie uvedenú abstraktnú triedu AbstractEntity
. Keďže táto trieda predstavuje adaptér pre rozhranie EntityBean
, už by nemalo byť nutné deklarovať, že entitná trieda implementuje rozhranie EntityBean
. Napriek tomu niektoré vývojové nástroje nie sú schopné túto skutočnosť rozpoznať, preto je nutné explicitne deklarovať implementáciu spomínaného rozhrania.
Podotýkam, že nasledujúca ukážka je iba fragment entitnej triedy EnglishAuctionBean
, preto sa vám ju nepodarí skompilovať.
…
public class EnglishAuctionBean extends AbstractEntity
implements EntityBean {
…
public Integer ejbCreateWithData(String name,
String description) throws CreateException {
// ak nebude dodané meno, vyhodíme výnimku
if ((name == null) || (name.trim().length() == 0)) {
throw new CreateException(„Aukcia musí mať názov!“);
}
Connection con = null;
PreparedStatement stmt = null;
try {
// priradíme primárny kľúč a inicializačné parametre
setId(computeNextPK(„auctionseq“));
setName(name);
setDescription(description);
// stav aukcie nastavíme na nevybavený
status = IAuctionStatus.AUCTION_PENDING;
con = DSConnectionHelper.getConnection(„auctionSource“);
/**
* Vytvoríme prepared statement a vložíme novú entitu
* do databázy (ostatné atribúty zatiaľ ponecháme na null)
**/
stmt = con.prepareStatement(
„INSERT INTO auction (id, Name, Description, Status)
VALUES (?,?,?,?)“);
stmt.setInt(1, id.intValue());
stmt.setString(2, name);
stmt.setString(3, description);
stmt.setString(4, status);
int rowsInserted = stmt.executeUpdate();
if (rowsInserted != 1) {
throw new EJBException(
„Nemôžem vložiť aukciu do databázy!“);
}
return getId();
}
catch (SQLException e) {
throw new EJBException;
}
finally {
DSConnectionHelper.cleanup(stmt, con);
}
}
}
Metóda ejbCreateWithData
začína vykonaním nutnej kontroly a následným priradením inicializačných parametrov k inštancii beanu. Metóda getConnection
triedy DSConnectionHelper
, ktorú sme si vytvorili v minulej časti, vráti objekt pripojenia, ktorý využijeme na vytvorenie príkazu INSERT
. Potom, čo je tento príkaz vykonaný, metóda vráti primárny kľúč priradený k entitnému objektu. Metóda cleanup
pomocnej triedy DSConnectionHelper
volaná vo finally
bloku, zapuzdruje obsluhu výnimiek používanú všetkými callback metódami pri uzatváraní objektu Statement
a databázového pripojenia.
Obsah tejto metódy si ukážeme nižšie. Samozrejme keďže aplikačný server manažuje tvorbu a uzatváranie databázových pripojení, v skutočnosti metóda cleanup()
spojenie neukončí. Zavolanie tejto metódy iba spôsobí, že kontajner bude vedieť, že dané spojenie bolo uvoľnené a môže byť vrátené do connection poolu.
public class DSConnectionHelper {
…
public static void cleanup(Statement stmt, Connection con) {
try {
if (stmt != null) {
stmt.close();
}
if (con != null) {
con.close();
}
}
catch (SQLException e) {
throw new EJBException;
}
}
…
}
Všimnite si, že metóda ejbCreateWithData
volá aj metódu computeNextPK
, s cieľom priradenia hodnoty primárneho kľúča. Každá tabuľka použitá v našom aukčnom systéme využíva primárny kľúč typu integer. Väčšina databázových systémov poskytuje možnosť automatického generovania sekvenčných čísiel, použitých ako unikátne primárne kľúče pri vkladaní nového riadku. Toto je celkom užitočná vec, pretože vás odbremeňuje od potreby vlastného generovania primárneho kľúča. Na druhej strane však môžu vzniknúť problémy pri prenose aplikácie na iný DB systém. Nie všetky totiž majú spomínanú funkcionalitu a tie, ktoré ju majú, môžu mať odlišný systém predávania takto generovaného čísla aplikácii.
Veľmi jednoduchým alternatívnym riešením je implementácia vašej vlastnej sekvenčnej tabuľky asociovanej s konkrétnou DB tabuľkou, ktorá vyžaduje použitie primárneho kľúča. Takáto tabuľka udržuje iba jednu samostatnú hodnotu, reprezentujúcu posledný primárny kľúč priradený tabuľke, s ktorou je asociovaná. Toto riešenie sme zvolili aj v našom prípade. Nasledujúci výpis ukazuje, ako môžete jednoducho udržiavať sekvenčnú tabuľku.
protected Integer computeNextPK(String tableName)
throws SQLException {
con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
con = DSConnectionHelper.getConnection(„auctionSource“);
// update sekvenčnej hodnoty v tabuľke
stmt = con.prepareStatement(“
UPDATE “ + tableName + “ set next_id = next_id + 1″);
if (stmt.executeUpdate() != 1) {
throw new SQLException(„Chyba generovania PK!“);
}
stmt.close();
// získame sekvenčnú hodnotu a použijeme ju ako primárny kľúč
stmt = con.prepareStatement(“
SELECT next_id from “ + tableName);
rs = stmt.executeQuery();
boolean found = rs.next();
if (found) {
return new Integer(rs.getInt(„next_id“));
}
else {
throw new SQLException(„Chyba generovania PK!“);
}
}
finally {
// zatvoríme spojenie
DSConnectionHelper.cleanup(stmt, con);
}
}
Okrem doteraz použitých zdrojových kódov, referencuje metóda ejbCreateWithData
aj rozhranie IAuctionStatus
. Toto rozhranie jednoducho definuje reťazce, použité v databáze na odlíšenie stavu, v ktorom sa aukcia práve nachádza.
/**
* Title: IAuctionStatus
* Description: Konštanty definujúce možné stavy aukcií
*/
public interface IAuctionStatus {
public static final String AUCTION_PENDING = „Pending“;
public static final String AUCTION_OPEN = „Open“;
public static final String AUCTION_CANCELLED = „Cancelled“;
public static final String AUCTION_CLOSED = „Closed“;
}
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Jak si vyzkoušet Apple Intelligence v EU
2. srpna 2024 -
Vstupte do éry umělé inteligence: ASOME Max Studio s AMD Ryzen™ 9 7940HS
14. listopadu 2023 -
ZONER Webmail jako první v Česku přináší BIMI s VMC
11. července 2024
Nejnovější
-
Doména .io v ohrožení: Co přinese předání Čagoských ostrovů?
10. října 2024 -
Jak se chránit před podvody na internetu – část 1
8. října 2024