Ve třetím díle seriálu jsme vytvořili jednoduchou
Java třídu, ke které jsme v díle předchozím vytvořili
zrcadlový obraz – persistentní Caché třídu. Jak
definice Caché třídy vypadá, jsme měli možnost již
vidět, nicméně pro nás v tomto okamžiku není její
znalost podstatná. S Caché totiž nebudeme pracovat
přímo, ale prostřednictvím objektů Javy. A o těchto
objektech si dnes budeme povídat.

Jalapeno poskytuje několik API objektů pro řízení
persistence. Jedním z těchto objektů je aplikační
kontext reprezentovaný třídou ApplicationContext
(com.intersys.pojo.ApplicationContext).

Tato třída implementuje různé možnosti připojení k
databázi a k získání instance nejdůležitější API
třídy – Správce objektů – ObjectManager
(com.intersys.pojo.ObjectManager). Následující krátký
kód ukazuje, jak je možno otevřít spojení s databází
a instancovat ObjectManager.

String url="jdbc:Cache://" + host +
":1972/SYM";

Class.forName
("com.intersys.jdbc.CacheDriver");


Connection connection = DriverManager.getConnection
(url, username, password);


objectManager =
ApplicationContext.createObjectManager (connection);

Mimochodem, z příkladu je zřejmé, že připojení ke
Caché je realizováno JDBC ovladačem. Ovladač Caché je
čistě javovská komponenta, která implementuje jak
relační, tak zároveň i objektový přístup k datům
uloženým v Caché a ke kódu uloženému formou metod v
Caché třídách. Ale o tom opět více v některém
budoucím díle.

Máme-li instancován objekt ObjectManager, můžeme
volat jeho metody pro manipulování s daty na straně
Caché. Například můžeme vložit do databáze nový
záznam pomocí metody insert.

import com.intersystems.objects.*;


...


faktura f = new faktura();


...


Id id = (Id)objectManager.insert(f, true);

Druhý argument metody říká, zda se má provést
„důsledné” uložení, tedy zda se mají uložit současně
i změny objektů na něž odkazuje právě ukládaný
objekt. V našem příkladu faktura ukazuje na objekty
polozka, tedy určitě budeme chtít spolu s fakturou
uložit i její případné položky. Caché zároveň provede
validaci čísla faktury, dle anotace uvedené u třídy
ucto.faktura:

@Index(name="cislofakturyIndex",
isUnique=true, propertyNames={"cislofaktury"})

Následující tabulka podává stručný přehled o
několika užitečných metodách správce objektů.

Specifikace

Návratová hodnota

Popis

openById(class,id)

Object

Otevírá objekt zadané třídy podle Id v
databázi a vrací referenci na něj

openByPrimaryKey(vlase,primaryKey)

Object

Otevírá instanci zadané třídy podle
primárního klíče a vrací referenci na něj

openByQuery(vlase,sql,args[])

java.util.Iterator

Vrací množinu instancí třídy dle zadané
SQL podmínky. Na SQL výraz jsou kladeny
určité podmínky, jejich popis jde nad rámec
tohoto článku

attach(object pojo)

void

Pokud byl objekt připojen ke Caché kopii
pomocí např. některé z metod open…(), nebo
uložen, či rozpojen, pak se provede
připojení. V praxi to znamená, že se vytvoří
proxy třída na straně Caché, která provádí
změny do databáze. Také to znamená, že
hodnoty vlastností třídy jsou z Caché
získávány až na vyžádání.

detach(object pojo)

object

Provede odpojení objektu od Caché, tedy od
proxy třídy v Caché. To znamená, že veškeré
hodnoty vlastností jak samotného objektu, tak
objektů provázaných pomocí referencí se
přenesou ze serveru Caché do klientské
aplikace. Tady ovšem opatrně: může to
znamenat někdy velký objem dat a zátěž
systému a případně i vést v extrémních
případech až k chybě OutOfMemoryError. Klient
však má k dispozici data lokálně a nemusí si
je vyžadovat nadále ze serveru.

Flush

void

Synchronizuje persistentní kontext s Caché
databází

Insert(object pojo,Boolean deep)

Id

Vytvoří novou instanci třídy v Caché a
zároveň ji uloží. Paramet deep specifikuje
způsob uložení – false: pouze samotná třída,
true: třída včetně všech otevřených referencí

Save(object pojo,Boolean deep)

Id

Vytvoří novou instanci v Caché, nebo
aktualizuje existující. Rozhodnutí zda se
vytvoří nová instance nebo aktualizuje
existující se dělá na základě určitých
kritérií, viz. dokumentace ke Caché

purgeFromMemory(object pojo)

void

Zruší asociaci mezi Java verzí objektu a
proxy třídou v Caché a uzavře proxy třídu na
straně Caché. Při použití těsné vazby (o níž
opět někdy později…) se zároveň uzavře i
Java verze objektu

refresh(object pojo)

void

Provede aktualizaci java objektu dle
aktuálního stavu v databázi Caché

removeFormDatabase(object pojo,Id id)

void

Nalezne odpovídající objet v databázi
Caché a vymaže jej.

close()

void

Uzavře správce objektů a zneplatní jej

Třída ObjectManager obsahuje též metody pro práci
s transakcemi, které zde nebudeme rozebírat, neboť na
nich není nic objevného a metody pro instancování
dalších objektů Jalapeno API a to jmenovitě Utilities
a ExtentManager.

ExtentManager


Tato Třída poskytuje rozhraní pro práci s oblastmi
databází na úrovni celých persistentních tříd, tedy
nikoliv na úrovni instancí objektů. Její metody lze
použít například pro zrušení definice třídy, smazání
všech instancí třídy najednou, přepočítání indexů
(toto normálně v Caché není třeba, jen pokud
programátor změní definici třídy, je nutno uvést
hodnoty indexů s jejich definicemi) apod. V
neposlední řadě lze použít metodu pro vygenerování
pseudonáhodných instancí tříd; to se hodí zvláště
potřebujeme-li otestovat aplikaci na velkém objemu
dat, která ovšem ne vždy pro testování máme k
dispozici z reálného provozu.

ObjectManagerFactory


Tato třída poskytuje rozhraní pro správu připojení ke
Caché databázi, např. definuje výchozí hodnoty
připojení – url, jméno a heslo a jiná nastavení.

Settings


Tato pomocná třída poskytuje rozhraní pro správu
chování třídy ObjectManager. Asi nejdůležitějšími
metodami jsou getFetchPolicy a setFetchPolicy. Správné nastavení politiky
synchronizace Java klienta se stranou Caché má totiž
zásadní vliv na výkon celé aplikace.


Caché podporuje dva typy politik pro synchronizaci a
to FETCH_POLICY_EAGER a FETCH_POLICY_LAZY. Pokud zvolíte politiku
EAGER, pak v okamžiku instancování POJO objektu se
automaticky z databáze načtou hodnoty všech
vlastností objektu včetně objektů na něž daný objekt
odkazuje a to do všech pokolení odkazů. Toto může
vést k přenosům velkého objemu dat a v krajním
případě k havárii aplikace z důvodu nedostatku
paměti. V druhém případě, při použití LAZY politiky,
se sice vytvoří instance Java objektu ale hodnoty
vlastností se načítají až na vyžádání, při prvním
odkazu na ně.

Utilities


Tato třída implementuje několik metod pro práci s XML
dokumenty. Zejména jde o metody pro serializaci do
XML a deserializaci z XML do instance POJO objektu.

Nyní si konečně můžeme poskládat celý příklad –
zde je jeho kód:

package ucto;





import java.util.*;


import java.io.*;





public class Main {

public Main()
{


}





public static void main(String[] args) {

String
cisloFaktury;


Random rnd = new Random();





try {


BufferedReader in = new BufferedReader(new
InputStreamReader(System.in));


System.out.println("Číslo faktury:");


cisloFaktury = in.readLine();





faktura f = new faktura();


f.polozky = new ArrayList();


f.cislo_faktury = cisloFaktury;


f.prijemce="Jiri Novy";


f.datum_vystaveni= new Date();





polozka p = new polozka();


p.castka = Float.valueOf(rnd.nextInt(1200));


p.popis = "položka číslo 1";


f.polozky.add(p);





polozka pp = new polozka();


pp.castka = Float.valueOf(rnd.nextInt(1800));


pp.popis = "položka číslo 2";


f.polozky.add(pp);





f.castka = p.castka + pp.castka;





System.out.println("Číslo faktury: " +
f.cislo_faktury);


System.out.println("Částka celkem: " + f.castka);






DBservice db = new DBservice();


db.ulozFakturu(f,true);


// znicime odkaz na fakturu;


f = null;





System.out.println("Uloženo!");





// upravime fakturu po jejim nacteni z databaze -
zmenime prijemce


Iterator faktury =
db.FakturaDleCisla(cisloFaktury);


// vime ze bude jen jedna, pokud vubec


...


if (faktury.hasNext()) {

faktura
fa = (faktura)faktury.next();


System.out.println("původní příjemce: " +
fa.castka);


fa.prijemce = "Moje Firma, s.r.o.";


System.out.println("částka: " + fa.castka);


db.ulozFakturu(fa,false);

}


System.out.println("Stiskni libovolnou klávesu
pro dokončení...");


String input = in.readLine();;


} catch (Exception ex) {


ex.printStackTrace();

}

}

}

 

Servisní třída:

package ucto;





import com.intersys.pojo.*;


import java.sql.Connection;


import java.sql.DriverManager;


import java.util.*;


import com.intersys.objects.*;





public class DBservice {

ObjectManager
objectManager = null;





/** Creates a new instance of DBservice */


public DBservice() throws Exception {


String host
= "localhost";


String username="SYSTEM";


String password="_SYS";


String url="jdbc:Cache://" + host +
":1972/SAMPLES";





Class.forName("com.intersys.jdbc.CacheDriver");


Connection connection = DriverManager.getConnection
(url, username, password);


objectManager =
ApplicationContext.createObjectManager(connection);


}





protected void ulozFakturu(faktura f, Boolean nova)
throws Exception {

Id id =
(nova ? (Id)objectManager.insert(f, true):
(Id)objectManager.save(f, true));


System.out.println("object id: " + id.toString());

}





Iterator FakturaDleCisla(String cisloFaktury) throws
Exception {

String[]
args = {cisloFaktury};


return objectManager.openByQuery(faktura.class,
"cislofaktury = ?", args);

}

}

Zkušený programátor mi snad promine styl, zde mi
jde jen o ukázku a uvedení některých metod API.

Příště nás čeká nová sekce, začneme popisovat
spolupráci Caché a Javy z druhé strany, z prostředí
Caché.