Informatika | Tanulmányok, esszék » Informatikai navigátor, Gondolatok a szoftverek használatáról és fejlesztéséről VII.

Alapadatok

Év, oldalszám:2012, 75 oldal

Nyelv:magyar

Letöltések száma:71

Feltöltve:2013. április 10.

Méret:1 MB

Intézmény:
-

Megjegyzés:

Csatolmány:-

Letöltés PDF-ben:Kérlek jelentkezz be!



Értékelések

Nincs még értékelés. Legyél Te az első!

Tartalmi kivonat

2012. December Informatikai Navigátor Érdekességek programozóknak Gondolatok a szoftverek használatáról és fejlesztéséről 7. szám Informatikai Navigator Gondolatok a szoftverek használatáról és fejlesztéséről Tartalomjegyzék 1. A programozói könyvtárak használata Linux környezetben 3 2. CMAKE – Az alkalmazások összeépítése 9 3. Object Pascal – C/C++ könyvtárak használata 16 4. C# – C/C++ könyvtárak használata 28 5. Java – C/C++ rutinok és könyvtárak használata 36 6. Python – C/C++ rutinok és könyvtárak használata 49 7. HyperSQL DataBase (HSQLDB) 53 8. Tippek és Trükkök 68 9. A Visitor tervezési minta 71 10.Az Adapter tervezési minta 74 Főszerkesztő: Nyiri Imre (imre.nyiri@gmailcom) 2 Programozási eszközök 1. A programozói könyvtárak használata Linux környezetben A programozói könyvtárak használata Linux környezetben Ebben a kiadványban a programozók által használt

eszközök áttekintése kiemelt figyelmet kap, így ebben a cikkben a legalapvetőbb eszköz, a kód ismételt felhasználását támogató programozói könyvtárak használata kerül áttekintésre. Az itt megszerzett ismeretek szükségesek lesznek a további cikkek alaposabb megértéséhez is. A programozói könyvtár fogalma #include <s t d i o . h> A programok forráskódja szinte mindig több fájlból áll, amiket külön-külön le kell fordítani, majd az így kapott bináris fájlokat (ezek az object fájl, aminek a kiterjesztése Linuxon .o) össze kell kapcsolni (linkelni) futtatható programmá. A több forrásfájl használata 2 szempontból is szükséges: void gv1 ( char ∗ s ) { p r i n t f ( " n C a l l e d ␣ gv1 : ␣%s " , s ) ; } 1. A program kezelhető méretű darabokra való szétszedése void gv2 ( char ∗ s ) { p r i n t f ( " n C a l l e d ␣ gv2 : ␣%s " , s ) ; } A 3. Programlista egy főprogram, ahol az 5

függvény közül 3-at használunk is. 2. A már máshol használt függvények könnyű // 3 P r o g r a m l i s t a ( main c ) újrahasznosíthatósága #include <s t d i o . h> Nézzünk erre mindjárt itt az elején egy példát! #include < s t d l i b . h> Az 1. és 2 Programlisták C függvényeket tartalmaznak, a 2 forrásfájlban összesen 5 darabot #include " r u t i n o k h" // 1 . P r o g r a m l i s t a ( r u t i n o k −1 c ) #include <s t d i o . h> void f v 1 ( char ∗ s ) { p r i n t f ( " n C a l l e d ␣ f v 1 : ␣%s " , s ) ; } void f v 2 ( char ∗ s ) { p r i n t f ( " n C a l l e d ␣ f v 2 : ␣%s " , s ) ; } void f v 3 ( char ∗ s ) { p r i n t f ( " n C a l l e d ␣ f v 3 : ␣%s " , s ) ; } // 2 . P r o g r a m l i s t a ( r u t i n o k −2 c ) int main ( int argc , char ∗∗ argv ) { f v 1 ( " aaaaaa " ) ; f v 2 ( " aaaaaa " ) ; gv2 ( " aaaaaa " ) ; return

(EXIT SUCCESS) ; } A következő feladat a futtatható program előállítása, amihez itt most a gcc-t használjuk. Adjuk ki ezt a parancsot: g c c main . c r u t i n o k −1 c r u t i n o k −2 c −o t e s t Ekkor létrejön egy test nevű futtatható program, amit a ./test paranccsal futtatva ezt kapjuk: C a l l e d f v 1 : aaaaaa C a l l e d f v 2 : aaaaaa C a l l e d gv2 : aaaaaa 3 Programozási eszközök A programozói könyvtárak használata Linux környezetben Itt mindent a kiinduló forrásfájlokból állítottunk elő, azonban ez több szempontból sem a legjobb megoldás, ugyanis, ha ezek közül valamelyik nem változott, akkor fölösleges ismételten újrafordítani. A következő parancsok emiatt a rutinok-1.c és rutinok-2c fájlokat egyenként fordítják le (a -c kapcsoló csak fordítást kér), aminek az eredménye a rutinok-1.o és rutinok2o object fájlok keletkeznek: A statikus library A fent bemutatott módszer remekül működik, azonban a

keletkezett object fájlok nagy száma és külön-külön kezelése egy idő után nagy terhet jelentene a fejlesztők számára. Jó lenne tematikusan, valamilyen rendezőelvek betartása mentén az így összetartozó object fájlokat is becsomagolni egy-egy tároló fájlba. Ennek a megvalósítását hívjuk programozói g c c −c r u t i n o k −1. c könyvtárnak (library). Történelmileg úgy alag c c −c r u t i n o k −2 c kult, hogy erre a Unix ar (archive) paranEzután a program összeépítése már így is le- csát használjuk, amiről részletesen itt olvashatunk: http://linux.aboutcom/library/ hetséges: cmd/blcmdl1 ar.htm Ennyit azonban nem kell g c c main . c r u t i n o k −1 o r u t i n o k −2 o −o t e s t 2 tudni róla, mert mindig a következő példában A ./test2 program futása természetesen mutatott módon használjuk: ugyanazt csinálja, mint a ./test Mi ennek az a r r c s l i b r u t i n o k a r u t i n o k −1 o r u t i n o k −2 o előnye? A

4. Programlista pirossal kiemelt sora Ezzel létrejön egy librutinok.a (statikus haszúj, azonban a másik 2 forrásfájl változatlan, így láthatjuk, hogy csak a main.c fordítása szük- nálatra tervezett) könyvtár Nézzük meg a séges, majd egyből építhetjük a binárisokból a Unix nm parancsával (http://linux.about com/library/cmd/blcmdl1 nm.htm) a kivonaprogramot: tolt tartalmát! // 4 . P r o g r a m l i s t a ( main c ) #include <s t d i o . h> #include < s t d l i b . h> #include " r u t i n o k . h" i n t main ( i n t arg c , char ∗∗ a r g v ) { f v 1 ( " aaaaaa " ) ; f v 2 ( " aaaaaa " ) ; gv2 ( " aaaaaa " ) ; fv3("333333"); return (EXIT SUCCESS) ; } nm l i b r u t i n o k . a r u t i n o k −1. o : 00000000 T f v 1 0000001 c T f v 2 00000038 T f v 3 U printf r u t i n o k −2. o : 00000000 T gv1 0000001 c T gv2 U printf Látható, hogy mindkét object fájl ott van, sőt még az elérhető

globális rutinok (függvények) Fordítsuk le újra: neveit is láthatjuk. A T azt jelenti, hogy ez g c c main . c r u t i n o k −1 o r u t i n o k −2 o −o t e s t 2 egy olyan név, aminek a kódja meg is van az A futási kép a következő lesz, azaz a megvál- object file-ban. Az U a printf függvényre való undefined, azaz fel nem oldott külső hivatkozást toztatott program előállt: jelenti. A gcc a linkelés (azaz a kód darabkák C a l l e d f v 1 : aaaaaa összeépítése során) a printf függvényt máshol C a l l e d f v 2 : aaaaaa fogja megkeresni, azaz nem itt van megadva, de C a l l e d gv2 : aaaaaa innen használják. Ezt persze mi is tudjuk, hiC a l l e d f v 3 : 333333 szen mi írtuk a forráskódot. Rendelkezünk egy 4 Programozási eszközök A programozói könyvtárak használata Linux környezetben bináris librutinok.a könyvtárral, építsük össze a programot most ennek a használatával! g c c main . c −L −l r u t i n o k −o t e s t 3

A -L kapcsoló után egy fájlrendszerbeli keresési utakat adhatunk meg, az összekapcsolásnál innen próbálja meg a linker megtalálni a használt külső, globális függvényeket. A -l a librutinoka könyvtárat jelöli ki, itt az a névkonvenció, hogy a kezdő lib és .a kiterjesztés mindig elmarad A -o pedig a már megszokott módon azt mondja meg, hogy a legyártandó bináris programunk neve test3 legyen. A test3 persze bitre pontosan ugyanaz, mint a korábbi test2. A statikus könyvtárakat úgy kell kezelni, mint általában minden archívumot, azaz kiegészíthetjük, törölhetünk belőle. Az 5 Programlista egy új object fájl forrása. // 5 . P r o g r a m l i s t a ( matek−r u t i n o k c ) int o s s z e g ( int a , int b ) { return a + b ; } int kulonbseg ( int a , int b ) { return a − b ; } Fordítsuk le: g c c −c matek−r u t i n o k . c A keletkezett matek-rutinok.o fájlt tegyük be a librutinok.a könyvtárunkba: a r r l i b r u t i n o k . a

matek−r u t i n o k o Az új főprogramunk a következő, ahol pirossal jelöltük a változást: // 6 . P r o g r a m l i s t a ( matek−r u t i n o k c ) #include <s t d i o . h> #include < s t d l i b . h> #include " r u t i n o k . h" i n t main ( i n t arg c , char ∗∗ a r g v ) { f v 1 ( " aaaaaa " ) ; f v 2 ( " aaaaaa " ) ; gv2 ( " aaaaaa " ) ; f v 3 ( " 333333 " ) ; int e = kulonbseg(12, 4); } printf(" A %i és %i különbsége: %i", 12, 4, e); return (EXIT SUCCESS) ; Készítsük el az új test4 bináris programot: g c c main . c −L −l r u t i n o k −o t e s t 4 A ./test4 futási eredménye a következő lesz: C a l l e d f v 1 : aaaaaa C a l l e d f v 2 : aaaaaa C a l l e d gv2 : aaaaaa C a l l e d f v 3 : 333333 A 12 é s 4 k ü l ö n b s é g e : 8 Most az nm paranccsal nézzünk bele az új könyvtárba: nm l i b r u t i n o k . a r u t i n o k −1. o : 00000000 T f v 1 0000001 c

T f v 2 00000038 T f v 3 U printf r u t i n o k −2. o : 00000000 T gv1 0000001 c T gv2 U printf matek−r u t i n o k . o : 0000000 d T k u l o n b s e g 00000000 T o s s z e g Befejezésül nézzük meg azt is, amikor több könyvtárból szedi össze a gcc az összeépítendő programot. Ehhez a matek-rutinokc forrást egészítsük ki a következő függvénnyel: #include <math . h> #define PI 3 . 1 4 1 5 9 2 6 5 . double sinWithDeg ( double x ) { return s i n ( PI ∗x /180 ) ; } Itt a C standard matematikai csomagját is használjuk, mert a sin(x) a libm.a könyvtárban található. A mi rutinunk a fokban való számítást valósítja meg az eredeti radián helyett. Készítsük el az új object fájlt: g c c −c matek−r u t i n o k . c Cseréljük erre a librutinok.a fájlban lévő változatot: a r r l i b r u t i n o k . a matek−r u t i n o k o 5 Programozási eszközök A programozói könyvtárak használata Linux környezetben Építsük össze az

új test5 programot, ami futáskor kiegészül a 0.500000 érték megjelenítésével g c c main . c −L −l r u t i n o k −lm −o t e s t 5 Felhívjuk a figyelmet, hogy itt minden jól működik, a kívánt sinus érték jelenik meg és több könyvtárat (a matematikai és a saját rutinok) is használtunk. Azonban valamit elrontottunk! A Unix ldd parancs (http://linux.about com/library/cmd/blcmdl1 ldd.htm) kiírja egy futtatható programról, hogy milyen dinamikus könyvtárakat használ, nézzük meg! ldd t e s t 5 l i n u x −g a t e . s o 1 => ( 0 x00110000 ) libm . s o 6 => / l i b / i 3 8 6 −l i n u x −gnu / libm å so . 6 (0 x002f1000 ) l i b c . s o 6 => / l i b / i 3 8 6 −l i n u x −gnu / l i b c å s o . 6 ( 0 x00111000 ) / l i b / ld −l i n u x . s o 2 ( 0 x00922000 ) Ez pedig nem jó, mert mi a statikus változatot szerettük volna a példában linkelni. Ehhez a static kapcsoló használatát felejtettük el kiadni, azaz a fordítás és

linkelés helyes parancsa ez lett volna: g c c −s t a t i c main . c −L −l r u t i n o k −lm −o t e s t 5 Most nézzük meg az előzőeket: ldd t e s t 5 not a dynamic e x e c u t a b l e Ez már rendben van, a futás is sikeres. A bináris könyvtárak legtöbbször statikus (.a) és dinamikus (.so=shared object) változatban is elérhetőek, így jogos, hogy választanunk kell közöttük Az osztott változat használata az alapértelmezett, általában annak külön oka van, ha mégis a futtatható programhoz akarunk statikusan linkelni. Ez ma már egy ritkábban használt, régebbi módszer. 1. Több bináris programhoz is ugyanazt az egy könyvtárat használjuk, így nem kell mindegyikhez külön hozzászerkeszteni. Ezzel operatív memóriát (persze lemez tárhelyet is) takarítunk meg, ugyanis ugyanaz a kód már nem töltődik be többször, míg a statikus szerkesztésű programoknál erre nincs ráhatásunk. 2. Verziókezelés A program egyes komponensei

fizikailag is több bináris fájlban jelennek meg, így az egyes könyvtárak cseréje is elég, amikor a programot frissítjük 3. Unix alatt használhatunk szimbolikus linkeket a fájlokra, ami azok alias nevei Amennyiben N darab program használja a libKonvytar.so library-t és annak elkészítjük egy új változatát, akkor megtehetjük, hogy azt így hívjuk: libKonyvtarMutansso Persze a főprogram továbbra is a libKonvytar.so névhez ragaszkodik, de létrehozhatunk egy ilyen nevű linket a mutáns változatra A dinamikus linkelés keresési sorrendjével pedig biztosítható, hogy ez a link kerüljön először megtalálásra. Mit nyertünk? Képesek lettünk arra, hogy az új környezetben már csak N-1 darab program használja az eredeti könyvtárat, míg az N. már a mutáns változat szerint működik. A továbbiakban a 3 forráskönyvtár tartalma alapján készítsünk egy .so könyvtárat! Ehhez az alábbi módon újra el kell készíteni az object fájlokat, ugyanis

ilyenkor az fPIC (position independent code) kapcsolót meg kell adni: g c c −fPIC −c r u t i n o k −1. c g c c −fPIC −c r u t i n o k −2. c g c c −fPIC −c matek−r u t i n o k . c A lefordított object fájlokból így tudjuk elkészíteni a librutinok.so101 fizikai bináris fájlt, A dinamikus, futás során történő linkelésnek amit valódi vagy fizikai so névnek is nevezünk. h a r e d −W1,−soname , l i b r u t i n o k . s o 1 −o å több előnye is van, amiből általában hármat g c c −s l i b r u t i n o k . s o 1 0 1 r u t i n o k −1 o r u t i n o k −2å mindig meg szoktak említeni: o matek−r u t i n o k . o Az osztott használatú library 6 Programozási eszközök A programozói könyvtárak használata Linux környezetben Ezt követően kiadunk 2 szimbolikus link készítő parancsot. A librutinokso1 alias név az un. so név A futó program ténylegesen ezt fogja meghivatkozni. A számot (esetünkben most 1) a főverziónak

nevezzük. A hivatkozott fizikai név változhat alatta, emiatt abban a további 2 szám az alverzió és a release szám. Mindez persze nem kötelező, de ajánlott: l n −s l i b r u t i n o k . s o 1 0 1 l i b r u t i n o k s o 1 A 2. szimbolikus link a so névre mutat és csak az a feladata, hogy a futtatható programban a -l kapcsoló után legyen egy olyan név, amit lib előtaggal és .so kiterjesztéssel fájlnévre lehet asszociálni, azaz esetünkben ez írható: -lrutinok. l n −s l i b r u t i n o k . s o 1 l i b r u t i n o k s o g c c main . c −l r u t i n o k −lm −o t e s t 6 A többi esetben a program előállításához mindig meg kell adni azt a könyvtárat, ahol az so fájljaink vannak. Mi a példában ide másoltuk a fájlt és a 2 linkjét: /usr/local/lib/creedsoft-org/. Ekkor a fordítás: g c c main . c −L/ u s r / l o c a l / l i b / c r e e d s o f t −o r g −å l r u t i n o k −lm −o t e s t 6 A lefordított program futtatásához

1. vagy 2. keresést kell alkalmazni. A 2. esetben a /etc/ld.soconf fájlba fel kell venni a /usr/local/lib/creedsoft-org/ könyvtárat, majd futtatni ezt a parancsot, ami frissíti az ld.socashe file-t, azaz bejegyzi a mi osztott könyvtárunk elérhetőségét is: Miután legyártottuk a könyvtárat és a kul- sudo l d c o n f i g −n / u s r / l o c a l / l i b / c r e e d s o f t −o r g turált és rugalmas használatot biztosító 2 linket, felmerül a következő kérdés: Hogyan telepítsük? A helyes telepítés mindig a következő 2 igény Dinamikus könyvtárhasználat megfelelő kielégítését jelenti: A fentiek kiegészítésképpen szeretnénk röviden 1. A program összeépítése során a linker megbemutatni azt a lehetőséget, amikor a fordítás találja a hivatkozott osztott könyvtárakat során nem kapcsoljuk a programhoz az osztott 2. A program futtatása során a linker meg- library-t, azonban futás közben azt mégis hasztalálja és betölthesse a

hivatkozott osztott náljuk Erre mutat egy példát a 7 Programlista könyvtárakat // 7 . P r o g r a m l i s t a ( main c ) Látható, hogy itt nagy hangsúly van a keresésen, aminek sorrendje az alábbi szabályok szerint alakul: 1. Az LD LIBRARY PATH környezeti változóban felsorolt könyvtárak #include <s t d i o . h> #include < s t d l i b . h> #include <d l f c n . h> i n t main ( i n t a r g c , char ∗∗ a r g v ) { void ∗ h a n d l e ; double ( ∗ s i n u s ) ( double ) ; 2. A /etc/ldsocashe fájlba felvett könyvtárakban 3. /usr/lib 4. /lib Amennyiben a 3. vagy 4 helyre másoljuk a 3 so fájlunkat, úgy a linkelés és futtatás is megtalálja automatikusan a könyvtárat. Ez azt jelenti, hogy ilyenkor így állíthatjuk elő a programot: } char ∗ e r r o r ; h a n d l e = d l o p e n ( " / l i b / i 3 8 6 −l i n u x −gnu / libm . å s o . 6 " , RTLD LAZY) ; i f ( ! handle ) { fputs ( dlerror () , stderr ) ; exit (1) ; } s i n

u s = dlsym ( handle , " s i n " ) ; i f ( ( e r r o r = d l e r r o r ( ) ) != NULL) { fputs ( error , stderr ) ; exit (1) ; } p r i n t f ( "%f " , ( ∗ s i n u s ) ( 2 . 0 ) ) ; d l c l o s e ( handle ) ; 7 Programozási eszközök A programozói könyvtárak használata Linux környezetben A programot egyszerűen csak így kell lefordítani, miután a test8 binárist kapjuk: g c c −o t e s t 8 main . c − l d l A dlfcn.h deklaráción keresztül használhatjuk a dlopen() függvényt, ami betölti azt az so tartalmat, ami a sin könyvtári függvényt tartalmazza. A sinus név pedig egy függvényre mutató pointer A C nyelv ismeretében ennyi már elég is a megértéshez. Mikor érdemes a dinamikus betöltést használni? A pluginok és modulok esetén. Képzeljünk el egy másik könyvtárat is, ahol a sin szintén meg van valósítva, persze ugyanazzal a felülettel. A paramétere 1 double és azt is ad vissza. Akkor viszont csak 1 string annak a

paramétere, hogy melyik so-t töltjük be Ezzel pontosan olyan környezetet tudunk használni, amit az ilyen dinamikusan bepattintható program darabkák szeretnek. A Linux sok alrendszere így van kialakítva, például a PAM (Pluggable Authentication Module) is. A header fájl szerepe A kódkönyvtárak kialakításához szükséges, hogy azokhoz 1 vagy több C header fájlt is készítsünk. A mi librutinok.so könyvtárunkhoz például ezt használhatjuk: // 8 . P r o g r a m l i s t a ( r u t i n o k h ) #i f n d e f RUTINOK H #define RUTINOK H #i f d e f cplusplus extern "C" { #endif void f v 1 ( char ∗ s ) ; void f v 2 ( char ∗ s ) ; void f v 3 ( char ∗ s ) ; void gv1 ( char ∗ s ) ; void gv2 ( char ∗ s ) ; int o s s z e g ( int a , int b ) ; int kulonbseg ( int a , int b ) ; double sinWithDeg ( double x ) ; #i f d e f } #endif 8 cplusplus #endif /∗ RUTINOK H ∗/ A C nyelvben fontos, hogy a kódgenerálás során legyen elég ismeretünk a

használt dolgokról, még akkor is, ha nem ott implementáljuk. Amikor meghívjuk a sinWithDeg() függvényt, tudnunk kell, hogy az milyen paraméterezésű, mi neve és a visszatérési értéke. Ezt deklarálni kell a használat előtt, erre szolgálnak a header (vagy fejléc) fájlok, hogy ne kelljen mindig, minden esetben ezt a programozónak végeznie. Érdemes a fejlécfájlokat a 8 Programlistán látható módon formalizálni, amivel a következő 2 előnyt érjük el: 1. A header file csak 1 alkalommal lesz beemelve a gcc részére, mert másodszor a RUTINOK H beállítása miatt már kimarad. 2. A C++ fordító biztosít egy cplusplus flag-et, így abban az esetben az extern "C" megakadályozza a nevek kódolását, ami a C++ alapértelmezése, de ekkor nem találná meg a linker a C könyvtárban a keresett objektumot, hiszen ott kódolatlanul lett regisztrálva. Erre mindig tekintettel kell lennünk, amikor C és C++ kódot keverve használunk. A könyvtár

kompatibilitásának elvesztése Csak röviden megemlítjük azokat az okokat, ami miatt a linker vagy a futtató nem tud már használni egy könyvtárat: 1. Az üzleti logika megváltozott 2. Globális (exportált) függvények törlődtek 3. Megváltozott egy vagy több függvény felülete A fenti esetekben kötelező a főverzió növelése. Programozási eszközök 2. CMAKE – Az alkalmazások összeépítése CMAKE – Az alkalmazások összeépítése Tisztán emlékszünk a CMake eszközzel való első találkozásunkra. A Kdevelop 4-es sorozattal kezdtünk dolgozni, amikor a fájlok között feltünt egy puritán kinézetű CMakeLists.txt nevű Elkezdtük nézgetni és rájöttünk, hogy a K Desktop Environment és a Linux egyik legjobb fejlesztői környezete miért is használja. A CMake nagyon sokat tud, a fejlesztési életciklus build, teszt és csomagolás (telepítés) munkáit egyaránt hatékonyan támogatja. • m libm.so (matematikai könyvtár) A CMake

egy Cross-Platform Makefile Generator, azaz egy egyszerű leíró szövegfájl (en• dl libdl.so (a dinamikus betöltéshez nek neve általában CMakeLists.txt) alapján el szükséges könyvtár) tudja készíteni a program összeépítéséhez szükséges Makefile-t (ismeri ezenkívül az MS Visual A fenti CMakeLists.txt fájlra futtassuk le a Studio, Apple Xcode formátumot is). cmake parancsot: cmake CMakeLists . t x t A CMake használata A továbbiakban bemutatjuk, hogy az első cikk forráskódjait használva miképpen foghatjuk munkára a CMake-et. Készítettünk egy ilyen CMakeLists.txt fájlt: 1 2 3 4 5 6 7 8 9 cmake minimum required (VERSION 2 . 6 ) p r o j e c t ( cmake−t e s t ) a d d e x e c u t a b l e ( cmake−t e s t main . c r u t i n o k −1 c r u t i n o k −2 c matek−r u t i n o k . c ) t a r g e t l i n k l i b r a r i e s ( cmake−t e s t m d l ) Az 1. sort minden esetben érdemes kitenni Az érdemi rész a 2. sornál kezdődik, ahol a project

paranccsal megmondjuk, hogy a mi projektünk most cmake-test névre hallgasson. A 4-7. sorok között az add executable kulcsszóval rendelkezünk arról, hogy milyen forrásfájlokat akarunk a projektbe építeni Itt az 1 cikkből ismert forrásokat látjuk természetesen, hiszen a példánk erről szól. A 9 sor target link libraries parancsával a projektünkhöz (azaz a cmake-test-hez) hozzátesszük a használt dinamikus könyvtárakat (látható, hogy a könyvtárak neveit ugyanúgy kell megadnunk, ahogy azt a gcc -l paraméterénél tettük): Ez −− −− −− a parancs képernyős kimenete : C o n f i g u r i n g done G e n e r a t i n g done B u i l d f i l e s have been w r i t t e n t o : /home/å t a n u l a s / cpp / InfNavCProj Ennek eredményeképpen létrejön a Makefile, amit így nem kell kézzel elkészítenünk. Futtassuk is le! make Ez a p a r a n c s k é p e r n y ő s k i m e n e t e : [ 1 0 0 % ] B u i l t t a r g e t cmake−t e s t Csak

emlékeztetőül, nézzük meg a main.c forrás utolsó változatát: // 1 . P r o g r a m l i s t a ( main c ) #include <s t d i o . h> #include < s t d l i b . h> #include <d l f c n . h> #include " r u t i n o k . h" /∗ ∗ Test Program ∗/ i n t main ( i n t a r g c , char ∗∗ a r g v ) { void ∗ h a n d l e ; double ( ∗ s i n u s ) ( double ) ; char ∗ e r r o r ; h a n d l e = d l o p e n ( " / l i b / i 3 8 6 −l i n u x −gnu / libm . å s o . 6 " , RTLD LAZY) ; 9 Programozási eszközök if ( ! handle ) { fputs ( dlerror () , stderr ) ; exit (1) ; } s i n u s = dlsym ( handle , " s i n " ) ; i f ( ( e r r o r = d l e r r o r ( ) ) != NULL) { fputs ( error , stderr ) ; exit (1) ; } p r i n t f ( " Dinamikus ␣ s i n u s : ␣%f " , ( ∗ s i n u s ) å (2.0) ) ; d l c l o s e ( handle ) ; f v 1 ( " aaaaaa " ) ; f v 2 ( " aaaaaa " ) ; gv2 ( " aaaaaa " ) ; f v 3 ( "

333333 " ) ; int e = kulonbseg (12 , 4) ; p r i n t f ( " A␣%i ␣ é s ␣%i ␣ k ü l ö n b s é g e : ␣%i " , 1 2 , å 4, e) ; double d = sinWithDeg ( 30 ) ; p r i n t f ( " ␣%f " , d ) ; } return (EXIT SUCCESS) ; A make parancs a projekt nevével megegyező cmake-test futtatható bináris programot hozta létre, futtassuk is le! CMAKE – Az alkalmazások összeépítése ) a d d e x e c u t a b l e ( cmake−t e s t main . c ) t a r g e t l i n k l i b r a r i e s ( r u t i n o k m) t a r g e t l i n k l i b r a r i e s ( cmake−t e s t d l r u t i n o k ) Az igazi újdonság a 4-7. sorok között van, ahol az add library paranccsal egy új rutinok nevű so könyvtár felépítését kérjük (aminek a fizikai neve persze librutinok.so lesz ezzel) a megadott 3 darab C forrásból A 12 sor target link libraries utasítása arról rendelkezik, hogy a célja (azaz most a rutinok) felépítéséhez a libm matematikai könyvtár is

szükséges. A 13 sor a futtatható cmake-test előállításához szükséges osztott könyvtárakat jelöli ki: • A dl azért kell, mert a main.c használ belőle • A rutinok pedig a librutinok.so használatát definiálja, persze azért mert most már ott vannak a meghívott függvények. . / cmake−t e s t Ez a p a r a n c s k é p e r n y ő s k i m e n e t e : Dinamikus s i n u s : 0 . 9 0 9 2 9 7 C a l l e d f v 1 : aaaaaa C a l l e d f v 2 : aaaaaa C a l l e d gv2 : aaaaaa C a l l e d f v 3 : 333333 A 12 é s 4 k ü l ö n b s é g e : 8 0.500000 Minden rendben van, ezt vártuk. Használjunk könyvtárakat is! A fenti kód építését most csináljuk meg úgy, hogy építünk egy librutinok.so könyvtárat és a main.c ebből használja majd a meghívandó függvényeket. Mindehhez egy kicsit átírtuk a CMakeLists.txt fájlt: cmake minimum required (VERSION 2 . 6 ) p r o j e c t ( cmake−t e s t ) a d d l i b r a r y ( r u t i n o k SHARED r u t i n o k −1. c r u

t i n o k −2. c matek−r u t i n o k . c 10 A forráskód konfigurálása A következőkben megtanuljuk, hogy a forrásprogram egyes header fájljait hogyan lehet dinamikusan konfigurálni, illetve erre való példaként megnézzük a verziókezelés egy megvalósítási lehetőségét. Előtte azonban ismerjünk meg néhány CMake elemet, ami ehhez szükséges! CMake változók A CMake sok előre beállított (környezeti) változóval rendelkezik, amelyekre a CMakeList.txt fájlban hivatkozni tudunk, ugyanakkor ilyeneket magunk is létrehozhatunk a set paranccsal, aminek felépítése ilyen: set(<variable> <value-list>). Példa: s e t (MyVar alma ) vagy egy lista, aminek elemei ’;’-vel kerülnek elválasztásra: s e t (MyVar alma ; k ö r t e ; s z i l v a ) Programozási eszközök A változókra ${MyVar} szintaxissal tudunk a CMakeList.txt file egyéb helyein hivatkozni A példánkban használni fogunk 2 előre definiált CMake változót, emiatt itt

megadjuk a jelentésüket: CMAKE – Az alkalmazások összeépítése majd a rutinok.h lesz használva, aminek mappáját (pontosabban szólva szóközökkel elválasztott könyvtárlistát sorolhatunk fel) így adhatjuk meg a CMake leíróban: i n c l u d e d i r e c t o r i e s ( " $ {PROJECT BINARY DIR} " ) • PROJECT SOURCE DIR: Az a mappa, ami a forráskód gyökere (top level source A példa - verzió kiírás mappa). Ennyi előzetes ismeret már elegendő lesz, hogy a verziókezelés példát megértsük. A 2 Prog• PROJECT BINARY DIR: Az a mappa, ramlista mutatja a rutinok.hin fájl tartalami a bináris építés gyökere (top level mát, ahol definiáltuk a MAIN VERSION és build mappa). SUB VERSION konstansokat, amelyek értékét A fentiek alapján például a PRO- a CMake fogja végül megadni, amikor előállítja JECT BINARY DIR változóra így tudunk hi- a fordításhoz szükséges rutinok.h header fájlt vatkozni: ${PROJECT BINARY DIR}. A configure

file parancs A configure file command egy fájlt másol, miközben megváltoztatja annak a tartalmát. Az alapvető szintaxisa így néz ki: c o n f i g u r e f i l e (< i n p u t > <output >) Esetünkben majd a rutinok.h fájl végleges, verziózott alakját fogjuk így előállítani, így arra így fog kinézni a használata: configure file ( " $ {PROJECT SOURCE DIR}/ r u t i n o k . h i n " " $ {PROJECT BINARY DIR}/ r u t i n o k . h" ) // 2 . P r o g r a m l i s t a ( r u t i n o k h i n ) #i f n d e f RUTINOK H #define RUTINOK H #i f d e f cplusplus extern "C" { #endif #define MAIN VERSION @MAIN VERSION@ #define SUB VERSION @SUB VERSION@ void f v 1 ( char ∗ s ) ; void f v 2 ( char ∗ s ) ; void f v 3 ( char ∗ s ) ; void gv1 ( char ∗ s ) ; void gv2 ( char ∗ s ) ; int o s s z e g ( int a , int b ) ; int kulonbseg ( int a , int b ) ; double sinWithDeg ( double x ) ; #i f d e f } #endif cplusplus Az egy elfogadott

konvenció, hogy egy file.ext output esetén a parancs input-ja file.extin le#endif /∗ RUTINOK H ∗/ gyen. Az in fájl készítése során a környezeti válA 3 Programlista a teljes és új CMaketozókra ’@’ jelek között hivatkozhatunk, amire Lists.txt fájlt mutatja Az előző változathoz kénemsokára látunk példát pest már megjegyzéseket is tartalmaz, amit ’#’ karakterrel kezdve tudunk elhelyezni. A VariAz include directories parancs ables résznél láthatjuk a 2 változónkat, amiket A make file előállításakor be kell tudni állítani, set paranccsal hoztunk létre. A configure file hogy a forráskód fordítása során milyen könyv- előállítja a rutinok.hin rutinokh transzfortárakban keressen include fájlokat a fordító Ez mációt Az include directories rögzíti, hogy a a gcc -I kapcsolójának felel meg. Esetünkben megadott könyvtárban is keressen header fájlt a 11 Programozási eszközök CMAKE – Az alkalmazások összeépítése

fordító rendszer. A fájl többi része nem válto- Az so fájlok az alkönyvtárakban zott. Nagy projekt esetén érdemes annak részeit több # 3 . P r o g r a m l i s t a ( CMakeLists t x t ) mappába szétosztani. Az ilyen alkönyvtárakat cmake minimum required (VERSION 2 . 6 ) az add subdirectory paranccsal lehet megadni a p r o j e c t ( cmake−t e s t ) CMake számára. A librutinokso fájt most he# Variables lyezzük a rutinok nevű mappába. Ehhez a pros e t (MAIN VERSION 1 ) jekt gyökér alatt hozzunk létre egy rutinok nevű s e t (SUB VERSION 0 ) mappát: # Configure f i l e s configure file ( " $ {PROJECT SOURCE DIR}/ r u t i n o k . h i n " " $ {PROJECT BINARY DIR}/ r u t i n o k . h" ) # Directories for include f i l e s i n c l u d e d i r e c t o r i e s ( " $ {PROJECT BINARY DIR} " ) # To make l i b r u t i n o k . s o a d d l i b r a r y ( r u t i n o k SHARED r u t i n o k −1. c r u t i n o k å −2. c matek−r u t i n o

k c ) # To make an e x e c u t a b l e program a d d e x e c u t a b l e ( cmake−t e s t main . c ) t a r g e t l i n k l i b r a r i e s ( r u t i n o k m) t a r g e t l i n k l i b r a r i e s ( cmake−t e s t d l r u t i n o k ) Az alábbi főprogram csak a verzió kiírásával egészült ki: i n t main ( i n t arg c , char ∗∗ a r g v ) { p r i n t f ( " The␣ program ␣ v e r s i o n ␣ i s ␣%d.%d " , å MAIN VERSION, SUB VERSION) ; } void ∗ h a n d l e ; . mkdir r u t i n o k Ezután a CMakeList.txt fájlt változtassuk ilyenre: # 4 . P r o g r a m l i s t a ( CMakeLists t x t ) cmake minimum required (VERSION 2 . 6 ) p r o j e c t ( cmake−t e s t ) # Variables s e t (MAIN VERSION 1 ) s e t (SUB VERSION 0 ) # Configure f i l e s configure file ( " $ {PROJECT SOURCE DIR}/ r u t i n o k . h i n " " $ {PROJECT BINARY DIR}/ r u t i n o k . h" ) # Directories for include f i l e s i n c l u d e d i r e c t o r i e s (

" $ {PROJECT BINARY DIR} " ) # To make l i b r u t i n o k . s o #a d d l i b r a r y ( r u t i n o k SHARED r u t i n o k −1. c å r u t i n o k −2. c matek−r u t i n o k c ) add subdirectory ( rutinok ) # To make an e x e c u t a b l e program a d d e x e c u t a b l e ( cmake−t e s t main . c ) #t a r g e t l i n k l i b r a r i e s ( r u t i n o k m) t a r g e t l i n k l i b r a r i e s ( cmake−t e s t d l r u t i n o k ) A következő képernyő szekvencia a cmake make futtatás parancssorozatot mutatja. A ./cmake-test futási képét is idemásoltuk a jobb Az add library(rutinok SHARED .) sor megértés kedvéért, láthatjuk a megjelenített The megjegyzésbe került, ehelyett azt deklaráltuk az program version is 1.0 szöveget add subdirectory( rutinok ) sorral, hogy a rutinok könyvtárban is van még „teendő”, azaz cmake CMakeLists . t x t make egy ott elhelyezett CMakeList.txt fájl A target link libraries(rutinok m) sor is

kikerült a . / cmake−t e s t végrehajtandók közül, de nézzük csak meg a The program v e r s i o n i s 1 . 0 rutinok mappa alatt lévő CMakeList.txt fájt Dinamikus s i n u s : 0 . 9 0 9 2 9 7 ugyanis átkerült oda: C a l l e d f v 1 : aaaaaa C a l l e d f v 2 : aaaaaa C a l l e d gv2 : aaaaaa C a l l e d f v 3 : 333333 A 12 é s 4 k ü l ö n b s é g e : 8 0.500000 12 # 5 . P r o g r a m l i s t a ( CMakeLists t x t ) # A r u t i n o k mappa a l a t t a d d l i b r a r y ( r u t i n o k SHARED r u t i n o k −1. c r u t i n o k å −2. c matek−r u t i n o k c ) t a r g e t l i n k l i b r a r i e s ( r u t i n o k m) Programozási eszközök Természetesen a rutinok alkönyvtárba átmozgattuk a 3 darab C forrásfájlt is. A cmake CMakeLists.txt és make futtatása után a librutinokso a rutinok, míg a cmake-test pedig a gyökérkönyvtárba jött létre és ugyanaz a futási eredménye, mint eddig CMAKE – Az alkalmazások összeépítése i f ( CMAKE

A CASE ) a d d l i b r a r y ( r u t i n o k SHARED r u t i n o k −1. c r u t i n o k −2. c matek−r u t i n o k . c ) t a r g e t l i n k l i b r a r i e s ( r u t i n o k m) e n d i f ( CMAKE A CASE ) Opcionális részletek a forráskódban Telepítési támogatás Lehetőségünk van az in fájlokban egy #cma- Általában a következő fájltípusok telepítése mekedefine utasítással megadni azt a lehetőséget, rül fel: hogy a generált header fájlba egy #define bekerüljön vagy sem. A mi esetünkbe a rutinokhin • statikus és dinamikus könyvtárak fájlba betettük ezt: #c m a k e d e f i n e USE FV1 • futtatható programok Ennek hatására a generált rutinok.h fájlba ez a sor is létrejött: • header fájlok #d e f i n e USE FV1 • konfigurációs fájlok Amennyiben ezzel azt szeretnénk szabályozni, hogy fv1() vagy fv2() függvény hívódjon Tegyük be a CMakeList.txt fájlba a következő meg, így kell megváltoztatni a main.c kódot: sort,

majd generáljuk le a Makefile-t és buildi n t main ( i n t arg c , char ∗∗ a r g v ) eljünk a make paranccsal. { p r i n t f ( " The␣ program ␣ v e r s i o n ␣ i s ␣%d.%d " , å MAIN VERSION, SUB VERSION) ; . #i f d e f USE FV1 f v 1 ( " aaaaaa " ) ; #e l s e f v 2 ( " aaaaaa " ) ; #endif . } i n s t a l l (TARGETS cmake−t e s t DESTINATION /home/å t a n u l a s / cpp / InfNavCProj / b i n ) A fenti parancs lehetővé teszi a make install parancs kiadását, ahol a TARGETS mögött a telepítendő bináris, a DESTINATION után pedig a telepítési célkönyvtár található. Futása után a megadott könyvtárban fogjuk találni a cmake-test programot Ugyanezen parancs természetesen a bináris könyvtárakra is A CMakeList.txt opciók működik. A header és konfigurációs fájlok másoLehetőségünk van arra, hogy a CMakeListtxt lására (telepítésére) egyaránt alkalmas az install munkautasításait is opcionálisan

választhatónak command következő alakja: adjuk meg. Erre szolgál az option parancs, mely- i n s t a l l ( FILES r u t i n o k h DESTINATION /home/å t a n u l a s / cpp / InfNavCProj / i n c l u d e ) nek használatára egy példa: o p t i o n (CMAKE A CASE "CMake A o r B Cases " ON) Itt a CMAKE A CASE az opció neve, ami ON vagy OFF állapotú lehet. Ezután a CMAKE A CASE így használható a CMakeList.txt fájlban: Használhatjuk a CMAKE INSTALL PREFIX környezeti változót telepítési root helyre, ami esetünkben például /home/tanulas/cpp/InfNavCProj/ könyvtár. Ekkor elég lett volna a bin, include, . megadása is destinationnak 13 Programozási eszközök CMAKE – Az alkalmazások összeépítése Tesztelési támogatás Természetesen most is a CMakeList.txt fájlban kell meghatároznunk a teszteseteket. A fájl végéhez tegyük hozzá ezt a sort: Ez a cmake futtatásakor létrehozza a következő 2 fájlt: • CPackConfig.cmake bináris csomag

előállítására enable testing () • CPackSourceConfig.cmake source csoEkkor a fordítás után a make test parancs is mag előállítására használható lesz. Az egyes teszteseteket a követ- Példánkban állítsunk elő egy debian bináris csokező sorokkal vehetjük fel: magot! A generált CPackConfig.cmake file-ban add test ( Run1 cmake−t e s t 2 5 ) tegyünk 3 változtatást, mely után így néznek Itt a Run1 a teszteset neve, a cmake-test, a majd ki ezek a sorok: target, amit tesztelünk. A 25 helyén egy arg1, • SET(CPACK BINARY BUNDLE "ON") arg2, . parancssori paraméterlista lehet A • SET(CPACK BINARY DEB "ON") CMake macro lehetőséget ad a fentiekhez ha• SET(CPACK GENERATOR "DEB") sonló tesztesetek generálására is. Most futtassuk le a teszteket! Ezután a már megismert 2 parancs használata make t e s t szükséges: Running t e s t s . Test p r o j e c t /home/ t a n u l a s / cpp / InfNavCProj S t a r t 1 : Run1 1/1

Test #1: Run1 å . Passed 0.00 sec make make i n s t a l l 100% t e s t s p ass ed , 0 t e s t s f a i l e d out o f 1 T o t a l Test time ( r e a l ) = 0.05 sec Telepítőkészlet építés å Végül futtassuk le a telepítő generátort, ami az installált tartalom alapján fog dolgozni, így mások gépén is ilyen fájl elrendezés fog létrejönni. Ezt kétféleképpen is megtehetjük: cpack −C CPackConfig . cmake Ez a Makefile része is, ezért így is előállíthatjuk: make package Egyszer elérkezik az az idő, amikor az alkalmaA fájlrendszerbe létrejött a következő debian zásunkat telepíthető csomag formájában terjesz- csomagfájl: cmake-test-1.01-Linuxdeb teni szeretnénk. Erre Linux alatt mindenképpen Kukkantsunk bele: valamilyen csomagformátumot érdemes válasz- new d e b i a n package , v e r s i o n 2 . 0 s i z e 3934 b y t e s : c o n t r o l a r c h i v e =316 b y t e s . 169 b y t e s , 9 lines control tani: debian (.deb), Red Hat (rpm) Az

aláb78 b y t e s , 1 lines md5sums Package : cmake−t e s t biakban a debian csomag elkészítését mutatjuk V e r s i o n : 1 . 0 1 be röviden. A CMakeListtxt fájl végére tegyük SPerci ot iroi nt y: : d oe vp et li o n a l Architecture : i386 a következő sorokat: I n s t a l l e d −S i z e : 8 . # b u i l d a CPack d r i v e n i n s t a l l e r package include ( InstallRequiredSystemLibraries ) s e t (CPACK RESOURCE FILE LICENSE " $ {å CMAKE CURRENT SOURCE DIR}/ L i c e n s e . t x t " ) s e t (CPACK PACKAGE VERSION MAJOR " $ {å MAIN VERSION} " ) s e t (CPACK PACKAGE VERSION MINOR " $ {å SUB VERSION} " ) s e t (CPACK PACKAGE CONTACT " p r i v a t e " ) i n c l u d e ( CPack ) 14 Maintainer : private D e s c r i p t i o n : cmake−t e s t built u s i n g CMake drwxrwxr−x r o o t / r o o t 0 2012−10−20 2 0 : 2 6 / drwxrwxr−x r o o t / r o o t 0 2012−10−20 2 0 : 2 6 / tanulas / drwxrwxr−x r o o t / r o o t 0

2012−10−20 2 0 : 2 6 / t a n u l a s / cpp / drwxrwxr−x r o o t / r o o t 0 2012−10−20 2 0 : 2 6 / t a n u l a s / cpp / I n f N a v C P r o j / drwxrwxr−x r o o t / r o o t 0 2012−10−20 2 0 : 2 6 / t a n u l a s / cpp / I n f N a v C P r o j / b i n / −rwxr−xr−x r o o t / r o o t 7759 2012−10−20 2 0 : 1 1 / t a n u l a s / cpp / I n f N a v C P r o j / b i n / cmake−t e s t . / homeå . / homeå . / homeå . / homeå . / homeå . / homeå Programozási eszközök CMAKE – Az alkalmazások összeépítése A tartalma jelenleg csak a cmake-test program, mert az install-t is csak erre definiáltuk a példánkban. CMake részletesebben A CMake egy összetett rendszer, amit eddig bemutattunk arra nagyjából mindig szükség van. Fontosságát az is mutatja, hogy a KDevelop környezet néhány éve már ezt a build system-et használja maga alatt. A kiterjedtségét mutatja, hogy csak az előre definiált változó kategóriáiból az alábbi 5

létezik: • A viselkedést megváltoztató változók • A rendszert leíró változók { } A a; a = new A( ) ; a . printName ( ) ; System . out p r i n t l n ( " H e l l o ␣World ! " ) ; } Ehhez a következő CMakeList.txt készíthető: p r o j e c t ( h e l l o Java ) cmake minimum required (VERSION 2 . 6 ) s e t (CMAKE VERBOSE MAKEFILE 1 ) f i n d p a c k a g e ( Java COMPONENTS Development ) i n c l u d e ( UseJava ) add jar ( h e l l o A. j a v a HelloWorld j a v a ) Futtassuk a cmake parancsot! cmake CMakeLists . t x t A létrejött Makefile az operációs rendszerre előzőleg telepített Java JDK javac és jar parancsai segítségével fordít és végeredményként ke• A buildelés vezérlését befolyásoló változók letkezik egy hello.jar nevű java könyvtár, amibe • Különféle információkat szolgáltató válto- belenézve ezt láthatjuk: Archive : / media / s d a 3 / documents / cmake / cmake − 2 . 8 8 / å zók T e s t s / Java /

h e l l o . j a r • A nyelvek használatát segítő változók Persze a fentiek kifinomult használatára ritkán van szükség. Több környezetet is támogat, például csak pillantsunk rá a Java használatára Legyen egy A class: class A { public A( ) { } } public void printName ( ) { System . out p r i n t l n ( "A" ) ; } És egy HelloWorld osztály: c l a s s HelloWorld { public s t a t i c void main ( S t r i n g a r g s [ ] ) 0 68 480 377 D e f l :N 2 0% 2012−10−20 0 0 0 0 0 0 0 0 META−INF/ D e f l :N 67 2% 2012−10−20 a 3 c META−INF/MANIFEST .MF D e f l :N 325 32% 2012−10−20 4814829 a HelloWorld . c l a s s D e f l :N 264 30% 2012−10−20 bf405ede A. c l a s s 19:20 å 1 9 : 2 0 31533å 19:20 å 19:20 å * Befejezésül 2 fontos információ forrást szeretnénk kiemelni: • A CMake project weboldala: http://www.cmakeorg/ • Mastering CMake 1930934114) könyv (ISBN-10: 15 Programozási eszközök 3. Object Pascal – C/C++

könyvtárak használata Object Pascal – C/C++ könyvtárak használata A Delphi fejlesztői környezetet sokan ismerik és szeretik, aminek létezik egy kiváló linuxos implementációja a Lazarus. Ez az IDE a Free Pascalt használja, ami természetesen pontosan ugyanazt az Object Pascalt valósítja meg, amit a Delphi is használ. A Lazarus ma már egy kiérlelt, stabil környezet, amivel bármilyen produktív alkalmazásfejlesztés megvalósítható. Fejlesztése 1999-ben indult, így ma már 13 éves múltra tekinthet vissza. Ebben a cikkben azt mutatjuk be, hogyan lehet ehhez a környezethez C/C++ részleteket illeszteni. A librutinok.so elérése Az első 2 cikkben megismertük a meglehetősen egyszerű, de a céljainknak eddig tökéletesen megfelelő librutinok.so könyvtárat Időközben kiegészült 2 új, hasonlóan kicsi függvénnyel (echo() és concatByC()), így tekintsük meg a használatához szükséges aktuális header fájlt (31. Programlista) // 3−1. P r o

g r a m l i s t a : A r u t i n o k h #i f n d e f RUTINOK H #d e f i n e RUTINOK H #i f d e f cplusplus e x t e r n "C" { #e n d i f #d e f i n e MAIN VERSION 1 #d e f i n e SUB VERSION 0 //#d e f i n e USE FV1 void f v 1 ( char ∗ s ) ; void f v 2 ( char ∗ s ) ; void f v 3 ( char ∗ s ) ; void gv1 ( char ∗ s ) ; void gv2 ( char ∗ s ) ; int o s s z e g ( int a , int b ) ; int kulonbseg ( int a , int b ) ; double sinWithDeg ( double x ) ; char ∗ echo ( char ∗ s ) ; void concatByC ( char d [ ] , char ∗ s ) ; #i f d e f } #e n d i f cplusplus #e n d i f /∗ RUTINOK H ∗/ A 3-2. Programlista a 2 új függvény implementációját mutatja Az echo() egyszerűen visszaadja a kapott karaktersorozatot. A concatByC() kap 2 karaktersorozatot és az elsőben 16 visszaadja a konkatenációját. Ehhez az sb[] tömböt is használja // 3−2. P r o g r a m l i s t a : A r u t i n o k −1 c 2 ú j å függvénye #i n c l u d e <s t d i o . h> #i n c l u d e

< s t d l i b . h> #i n c l u d e < s t r i n g . h> char sb [ 1 0 0 ] ; . char ∗ echo ( char ∗ s ) { return s ; } void concatByC ( char d [ ] , char ∗ s ) { strcat (d , s ) ; } Van tehát egy osztott könyvtárunk és egy header fájl, ami az eléréséhez, használatához szükséges deklarációkat tartalmazza. A kérdés az, hogy ezt mi módon tudnánk használni Free Pascal-ból? Szerencsénk van! A rendszerhez tartozik egy h2pas utility, ami képes a header fájlból az Object Pascal unit-ot automatikusan legenerálni. Erre a következő parancs megfelelő: h2pas −d −D − l l i b r u t i n o k . s o −o / r u t i n o k pp å . / cpp / InfNavCProj / r u t i n o k h Vegyük sorra az egyes paraméterek jelentését! • -d az external használat előírása, ugyanis minden függvényt a külső librutinok.so fájl implementál majd • -D az external függvény neve legyen az, ami az so-ban van. Programozási eszközök Object Pascal – C/C++

könyvtárak használata • -l librutinok.so Ezt az so könyvtárat használjuk az implementációhoz. • -o ./rutinokpp A generált Object Pascal unitnak ez lesz a neve • ./cpp/InfNavCProj/rutinokh A generálás alapja ez a header fájl lesz • cdecl Ez egy technikai különbségre utal, ami a C/C++ és Pascal eljáráshívás különbségéből adódik. Híváskor a paraméterek mindig a program STACK területére kerülnek, az eljárás onnan tudja kiolvasni azokat. A Pascal a paramétereket balróljobbra, míg a C/C++ jobbról-balra pakolja ide Amennyiben C/C++ rutint hívunk, akkor követnünk kell Pascalban is a jobbról-balra konvenciót, amit ez a kulcsszó jelöl meg. Ez fontos, hiszen az alprogram erre a sorrendre számít miközben futása során eléri a paraméterek értékeit A futtatás eredményeképpen keletkező rutinok unit forráskódját a 3-3. Programlista tartalmazza Ez egy teljesen automatikusan generált kód, aminek néhány sorához szeretnénk

egy kis magyarázatot fűzni. A 19 sorban elnevezte • external Ezzel lehet megadni, hogy az a generátor External library-nak a librutinok.so adott Pascal eljárás implementációja nem stringet, ami a könyvtárunk fizikai neve. A 37Pascalban, hanem egy külső helyen lesz el46 sorok között minden procedure és function érhető. (aminek a neveit felismerhetjük a header fájl tartalmából származtatva) ezzel a névvel linkeli be Tekintettel arra, hogy a rutinok unit összes ela külső könyvtárat. A következő 2 kulcsszó itt járása external, így a unit implementation része mindig előfordul: üres maradt. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // 3 −3. P r o g r a m l i s t a : A g e n e r á l t r u t i n o k u n i t unit rutinok ; interface { } A u t o m a t i c a l l y c o n v e r t e d by H2Pas 1 . 0 0 from / cpp / InfNavCProj / r u t i n o k h The f o l l o w i n g command l i n e p a r a m e t e r s were used : −d −D −l

l i b r u t i n o k . so −o . / r u t i n o k pp . / cpp / InfNavCProj / r u t i n o k h const E x t e r n a l l i b r a r y= ’ l i b r u t i n o k . s o ’ ; { S et u p as you need } Type Pchar = ^char ; {$IFDEF FPC} {$PACKRECORDS C} {$ENDIF} 17 Programozási eszközök 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 Object Pascal – C/C++ könyvtárak használata { $ i f n d e f RUTINOK H} { $ d e f i n e RUTINOK H} { C++ e x t e r n C c o n d i t i o n n a l removed } const MAIN VERSION = 1 ; SUB VERSION = 0 ; {#d e f i n e USE FV1 } procedure f v 1 ( s : Pchar ) ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name ’ f v 1 ’ ; procedure f v 2 ( s : Pchar ) ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name ’ f v 2 ’ ; procedure f v 3 ( s : Pchar ) ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name ’ f v 3 ’ ; procedure gv1 ( s : Pchar ) ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name

’ gv1 ’ ; procedure gv2 ( s : Pchar ) ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name ’ gv2 ’ ; function o s s z e g ( a : l o n g i n t ; b : l o n g i n t ) : l o n g i n t ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y å name ’ o s s z e g ’ ; function k u l o n b s e g ( a : l o n g i n t ; b : l o n g i n t ) : l o n g i n t ; c d e c l ; e x t e r n a l å E x t e r n a l l i b r a r y name ’ k u l o n b s e g ’ ; function sinWithDeg ( x : d o u b l e ) : d o u b l e ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name ’ å sinWithDeg ’ ; function echo ( s : Pchar ) : Pchar ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name ’ echo ’ ; procedure concatByC ( d : Pchar ; s : Pchar ) ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y name ’ å concatByC ’ ; 43 44 45 46 47 48 { C++ end o f e x t e r n C c o n d i t i o n n a l removed } 49 { $ e n d i f } 50 { RUTINOK H } 51 52

i m p l e m e n t a t i o n 53 54 end . A unit kipróbálását egy egyszerű konzol programmal fogjuk elvégezni, amit a 3.1 ábra bal oldali editor ablaka mutat. Az ábra a Lazarus IDE-t jeleníti meg, ahogy a Project Inspector segítségével (a + gombra kattintva) beimportáltuk a rutinokpp fájlt, így elérhetővé vált a unit is. Az EgyszeruConsoleos program nem túl bonyolult. A már ismert sinWithDeg() mellett az echo() és concatByC() használatát teszteli le, aminek a futási képe így néz ki: ./ EgyszeruConsoleos S t a r t program N y i r i Imre 18 12345 é s őŐúÚűŰíÍóÓ . 0.50000 End program Az echo() tényleg visszaadja a stringet. A concatByC() a s t r : a r r a y [ 1 . 1 0 0 ] o f char = ’ 1 2 3 4 5 ’ ; helyen megadott buffert használja, majd a következő sor tényleg azt írja ki, amit vártunk. A 0.50000 érték pedig a sin(30) fok Szeretnénk kiemelni még a program elejét is, ahol a uses szekciónál láthatjuk a rutinok unit használatának

igénylését. Programozási eszközök Object Pascal – C/C++ könyvtárak használata 3.1 ábra: Lazarus - A rutinok unit importálása Fejlettebb C szerkezetek használata Célunk az, hogy összetettebb C nyelvi struktúrákat is kipróbáljunk Pascal program-elemként. Ehhez most nézzük meg az erre a célra elkészített header fájlt: // 3−4. P r o g r a m l i s t a : p a s c a l −r u t i n s h #define TRUE 1 #define FALSE 0 typedef i n t S a l a r y ; typedef i n t b o o l ; typedef struct { unsigned e x p e r i e n c e d unsigned p r i o r i t y unsigned c a n d i d a t e unsigned t r a i n e d } EmployeeFlags ; : : : : 1; 1; 1; 1; char∗ name ; int category ; bool expert ; long s a l a r y ; EmployeeFlags f l a g s ; double p e r c e n t ; } Worker ; typedef struct { char∗ name ; int category ; b o o l manager ; long s a l a r y ; long bonus ; EmployeeFlags f l a g s ; double p e r c e n t ; } Boss ; typedef union { Worker w ; Boss b; } Employee ; typedef

struct { 19 Programozási eszközök Object Pascal – C/C++ könyvtárak használata typedef enum { S p r i n g , Summer , Autumn , Winter å } Season ; i n t i n c r e a s e S a l a r y ( Employee ∗ e , i n t d e l t a , å bool isBoss ) { i f ( isBoss ) { e−>b . s a l a r y += d e l t a ; return e−>b . s a l a r y ; } { e−>w . s a l a r y += d e l t a ; return e−>w . s a l a r y ; } } typedef ); typedef typedef ; typedef typedef i n t ( ∗ MyFunction ) ( double x1 , double x2å i n t ( ∗ PFunction ) ( i n t a , i n t b ) ; i n t ( ∗ PFunctionArray [ 5 ] ) ( i n t a , i n t b ) å i n t ∗ PInt ; int ∗ IntPointerArray [ 7 ] ; typedef i n t I n t A r r a y [ 7 ] ; typedef I n t A r r a y ∗ PIntArray ; extern i n t i n c r e a s e W o r k e r S a l a r y ( Worker ∗ w, i n t å delta ) ; extern i n t i n c r e a s e B o s s S a l a r y ( Boss ∗ b , i n t å delta ) ; extern i n t i n c r e a s e S a l a r y ( Employee ∗ e , i n t å delta

, bool isBoss ) ; extern b o o l i s G o o d S a l a r y ( i n t s a l a r y ) ; extern void s e t E m p l o y e e F l a g s ( Employee ∗ e , b o o l å i s B o s s , EmployeeFlags f l a g s ) ; extern b o o l g e t T r a i n e d ( Employee ∗ e , b o o l å isBoss ) ; extern void a n O p e r a t i o n ( Worker ∗w, PFunction å op , i n t d e l t a ) ; Aki ismeri az alap C nyelvet, annak a fenti kód úgy tűnhet, hogy itt összehordtuk a C nyelv csaknem összes elemét. Az egyszerű típusnév definíció mellett (példa: typedef int Salary;) láthatunk struktúra megadást: Worker, Boss Ezek a pascal record -nak felelnek meg. Deklaráltunk egy EmployeeFlags szerkezetet, ami biteken tárol logikai értékeket. A union (Employee) a változó record. A következő sorokban többféle pointer típust is megalkottunk. A header fájl 7 függvény deklarációjával zárul, aminek implementációját a következő 3-5. Programlista mutatja Nem túl bonyolúltak, ezért nem is fűzünk

további magyarázatot hozzá. // 3−5. P r o g r a m l i s t a : p a s c a l −r u t i n s c #include " p a s c a l −r u t i n s . h" i n t i n c r e a s e W o r k e r S a l a r y ( Worker ∗ w, i n t d e l t a ) { w−>s a l a r y += d e l t a ; return w−>s a l a r y ; } i n t i n c r e a s e B o s s S a l a r y ( Boss ∗ b , i n t d e l t a ) { b−>s a l a r y += d e l t a ; return b−>s a l a r y ; } 20 bool isGoodSalary ( int s a l a r y ) { i f ( s a l a r y > 1000000 ) return TRUE; e l s e return FALSE ; } void s e t E m p l o y e e F l a g s ( Employee ∗ e , b o o l i s B o s s å , EmployeeFlags f l a g s ) { i f ( isBoss ) { e−>b . f l a g s = f l a g s ; } { e−>w . f l a g s = f l a g s ; } } b o o l g e t T r a i n e d ( Employee ∗ e , b o o l i s B o s s ) { i f ( isBoss ) { return ( e−>b . f l a g s t r a i n e d != 0 ) ; } { return ( e−>w . f l a g s t r a i n e d != 0 ) ; } } void a n O p e r a t i o n (

Worker ∗w, PFunction op , i n t å delta ) { w−>s a l a r y = op (w−>s a l a r y , d e l t a ) ; } A 3-6. Programlista az előzőekben megalkotott kód C nyelven való tesztelésére szolgál Láthatjuk, hogy ezeket a nyelvi elemeket hogyan használjuk, de még maradunk a C nyelv keretein belül. Ez hasznos lesz, amikor mindezt már pascal nyelven fogjuk használni, ugyanis ismerős kódot kell majd ott megérteni és összehasonlíthatjuk a C-beli alkalmazással. // 3−6. P r o g r a m l i s t a : t e s t c #include " p a s c a l −r u t i n s . h" Programozási eszközök i n t add ( i n t a , i n t b ) { return a+b ; } i n t main ( ) { p r i n t f ( " H e l l o ␣World ! ␣ S t a r t ␣ t e s t . n" ) ; EmployeeFlags f l a g s ; f l a g s . c a n d i d a t e =1; f l a g s . e x p e r i e n c e d =0; f l a g s . p r i o r i t y =1; f l a g s . t r a i n e d =1; Worker w ; w . s a l a r y =10000; w . name=" N y i r i ␣ Imre " ;

w . c a t e g o r y =1; w . e x p e r t =1; w. percent =056; w . f l a g s=f l a g s ; Object Pascal – C/C++ könyvtárak használata p r i n t f ( " F i z e t é s : ␣%i ␣ Ft " , w . s a l a r y ) ; } return 1 ; A pascal-rutins.c kódot azért készítettük, hogy egy osztott könyvtár legyen belőle, amit most így hoztunk létre (eredménye: libpasruts.so101 ): g c c −fPIC −c p a s c a l −r u t i n s . c g c c −s h a r e d −Wl,−soname , l i b p a s r u t s . s o 1 −o å l i b p a s r u t s . s o 1 0 1 p a s c a l −r u t i n s o A 3.2 ábra mutatja a futási képét annak a Lazarus (Object Pascal) kódnak, amit erre a könyvtárra építve készítettünk. A soron következő részekben ennek a forráskódját láthatjuk Boss b ; Employee e ; e . w c a t e g o r y=w c a t e g o r y ; e . w e x p e r t=w e x p e r t ; e . w f l a g s=w f l a g s ; e . w name=w name ; e . w p e r c e n t=w p e r c e n t ; e . w s a l a r y=w s a l

a r y ; p r i n t f ( "%i " , i s G o o d S a l a r y ( 1 0 0 0 0 0 0 0 0 0 ) ) ; p r i n t f ( " F i z e t é s : ␣%i ␣ Ft " , w . s a l a r y ) ; i n c r e a s e W o r k e r S a l a r y (&w, 5 0 0 0 ) ; p r i n t f ( " F i z e t é s : ␣%i ␣ Ft " , w . s a l a r y ) ; p r i n t f ( " F i z e t é s : ␣%i ␣ Ft " , e . w s a l a r y ) ; i n c r e a s e S a l a r y (&e , 3 0 0 0 , 0 ) ; p r i n t f ( " F i z e t é s : ␣%i ␣ Ft " , e . w s a l a r y ) ; p r i n t f ( " Trai ned : ␣%i " , g e t T r a i n e d (&e , 0 ) ) å ; EmployeeFlags f l a g s 2 ; f l a g s . c a n d i d a t e =1; f l a g s . e x p e r i e n c e d =0; f l a g s . p r i o r i t y =1; f l a g s . t r a i n e d =0; s e t E m p l o y e e F l a g s (&e , 0 , f l a g s 2 ) ; p r i n t f ( " Trai ned : ␣%i " , g e t T r a i n e d (&e , 0 ) ) å ; p r i n t f ( w . name ) ; w . name=" Másik ␣ név

" ; p r i n t f ( w . name ) ; p r i n t f ( e . w name ) ; PFunction p f u n c = add ; a n O p e r a t i o n (&w, add , 7 0 0 0 ) ; 3.2 ábra: A TestGUIForC program Az első és példánk szempontjából legfontosabb a h2pas által generált (a pascal-rutins.h alapján) pascal unit (3-7. Programlista) A unit-ot kézzel egy kicsit javítottuk, de alapvetően automatikusan generálódott és hasonlít az előző példában megismert szerkezethez. A 22-68 sorok között láthatjuk a C header által generált megfelelő pascal típusokat. A 75-76 sorokban eredetileg TRUE és FALSE szerepelt, de ezt át kellett nevezni, hiszen ezek foglalt szavak. A 7986 sorok az EmployeeFlags kezeléséhez szükségesek Az implementation rész 119-164 sorai pedig ezt valósítják meg, mert a pascal nem rendelkezik hasonló bitenkénti mező megadási lehetőséggel. Ez az oka, hogy most ebbe a szekcióba is 21 Programozási eszközök Object Pascal – C/C++ könyvtárak használata

generálódott kód, hiszen ezt nem fogjuk megta- miatt szükséges, azaz azt kell itt megadni, hogy lálni a könyvtári so fájlban sem. A 7 külső függ- pascal-ból milyen felületen hívjuk a libpasrutsso vény (97-116 sorok) csak az interface megadása rutinjait. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 // 3 −7. P r o g r a m l i s t a : A p a s c a l r u t i n s u n i t unit pascal rutins ; interface { } A u t o m a t i c a l l y c o n v e r t e d by H2Pas 1 . 0 0 from p a s c a l −r u t i n s h The f o l l o w i n g command l i n e p a r a m e t e r s were used : −d −D −l l i b p a s r u t s . so 1 0 1 −o . / p a s c a l −r u t i n s pp p a s c a l −r u t i n s . h const E x t e r n a l l i b r a r y = ’ l i b p a s r u t s . s o 1 0 1 ’ ; { S et u p as you need } type PInt = ^ l o n g i n t ; I n t P o i n t e r A r r a y = array [ 0 . 6 ] of ^ l o

n g i n t ; I n t A r r a y = array [ 0 . 6 ] of l o n g i n t ; PIntArray = ^I n t A r r a y ; Season = ( Spring , Summer , Autumn , Winter ) ; Salary = longint ; bool = longint ; EmployeeFlags = record f l a g 0 : word ; end ; Worker = record Name : ^char ; category : longint ; expert : bool ; salary : longint ; f l a g s : EmployeeFlags ; percent : double ; end ; Boss = record Name : ^char ; category : longint ; 22 Programozási eszközök 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 Object Pascal – C/C++ könyvtárak használata manager : b o o l ; salary : longint ; bonus : l o n g i n t ; f l a g s : EmployeeFlags ; percent : double ; end ; Employee = record case l o n g i n t of 0 : (w : Worker ) ; 1 : ( b : Boss ) ; end ; PBoss = ^Boss ; PEmployee = ^Employee ; PWorker = ^Worker ; MyFunction = function ( x1 : d o u b l e ; x2 : d o u b l e ) : l o n g i n t ;

c d e c l ; PFunction = function ( a : l o n g i n t ; b : l o n g i n t ) : l o n g i n t ; c d e c l ; // PFunctionArray = array [ 0 . 4 ] of function ( a : l o n g i n t ; b : l o n g i n t ) : l o n g i n t ; c d e c l ; // PFunctionArray = array [ 0 . 4 ] of PFunction ; c d e c l ; {$IFDEF FPC} {$PACKRECORDS C} {$ENDIF} const XTRUE = 1 ; XFALSE = 0 ; const bm EmployeeFlags experienced = $1 ; bp EmployeeFlags experienced = 0 ; bm EmployeeFlags priority = $2 ; bp EmployeeFlags priority = 1 ; bm EmployeeFlags candidate = $4 ; bp EmployeeFlags candidate = 2 ; bm EmployeeFlags trained = $8 ; bp EmployeeFlags trained = 3 ; function e x p e r i e n c e d ( var a : EmployeeFlags ) : dword ; procedure s e t e x p e r i e n c e d ( var a : EmployeeFlags ; experienced : dword ) ; function p r i o r i t y ( var a : EmployeeFlags ) : dword ; procedure s e t p r i o r i t y ( var a : EmployeeFlags ; p r i o r i t y : dword ) ; function c a n d i d a t e ( var a : EmployeeFlags ) :

dword ; procedure s e t c a n d i d a t e ( var a : EmployeeFlags ; candidate : dword ) ; function t r a i n e d ( var a : EmployeeFlags ) : dword ; procedure s e t t r a i n e d ( var a : EmployeeFlags ; trained : dword ) ; function i n c r e a s e W o r k e r S a l a r y (w: PWorker ; d e l t a : l o n g i n t ) : l o n g i n t ; c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y Name ’ i n c r e a s e W o r k e r S a l a r y ’ ; 23 Programozási eszközök Object Pascal – C/C++ könyvtárak használata 100 function i n c r e a s e B o s s S a l a r y ( b : PBoss ; d e l t a : l o n g i n t ) : l o n g i n t ; 101 c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y Name ’ i n c r e a s e B o s s S a l a r y ’ ; 102 103 function i n c r e a s e S a l a r y ( e : PEmployee ; d e l t a : l o n g i n t ; i s B o s s : b o o l ) : l o n g i n t ; 104 c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y Name ’ i n c r e a s e S a l a r y

’ ; 105 106 function i s G o o d S a l a r y ( s a l a r y : l o n g i n t ) : b o o l ; c d e c l ; 107 e x t e r n a l E x t e r n a l l i b r a r y Name ’ i s G o o d S a l a r y ’ ; 108 109 procedure s e t E m p l o y e e F l a g s ( e : PEmployee ; i s B o s s : b o o l ; f l a g s : EmployeeFlags ) ; 110 c d e c l ; e x t e r n a l E x t e r n a l l i b r a r y Name ’ s e t E m p l o y e e F l a g s ’ ; 111 112 function g e t T r a i n e d ( e : PEmployee ; i s B o s s : b o o l ) : b o o l ; c d e c l ; 113 e x t e r n a l E x t e r n a l l i b r a r y Name ’ g e t T r a i n e d ’ ; 114 115 procedure anOperation (w: PWorker ; op : PFunction ; d e l t a : l o n g i n t ) ; c d e c l ; 116 e x t e r n a l E x t e r n a l l i b r a r y Name ’ anOperation ’ ; 117 118 119 i m p l e m e n t a t i o n 120 121 function e x p e r i e n c e d ( var a : EmployeeFlags ) : dword ; 122 begin 123 e x p e r i e n c e d := ( a . f l a g 0 and bm EmployeeFlags

experienced ) s h r 124 bp EmployeeFlags experienced ; 125 end ; 126 127 procedure s e t e x p e r i e n c e d ( var a : EmployeeFlags ; experienced : dword ) ; 128 begin 129 a . f l a g 0 := a f l a g 0 or ( ( experienced s h l bp EmployeeFlags experienced ) and 130 bm EmployeeFlags experienced ) ; 131 end ; 132 133 function p r i o r i t y ( var a : EmployeeFlags ) : dword ; 134 begin 135 p r i o r i t y := ( a . f l a g 0 and bm EmployeeFlags priority ) s h r å bp EmployeeFlags priority ; 136 end ; 137 138 procedure s e t p r i o r i t y ( var a : EmployeeFlags ; p r i o r i t y : dword ) ; 139 begin 140 a . f l a g 0 := a f l a g 0 or ( ( p r i o r i t y s h l bp EmployeeFlags priority ) and 141 bm EmployeeFlags priority ) ; 142 end ; 143 144 function c a n d i d a t e ( var a : EmployeeFlags ) : dword ; 145 begin 146 c a n d i d a t e := ( a . f l a g 0 and bm EmployeeFlags candidate ) s h r å bp EmployeeFlags candidate ; 147 end ; 148 149 procedure s e t c a

n d i d a t e ( var a : EmployeeFlags ; candidate : dword ) ; 24 Programozási eszközök 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Object Pascal – C/C++ könyvtárak használata begin a . f l a g 0 := a f l a g 0 or ( ( candidate s h l bp EmployeeFlags candidate ) and bm EmployeeFlags candidate ) ; end ; function t r a i n e d ( var a : EmployeeFlags ) : dword ; begin t r a i n e d := ( a . f l a g 0 and bm EmployeeFlags trained ) s h r bp EmployeeFlags trained ; end ; procedure s e t t r a i n e d ( var a : EmployeeFlags ; trained : dword ) ; begin a . f l a g 0 := a f l a g 0 or ( ( trained s h l bp EmployeeFlags trained ) and bm EmployeeFlags trained ) ; end ; end . // 3 −8. P r o g r a m l i s t a : A TestForm u n i t u n i t TestForm ; {$mode o b j f p c }{$H+} interface uses C l a s s e s , S y s U t i l s , F i l e U t i l , Forms , C o n t

r o l s , Graphics , D i a l o g s , S t d C t r l s , ExtCtrls , pascal rutins ; type { TForm1 } TForm1 = c l a s s (TForm) btnOK : TButton ; Button1 : TButton ; checkGroup : TCheckGroup ; e d t F i z e t e s : TEdit ; edtText : TEdit ; b t n I n i t W o r k e r : TToggleBox ; L ab el 1 : TLabel ; L ab el 2 : TLabel ; procedure btnInitWorkerChange ( Sender : TObject ) ; procedure btnOKClick ( Sender : TObject ) ; procedure B u t t o n 1 C l i c k ( Sender : TObject ) ; procedure checkGroupClick ( Sender : TObject ) ; private { private declarations } public { public declarations } 25 Programozási eszközök Object Pascal – C/C++ könyvtárak használata 34 end ; 35 36 var 37 Form1 : TForm1 ; 38 39 d o l g o z o : Worker ; 40 flags : EmployeeFlags ; 41 42 i m p l e m e n t a t i o n 43 44 {$R ∗ . l f m } 45 46 { TForm1 } 47 48 procedure TForm1 . btnOKClick ( Sender : TObject ) ; 49 begin 50 edtText . Text := ’ Alma ’ ; 51 end ; 52 53 procedure TForm1 . B u t t o n 1 C l

i c k ( Sender : TObject ) ; 54 var 55 s : string ; 56 begin 57 i n c r e a s e W o r k e r S a l a r y ( @dolgozo , 5 0 0 0 ) ; 58 s t r ( dolgozo . salary , s ) ; 59 e d t F i z e t e s . Text := s ; 60 end ; 61 62 procedure TForm1 . checkGroupClick ( Sender : TObject ) ; 63 begin 64 65 end ; 66 67 procedure TForm1 . btnInitWorkerChange ( Sender : TObject ) ; 68 var 69 s : string ; 70 begin 71 dolgozo . category :=1; 72 d o l g o z o . name:= ’ N y i r i ␣ Imre ’ ; 73 dolgozo . s a l a r y :=100000; 74 d o l g o z o . e x p e r t :=XTRUE; 75 dolgozo . percent :=565; 76 set candidate ( f l a g s , 1) ; 77 set experienced ( f l a g s , 1) ; 78 s e t p r i o r i t y ( f l a g s , 0) ; 79 set trained ( f l a g s , 0) ; 80 d o l g o z o . f l a g s := f l a g s ; 81 edtText . Text := d o l g o z o name ; 82 s t r ( dolgozo . salary , s ) ; 83 e d t F i z e t e s . Text := s ; 84 checkGroup . Checked [ 0 ] : = ( d o l g o z o c a t e g o r y =1) ; 85 checkGroup . Checked [ 1 ] :

= t r a i n e d ( f l a g s ) =1; 26 Programozási eszközök Object Pascal – C/C++ könyvtárak használata 86 checkGroup . Checked [ 2 ] : = e x p e r i e n c e d ( f l a g s ) =1; 87 end ; 88 89 end . A 3.2 ábra formját a 3-8 Programlista tar- tud majd ezzel szerkesztődni A libcs-libso a talmazza, a 11. sorban láthatjuk a pascal rutins Testcpp és burkolocpp fájlok fordításával keletunit használatát is A figyelmet a btnInitWor- kezett ker és a Button1 gomb eseménykezelőire sze- // 3 −11. P r o g r a m l i s t a : b u r k o l o h retnénk felhívni. Az első a 67-86 sorok között extern "C" van kifejtve, a program futása során ezt a gom- { bot nyomtuk meg először, ami feltölt egy dol- } i n t b u r k o l o ( i n t a , i n t b ) ; gozo record-ot (a 39. sorban definiáltuk) A futás során a 2. lépés a Button1 gombon való // 3 −12 P r o g r a m l i s t a : b u r k o l o cpp click volt, a kódját az 53-60 közötti soroknál lát-

#include " Test . h" hatjuk, azaz a dolgozó fizetését 5000 egységgel #include " b u r k o l o . h" emeltük meg. extern "C" { C++ osztályok használata int burkolo ( int a , int b ) { Test t e s t ; return t e s t . egyop ( a , b ) ; } A C++ közvetlen illesztése nem triviális, } ugyanis az objektum nevek átkódoltan kerülnek Végül a 3-13. Programlista a generált pascal be az object fájlba. Ennek oka természetesen köunitot mutatja be, ami modulként tud kapcsovetkezik a C++ lehetőségeiből, de itt ezt most lódni a pascal forráskód más elemeihez. nem részletezzük. // 3−9. P r o g r a m l i s t a : Test h c l a s s Test { public : i n t egyop ( i n t a , i n t b ) ; }; // 3 −10. P r o g r a m l i s t a : Test cpp #include " Test . h" i n t Test : : egyop ( i n t a , i n t b ) { return a+b ; } // 3 −13. P r o g r a m l i s t a : A b u r k o l o u n i t unit burkolo ; interface const E x t e r n a l l i b r a r y=

’ l i b c s −l i b . s o ’ ; {å S et up as you need } {$IFDEF FPC} {$PACKRECORDS C} {$ENDIF} function b u r k o l o ( a : l o n g i n t ; b : l o n g i n t å A 3-9. és 3-10 listák egy Test nevű osztályt ) : longint ; cdecl ; external å E x t e r n a l l i b r a r y name ’ b u r k o l o ’ ; adnak meg. A 3-11 és 3-12 listák pedig egy segéd C++ modult, ahol extern "C" utasításimplementation sal kértük, hogy a burkolo név ne változzon meg end . az object fájlban, így a pascal is könnyen össze 27 Programozási eszközök 4. C# – C/C++ könyvtárak használata C# – C/C++ könyvtárak használata A C# nyelv és a .NET környezet a Microsoft fejlesztése, de létezik hozzá jó minőségű linuxos implementáció, a Mono Az eddigiek folytatásaként most azt vizsgáljuk meg, hogy a C# programjaink számára miként tehetjük elérhetővé a C/C++ nyelven készült kódokat. Ehhez egy SWIG (Simplified Wrapper and Interface Generator )

nevű eszközt fogunk használni ami egy igazi svájci bicska az ilyen típusú feladatok megoldásához. Webhelye: http://wwwswigorg/ Linux, OS-X/Darwin és MS Windows környezetek alatt egyaránt használható. Példáinkban a C/C++ nyelven megírt programrészek más számítógépes nyelvekhez, platformokhoz való integrálását mutatjuk be, eközben így azt is megtanuljuk, hogy egy létező bináris könyvtárat hogyan lehet illeszteni a célkörnyezethez. Ebben a cikkben a C# nyelvhez való illesztés példáin keresztül adunk erre ízelőt. A swig 1996 óta fejlődik, magas tudású szoftver, amit – jellegénél fogva – elsősorban rendszerintegrációs és/vagy prototípus készítési feladatokhoz lehet hatékonyan használni. Még ma is intenzíven fejlesztik, amit innen is áttekinthetünk: http://www.swigorg/historyhtml Ismeri az ANSI C/C++ szintaxist, így használata meglehetősén széles skálán lehetséges. A librutinok.so használata Az eddigi

hagyományainknak megfelelően most is nézzük meg az 1. cikkben elkészített librutinokso használatát, persze most C# környezetből Mindehhez a swig eszközt hívjuk segítségül, aminek a használata alapszinten könnyű, bár igen kifinomult megoldásokat is lehetővé tesz. Ennek első lépése egy swig konfigurációs fájl (aminek a kiterjesztése a konvenció szerint .swg vagy .i szokott lenni) készítése: /∗ r u t i n o k . swg ∗/ %module Rutinok %{ #i n c l u d e " r u t i n o k . h" %} int osszeg ( int a , int b) ; 28 i n t kulonbseg ( i n t a , i n t b) ; d o u b l e sinWithDeg ( d o u b l e x ) ; c h a r ∗ echo ( c h a r ∗ s ) ; Láthatjuk, hogy ez egyszerű. A module neve Rutinok lesz, ami egyben a C#-ból használt osztály neveként is feltűnik majd. Van egy automatizmus, ami ilyenkor a hozzá tartozó so fájlt is ilyen néven keresi, ezért az eredeti librutinok.sora egy libRutinokso linket is tettünk (az is lehetett volna, hogy a module

neve rutinok lesz, de a kis betűs class név nem szép). A %{%} között a használt header fájl nevét kell megadnunk, majd felsorolni azokat a függvényeket, amire illesztő felületet kérünk és ezzel bekerül a generálandó Rutinok.cs C# fájlba A fentiekben látható, hogy itt most 4 ilyen meghívható nevet jegyeztünk be. Ennyit kell mindösszesen tennünk és már a következő paranccsal hívhatjuk is a swig-et: s w i g −c s h a r p r u t i n o k . swg Az swg fájl független a generálandó célnyelvtől, ami egy nagyon kiváló tulajdonság. Ugyanazt a leírót használhatjuk C#, Java, PHP, Python, Perl, R, Ruby, Tcl/Tk esetén is A -csharp kapcsolóval természetesen most C# illesztőt kérünk, ami esetünkben az alábbi 3 fájl legenerálását eredményezte: • rutinok wrap.c • RutinokPINVOKE.cs • Rutinok.cs Programozási eszközök C# – C/C++ könyvtárak használata A Rutinok.cs tartalmazza azt a felületet, amit helyén csak megadjuk újra az

include fájl nevét közvetlenül használni fogunk, a 4-1. Program- /∗ r u t i n o k swg − 2 v á l t o z a t ∗/ lista mutatja a tartalmát. A rutinok wrapc és %module Rutinok RutinokPINVOKE.cs fájlok belsejével nem kell %{ törődnünk, csak használni kell őket. Az elsőt le %} #i n c l u d e " r u t i n o k h" kell fordítanunk és be kell tenni az .so lib-be Amennyiben nem lenne libRutinok.so könyvtá- %i n c l u d e " r u t i n o k h" runk, akkor esetünkben ezt a 2 lépést kell csiKész vagyunk az illesztéssel, ezért írjunk egy nálni: C# tesztprogramot, ami használja is azt. Ennek g c c −c −fPIC r u t i n o k −1. c r u t i n o k −2 c matek−å a neve runme.cs lesz (4-2 Programlista) r u t i n o k . c rutinok wrap c g c c −s h a r e d r u t i n o k −1. o r u t i n o k −2 o matek−å r u t i n o k . o rutinok wrap o −o l i b R u t i n o k s o // 4−2. P r o g r a m l i s t a : runme c s // 4−1. P r o g r a m l i

s t a : Rutinok c s p u b l i c c l a s s runme { /∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ s t a t i c void Main ( ) { C o n s o l e . W r i t e L i n e ( Rutinok o s s z e g ( 3 4 , 5 6 ) ) ; C o n s o l e . W r i t e L i n e ( Rutinok sinWithDeg ( 3 0 ) ) ; C o n s o l e . W r i t e L i n e ( Rutinok k u l o n b s e g ( 3 4 , 5 6 ) å ); C o n s o l e . W r i t e L i n e ( Rutinok echo ( " H e l l o ␣ echo ! "å ) ); } } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− This f i l e was a u t o m a t i c a l l y g e n e r a t e d by SWIG ( h t t p : / /www. s w i g o r g ) Version 2 . 0 7 Do n o t make c h a n g e s t o t h i s f i l e u n l e s s you know what you a r e doing−−modify t h e SWIG i n t e r f a c e f i l e i n s t e a d . −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/ u s i n g System ; u s i n g

System . Runtime I n t e r o p S e r v i c e s ; p u b l i c c l a s s Rutinok { p u b l i c static int o s s z e g ( int a , int b ) { i n t r e t = RutinokPINVOKE . o s s z e g ( a , b ) ; return r e t ; } p u b l i c static int kulonbseg ( int a , int b ) { i n t r e t = RutinokPINVOKE . k u l o n b s e g ( a , b ) ; return r e t ; } p u b l i c s t a t i c double sinWithDeg ( double x ) { double r e t = RutinokPINVOKE . sinWithDeg ( x ) ; return r e t ; } p u b l i c s t a t i c s t r i n g echo ( s t r i n g s ) { s t r i n g r e t = RutinokPINVOKE . echo ( s ) ; return r e t ; } u s i n g System ; A teszt forráskódja triviális, további megjegyzéseket nem fűzünk hozzá. A következő lépés a fordítás és futtatás Az alábbi utasítás a mono (egyik) C# fordítójával lefordít minden cs kiterjesztésű forrást az aktuális könyvtárban, majd a generált kódot a runme.exe bináris fájlba helyezi el. dmcs −out : runme . e x e ∗ c s A futtatási kép így

néz ki: . / runme e x e 90 0 ,499999999481858 −22 H e l l o echo ! Láthatjuk, hogy a programot egyszerűen csak a parancssorba írva futtathatjuk. A sinFelhívjuk a figyelmet arra, hogy a Rutinok WithDeg(30) eredményével kapcsolatosan 2 fonclass valóban csak a kért 4 darab metódust tar- tos dolgot szeretnék kiemelni: talmazza. Abban az esetben, ha egy header fájl összes függvényére szeretnénk illesztést kérni, • Nem 0.5000 a kiírt érték, mert most semakkor azok felsorolása helyett a lenti 2 váltomit sem tettünk a double érték kerekítése zatú swg fájl is használható, azaz a felsorolás ügyében. } 29 Programozási eszközök • A metódus – remélhetőleg még emlékszünk erre – a libm.so matematikai könyvtárat is használja, azaz láthatóan ez is feloldásra került a futás során. C# – C/C++ könyvtárak használata g++ h e l l o . o e l s o o −o p r o g i e x e h e l l o . o : I n f u n c t i o n ‘ main ’ : h e l l o .

cpp : ( t e x t +0x3d ) : u n d e f i n e d r e f e r e n c e t o å ‘ osszead ( int , int ) ’ c o l l e c t 2 : error : ld returned 1 exit status Jelen példánkat azzal szeretnénk zárni, hogy a rutinok.swg 2 változata helyett közvetlenül is használhatjuk a rutinok.h header fájlt, azaz teljes import esetén valójában nem is kell swig konfigurációs leírást készítenünk Hoppá! Ez nem ment, nem találja az osszead(int, int) függvényt a hello.cpp Az elso.c egy C program C fordítóval (gcc), míg a hello.cpp egy C++ kód C++ fordítóval (g++) fordítva. Nézzük meg az elsoo fájl belsejét: s w i g −c s h a r p −module Rutinok r u t i n o k . h nm e l s o . o 00000000 T o s s z e a d A C és C++ együtt A továbbiakhoz jól fog jönni annak a megértése, hogy a C és C++ nyelveket hogyan tudjuk együtt használni. Ehhez tekintsük az alábbi kis C programot. Majd a hello.o fájlból egy részletet is: U osszead ( int , int ) U s t d : : o str ea m : : o

p e r a t o r <<( i n t ) U s t d : : o str ea m : : o p e r a t o r <<(s t d : : o st re am& ( ∗ ) ( å s t d : : o st re am &) ) U std : : ios base : : I n i t : : I n i t ( ) U std : : ios base : : I n i t : : ~ I n i t ( ) U std : : cout // e l s o . c Valóban láthatjuk, hogy C++ esetén az object fájlban az osszead() neve kódolt abban az értelemben, hogy a paraméter típusok nevei is return a+b ; } belekerülnek abban a névbe, ahogy azt elneMajd nézzük meg az őt használó C++ for- vezi a szimbólumtáblában. Ekkor persze hiába mondtunk extern-t, ilyen nevűt nem fog tarásfájlt is: lálni az elso.o fájlban, ugyanis azt C fordítóval // h e l l o . cpp csináltuk, ami ilyesmi kódolással nem foglalko#include <i o s t r e a m > zik. A C++ azért kódolta el a függvény nevét, hogy a forráskódban több ilyen nevű is lehessen, extern i n t o s s z e a d ( int , i n t ) ; amennyiben azok paraméterei eltérnek. Ugyani n t main ( ) {

akkor ez a többértelműség az object fájlban már s t d : : c o u t << " H e l l o ␣World ! " << s t d : : e n d l ; nem lesz meg, ahogy láthattuk. Mi akkor a megs t d : : c o u t << o s s z e a d ( 3 4 , 6 ) ; return 0 ; oldás erre az esetre? A C++ extern kulcsszónak } van egy módosult alakja: extern „C”. Használjuk A hello.cpp C++ kód használja az osszead() ezt, ahogy a javított hellocpp tartalmazza: függvényt, emiatt extern módosítóval be kell // h e l l o . cpp őt mutatni (deklarálni kell, amit általában hea- #include <i o s t r e a m > der fájlban teszünk, de most eltekintünk ettől). extern "C" i n t o s s z e a d ( int , i n t ) ; Most fordítsuk le mindkettőt! int { osszead ( int a , int b ) g c c −c e l s o . c g++ −c h e l l o . cpp Kaptunk 2 object fájlt, szerkesszük össze őket egy progi.exe futtatható programmá! 30 i n t main ( ) { s t d : : c o u t << " H e l l o ␣World !

" << s t d : : e n d l ; s t d : : c o u t << o s s z e a d ( 3 4 , 6 ) ; return 0 ; } Programozási eszközök C# – C/C++ könyvtárak használata Nézzük meg a keletkezett hello.o egy részle- fájltranszfer-folytatást és a HTTP proxyt A tét, láthatjuk, hogy az osszead -ból kikerült min- következő példában bemutatjuk a használatát, den típusinformáció: először egy tiszta C++ programon keresztül. A 4-3. Programlista a fejlesztendő CurlHelper oszU osszead U s t d : : ostream : : o p e r a t o r <<( i n t ) tály deklarációját tartalmazza, egyetlen hasznos U s t d : : ostream : : o p e r a t o r <<(s t d : : ostream& ( ∗ ) ( å metódussal, a getHttp() hívás lehetőségével. A s t d : : ostream &) ) U std : : ios base : : I n i t : : I n i t ( ) metódus a paraméterül kapott URL alapján leU std : : ios base : : I n i t : : ~ I n i t ( ) U std : : cout tölt egy html lapot. Próbáljuk meg újra a szerkesztést,

sikerülni fog! A futási eredményt a következő: . / p r o g i exe // 4−3. P r o g r a m l i s t a : C u r l H e l p e r h #i f n d e f CURLHELPER H #define CURLHELPER H H e l l o World ! #include <i o s t r e a m > #include <s t r i n g > #include <c u r l / c u r l . h> A curl használata using namespace s t d ; class CurlHelper { A cURL több protokollon keresztüli fájlelérést public : CurlHelper ( ) ; biztosít egy parancssori eszköz és egy könyvtár C u r l H e l p e r ( const C u r l H e l p e r& o r i g ) ; segítségével. A libcurl egy ingyenes kliensolvirtual ~CurlHelper ( ) ; dali URL-transzfer könyvtár, amely támogatja char ∗ g e t H t t p ( char ∗ u r l ) ; az FTP, FTPS, Gopher, HTTP, HTTPS, SCP, s t r i n g g e t H t t p ( const s t r i n g u r l ) ; SFTP, TFTP, Telnet, DICT, fájl URI-séma, private : LDAP, LDAPS, IMAP, POP3, SMTP és RTSP } ; protokollokat. A könyvtár kezeli a HTTPS tanú- #endif /∗ CURLHELPER H ∗/

sítványokat, a HTTP POST-ot, a HTTP PUTA 4-4. Programlista az osztály implementáot, az FTP-feltöltést, Kerberost, a HTTP űrlap alapú feltöltést, a proxykat, a sütiket, a cióját tartalmazza, a hívott függvények a lubcurl felhasználónév-jelszóval történő autentikációt, a függvényei. 1 // 4−4. P r o g r a m l i s t a : C u r l H e l p e r cpp 2 3 #include " C u r l H e l p e r . h" 4 5 int w r i t e r ( char ∗ data , s i z e t s i z e , s i z e t nmemb, s t r i n g ∗ b u f f e r ) ; 6 7 CurlHelper : : CurlHelper () 8 { 9 } 10 11 C u r l H e l p e r : : C u r l H e l p e r ( const C u r l H e l p e r& o r i g ) 12 { 13 } 14 15 C u r l H e l p e r : : ~ C u r l H e l p e r ( ) 16 { 17 } 31 Programozási eszközök 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 C# – C/C++ könyvtárak használata char ∗ C u r l H e l p e r : :

getHttp ( char ∗ u r l ) { s t r i n g s = getHttp ( s t r i n g ( u r l ) ) ; return ( char ∗ ) s . c st r ( ) ; } s t r i n g C u r l H e l p e r : : getHttp ( const s t r i n g u r l ) { string buffer ; CURL ∗ c u r l ; CURLcode r e s u l t ; curl = curl easy init () ; if ( curl ) { curl easy setopt ( curl curl easy setopt ( curl curl easy setopt ( curl curl easy setopt ( curl , , , , CURLOPT URL, u r l . c s t r ( ) ) ; CURLOPT HEADER, 0 ) ; CURLOPT WRITEFUNCTION, w r i t e r ) ; CURLOPT WRITEDATA, &b u f f e r ) ; r e s u l t = curl easy perform ( c u r l ) ; // h t t p g e t performed curl easy cleanup ( c u r l ) ; // must c l e a n u p } } // e r r o r c o d e s : h t t p : / / c u r l . haxx s e / l i b c u r l / c / l i b c u r l −e r r o r s html i f ( r e s u l t == CURLE OK) return b u f f e r ; // c u r l e a s y s t r e r r o r was added i n l i b c u r l 7 . 1 2 0 c e r r << " e r r o r : ␣" << r e s u l t <<

" ␣ " << c u r l e a s y s t r e r r o r ( r e s u l t ) << e n d l ; return "" ; c e r r << " e r r o r : ␣ c o u l d ␣ not ␣ i n i t a l i z e ␣ c u r l " << e n d l ; return " " ; int w r i t e r ( char ∗ data , s i z e t s i z e , s i z e t nmemb, s t r i n g ∗ b u f f e r ) { int r e s u l t = 0 ; i f ( b u f f e r != NULL) { b u f f e r −>append ( data , s i z e ∗ nmemb) ; r e s u l t = s i z e ∗ nmemb ; } return r e s u l t ; } Az osztály használatát a 4-5. Programlista (test-curlcpp) mutatja be, ahol a Google induló 32 Programozási eszközök C# – C/C++ könyvtárak használata lapját kérjük le és írjuk ki a képernyőre. // 4−5. P r o g r a m l i s t a : t e s t −c u r l cpp #include <c s t d l i b > #include <i o s t r e a m > #include " C u r l H e l p e r . h" using namespace s t d ; i n t main ( i n t arg c , char ∗∗ a r g v ) {

s t r i n g u r l = " h t t p : / /www. g o o g l e com" ; C u r l H e l p e r ch ; s t r i n g s = ch . g e t H t t p ( u r l ) ; c o u t << s ; return 0 ; } A fordítást az alábbi 3 paranccsal végeztük: g++ −c C u r l H e l p e r . cpp g++ −c t e s t −c u r l . cpp g++ c u r l −t e s t . o C u r l H e l p e r o − l c u r l −o å c u r l t e s t . exe Megjegyezzük, hogy ebben a kisebb példában persze ez az 1 parancs is hatékonyan használható lett volna: g++ t e s t −c u r l . cpp C u r l H e l p e r cpp − l c u r l −o å c u r l t e s t . exe A program futási képernyője: . / c u r l t e s t exe C++ kódot kértünk a wrapper-hez, az illesztő module neve pedig CurlHelperModule lett. A következő fájlok jöttek létre: • CurlHelperModule wrap.cxx • CurlHelper.cs • CurlHelperModule.cs • CurlHelperModulePINVOKE.cs • SWIGTYPE p string.cs Tekintettel arra, hogy a C++ string osztály illesztését most még nem ismerjük,

ezért a CurlHelper osztály char * változatú metódusát fogjuk használni, ami a C# string-re mappelődik (ez egyébként a másik, string-es metódushoz deA következő lépésekben a CurlHelper oszlegálja a kérést): tályt C# kódból fogjuk használni. Ehhez gechar ∗ C u r l H e l p e r : : g e t H t t p ( char ∗ u r l ) ; neráljuk le az illesztő forráskódot! A swig konA SWIGTYPE p string.cs a C++ figurációs file (CurlHelperModule.swg) tartalma ez lett, azaz semmi különlegeset nem tartalmaz, std::string reprezentációja, ennek használatáegyszerűen használja a meglévő header fájlun- ról lentebb írunk. Fordítsuk le a C++ fájlokat, majd építsük meg az so fájlt: kat: <HTML><HEAD><meta h t t p−e q u i v=" c o n t e n t −t y p e " content="å t e x t / html ; c h a r s e t=u t f −8"> <TITLE>302 Moved</TITLE></HEAD><BODY> <H1>302 Moved</H1> The document h a s moved <A

HREF=" h t t p : / /www. g o o g l e hu / ">h e r e</A> </BODY></HTML> %module %{ #i n c l u d e " C u r l H e l p e r . h" %} g++ −c −fPIC CurlHelperModule wrap . cxx g++ −c −fPIC C u r l H e l p e r . cpp g++ −s h a r e d C u r l H e l p e r . o CurlHelperModule wrapå . o − l c u r l −o l i b C u r l H e l p e r M o d u l e s o %i n c l u d e " C u r l H e l p e r . h" A generált CurlHelperModule.cs most gyaA proxy forrásokat ezután így lehet előállí- korlatilag üres, mert csak a CurlHelper class van tani a CurlHelperModule modulra: alapvetően exportálva, az swg fájl ezenfelül mást s w i g −c++ −c s h a r p CurlHelperModule . swg nem tartalmaz: 33 Programozási eszközök // 4−6. P r o g r a m l i s t a : CurlHelperModule c s u s i n g System ; u s i n g System . Runtime I n t e r o p S e r v i c e s ; p u b l i c c l a s s CurlHelperModule { } C# – C/C++ könyvtárak használata

</head><body> å <h1>Moved P e r m a n e n t l y</h1> å <p>The document h a s moved <a h r e f=" h t t p : / / i n d e x . hu/ ">h e r e</a> </p><hr> å <address>Apache / 2 . 2 9 ( Debian ) mod ssl / 2 2 9 å OpenSSL / 0 . 9 8 g S e r v e r a t www i n d e x hu P o r t 80</å address> </body></html> A CurlHelper class számára viszont egy külön C# forrás jött létre, itt (4-7. Programlista) csak az általunk használt részletet mutat- C++ illesztés juk meg: Ez egy olyan nagy témakör, amit itt nem lehet // 4−7. P r o g r a m l i s t a : C u r l H e l p e r c s részletesen bemutatni, ehelyett ajánljuk a swig u s i n g System ; dokumentáció tanulmányozását. Itt most arra u s i n g System . Runtime I n t e r o p S e r v i c e s ; vállalkozunk, hogy bemutatjuk az std::string public c l a s s CurlHelper : IDisposable { használatát, ahogy azt már korábban ígértük. . p u b

l i c s t r i n g getHttp ( s t r i n g u r l ) { Az ilyen és ehhez hasonló C++/STL (Standard s t r i n g r e t = CurlHelperModulePINVOKE . å Template Library) típusok leképzését ismeri a CurlHelper getHttp SWIG 0 ( swigCPtr , å url ) ; swig, amiket include fájlokban határoz meg. Írreturn r e t ; juk be ezt a parancsot: } . } s w i g −s w i g l i b / usr / share / swig2 . 0 A főprogram végül az alábbi lett: // 4−8. P r o g r a m l i s t a : runme c s u s i n g System ; p u b l i c c l a s s runme { s t a t i c void Main ( ) { C u r l H e l p e r ch = new C u r l H e l p e r ( ) ; s t r i n g s = ch . g e t H t t p ( " h t t p : / /www i n d e x huå ") ; Console . WriteLine ( s ) ; } } Fordítsuk le a C# fájlokat, a futtatható program neve runme.exe lesz ismét: dmcs −out : runme . e x e ∗ c s A válasz azt a könyvtárat adja meg, ahol ezek a típus mappingek megtalálhatóak (ezek a swig program részei). A string használatához mi most a

/usr/share/swig2.0/csharp/std stringi include fájlt fogjuk használni. Ennek megfelelően tekintsük meg most a módosított CurlHelperModule.swg állományt, ahova egy std string.i include is bekerült! %module CurlHelperModule %{ #i n c l u d e " C u r l H e l p e r . h" %} %i n c l u d e " s t d s t r i n g . i " %i n c l u d e " C u r l H e l p e r . h" Végül nézzük meg a futási eredményt! LátA CurlHelper.h header-ben csak a string-es hatjuk, hogy működik a curl könyvtár C# alatt. metódus maradt meg, azaz megjegyzésbe tettük Csak gondoljunk egy kicsit bele! A curl egy C az előző példában használt char * típust hasznyelven írt könyvtár, amire C++ felületet húz- náló alakot: tunk és végül C# (mono) környezetből használ- // 4−9. P r o g r a m l i s t a : C u r l H e l p e r h tuk. . / runme e x e < !DOCTYPE HTML PUBLIC "−//IETF//DTD␣HTML␣ 2 . 0 / /EN"> å <html><head> å < t i t

l e>301 Moved P e r m a n e n t l y</ t i t l e> å 34 #i f n d e f CURLHELPER H #define CURLHELPER H å #include <i o s t r e a m > #include <s t r i n g > å Programozási eszközök #include <c u r l / c u r l . h> using namespace s t d ; class CurlHelper { public : CurlHelper ( ) ; C u r l H e l p e r ( const C u r l H e l p e r& o r i g ) ; virtual ~CurlHelper ( ) ; // c h a r ∗ g e t H t t p ( c h a r ∗ u r l ) ; s t r i n g getHttp ( s t r i n g u r l ) ; private : C# – C/C++ könyvtárak használata <html><head> < t i t l e >301 Moved Permanently </ t i t l e > </head><body> <h1>Moved Permanently </h1> <p>The document has moved <a h r e f ="h t t p : / / å i n d e x . hu/"> h e r e </a></p> <hr> <a d d r e s s >Apache / 2 . 2 9 ( Debian ) mod ssl / 2 2 9 å OpenSSL / 0 . 9 8 g S e r v e r a t www i n d e x hu Portå 80</ a d d r e

s s > </body></html> Minden a helyén van, a futási eredmény is a kívánt kimenetet adta, miközben már a C++ }; sokat tudó string osztályát használtuk közvet#endif /∗ CURLHELPER H ∗/ lenül. A swig sok mintapéldával van összecsoA következő parancs futása után már nem magolva, így valószínű, hogy a legtöbb problékeletkezik meg a SWIGTYPE p stringcs: mánkra már ott van egy lehetséges megoldás. s w i g −c++ −c s h a r p CurlHelperModule . swg Befejezésül megadjuk a fontosabb C++ és C# Ugyanakkor viszont látható az alábbi kód- kapcsolatú include fájlok listáját, amiben a mi részletben, hogy a C# CurlHelper class metó- string típusunk is ott van: dusa immár C# string típuson keresztül érhető • std common.i el. u s i n g System ; • std deque.i u s i n g System . Runtime I n t e r o p S e r v i c e s ; public c l a s s CurlHelper : IDisposable { p r i v a t e HandleRef swigCPtr ; p r o t e c t e d b o o l swigCMemOwn

; . p u b l i c s t r i n g getHttp ( s t r i n g u r l ) { s t r i n g r e t = CurlHelperModulePINVOKE . å C ur l He l pe r g e tH t tp ( swigCPtr , u r l ) ; i f ( CurlHelperModulePINVOKE . å SWIGPendingException . Pending ) throw å CurlHelperModulePINVOKE . å SWIGPendingException . R e t r i e v e ( ) ; return r e t ; } . Végül adjuk ki a következő parancsokat újra: g++ −c −fPIC CurlHelperModule wrap . cxx g++ −c −fPIC C u r l H e l p e r . cpp g++ −s h a r e d C u r l H e l p e r . o CurlHelperModule wrapå . o − l c u r l −o l i b C u r l H e l p e r M o d u l e s o dmcs −out : runme . e x e ∗ c s Majd futtassuk le a C# programot! . / runme e x e <!DOCTYPE HTML PUBLIC "−//IETF//DTD HTML 2 . 0 / / å EN"> • std except.i • std map.i • std pair.i • std shared ptr.i • std string.i • std vector.i • std wstring.i stli • typemaps.i • wchar.i Makrókat és saját include fájlokat természetesen magunk is

fejleszthetünk, így az illesztési feladatokat – igény esetén – teljesen testre szabva végezhetjük el. 35 Programozási eszközök 5. Java – C/C++ rutinok és könyvtárak használata Java – C/C++ rutinok és könyvtárak használata Az előző írás folytatásaként nézzük meg a Java és a külső könyvtárak és C/C++ kódrészletek illesztését is. Természetesen ezt is a swig utility segítségével fogjuk elvégezni és bemutatni Java oldalról az ismert JNI (Java Native Interface) felülethez kell kötnünk mindezt. A példák megoldásainak szépségét az adja, hogy a már ismert swig swg konfigurációs fájlokat fogjuk használni, demonstrálni azok nyelvfüggetlen voltát is. szerkezetű, mint a C# kód, ugyanis a Java egy alaposan átgondolt native interfésszel rendelkezik. Látható, hogy az egyes metódusok csak deklarálva lettek, mert a native kulcsszó jelzi, hogy az implementáció más helyen található (a libRutinok.so fájlban) A

szokásos „rutinok” példánk Ezzel a cikkel nem csupán annyi a célunk, hogy Java esetére is bemutassuk a C/C++ illesztést, hanem a swig eszközről további tudnivalókat is szeretnénk átadni. Most azonban vegyük az ismerős libRutinokso használatára való példát! A rutinok.swg fájlon a már említettek miatt nem kell változtatni, ezzel a paranccsal lehet legenerálni a Java illesztés kódját: • rutinok wrap.c A kapcsolat másik, C/C++-os oldala, tartalmát nem szükséges megérteni. s w i g −j a v a −package o r g . c s s w i g t e s t r u t i n o k å swg Itt most megadtuk azt is, hogy a generált Java forráskód milyen csomagba kerüljön: org.csswigtest C# esetén a package opció helyett namespace van, ezt nem használtuk az előzőekben, de ezzel a swig paranccsal tehettük volna: s w i g −c s h a r p −namespace o r g . c s s w i g t e s t å r u t i n o k . swg // 5−1. P r o g r a m l i s t a : Rutinok j a v a package o r g . c s s w

i g t e s t ; public c l a s s Rutinok { public s t a t i c i n t o s s z e g ( i n t a , i n t b ) { return RutinokJNI . o s s z e g ( a , b ) ; } public s t a t i c i n t k u l o n b s e g ( i n t a , i n t b ) { return RutinokJNI . k u l o n b s e g ( a , b ) ; } A következő fájlok jöttek létre: • Rutinok.java Ez az az osztály (5-1 Programlista), amit a Java programok használhatnak. Neve a module nevével egyezik. • RutinokJNI.java A Java JNI illesztés rétege (5-2. Programlista) Ez egyszerűbb public s t a t i c double sinWithDeg ( double x ) { return RutinokJNI . sinWithDeg ( x ) ; } } public s t a t i c S t r i n g echo ( S t r i n g s ) { return RutinokJNI . echo ( s ) ; } // 5−2. P r o g r a m l i s t a : RutinokJNI j a v a package o r g . c s s w i g t e s t ; public c l a s s RutinokJNI { public f i n a l s t a t i c native public f i n a l s t a t i c native public f i n a l s t a t i c native public f i n a l s t a t i c native } 36 int o s s z e

g ( int jarg1 , int j a r g 2 ) ; int kulonbseg ( int jarg1 , int j a r g 2 ) ; double sinWithDeg ( double j a r g 1 ) ; S t r i n g echo ( S t r i n g j a r g 1 ) ; Programozási eszközök Java – C/C++ rutinok és könyvtárak használata Végül nézzük meg a teszteléshez használt indító osztályt: // 5−3. P r o g r a m l i s t a : Runme j a v a package o r g . c s s w i g t e s t ; public c l a s s Runme { static { try { } } System . l o a d L i b r a r y ( " Rutinok " ) ; } catch ( U n s a t i s f i e d L i n k E r r o r e ) { System . e r r p r i n t l n ( " N a t i v e ␣ code ␣ l i b r a r y ␣ f a i l e d ␣ t o ␣ l o a d n" + e ) ; System . e x i t ( 1 ) ; } public s t a t i c void main ( S t r i n g argv [ ] ) { int o = Rutinok . o s s z e g ( 3 2 , 1 8 ) ; System . out p r i n t l n ( " Összeg ␣=␣" + o ) ; System . out p r i n t l n ( " s i n ( 3 0 )=" + Rutinok sinWithDeg ( 30 ) ) ; System .

out p r i n t l n ( " Ezt ␣ küldtem=" + Rutinok echo ( " Á r v í t ű r ő ␣ t ü k ö r f ú r ó g é p " ) ) ; } A Rutinok class betöltésekor, annak inicia- táció rendelkezésre fog állni. Egy olyan libRutilizációja során a SystemloadLibrary() is lefut, nokso fájl szükséges, amiben a rutinok wrapc ami dinamikusan betölti a libRutinok.so osz- is benne van: tott könyvtárat, így a külső native implemeng c c −I / u s r / l i b / jvm / d e f a u l t −j a v a / i n c l u d e / −c −fPIC r u t i n o k −1. c r u t i n o k −2 c matek−r u t i n o k c r u t i n o k w r a p c g c c −s h a r e d ∗ . o −o l i b R u t i n o k s o A -I include kapcsolót azért adtuk meg, mert a Java JNI illesztés header fájljait el kell érni fordításkor, emiatt meg kell adnunk, hogy hol van. A Java forrásokat a következő utasítással lehet fordítani: j a v a c −d . Rutinok j a v a RutinokJNI j a v a Runme å java A -d kapcsoló

a csomagnak megfelelő könyvtár szerkezetet is létrehozza az aktuális mappa alatt. Utolsó lépésként már futtathatjuk a Java kódot, minden rendben működik: j a v a o r g . c s s w i g t e s t Runme Összeg = 50 s i n ( 3 0 ) =0.499999999481858 Ezt küldtem=Á r v í t ű r ő t ü k ö r f ú r ó g é p Konstansok használata A swig konfigurációs fájlokban konstansok is definiálhatók, amit a generált forráskód tartalmazni fog. A rutinokswg állományt például most így egészítettük ki, azaz különféle módon állandó értékeket határoztunk meg: 37 Programozási eszközök Java – C/C++ rutinok és könyvtárak használata %module Rutinok %{ #i n c l u d e " r u t i n o k . h" %} /∗ F o rc e t h e g e n e r a t e d Java code t o u s e t h e C c o n s t a n t v a l u e s r a t h e r than making a JNI c a l l ∗/ %j a v a c o n s t ( 1 ) ; /∗ A few p r e p r o c e s s o r macros ∗/ #d e f i n e #d e f i n e #d e f i n e #d e f i n

e #d e f i n e #d e f i n e ICONST FCONST CCONST CCONST2 SCONST SCONST2 42 2.1828 ’x ’ ’ ’ " H e l l o World" "" H e l l o World "" /∗ This s h o u l d work j u s t f i n e ∗/ #d e f i n e EXPR ICONST + 3 ∗ (FCONST) /∗ This shouldn ’ t do a n y t h i n g ∗/ #d e f i n e EXTERN extern /∗ N e i t h e r s h o u l d t h i s (BAR i s n ’ t d e f i n e d ) ∗/ #d e f i n e FOO (ICONST + BAR) /∗ The f o l l o w i n g d i r e c t i v e s a l s o pr oduce c o n s t a n t s ∗/ %c o n s t a n t i n t i c o n s t = 3 7 ; %c o n s t a n t d o u b l e f c o n s t = 3 . 1 4 ; int osszeg ( int a , int b) ; i n t kulonbseg ( i n t a , i n t b) ; d o u b l e sinWithDeg ( d o u b l e x ) ; c h a r ∗ echo ( c h a r ∗ s ) ; A fentiek egyértelműek, de a %javaconst(1) direktíva magyarázatra szorul. Amennyiben nem adjuk meg, úgy a konstansok a wrapper C/C++ forrásba kerülnek és csak a JNI felületről lesznek elérhetők. Ez azonban

nem szükséges mindig, hiszen ezeket az állandókat a célnyelvben (most Java) is felvehetjük és ekkor az alábbi extra RutinokConstants.java Java forrás generálódik: public f i n a l s t a t i c H e l l o ␣World " " ; public f i n a l s t a t i c 42+3∗(2.1828) ; public f i n a l s t a t i c public f i n a l s t a t i c } S t r i n g SCONST2 = " "å double EXPR = å int i c o n s t = 3 7 ; double f c o n s t = 3 . 1 4 ; Változók használata Ebben a pontban arra látunk példát, hogy a külső C/C++ kódban hogyan definiálunk változókat, illetve azokat milyen módon érjük el Javaból. A rutinokswg fájlunkba most betettünk több extern deklarációt különféle C/C++ típusú változóra. Újdonság még, hogy meghatároztuk 5 új függvény exportálását is, amit majd természetesen a Java kódból szeretnénk használni. Ezek implementációja és a változók definíciója (azaz tényleges létrehozása) is a rutinok-2.c forrásba (5-5.

Programlista) került %module Rutinok %{ #i n c l u d e " r u t i n o k . h" %} /∗ Some g l o b a l v a r i a b l e d e c l a r a t i o n s ∗/ %i n l i n e %{ extern int ivar ; extern short svar ; extern long lvar ; extern unsigned i n t uivar ; extern unsigned short usvar ; extern unsigned long ulvar ; extern signed char scvar ; extern unsigned char ucvar ; extern char cvar ; extern f l o a t fvar ; extern double dvar ; extern char ∗ strvar ; extern const char cstrvar [ ] ; extern int ∗ iptrvar ; extern char name [ 2 5 6 ] ; // 5−4. P r o g r a m l i s t a : R u t i n o k C o n s t a n t s j a v a extern Point extern Point %} package o r g . c s s w i g t e s t ; /∗ Some read−o n l y v a r i a b l e s ∗/ public i n t e r f a c e R u t i n o k C o n s t a n t s { public f i n a l s t a t i c i n t ICONST = 4 2 ; public f i n a l s t a t i c double FCONST = 2 . 1 8 2 8 ; public f i n a l s t a t i c char CCONST = ’ x ’ ; public f i n a l s t a t i c

char CCONST2 = ’ ’ ; public f i n a l s t a t i c S t r i n g SCONST = " H e l l o ␣å World" ; %immutable ; 38 %i n l i n e %{ extern int status ; e x t e r n c h a r path [ 2 5 6 ] ; %} ∗ ptptr ; pt ; Programozási eszközök %mutable ; /∗ Some h e l p e r f u n c t i o n s t o make i t e a s i e r t o t e s t ∗/ %i n l i n e %{ extern void print vars () ; e x t e r n i n t ∗ new int ( i n t v a l u e ) ; e x t e r n P o i n t ∗ new Point ( i n t x , i n t y ) ; e x t e r n c h a r ∗ P o i n t p r i n t ( P o i n t ∗p ) ; extern void pt print ( ) ; %} Java – C/C++ rutinok és könyvtárak használata /∗ O r i g i n a l f u n c t i o n s ∗/ int osszeg ( int a , int b) ; i n t kulonbseg ( i n t a , i n t b) ; d o u b l e sinWithDeg ( d o u b l e x ) ; c h a r ∗ echo ( c h a r ∗ s ) ; Amikor lefuttatjuk a swig generátort, akkor persze ezek az deklarációk benne lesznek a generált rutinok wrap.c kódban // 5−5. P r o g r a m l

i s t a : r u t i n o k −2 c #include <s t d i o . h> #include < s t d l i b . h> #include " r u t i n o k . h" int short long unsigned int unsigned short unsigned long signed char unsigned char char float double char const char int char char ivar = 0; svar = 0; lvar = 0; uivar = 0; usvar = 0 ; ulvar = 0; scvar = 0; ucvar = 0 ; cvar = 0 ; fvar = 0; dvar = 0 ; ∗ strvar = 0; c s t r v a r [ ] = "Goodbye" ; ∗ iptrvar = 0; name [ 2 5 6 ] = "Dave" ; path [ 2 5 6 ] = "/home/ b e a z l e y " ; /∗ G l o b a l v a r i a b l e s i n v o l v i n g a s t r u c t u r e ∗/ P oi nt ∗ ptptr = 0; P oi nt pt = { 1 0 , 20 } ; /∗ A v a r i a b l e t h a t we w i l l make read−o n l y i n t h e i n t e r f a c e ∗/ int status = 1; //−−− V a r i a b l e s void p r i n t v a r s ( ) { p r i n t f ( " i v a r ␣␣␣␣␣␣=␣%d " , i v a r ) ; p r i n t f ( " s v a r ␣␣␣␣␣␣=␣%d " , s v a r )

; p r i n t f ( " l v a r ␣␣␣␣␣␣=␣%l d " , l v a r ) ; p r i n t f ( " u i v a r ␣␣␣␣␣=␣%u " , u i v a r ) ; p r i n t f ( " u s v a r ␣␣␣␣␣=␣%u " , u s v a r ) ; p r i n t f ( " u l v a r ␣␣␣␣␣=␣%l u " , u l v a r ) ; p r i n t f ( " s c v a r ␣␣␣␣␣=␣%d " , s c v a r ) ; 39 Programozási eszközök } Java – C/C++ rutinok és könyvtárak használata p r i n t f ( " ucvar ␣␣␣␣␣=␣%u " , ucvar ) ; p r i n t f ( " f v a r ␣␣␣␣␣␣=␣%g " , f v a r ) ; p r i n t f ( " dvar ␣␣␣␣␣␣=␣%g " , dvar ) ; p r i n t f ( " c v a r ␣␣␣␣␣␣=␣%c " , c v a r ) ; p r i n t f ( " s t r v a r ␣␣␣␣=␣%s " , s t r v a r ? s t r v a r : " ( n u l l ) " ) ; p r i n t f ( " c s t r v a r ␣␣␣=␣%s " , c s t r v a r ? c s t r v a r : " ( n u l l )

" ) ; p r i n t f ( " i p t r v a r ␣␣␣=␣%p " , i p t r v a r ) ; p r i n t f ( "name␣␣␣␣␣␣=␣%s " , name ) ; p r i n t f ( " p t p t r ␣␣␣␣␣=␣%p␣(%d , ␣%d ) " , p t p t r , p t p t r ? p t p t r −>x : 0 , p t p t r ? p t p t r å −>y : 0 ) ; p r i n t f ( " pt ␣␣␣␣␣␣␣␣=␣(%d , ␣%d ) " , pt . x , pt y ) ; p r i n t f ( " s t a t u s ␣␣␣␣=␣%d " , s t a t u s ) ; /∗ A f u n c t i o n t o c r e a t e an i n t e g e r ( t o t e s t i p t r v a r ) ∗/ int ∗ new int ( int v a l u e ) { int ∗ i p = ( int ∗ ) m a l l o c ( s i z e o f ( int ) ) ; ∗ ip = value ; return i p ; } /∗ A f u n c t i o n t o c r e a t e a p o i n t ∗/ P oi nt ∗new Point ( int x , int y ) { Po i nt ∗p = ( Point ∗ ) m a l l o c ( s i z e o f ( P oi nt ) ) ; p−>x = x ; p−>y = y ; return p ; } char ∗ P o i n t p r i n t ( Point ∗p ) { s t a t i c char

b u f f e r [ 2 5 6 ] ; i f (p) { s p r i n t f ( b u f f e r , "(%d,%d ) " , p−>x , p−>y ) ; } else { sprintf ( buffer , " null ") ; } return b u f f e r ; } void p t p r i n t ( ) { p r i n t f ( "(%d , ␣%d ) " , pt . x , pt y ) ; } //−−− V a r i a b l e s void gv1 ( char ∗ s ) { p r i n t f ( " n C a l l e d ␣ gv1 : ␣%s " , s ) ; } 40 Programozási eszközök Java – C/C++ rutinok és könyvtárak használata void gv2 ( char ∗ s ) { p r i n t f ( " n C a l l e d ␣ gv2 : ␣%s " , s ) ; } Az 5-6. Programlista az új tesztprogramot is látható, hogy az 5 db új függvény is elérhető a mutatja. Az érdekessége az, hogy a változók Java Rutinok osztályon keresztül (példa a kódelérését az illesztőfüggvényen és a segédfüggvé- ból: Rutinoknew int(37)) nyen (print vars()) keresztül is bemutatja. Az // 5−6. P r o g r a m l i s t a : Runme j a v a package o r g . c s s w i g t

e s t ; public c l a s s Runme { static { try { } System . l o a d L i b r a r y ( " Rutinok " ) ; } catch ( U n s a t i s f i e d L i n k E r r o r e ) { System . e r r p r i n t l n ( " N a t i v e ␣ code ␣ l i b r a r y ␣ f a i l e d ␣ t o ␣ l o a d n" + e ) ; System . e x i t ( 1 ) ; } public s t a t i c void main ( S t r i n g argv [ ] ) { // Try t o s e t t h e v a l u e s o f some g l o b a l v a r i a b l e s Rutinok . s e t I v a r ( 4 2 ) ; Rutinok . s e t S v a r ( ( short ) −31000) ; Rutinok . s e t L v a r ( 6 5 5 3 7 ) ; Rutinok . s e t U i v a r ( 1 2 3 4 5 6 ) ; Rutinok . s e t U s v a r ( 6 1 0 0 0 ) ; Rutinok . s e t U l v a r ( 6 5 4 3 2 1 ) ; Rutinok . s e t S c v a r ( ( byte ) −13) ; Rutinok . s e t U c v a r ( ( short ) 2 5 1 ) ; Rutinok . s e t C v a r ( ’ S ’ ) ; Rutinok . s e t F v a r ( ( f l o a t ) 3 1 4 1 5 9 ) ; Rutinok . setDvar ( 2 1 8 2 8 ) ; Rutinok . s e t S t r v a r ( " H e l l o ␣World" ) ;

Rutinok . s e t I p t r v a r ( Rutinok new int ( 3 7 ) ) ; Rutinok . s e t P t p t r ( Rutinok new Point ( 3 7 , 4 2 ) ) ; Rutinok . setName ( " B i l l " ) ; // Now p r i n t o u t t h e v a l u e s o f t h e v a r i a b l e s System . out p r i n t l n ( " V a r i a b l e s ␣ ( v a l u e s ␣ p r i n t e d ␣ from ␣ Java ) " ) ; System . out p r i n t l n ( " i v a r ␣␣␣␣␣ ␣=" + Rutinok g e t I v a r ( ) ) ; 41 Programozási eszközök System . out System . out System . out System . out System . out System . out System . out System . out System . out System . out System . out System . out System . out println ( println ( println ( println ( println ( println ( println ( println ( println ( println ( println ( println ( println ( Java – C/C++ rutinok és könyvtárak használata " s v a r ␣␣␣␣␣ ␣=" " l v a r ␣␣␣␣␣ ␣=" " u i v a r ␣␣␣␣ ␣=" " u

s v a r ␣␣␣␣ ␣=" " u l v a r ␣␣␣␣ ␣=" " s c v a r ␣␣␣␣ ␣=" " ucvar ␣␣␣␣ ␣=" " f v a r ␣␣␣␣␣ ␣=" " dvar ␣␣␣␣␣ ␣=" " c v a r ␣␣␣␣␣ ␣=" " s t r v a r ␣␣␣ ␣=" " c s t r v a r ␣␣ ␣=" "name␣␣␣␣␣ ␣=" + + + + + + + + + + + + + Rutinok . g e t S v a r ( ) ) ; Rutinok . g e t L v a r ( ) ) ; Rutinok . g e t U i v a r ( ) ) ; Rutinok . g e t U s v a r ( ) ) ; Rutinok . g e t U l v a r ( ) ) ; Rutinok . g e t S c v a r ( ) ) ; Rutinok . getUcvar ( ) ) ; Rutinok . getF var ( ) ) ; Rutinok . getDvar ( ) ) ; ( char ) Rutinok . getCvar ( ) ) ; Rutinok . g e t S t r v a r ( ) ) ; Rutinok . g e t C s t r v a r ( ) ) ; Rutinok . getName ( ) ) ; System . out p r i n t l n ( " n V a r i a b l e s ␣ ( v a l u e s ␣ p r i n t e d ␣ from ␣C) " ) ; Rutinok . p r i n t v a r s ( ) ; System .

out p r i n t l n ( " Now␣ I ’m␣ g o i n g ␣ t o ␣ t r y ␣and␣ modify ␣some␣ r e a d ␣ o n l y ␣å variables " ) ; } } System . out p r i n t l n ( "␣␣␣␣␣ Trying ␣ t o ␣ s e t ␣ ’ path ’ " ) ; A Runme osztály futási eredménye a következő lett: j a v a o r g . c s s w i g t e s t Runme Variables ivar svar lvar uivar usvar ulvar scvar ucvar fvar dvar cvar strvar cstrvar iptrvar name ptptr pt ( v a l u e s p r i n t e d from Java ) =42 =−31000 =65537 =123456 =61000 =654321 =−13 =251 =3.14159 =2.1828 =S =H e l l o World =Goodbye =7cae 6d1 0 =B i l l =7c a f 4 5 7 0 ( 3 7 , 4 2 ) =7 c a f 8 c 6 8 ( 1 0 , 2 0 ) Variables ivar svar lvar uivar usvar ulvar scvar ucvar fvar dvar ( v a l u e s p r i n t e d from C) = 42 = −31000 = 65537 = 123456 = 61000 = 654321 = −13 = 251 = 3 ,14159 = 2 ,1828 42 cvar strvar cstrvar iptrvar name ptptr pt status = = = = = = = = S H e l l o World Goodbye 0 x7cae6d10 Bill 0

x7caf4570 (37 , 42) (10 , 20) 1 A C++ enum használata A C++ felsorolás típust itt nem mutatjuk be, de az alábbiakban bemutatjuk annak a Java oldali használati módját, amihez készítettünk egy enum-test.cpp forrást Előtte azonban az enumtesth header állományba vegyünk fel egy egyszerű C++ felsorolást (5-7 Programlista)! Ez a Color típus, amit az enum test() függvényen keresztül fogunk most használni. // 5−7. P r o g r a m l i s t a : enum−t e s t h enum C o l o r { RED, BLUE, GREEN } ; void enum test ( C o l o r c ) ; Erre írjuk egy C++ függvényt, amit az 5-8. Programlista mutat. Programozási eszközök Java – C/C++ rutinok és könyvtárak használata // 5−8. P r o g r a m l i s t a : enum−t e s t cpp %module EnumTest #include "enum−t e s t . h" #include <s t d i o . h> %{ void enum test ( C o l o r c ) { i f ( c == RED) { p r i n t f ( " c o l o r ␣=␣RED, ␣ " ) ; } e l s e i f ( c == BLUE) { p r i n t f

( " c o l o r ␣=␣BLUE, ␣ " ) ; } e l s e i f ( c == GREEN) { p r i n t f ( " c o l o r ␣=␣GREEN, ␣ " ) ; } else { p r i n t f ( " c o l o r ␣=␣Unknown␣ c o l o r ! , ␣ " ) ; } } Mondjuk meg a swig számára, hogy miből kell főzni: %} #i n c l u d e "enum−t e s t . h" /∗ F o r c e t h e g e n e r a t e d Java code t o u s e t h e C enum v a l u e s r a t h e r than making a JNI c a l l ∗/ %j a v a c o n s t ( 1 ) ; %i n c l u d e "enum−t e s t . h" Adjuk ki a következő 3 parancsot, ami legenerálja a swig illesztést, fordít és könyvtárat készít libEnumTest.so néven s w i g −c++ −j a v a −package o r g . c s s w i g t e s t enum−t e s t swg g++ −I / u s r / l i b /jvm/ d e f a u l t −j a v a / i n c l u d e / −c −fPIC enum−t e s t . cpp enum−test wrap cxx g++ −s h a r e d enum−t e s t . o enum−test wrap o −o libEnumTest s o Ennyi csupán, amit tennünk

kellett az enum Fordítsuk le és futtassuk a Java tesztprograhasználatához, amit az 5-9. Programlista mutat munkat: // 5−9. P r o g r a m l i s t a : Runme j a v a package o r g . c s s w i g t e s t ; public c l a s s Runme { static { try { System . l o a d L i b r a r y ( "EnumTest" ) ; } catch ( U n s a t i s f i e d L i n k E r r o r e ) { System . e r r p r i n t l n ( " N a t i v e ␣ code ␣ l i b r a r y ␣å f a i l e d ␣ t o ␣ l o a d . n" + e ) ; System . e x i t ( 1 ) ; } } public s t a t i c void main ( S t r i n g a r g v [ ] ) { System . out p r i n t l n ( " ␣ ␣ ␣ ␣ " + C o l o r RED + "å ␣=␣ " + C o l o r .RED s w i g V a l u e ( ) ) ; } } EnumTest . enum test ( C o l o r RED ) ; j a v a c −d . ∗ j a v a j a v a o r g . c s s w i g t e s t Runme RED = 0 c o l o r = RED A curl könyvtár használata Most a már ismert curl illesztést elvégezzük Java-ra is. A CurlHelperModuleswg fájl

természetesen most is ugyanaz marad, de ezúttal Java nyelvre generáljuk az illesztést: s w i g −c++ −j a v a −package o r g . c s s w i g t e s t å CurlHelperModule . swg A C++ rész fordítása a következő parancsokkal lehetséges: g++ −I / u s r / l i b /jvm/ d e f a u l t −j a v a / i n c l u d e / −c −fPIC CurlHelperModule wrap . cxx g++ −c −fPIC CurlHelperModule wrap . cxx g++ −s h a r e d C u r l H e l p e r . o CurlHelperModule wrap o − l c u r l −o l i b C u r l H e l p e r M o d u l e s o 43 Programozási eszközök Java – C/C++ rutinok és könyvtárak használata Java tesztprogramként ezt használtuk (5-10. (referencia-testh) operator+() metódusa 2 VecProgramlista): tor -ra vonatkozó referencia paraméterrel rendelkezik: a és b. A visszatérési érték pedig egy // 5 −10. P r o g r a m l i s t a : Runme j a v a értékként kezelt Vector, ami megfelel az összepackage o r g . c s s w i g t e s t ; adás megszokott

szemantikájának. A VectorArpublic c l a s s Runme { ray class operator[]() metódusa (indexelő operátor) pedig visszatérésként egy Vector referenciát static { ad. } } try { System . l o a d L i b r a r y ( " CurlHelperModule " ) ; } catch ( U n s a t i s f i e d L i n k E r r o r e ) { System . e r r p r i n t l n ( " N a t i v e ␣ code ␣ l i b r a r y ␣å f a i l e d ␣ t o ␣ l o a d . n" + e ) ; System . e x i t ( 1 ) ; } public s t a t i c void main ( S t r i n g a r g v [ ] ) { C u r l H e l p e r ch = new C u r l H e l p e r ( ) ; S t r i n g s = ch . g e t H t t p ( " h t t p : / /www i n d e x å hu" ) ; System . out p r i n t l n ( s ) ; } Végül a Java források fordítása és a tesztfuttatás így alakul: j a v a c −d . ∗ j a v a j a v a o r g . c s s w i g t e s t Runme <!DOCTYPE HTML PUBLIC "−//IETF//DTD HTML 2 . 0 / / å EN"> <html><head> < t i t l e >301 Moved Permanently

</ t i t l e > </head><body> <h1>Moved Permanently </h1> <p>The document has moved <a h r e f ="h t t p : / / å i n d e x . hu/"> he re </a></p> <hr> <a d d r e s s >Apache / 2 . 2 9 ( Debian ) mod ssl / 2 2 9 å OpenSSL / 0 . 9 8 g S e r v e r a t www i n d e x hu Portå 80</ a d d r e s s > </body></html> // 5 −11. P r o g r a m l i s t a : r e f e r e n c i a −t e s t h class Vector { private : double x , y , z ; public : Vector ( ) : x ( 0 ) , y ( 0 ) , z ( 0 ) { } ; V e c t o r ( double x , double y , double z ) : x ( x ) , å y(y) , z ( z ) { }; friend V e c t o r operator+(const V e c t o r &a , å const V e c t o r &b ) ; char ∗ p r i n t ( ) ; }; c l a s s V e ct o r A rr a y { private : Vector ∗ items ; int maxsize ; public : V e ct o r A rr a y ( i n t m a x s i z e ) ; ~V e ct o r A rr a y ( ) ; V e c t o r &operator [ ] ( i n t ) ; int s i z e ( ) ; };

Balérték, Jobbérték. Egy C/C++ változó állhat az értékadás jobb vagy bal oldalán. Amikor jobb oldalon áll, akkor a változó mögötti értéket veszi a fordító. Amikor a bal oldalon, akkor a címét, hogy ahhoz a memória rekeszhez egy értéket rendeljen. Az osztályok implementációját a 5-12. Programlista mutatja Az operator+() 2 vektor összegét adja vissza értékként. A print() metódus a Vector string alakját adja vissza A C++ referencia típus VectorArray indexelő operátora visszaadja az i. elemet, ami egy Vector-ra mutató referencia, így A C++ referencia változó egy olyan változó, balértékként is használható. Ez természetes viamely egy másiknak az alias neve Deklaráselkedés, mert a tömböknél megszoktuk, hogy láskor erre az & jellel utalunk. Gondolhatunk egy v[i] lehet az értékadás bal és jobb oldalán is. rá, mint egy automatikus működésű pointerre, aminek azonban csak egyszer állíthatjuk be azt // 5 −12. P r o g r a m

l i s t a : r e f e r e n c i a −t e s t cpp a címet, amire mutat. Az 5-11 Programlista #include " r e f e r e n c i a −t e s t h" 44 Programozási eszközök Java – C/C++ rutinok és könyvtárak használata 3. Exportálja a VectorArray class-t, de az osztályhoz az indexelő operátor helyett bevezeti a get() és set() metódusokat. #include <s t d i o . h> #include < s t d l i b . h> V e c t o r operator+(const V e c t o r &a , const V e c t o r å &b ) { Vector r ; r .x = ax + bx; r .y = ay + by; r .z = a z + b z; return r ; } %module R e f e r e n c i a T e s t char ∗ V e c t o r : : p r i n t ( ) { s t a t i c char temp [ 5 1 2 ] ; s p r i n t f ( temp , " V e c t o r ␣%p␣(%g ,%g ,%g ) " , this , xå ,y, z) ; return temp ; } c l a s s Vector { public : Vector ( double x , double y , double z ) ; ~V e c t o r ( ) ; char ∗ p r i n t ( ) ; }; V ectorArray : : VectorArray ( i n t s i z e ) { i t e m s = new V e c t o

r [ s i z e ] ; maxsize = s i z e ; } /∗ This h e l p e r f u n c t i o n c a l l s an o v e r l o a d e d o p e r a t o r ∗/ V ectorArray : : ~ VectorArray ( ) { delete [ ] i t e m s ; } V e c t o r &VectorArray : : operator [ ] ( i n t i n d e x ) { i f ( ( i n d e x < 0 ) | | ( i n d e x >= m a x s i z e ) ) { p r i n t f ( " Panic ! ␣ Array ␣ i n d e x ␣ out ␣ o f ␣ bounds . å n" ) ; exit (1) ; } return i t e m s [ i n d e x ] ; } %{ #i n c l u d e " r e f e r e n c i a −t e s t . h" %} %i n l i n e %{ V e c t o r addv ( V e c t o r &a , V e c t o r &b ) { r e t u r n a+b ; } %} /∗ Wrapper around an a r r a y o f v e c t o r s c l a s s ∗/ c l a s s V e c t o rA r r ay { public : V e ct o r A rr a y ( i n t m a x s i z e ) ; ~V e ct o r A rr a y ( ) ; int size () ; i n t VectorArray : : s i z e ( ) { return m a x s i z e ; } A swig konfigurációt az alábbi referenciatest.swg fájl mutatja Mit látunk belőle? 1.

Exportálja a wrapper C++ kód felé a Vector class-t 2. Kéri, hogy szó szerint bekerüljön a wrapper-be az addv() segédfüggvény, mert Javaból még nem lehet operator overloading mechanizmust használni. }; /∗ This wrapper p r o v i d e s an a l t e r n a t i v e t o å t h e [ ] o p e r a t o r ∗/ %e x t e n d { V e c t o r &g e t ( i n t i n d e x ) { return (∗ $ s e l f ) [ index ] ; } v o i d s e t ( i n t index , V e c t o r &a ) { (∗ $ s e l f ) [ index ] = a ; } } Generáljuk le a Java illesztést forrásait: s w i g −c++ −j a v a −package o r g . c s s w i g t e s t å r e f e r e n c i a −t e s t . swg A következő lépésben a C++ oldalt fordítsuk le a szokásos módon, aminek az eredménye a libReferenciaTest.so fájl lesz g++ −I / u s r / l i b /jvm/ d e f a u l t −j a v a / i n c l u d e / −c −fPIC r e f e r e n c i a −test wrap . cxx r e f e r e n c i a −t e s t cpp g++ −s h a r e d r e f e r e n c i a −test wrap . o

r e f e r e n c i a −t e s t o −o l i b R e f e r e n c i a T e s t s o 45 Programozási eszközök Java – C/C++ rutinok és könyvtárak használata A teszteléshez írt kódot az 5-13. Program- mikusan Tanulmányozzuk a kódot! Nem bolista tartalmazza Láthatjuk, hogy most a lib- nyolult, amiatt nem is fűzünk hozzá külön megReferenciaTestso könyvtárat töltöttük be dina- jegyzéseket // 5 −13. P r o g r a m l i s t a : Runme j a v a package o r g . c s s w i g t e s t ; public c l a s s Runme { static { try { System . l o a d L i b r a r y ( " R e f e r e n c i a T e s t " ) ; } catch ( U n s a t i s f i e d L i n k E r r o r e ) { System . e r r p r i n t l n ( " N a t i v e ␣ code ␣ l i b r a r y ␣ f a i l e d ␣ t o ␣ l o a d n" + e ) ; System . e x i t ( 1 ) ; } } public s t a t i c void main ( S t r i n g a r g v [ ] ) { System . out p r i n t l n ( " C r e a t i n g ␣ 2 ␣ V e c t o r ␣ o b j e c t s :

" ) ; V e c t o r a = new V e c t o r ( 3 , 4 , 5 ) ; V e c t o r b = new V e c t o r ( 1 0 , 1 1 , 1 2 ) ; System . out p r i n t l n ( " ␣ ␣ ␣ ␣ Cre ated ␣ " + a p r i n t ( ) ) ; System . out p r i n t l n ( " ␣ ␣ ␣ ␣ Cre ated ␣ " + b p r i n t ( ) ) ; // System . out p r i n t l n ( " Adding ␣ a+b" ) ; V e c t o r c = R e f e r e n c i a T e s t . addv ( a , b ) ; System . out p r i n t l n ( " ␣ ␣ ␣ ␣ a+b␣=␣ " + c p r i n t ( ) ) ; c . delete () ; c = null ; // −−−−− C r e a t e a v e c t o r a r r a y −−−−− System . out p r i n t l n ( " C r e a t i n g ␣ an ␣ a r r a y ␣ o f ␣ v e c t o r s " ) ; VectorArray va = new VectorArray ( 1 0 ) ; System . out p r i n t l n ( " ␣ ␣ ␣ ␣ va ␣=␣ " + va t o S t r i n g ( ) ) ; va . s e t ( 0 , a ) ; va . s e t ( 1 , b ) ; va . s e t ( 2 , R e f e r e n c i a T e s t addv ( a , b ) ) ; // Get

some v a l u e s from t h e a r r a y System . out p r i n t l n ( " G e t t i n g ␣ some ␣ a r r a y ␣ v a l u e s " ) ; f o r ( i n t i =0; i <5; i ++) { System . out p r i n t l n ( " ␣ ␣ ␣ ␣ va ( " + i + " ) ␣=␣ " + va g e t ( i ) p r i n t ( ) ) ; } // Watch under r e s o u r c e meter t o c h e c k on t h i s System . out p r i n t l n ( " Making ␣ s u r e ␣we␣ don ’ t ␣ l e a k ␣memory " ) ; f o r ( i n t i =0; i <1000000; i ++) c = va . g e t ( i %10) ; } } 46 // −−−−− Clean up −−−−− System . out p r i n t l n ( " C l e a n i n g ␣up" ) ; va . d e l e t e ( ) ; a . delete () ; b . delete () ; Programozási eszközök Java – C/C++ rutinok és könyvtárak használata Miután átnéztük a tesztprogram kódját, fordításuk le és futtassuk! Mindezt a következő utasításokkal tehetjük meg: #endif }; j a v a c −d . ∗ j a v a Az ehhez tartozó

swig konfiguráció a következő: j a v a o r g . c s s w i g t e s t Runme %module TemplateTest Creating 2 Vector o b j e c t s : Cre ated V e c t o r 0 x 7 c 8 f 4 d 9 8 ( 3 , 4 , 5 ) Cre ated V e c t o r 0 x 7 c 8 f 4 d b 8 ( 1 0 , 1 1 , 1 2 ) Adding a+b a+b = V e c t o r 0 x 7 c 8 f 4 e 4 8 ( 1 3 , 1 5 , 1 7 ) C r e a t i n g an a r r a y o f v e c t o r s va = o r g . c s s w i g t e s t VectorArray@16218f9 G e t t i n g some a r r a y v a l u e s va ( 0 ) = V e c t o r 0 x 7 c 8 f 4 e 9 0 ( 3 , 4 , 5 ) va ( 1 ) = V e c t o r 0 x 7 c 8 f 4 e a 8 ( 1 0 , 1 1 , 1 2 ) va ( 2 ) = V e c t o r 0 x 7 c 8 f 4 e c 0 ( 1 3 , 1 5 , 1 7 ) va ( 3 ) = V e c t o r 0 x 7 c 8 f 4 e d 8 ( 0 , 0 , 0 ) va ( 4 ) = V e c t o r 0 x 7 c 8 f 4 e f 0 ( 0 , 0 , 0 ) Making s u r e we don ’ t l e a k memory . C l e a n i n g up %{ #i n c l u d e " t e m p l a t e −sample . h" %} C++ template A C++ template a generikus programozás és kódgenerálás eszköze. A következő 5-14

Programlista egy template függvényt és egy template class deklarációját tartalmazza. template<c l a s s T> c l a s s v e c t o r { T ∗v ; int sz ; public : v e c t o r ( i n t sz ) { v = new T [ sz ] ; s z = sz ; } T &g e t ( i n t i n d e x ) { return v [ i n d e x ] ; } void s e t ( i n t index , T &v a l ) { v [ index ] = val ; } #i f d e f SWIG %e x t e n d { T getitem ( int index ) { return $ s e l f −>g e t ( i n d e x ) ; } void s e t i t e m ( i n t index , T v a l ) { $ s e l f −>s e t ( index , v a l ) ; } } %i n c l u d e " t e m p l a t e −sample . h" /∗ Now i n s t a n t i a t e some s p e c i f i c t e m p l a t e d e c l a r a t i o n s ∗/ %t e m p l a t e ( maxint ) max<i n t >; %t e m p l a t e ( maxdouble ) max<double >; %t e m p l a t e ( v e c i n t ) v e c t o r <i n t >; %t e m p l a t e ( v e c d o u b l e ) v e c t o r <double >; A %template kulcsszó egy konkrét, példányosítás

utáni nevet ad a Java kód számára. Állítsuk elő az illesztést: s w i g −c++ −j a v a −package o r g . c s s w i g t e s t å t e m p l a t e −sample . swg A létrejött fájlok: • template-sample wrap.cxx // 5 −14. P r o g r a m l i s t a : t e m p l a t e −sample h template<c l a s s T> T max(T a , T b ) { return b ? a : b; } /∗ Let ’ s j u s t grab t h e o r i g i n a l h e a d e r f i l e h e r e ∗/ a>å • TemplateTest.java • TemplateTestJNI.java • vecdouble.java a vector<double> típusra • vecint.java a vector<int> típusra A teszteléshez használt következő Java forrás mutatja, hogy az előzőleg %template-tel adott nevet (példa: maxint() a függvényre vagy vecint a vector<int> típusra) milyen névvel használjuk. Egyébként a Runme teszt osztály egyértelmű A TemplateTest class a module osztály, ezen keresztül hívjuk a függvényket. A vecdouble és vecint saját típusként jelenik meg a Java

forráskódban is. 47 Programozási eszközök Java – C/C++ rutinok és könyvtárak használata // 5 −15. P r o g r a m l i s t a : Runme j a v a package o r g . c s s w i g t e s t ; public c l a s s Runme { static { try { System . l o a d L i b r a r y ( " TemplateTest " ) ; } catch ( U n s a t i s f i e d L i n k E r r o r e ) { System . e r r p r i n t l n ( " N a t i v e ␣ code ␣ l i b r a r y ␣ f a i l e d ␣ t o ␣ l o a d n" + e ) ; System . e x i t ( 1 ) ; } } public s t a t i c void main ( S t r i n g a r g v [ ] ) { // C a l l some t e m p l a t e d f u n c t i o n s System . out p r i n t l n ( TemplateTest maxint ( 3 , 7 ) ) ; System . out p r i n t l n ( TemplateTest maxdouble ( 3 1 4 , 2 1 8 ) ) ; // C r e a t e some c l a s s v e c i n t i v = new v e c i n t ( 1 0 0 ) ; v e c d o u b l e dv = new v e c d o u b l e ( 1 0 0 0 ) ; f o r ( i n t i =0; i <100; i ++) iv . setitem ( i ,2∗ i ) ; f o r ( i n t i =0; i

<1000; i ++) dv . s e t i t e m ( i , 1 0 / ( i +1) ) ; { i n t sum = 0 ; f o r ( i n t i =0; i <100; i ++) sum = sum + i v . g e t i t e m ( i ) ; System . out p r i n t l n ( sum ) ; } } } { double sum = 0 . 0 ; f o r ( i n t i =0; i <1000; i ++) sum = sum + dv . g e t i t e m ( i ) ; System . out p r i n t l n ( sum ) ; } A fordítást és futtatási eredményt itt láthatjuk: j a v a c −d . ∗ j a v a j a v a o r g . c s s w i g t e s t Runme 48 7 3.14 9900 7.485470860550343 Programozási eszközök 6. Python – C/C++ rutinok és könyvtárak használata Python – C/C++ rutinok és könyvtárak használata Az előző 2 írás folytatásaként most röviden áttekintjük a native kódrészletek és könyvtárak Python nyelvből való használatát. Ez a script nyelv napjaink egyik legnépszerűbb eszköze, így fontos tudni azt is, hogy a hiányzó külső funkcionalitások milyen módon integrálhatóak a nyelvbe. A továbbiakban 2 példán

keresztül mutatjuk be a külső könyvtárak és C/C++ kódrészek használatát. Az első az ismerős „rutinok” példa lesz, a másik pedig egy C++ class illesztéséről fog szólni. // 6 −1. P r o g r a m l i s t a : Rutinok py . import Rutinok . def o s s z e g ( ∗ a r g s ) : return Rutinok . o s s z e g ( ∗ a r g s ) o s s z e g = Rutinok . o s s z e g A szokásos „rutinok” példa def k u l o n b s e g ( ∗ a r g s ) : return Rutinok . k u l o n b s e g ( ∗ a r g s ) k u l o n b s e g = Rutinok . k u l o n b s e g A C kód (a rutinok.h header és C forrás) és a swig rutinok.swg fájlok az előző cikkekből megmaradva már készen vannak, most azonban a python illesztő parancsot kell lefuttatni: def sinWithDeg ( ∗ a r g s ) : return Rutinok . sinWithDeg ( ∗ a r g s ) sinWithDeg = Rutinok . sinWithDeg def echo ( ∗ a r g s ) : return Rutinok . echo ( ∗ a r g s ) echo = Rutinok . echo s w i g −python r u t i n o k . swg A python-hoz

generált rutinok wrap.c forA generált Rutinokpy illesztés egy részletét rással hozzuk létre a python megfelelő Rutimutatja a 6-1 Programlista Csak azt a részt nokso fájlt Python esetén fontos, hogy az so mutatjuk itt meg, ami a használat szempontjá- fájl ilyen szerkezű névvel rendelkezzen (aláhúból lényeges. zással kezdődik és nincs lib előtag). g c c −I / u s r / i n c l u d e / python2 . 7 −c −fPIC r u t i n o k −1 c r u t i n o k −2 c matek−r u t i n o k c rutinok wrap c g c c −s h a r e d ∗ . o −o Rutinok s o Ezzel kész vagyunk, próbáljuk ki! Egyszerű >>> párbeszédes üzemmódban indítsuk el a pythont. Az import Rutinok sor behozza a most elkészült Rutinok modult Ezután a szokásos echo(), A C++ class használata sinWithDeg() és osszeg() függvényeket futtatjuk Vegyük a 6-3. Programlista által mutatott C++ interaktív módban. osztályokat (és a hozzá tartozó header fájlt: 6-2. i n y i r i @ c s d e v 1 : $

python Programlista). Python 2 . 7 3 ( d e f a u l t , Sep 26 2 0 1 2 , 2 1 : 5 3 : 5 8 ) [GCC 4 . 7 2 ] on l i n u x 2 Type " h e l p " , " c o p y r i g h t " , . >>> import Rutinok >>> Rutinok . echo ( " aaa " ) ’ aaa ’ >>> Rutinok . sinWithDeg ( 3 0 ) 0.499999999481858 >>> Rutinok . o s s z e g ( 4 9 , 5 1 ) 100 // 6−2. P r o g r a m l i s t a : example h c l a s s Shape { public : Shape ( ) { n s h a p e s++; } v i r t u a l ~Shape ( ) { nshapes −−; 49 Programozási eszközök }; double void virtual virtual static }; Python – C/C++ rutinok és könyvtárak használata x, y; move ( double dx , double dy ) ; double a r e a ( void ) = 0 ; double p e r i m e t e r ( void ) = 0 ; int nshapes ; c l a s s C i r c l e : public Shape { private : double r a d i u s ; public : C i r c l e ( double r ) : r a d i u s ( r ) { } ; v i r t u a l double a r e a ( void ) ; v i r t u a l double p e r i m e t

e r ( void ) ; }; c l a s s Square : public Shape { private : double width ; public : Square ( double w) : width (w) { } ; v i r t u a l double a r e a ( void ) ; v i r t u a l double p e r i m e t e r ( void ) ; }; // 6−3. P r o g r a m l i s t a : example cpp #include " example . h" #define M PI 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 /∗ Move t h e s h a p e t o a new l o c a t i o n ∗/ void Shape : : move ( double dx , double dy ) { x += dx ; y += dy ; } i n t Shape : : n s h a p e s = 0 ; double C i r c l e : : a r e a ( void ) { return M PI∗ r a d i u s ∗ r a d i u s ; } double C i r c l e : : p e r i m e t e r ( void ) { return 2∗M PI∗ r a d i u s ; } double Square : : a r e a ( void ) { return width ∗ width ; } double Square : : p e r i m e t e r ( void ) { return 4∗ width ; } Az osztály python-hoz való illesztéséhez a következő, meglehetősen egyszerű swig konfigurációs fájlt lehet készíteni: %module example %{ #i n c l u d e

" example . h" %} /∗ Let ’ s j u s t grab t h e o r i g i n a l h e a d e r f i l e h e r e ∗/ %i n c l u d e " example . h" A következő parancsok a már jól ismert lépések, aminek az eredményeként az example.so és example.py python forrás jön létre s w i g −c++ −python example . swg g++ −I / u s r / i n c l u d e / python2 . 7 −c −fPIC example cpp example wrap cxx g++ −s h a r e d ∗ . o −o example s o A tesztelést most nem interaktív módon, hanem a 6-4. Programlista által mutatott runme.py scripttel végezzük el Ez a tesztprogram érthető, megértéséhez talán nem szükséges // 6 −4. P r o g r a m l i s t a : runme py import example # −−−−− O b j e c t c r e a t i o n −−−−− print " C r e a t i n g ␣ some ␣ o b j e c t s : " c = example . C i r c l e ( 1 0 ) print " ␣ ␣ ␣ ␣ C reate d ␣ c i r c l e " , c s = example . Square ( 1 0 ) print " ␣ ␣ ␣ ␣

C reate d ␣ s q u a r e " , s 50 külön magyarázat. Az elején beimportálja a most megalkotott example modult és különféle módon használja a Circle és Square osztályokat, amik C++ nyelven készültek. Programozási eszközök Python – C/C++ rutinok és könyvtárak használata # −−−−− Access a s t a t i c member −−−−− print " A␣ t o t a l ␣ o f " , example . c v a r Shape nshapes , " s h a p e s ␣ were ␣ c r e a t e d " # Set the l o c a t i o n of the o b j e c t c . x = 20 c . y = 30 s . x = −10 s .y = 5 print " nHere ␣ i s ␣ t h e i r ␣ c u r r e n t ␣ p o s i t i o n : " print " ␣ ␣ ␣ ␣ C i r c l e ␣=␣(%f , ␣%f ) " % ( c . x , c y ) print " ␣ ␣ ␣ ␣ Square ␣=␣(%f , ␣%f ) " % ( s . x , s y ) # −−−−− C a l l some methods −−−−− print " nHere ␣ a r e ␣ some ␣ p r o p e r t i e s ␣ o f ␣ t h e ␣ s h a p

e s : " f o r o in [ c , s ] : print " ␣ ␣ ␣ " , o print " ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ a r e a ␣ ␣ ␣ ␣ ␣ ␣=␣ " , o . a r e a ( ) print " ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ p e r i m e t e r ␣=␣ " , o . p e r i m e t e r ( ) print " nGuess ␣ I ’ l l ␣ c l e a n ␣up␣now" # Note : t h i s i n v o k e s t h e v i r t u a l d e s t r u c t o r del c del s s = 3 print example . c v a r Shape nshapes , " s h a p e s ␣ remain " print "Goodbye" A tesztprogram futási képe a következő: i n y i r i @ c s d e v 1 : $ python runme . py C r e a t i n g some o b j e c t s : Cre ated c i r c l e <example . C i r c l e ; proxy o f <Swig O b j e c t o f t y p e ’ C i r c l e ∗ ’ a t 0 x 8 f c 0 b 3 0 > > Cre ated s q u a r e <example . Square ; proxy o f <Swig O b j e c t o f t y p e ’ Square ∗ ’ a t 0 x 8 f c 0 c f 8 > > A t o t a l o f 2 s h a p e s were c r e

a t e d Here i s t h e i r c u r r e n t p o s i t i o n : Circle = (20.000000 , 30000000) Square = ( − 1 0 . 0 0 0 0 0 0 , 5 0 0 0 0 0 0 ) Here a r e some p r o p e r t i e s o f t h e s h a p e s : <example . C i r c l e ; proxy o f <Swig O b j e c t o f t y p e ’ C i r c l e ∗ ’ a t 0 x 8 f c 0 b 3 0 > > area = 314.159265359 perimeter = 62.8318530718 <example . Square ; proxy o f <Swig O b j e c t o f t y p e ’ Square ∗ ’ a t 0 x 8 f c 0 c f 8 > > area = 100.0 perimeter = 40.0 Guess I ’ l l c l e a n up now 1 s h a p e s remain Goodbye sága miatt most az egyiket mutatjuk meg. Igaz ez nem C/C++ kiegészítés, de hasonlóan fonA Python és Java illesztés egy érdekes lehetőség, tos és közben a C++ nyelv is használatra kehiszen a Java nagyon kiterjedt osztálykönyvtár- rült. Most az apache JCC nevű eszközét mutatral bír Erre több megoldás is létezik, fontos- juk meg, aminek a webhelye: http://lucene Java 51 Programozási

eszközök Python – C/C++ rutinok és könyvtárak használata apache.org/pylucene/jcc/ A JCC bármely linux disztribúcióban állandó csomagként megtalálható. Vegyük a 6-5 Programlista TestClassjava osztályát A feladat az, hogy ezt illeszteni kell a python környezethez, aminek futásakor a Java VM egy példányát el lehet dinamikusan indítani és a Java releváns részeket abban végrehajtatni. // 6−5. P r o g r a m l i s t a : T e s t C l a s s j a v a package o r g . c s t e s t ; public c l a s s T e s t C l a s s { private S t r i n g msg ; public T e s t C l a s s ( ) { } public void s p e a k ( S t r i n g msg ) { System . out p r i n t l n ( msg ) ; } public void s e t S t r i n g ( S t r i n g s ) { msg = s ; } } public S t r i n g g e t S t r i n g ( ) { return msg ; } le is fordította azt ( testmodul.so) A később használható python modulnevet pedig a –python kapcsoló után adtuk meg. A következő lépés az elkészült testmodul -t próbáljuk

ki, ezért interaktív módban indítsuk el a python-t: i n y i r i @ c s d e v 1 : $ python Python 2 . 7 3 [GCC 4 . 7 2 ] on l i n u x 2 Type " h e l p " , " c o p y r i g h t " , . Töltsük be a most elkészült modulunkat: >>> im po rt t e s t m o d u l Inicializáljuk a JVM-et: >>> t e s t m o d u l . initVM ( c l a s s p a t h=t e s t m o d u l å CLASSPATH) <j c c . JCCEnv o b j e c t a t 0 x 8 7 0 6 1 f 0 > Végül hozzuk létre a Java TestClass osztály 1 példányát és hívjuk meg a speak() metódusát. >>> t = t e s t m o d u l . T e s t C l a s s ( ) >>> t . s p e a k ( " Alma " ) Alma >>> Ami kimaradt. Hasonlóan az előző cikkhez, itt sem tudunk minFordítsuk le a TestClass.java osztályt és te- den részletet ismertetni, ezért továbbra is biztagyük be a mytestjar fájlba: tunk mindenkit a swig dokumentáció önálló taj a v a c −d . T e s t C l a s s j a v a

nulmányozására. Sok speciális, de érdekes példa j a r −c f mytest . j a r o r g lehetett volna még: Ebben a lépésben használjuk a jcc programot • callback használat a következő módon: python −m j c c −−j a r mytest . j a r −−python å t e s t m o d u l −−b u i l d A következők jönnek létre: • C függvényre mutató pointerek használata • testmodul.so • változó paraméterek • testmodul mappa, ami egy python modul (tartalma: init .py és mytestjar ) • C++ template A jcc előállít a jar alapján C++ forrásokat és header fájlokat, sőt a build kapcsoló hatására 52 • kivételkezelés • C++ referencia • A haladó C++ lehetőségek illesztése Java alapú adatbáziskezelők 7. HyperSQL DataBase (HSQLDB) HyperSQL DataBase (HSQLDB) A HSQLDB (Hyper Structured Query Language Database) egy Javaban írt relációs adatbázis-kezelő rendszer. Gyors és kis méretű adatbázis kezelő, amelyben lehetőség van

memóriában, illetve lemezen is tárolni a táblákat Elérhető beágyazott és szerver módban egyaránt Használják adatbáziskezelőként és perzisztencia motorként több nyílt forráskódú projektben (LibreOffice Base), valamint kereskedelmi szoftverben (Mathematica) Elég nagy részhalmazát támogatja az SQL-92 és SQL-2008 szabványoknak. Webhelye: http://hsqldborg/ A HSQLDB már több, mint 10 éve fejlesz- mát egy mappába. A lib könyvtár alatt lévő tett, stabil, jó minőségű RDBMS1 . A Java vi- hsqldbjar fájl mindent tartalmaz: lágban sokszor lehet vele találkozni, mert stabi• Az adatbázis motort litása mellett van néhány olyan tulajdonsága is, amit a fejlesztők szeretnek. Egyszerűen rendel• Az kliens adminisztrációs eszközöket és a kezésre álló és teljes funkcionalitású SQL környezet, így a fejlesztés és tesztelés fázisban is gyors, • Java JDBC drivert hatékony segítséget ad. A hatékonyabb munkához érdemes elkészíteni a

következő 5 parancsindító scripet. A runManaA HSQLDB a projekt webhelyéről tölthető le gerSwingsh egy grafikus frontend vastag prograés egyszerűen csak ki kell csomagolni a tartal- mot indít el, aminek a képét a 71 ábra mutatja Alapvető ismeretek # runManagerSwing . sh j a v a −c l a s s p a t h h s q l d b / l i b / h s q l d b . j a r o r g h s q l d b u t i l DatabaseManagerSwing $1 $2 $3 $4 $5 $6 $7 å $8 $9 A runManager.sh egy hasonló, más stílusú SQL felületet indít el # runManager . sh j a v a −c l a s s p a t h h s q l d b / l i b / h s q l d b . j a r o r g h s q l d b u t i l DatabaseManager $1 $2 $3 $4 $5 $6 $7 $8 $9 A runServer.sh a HSQLDB szerver módját indítja el, így ebben az esetben az éppen megadott adatbázis hálózaton is elérhető lesz. Ez a működés a produktív mód, de fejleszteni is így érdemes # r u n S e r v e r . sh j a v a −c l a s s p a t h h s q l d b / l i b / h s q l d b . j a r o r g h s q l d b u t i l

DatabaseManager $1 $2 $3 $4 $5 $6 $7 $8 $9 Az adatbázis a http(s) felületen is elérhető ezzel a szolgáltatással (runWebServer.sh) # runWebServer . sh j a v a −c l a s s p a t h h s q l d b / l i b / h s q l d b . j a r o r g h s q l d b s e r v e r WebServer $1 $2 $3 $4 $5 $6 $7 $8 $9 A runUtil.sh utility osztályok indítását segíti # r u n U t i l . sh j a v a −c l a s s p a t h h s q l d b / l i b / h s q l d b . j a r o r g h s q l d b u t i l $1 $2 $3 $4 $5 $6 $7 $8 $9 1 RDBMS=Relation DataBase Management System 53 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) • alma.dbproperties Az adatbázisra vonatkozó property-k • alma.dblog Ide történik a naplózás, de adatbázis shutdown esetén ürül. • alma.dblck Amikor in-process módon használjuk az adatbázis-kezelőt, akkor azt csak 1 user érheti el egyidőben, mert lockolódik. Ez a korlátozás server módban természetesen nem áll fenn, akárhány user párhuzamosan dolgozhat

az adatbázison. 7.1 ábra: Database Manager (Swing) A HSQL Database Manager segítségével létrehoztunk egy alma.db nevű adatbázis Ezt úgy kell megtenni, hogy a Connect során ezt a JDBC stringet adtuk meg: jdbc:hsqldb:file://home/tanulas/hsqldb/alma.db Látható, hogy az adatbázis fájlok esetünkben a /home/tanulas/hsqldb mappában fognak megkeletkezni. Belépés után a következő 2 táblát hoztuk létre: CREATE TABLE PUBLIC .TABLA(M1 VARCHAR( 1 0 ) ,M2 å VARCHAR( 2 0 ) ) CREATE TABLE PUBLIC .NEVEK( FIRS VARCHAR( 5 0 ) , å LAST VARCHAR( 5 0 ) ) Végül már most az elején szeretnénk egy lényeges dolgot kiemelni. A perzisztens (fájl alapú) adattáblák 2 módon kezelődnek: • memory Ez az alapértelmezés. Ekkor az adatbázis tábla mindig a script fájlból jön létre, emiatt ez csak teszteléshez ajánlott. • cached Az adatok cached módon egy külső fájlban vannak, így produktív mód esetén ezt kell használni, mert nagyméretű táblák kezelésére

alkalmas. A következő paranccsal beállítottuk, hogy a nevek tábla cached legyen (ezt már a create table parancsban is megtehettük volna): Nézzük meg, hogy milyen fájlokból áll egy SET TABLE nevek TYPE CACHED adatbázis, esetünkben az alma.db Ekkor az eddigi fájlok mellett létrejön az adatok tárolója is: • alma.dbscript A teljes adatbázis nulláról való létrehozását tartalmazó SQL parancsok sorozata A HSQLDB képes az adatbázis fájlban és memóriában is tárolni. A memóriában való tárolás nem biztosít perzisztenciát, azaz az adatok elvesznek. Ekkor a JDBC connect string alakja: jdbc:hsqldb:mem:mymemdb. Lehetőség van az adatbázist fájlba perzisztálni, ekkor használatos ez a script. Ilyenkor így néz ki a JDBC string: j d b c : h s q l d b : f i l e : / / home/ t a n u l a s / h s q l d b /å alma . db 54 • alma.dbdata Ennyi előzmény után már meg is írhatjuk a 7-1. Programlista programját, amit először az 1 felhasználós (nem

szerver módú) környezetben próbáltunk ki a jdbc:hsqldb:file://home/tanulas/hsqldb/alma.db connection stringgel. A Database Manager futott és fogta a teljes adatbázis, így a program első futása kivételre ugrott. Ezután kilépve az admin programból, a mi tesztprogramunk is hibátlanul lefutott, bizonyítva ennek a módszernek az 1 felhasználós voltát. Elkerülendő, hogy Java alapú adatbáziskezelők ez többet ne forduljon elő, illetve a manager és sok más kliens párhuzamosan is használhassa az adatbázist, indítsuk azt el server/hálózatos módban: . / r u n S e r v e r sh −−d a t a b a s e 0 f i l e : å alma . db −−dbname 0 xdb HyperSQL DataBase (HSQLDB) ez látszik kívülről, hogy ne lehessen kitalálni az eredeti AB nevet. A 71 ábra már a hálózatos kapcsolódást mutatja, illetve a 7-1 Programlista éppen aktuális, nem megjegyzésbe tett connect stringje is ez: j d b c : h s q l d b : h s q l : / / l o c a l h o s t /xdb Az egyből

látható, hogy az alma.db lett fel- A hsql a server mód protokollja, létezik a hsqls mountolva, az xdb pedig az adatbázis alias neve, változata is a titkosított csatornához. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // 7−1. P r o g r a m l i s t a : TestHsqlDbConnection j a v a package o r g . c s t e s t ; import import import import import java . java . java . java . java . sql sql sql sql sql . Connection ; . DriverManager ; . ResultSet ; . SQLException ; . Statement ; public c l a s s TestHsqlDbConnection { public s t a t i c void main ( S t r i n g [ ] a r g s ) throws SQLException { // j d b c : h s q l d b : h s q l : / / l o c a l h o s t / xdb // j d b c : h s q l d b : f i l e : / / home/ t a n u l a s / h s q l d b / alma . db Connection conn = DriverManager . g e t C o n n e c t i o n ( " j d b c : h s q l d b : h s q l : / / å l o c a l h o s t /xdb" , "SA" , "" ) ; 18 Statement s t = conn . c r e a t e S t a t e m e n t ( ) ;

19 R e s u l t S e t r s = s t . executeQuery ( " s e l e c t ␣∗␣ from ␣ t a b l a " ) ; 20 21 f o r ( ; r s . next ( ) ; ) 22 { 23 System . out p r i n t l n ( r s g e t S t r i n g ( 1 ) ) ; 24 System . out p r i n t l n ( r s g e t S t r i n g ( 2 ) ) ; 25 } 26 27 st . close () ; 28 rs . close () ; 29 conn . c l o s e ( ) ; 30 } 31 } A runWebServer.sh paranccsal történő server mód indítás a https(s) kapcsolat felett publikálja ki az AB szervert. Ekkor a használható connect string: 55 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) C o n n e c t i o n c = DriverManager . g e t C o n n e c t i o n ( " j d b c : h s q l d b : h t t p : / / l o c a l h o s t /xdb " , "SA" , " " ) ; Adatbázis ezzel a Java sorral állítható le: C o n n e c t i o n = DriverManager . g e t C o n n e c t i o n ( " j d b c : h s q l d b : f i l e : / / home/ t a n u l a s / h s q l d b / alma db ; å shutdown=t r u e

" , "SA" , " " ) ; A CACHED vagy MEMORY tárolás alapértelmezett módját ezzel az SQL paranccsal lehet beállítani: SET DATABASE DEFAULT TABLE TYPE { CACHED | å MEMORY } ; • Datetime típusok (DATE, TIME(6), TIMESTAMP(2) WITH TIME ZONE) • Interval típusok (INTERVAL YEAR TO MONTH, INTERVAL SECOND(4,6)) A környezet támogatja az átmeneti (tempor• Tömbök (Arrays) ary) táblákat, amik csak a connect után jönnek létre, üresen. Disconnect esetén pedig megszűn- Kipróbáltunk sok SQL parancsot, mindegyik tönek Az ilyen táblák mindig egy session-höz ke- kéletesen működött A lentiek csak ebből egy letkeznek és rendelődnek. részletet tartalmaznak, hiszen a jelen cikk nem az SQL nyelvet szeretné ismertetni. Két példa tábla létrehozására: Az SQL nyelv támogatása A HSQLDB törekszik a legfrissebb SQL szabványok implementálására az adatbázis használat mindhárom területén: • DDL (Data Definition Language) • DML (Data

Manipulation Language) • DQL (Data Query Language) A szabványos adattípusokat támogatja, itt most nem térünk ki erre részletesen: • Numeric típusok (Integral Types, DECIMAL, DOUBLE) • Boolean típus • Character String típusok (CHARACTER, CHAR, VARCHAR, CLOB) CREATE nev1 nev2 ho nap ) TABLE nevnap ( v a r c h a r ( 2 5 ) NOT NULL, v a r c h a r ( 2 5 ) NOT NULL, i n t e g e r NOT NULL, i n t e g e r NOT NULL CREATE TABLE o r s z a g o k ( orszag varchar (27) , fovaros varchar (19) , foldr hely varchar (37) , t e r u l e t d e c i m a l ( 1 1 , 2 ) d e f a u l t 0 . 0 0 NOT NULL, allamforma varchar (30) , n e p e s s e g i n t d e f a u l t 0 NOT NULL , n e p f o v a r o s i n t d e f a u l t ’ 0 ’ NOT NULL , a u t o j e l char (3) , country varchar (31) , c a p i t a l varchar (19) , penznem v a r c h a r ( 2 0 ) , p e n z j e l char (3) , valtopenz varchar (18) , t e l e f o n i n t d e f a u l t ’ 0 ’ NOT NULL , gdp i n t d e f a u l t ’ 0 ’ NOT NULL ,

kat i n t d e f a u l t ’ 0 ’ NOT NULL ) Egy új index legenerálása: c r e a t e i n d e x idx nevnap datum on nevnap ( ho , å nap ) • Binary String típusok (BINARY, VARDomain létrehozása. Ez egy fontos SQL leheBINARY, BINARY VARYING, BLOB, tőség, amit a HSQLDB is támogat. Azért jelenLONGVARBINARY) tős, mert az egyes oszlopoknak megadható típu• Bit String típusok (BIT, BIT VARYING) sok helyett korábban megalkotott domain nevek 56 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) is alkalmazhatóak, amik előre preparált konkréJelenleg ezek a változók csak a tárolt eljátabb típusok és esetleg már a megszorítások is rások IN, OUT vagy INOUT paraméterei lehethozzá vannak rendelve. nek, azaz egy SQL műveletben nem használhatóak fel. CREATE DOMAIN p o s t a l c o d e AS v a r c h a r ( 2 0 ) CHECK( v a l u e I S NOT NULL AND CHARACTER LENGTH( å value ) > 2) ; Az ilyen táblák adnak információt az adat- Session Táblák

bázis metaadatairól: Ezek a táblák a session alatt hozhatók létre, azok SELECT ∗ FROM INFORMATION SCHEMA. TABLES lezárásával meg is szűnnek. Szekvencia létrehozása és a következő érték DECLARE LOCAL TEMPORARY TABLE b u f f e r ( i d å lekérése: INTEGER PRIMARY KEY, t e x t d a t a VARCHAR( 1 0 0 ) å CREATE SEQUENCE my sorszam SELECT n e x t v a l u e f o r my sorszam ) ON COMMIT PRESERVE ROWS from nevek A Session és Tranzakció Tranzakciók Minden SQL művelet a felhasználói bejelentke- A HSQLDB támogat különféle transaction isolazés után kialakult kapcsolathoz (session) ren- tion modellt: delve hajtódik végre. A session néhány előre beállított jellemzővel rendelkezik, amiket persze a • READ UNCOMMITTED használata során át is lehet állítani. Itt most nem adjuk meg az összes ilyen kapcsolathoz ren• READ COMMITTED delt változó és attribútum beállítási lehetőséget, de bemutatunk párat. A session a tranzakció• REPEATABLE

READ kezelés kerete is, amit a HSQLDB teljes körűen ismer (COMMIT, ROLLBACK ). • SERIALIZABLE Session változók Ezek az összes konkurenciavezérlési típus alatt A bejelentkezés után létrejön néhány beállított, elérhetőek, mely az alábbi paranccsal állítható de már nem megváltoztatható érték. Példák: be: • CURRENT USER (a bejelentkezett felhasználó login neve) SET DATABASE TRANSACTION CONTROL { LOCKS | å MVLOCKS | MVCC } A two-phase locking modell az alapértelme• CURRENT SCHEMA (az éppen haszzett mód, amelyben a HSQLDB az elosztott nált séma neve) tranzakciók részévé tud válni. A session-ök az Ezzel együtt képesek vagyunk új változókat is SQL környezetek ismert alter session parancsával állíthatók. Az auto commit ezzel a set utalétrehozni, melyre egy példa: sítással manipulálható: DECLARE c o u n t e r INTEGER DEFAULT 3 ; DECLARE r e s u l t VARCHAR( 2 0 ) DEFAULT NULL; SET c o u n t e r =15; CALL myroutine ( c o u n t e

r , r e s u l t ) SET AUTOCOMMIT { TRUE | FALSE } 57 Java alapú adatbáziskezelők Jogosultságkezelés HyperSQL DataBase (HSQLDB) Például a lehetséges tábla privilégiumokat ezzel a select-tel lehet lekérdezni: A HSQLDB – ahogy azt a komolyabb adatbázisSELECT ∗ FROM INFORMATION SCHEMA. å kezelők esetén megszoktuk – egy teljes körű hiteTABLE PRIVILEGES lesítési és jogosultságkezelési rendszerrel rendelNézzük meg egy példán keresztül a user, role kezik, így a más rendszerekből ismert adminisztrációs parancsok itt is használhatóak. Példaként és grant használatát a korábban létrehozott inyhozzunk létre egy inyiri nevű user-t (a parancs- iri user-re! Első lépésben csinálunk egy approle nevű szerepkört (role): ban 1 lépéssel admin lett): CREATE USER i n y i r i PASSWORD pppppp ADMIN CREATE ROLE a p p r o l e Ezután azt mondjuk, hogy inyiri felhasznáA repository (system tables) tartalmazza az lót felhatalmazzuk ennek a

szerepkörnek a beadatbázis összes felhasználóját, így ezzel a patöltésére: ranccsal már ez az új user is megjelenik: SELECT ∗ FROM INFORMATION SCHEMA.SYSTEM USERS GRANT a p p r o l e TO i n y i r i A szokásos alter és drop user parancsok is Innen kezdve az approle szerepkörhöz rendelt elérhetőek. Fontos annak a megadása, hogy be- jogokban inyiri is eljárhat A következő 3 pajelentkezés után melyik sémába kerül a felhasz- rancsban adunk a szerepkörnek néhány jogot: náló. Ez így lehetséges: GRANT SELECT, UPDATE ON TABLE nevnap TO å ALTER USER <u s e r name> SET INITIAL SCHEMA <å schema name> approle GRANT USAGE ON SEQUENCE a s e q u e n c e t o a p p r o l e GRANT EXECUTE ON ROUTINE a r o u t i n e TO a p p r o l e Persze ehhez sémákat is létre lehet hozni, a A fentiek értelmében szelektálhatja és frissítkésőbbiekben látjuk majd, hogy ezt a HSQLDB heti a nevnap táblát, használhatja az asequence támogatja. Egy új

adatbázis létrehozásakor létszekvenciát, valamint futtathatja az aroutine-t rejön 2 séma: A jogok az SQL-ben megszokott REVOKE pri• PUBLIC Amennyiben nem rendeltük vilege paranccsal vonhatóak vissza. A HSQLDB 2 előre létező, beépített felhaszmáshova a felhasználót, ez lesz a sémája. nálót biztosít: SA és SYS. Ugyanígy a következő • INFORMATION SCHEMA Az adat- szerepkörök is előredefiniáltak: bázis repository sémája. • PUBLIC Mindenkinek szükséges A user objektumok már az SQL-92 szabványban is léteztek, de a role csak az • SYSTEM Ez a role nem rendelhető SQL-99-ben jelent meg. Jogosultságokat user-hez, a rendszer használja. (GRANT =engedményezés) user vagy role kaphat, amelyek ezekhez hasonlóak lehetnek: • DBA Az összes adminisztratív taszkot végre lehet vele hajtani • Tábla select, • CREATE SCHEMA Egy sémát hoz• Tábla változtatási műveletek (insert, uphat létre, módosíthat vagy törölhet date, delete), •

Futtatás, • DDL műveletek 58 • CHANGE AUTHORIZATION Megváltoztathat jogosultságkezelési beállításokat Java alapú adatbáziskezelők A HSQLDB sémák és objektumok A séma HyperSQL DataBase (HSQLDB) Természetesen külön szekvenciát is használhatunk erre a célra: CREATE TABLE t ( i d INTEGER GENERATED BY DEFAULT AS SEQUENCE s , name VARCHAR( 2 0 ) PRIMARY KEY ) Egy adatbázis katalógusa tartalmaz sémákat, a sémák pedig az adatbázis objektumok névterei. Minden HSQLDB adatbázis pontosan 1 katalógust tartalmaz, aminek a neve PUBLIC, de ezt View az ALTER CATALOG RENAME TO utasítással át is lehet nevezni. Egy új sémát így hozha- A view egy SQL select, amit névvel is illetünk és úgy kezeljük, mintha egy tábla lenne. A jatunk létre: nuar nevek egy olyan nézete a nevnap táblának, CREATE SCHEMA <schema name c l a u s e > [ <schema å c h a r a c t e r s e t s p e c i f i c a t i o n > ] [ <schema å ami csak az 1. hónap sorait

tartalmazza: element > . ] ahol a schema name clause alakja így néz ki: c r e a t e view januar nevek a s s e l e c t ∗ from å nevnap where ho=1 <schema name> vagy AUTHORIZATION <a u t h o r i z a t i o n i d e n t i f i e r > vagy <schema name> AUTHORIZATION <a u t h o r i z a t i o n å identifier > A nézetekre DROP VIEW és ALTER VIEW lehetőségek használhatóak. Ez azt jelenti, hogy az egyszerű CREATE SCHEMA <schema name clause> esetben az aktuális user a séma tulajdonosa. Amennyiben authorization identifier részt is megadunk, úgy az egy user vagy role lehet. Példa: A sémákban minden objektumnak egy sémán belüli egyedi neve van, ezekkel hivatkozunk rá. Ez lehet minősített is, ahogy a következő lehetőség mutatja egy tábla oszlop esetére: CREATE SCHEMA ACCOUNTS AUTHORIZATION DBA; Nevek és referenciák <c a t a l o g name>.<schema name>< t a b l e name><å column name> Ezzel a teljes

névhivatkozással más objektuEbben az esetben az ACCOUNTS nevű sémát hoztuk létre, amit DBA szerepkörben lehet mok is megszólíthatóak, például egy szekvencia esetén ez így nézne ki: tulajdonolni. <c a t a l o g name>.<schema name>< s e q u e n c e name> Táblák Korábban ismertettük a táblákkal kapcsolatos alapvető ismereteket, így most csak annyit szeretnénk megjegyezni, hogy ezek az adatbázisbázis üzleti adatainak tárolói, így a sémák talán legfontosabb objektumai. Az SQL nyelv összes ismert DDM művelete használható. A táblák ID oszlopának értékét egy névtelen szekvenciából érdemes automatikusan feltölteni, ahogy a példa is mutatja: CREATE TABLE t ( i d INTEGER GENERATED ALWAYS AS IDENTITY(START WITH å 100) , name VARCHAR( 2 0 ) PRIMARY KEY ) Az egyes nevek az ALTER . RENAME TO utasítással át is nevezhetőek. Character Sets A karakter halmaz vagy a teljes UNICODE kódkészlet vagy annak egy részhalmaza. Van jó

pár előre definiált karakter halmaz, melyek közül a legfontosabbak: • SQL TEXT a teljes UNICODE kódkészlet • SQL CHARACTER az ASCII karakterek 59 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) Ezután a MONEY egy olyan név, amit a tárolt eljárások írása során felhasználhatunk, haA collation (egyeztetés) annak a megvalósítása, sonlóan a beépített típusokhoz. hogy a nemzeti lehetőségek figyelembevételével hasonlíthassunk össze 2 stringet. Az alapértelInformációk szerzése a sémáról mezett collation az SQL TEXT, ami az unicode karakter sorrend szerinti rendezést valósítja meg. Ahogy korábban említettük, az adatbázis minA HSQLDB rendszerben létező összes collation den meta adatát a katalógus, azaz a INFORMAneve így kérdezhető le a katalógusból: TION SCHEMA séma táblái tartalmazza. Ezt azt jelenti, hogy a séma összes objektumának a SELECT ∗ FROM INFORMATION SCHEMA. COLLATIONS definíciója az itt lévő

táblákban megtalálhatóak. Eredményként természetesen az SQL TEXT Most csak ízelítőül láthatjuk az ORSZAG tábla is megjelenik. A magyar collation neve: Hunga- szerkezetét, illetve a nemrég létrehozott getBook rian. További collation-ok létrehozására szolgál procedúra részleteit: a CREATE COLLATION, bár erre ritkán van SELECT ∗ FROM INFORMATION SCHEMA. å SYSTEM COLUMNS where table name =’ORSZAGOK’ szükség. Ezt a mechanizmust több helyen lehet SELECT ∗ FROM "INFORMATION SCHEMA" . "ROUTINES" å használni, de az egyik legnyilvánvalóbb a select where s p e c i f i c n a m e =’GETBOOK 12228’ order by utáni rendelkezési záradéka. Adjunk ki egy select parancsot: Collation Megszorítások (Constraints) s e l e c t ∗ from nevnap o r d e r by nev1 Ekkor például az Ábel a legvégén lesz, ami A HSQLDB ismeri a megszorításokat, azokat az nyilvánvalóan helytelen, azonban így már jó lesz Oracle vagy más hasonló

környezetekhez hasonlóan lehet megadni, így védhetjük az adatbázis a sorrend: konzisztenciáját. Tekintsük át őket röviden! s e l e c t ∗ from nevnap o r d e r by nev1 c o l l a t e Hungarian ’ ’å A NOT NULL A korábbiakban mutattunk egy példát a nevek tábla létrehozására, benne egy nev1 mezővel, A HSQLDB támogatja az SQL 3 szabványban ahol a NOT NULL a legegyszerűbb megszorílétező tárolt eljárásokat, amire itt most csak egy tások egyike: CREATE TABLE nevnap ( példát mutatunk: Tárolt eljárás c r e a t e p r o c e d u r e getBook ( i n t i t l e v a r c h a r ( 3 0 ) , å out a u t h o r v a r c h a r ( 3 0 ) ) READS SQL DATA b e g i n atomic s e l e c t t i t l e INTO a u t h o r FROM books WHERE å t i t l e =books . t i t l e ; end nev1 v a r c h a r ( 2 5 ) NOT NULL, . ) Ez annyit jelent, hogy a mező nem maradhat definiálatlan értékű, amikor egy új sort szúrunk a táblába. Hivatkozási épség és a kulcs SQL 3 Típusok Ez egy

nagyon hatékony eszköz, hiányában sok Egy új típus a CREATE TYPE utasítással hoz- programsort kéne arra fordítani, hogy a szülőható létre: gyerek kapcsolatok épségét fenntartsuk (foreign CREATE TYPE MONEY AS NUMERIC( 1 0 , 2 ) key). Hozzunk létre 2 táblát: 60 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) • AUTHORS : A szerzők. A tábla kulcsa egy ID oszlop. előfordul az AUTHORS táblában. Ezt a tényt pontosan meg is adtuk a FOREIGN KEY . REFERENCES részben, így a HSQLDB motor vigyázz arra, hogy csak olyan BOOKS.AUTHOR ID legyen, ami létezik. • BOOKS : Könyvek. A kulcs neve itt is ID Az AUTHOR ID a szerző azonosítóját tárolja, azaz csak olyan értéke lehet, ami CREATE TABLE AUTHORS( ID INT PRIMARY KEY, NAME VARCHAR( 2 5 ) ) ; CREATE TABLE BOOKS( ID INT PRIMARY KEY, AUTHOR ID INT , TITLE VARCHAR( 1 0 0 ) , FOREIGN KEY(AUTHOR ID) REFERENCES AUTHORS( ID ) ) ; Példaképpen töltsük is fel a két táblát néhány rekorddal:

INSERT INSERT INSERT INSERT INSERT INTO INTO INTO INTO INTO AUTHORS( ID , AUTHORS( ID , AUTHORS( ID , AUTHORS( ID , AUTHORS( ID , INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT INTO INTO INTO INTO INTO INTO INTO INTO INTO BOOKS( ID , BOOKS( ID , BOOKS( ID , BOOKS( ID , BOOKS( ID , BOOKS( ID , BOOKS( ID , BOOKS( ID , BOOKS( ID , NAME) NAME) NAME) NAME) NAME) VALUES( 1 , VALUES( 2 , VALUES( 3 , VALUES( 4 , VALUES( 5 , AUTHOR ID, AUTHOR ID, AUTHOR ID, AUTHOR ID, AUTHOR ID, AUTHOR ID, AUTHOR ID, AUTHOR ID, AUTHOR ID, TITLE) TITLE) TITLE) TITLE) TITLE) TITLE) TITLE) TITLE) TITLE) ’ Jack London ’ ) ; ’ Honore de Balzac ’ ) ; ’ Lion Feuchtwanger ’ ) ; ’ Emile Zola ’ ) ; ’ Truman Capote ’ ) ; VALUES( 1 , VALUES( 2 , VALUES( 3 , VALUES( 4 , VALUES( 5 , VALUES( 6 , VALUES( 7 , VALUES( 8 , VALUES( 9 , UNIQUE A unique egy olyan megszorítás, ami arra figyel, hogy egy oszlop minden értéke különböző legyen. Ilyen például a primary key is, ahol

emellett még a NOT NULL is feltétel ekkor: CREATE TABLE P e r s o n s ( P Id i n t NOT NULL UNIQUE, LastName v a r c h a r ( 2 5 5 ) NOT NULL, FirstName v a r c h a r ( 2 5 5 ) , ; Address v a r c h a r ( 2 5 5 ) , City varchar (255) ); 1, 1, 2, 2, 3, 4, 4, 5, 5, ( ) ’ C a l l o f t h e Wild ’ ) ; ’ Martin Eden ’ ) ; ’ Old G o r i o t ’ ) ; ’ Cousin Bette ’ ) ; ’ Jew Su es s ’ ) ; ’ Nana ’ ) ; ’ The B e l l y o f P a r i s ’ ) ; ’ I n Cold blood ’ ) ; ’ Breakfast at Tiffany ’ ) ; P Id i n t NOT NULL CHECK ( P Id>0) , LastName v a r c h a r ( 2 5 5 ) NOT NULL, FirstName v a r c h a r ( 2 5 5 ) , Address v a r c h a r ( 2 5 5 ) , City varchar (255) CREATE TABLE P e r s o n s ( P Id i n t NOT NULL, LastName v a r c h a r ( 2 5 5 ) NOT NULL, FirstName v a r c h a r ( 2 5 5 ) , Address v a r c h a r ( 2 5 5 ) , City varchar (255) , CONSTRAINT chk Person CHECK ( P Id>0 AND C i t y å =’ Sandnes ’ ) ) Az első check a P ID oszlophoz

kötődik, azonban a 2. példa már egy táblasor szintű elA check megszorítás egy oszlopra vagy a táb- lenőrzést valósít meg lázatra értelmez egy ellenőrző algoritmust, így segítségével az összes többi constraint is impleTriggerek mentálható lenne. Az alábbiak a Persons táblára adnak meg ellenőrzéseket: A triggerek az SQL-99 szabványban jelentek CREATE TABLE P e r s o n s meg, így azokat a HSQLDB is támogatja. Ezek CHECK Constraint 61 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) olyan események kezelői, amik a DML (INSERT, ahol a check megszorítás lenne a kívánatos. Az UPDATE, DELETE) műveletek során hívódnak alábbiak egy példát mutatnak egy HSQLDB trimeg. Már itt az elején szeretnénk kiemelni azt gger létrehozására: a gyakori hibát, amikor triggert használnak ott, /∗ t h e t r i g g e r throws an e x c e p t i o n i f a c u s t o m e r with t h e g i v e n l a s t name a l r e a d y e x i s t s ∗/ CREATE TRIGGER

t r i g o n e BEFORE INSERT ON c u s t o m e r REFERENCING NEW ROW AS newrow FOR EACH ROW WHEN ( newrow . i d > 1 0 0 ) BEGIN ATOMIC IF EXISTS (SELECT ∗ FROM CUSTOMER WHERE CUSTOMER.LASTNAME = NEWLASTNAME) THEN SIGNAL SQLSTATE ’ 4 5 0 0 0 ’ SET MESSAGE TEXT = ’ a l r e a d y e x i s t s ’ ; END IF ; END Trigger esemény Mikor csattanjon el? Azt már tudjuk, hogy az események kibocsátása A DML művelet szempontjából 3 helyen lehet a az INSERT, UPDATE, DELETE hatására tör- triggert kiváltani: ténhet a HSQLDB-ben is. Lényeges lehetőség, • Before: A DML művelet előtt váltódik ki, hogy szűrhessünk egy when feltétellel, ugyanis segítségével abortálhatjuk a műveletet. Itt általában nem kéne mindig elcsattannia a tria többi tábla tartalma nem változtatható ggernek: meg, de az aktuális táblának a sora igen. CREATE TRIGGER t r i g AFTER INSERT ON t e s t t r i g BEFORE o t h e r t r i g g e r REFERENCING NEW ROW AS newrow FOR EACH ROW WHEN (

newrow . i d > 1 ) BEGIN ATOMIC INSERT INTO t r i g l o g VALUES ( newrow . id , å newrow . data , ’ i n s e r t e d ’ ) ; /∗ more s t a t e m e n t s can be i n c l u d e d ∗/ END A működés finomsága • After : Az after trigger már nem változtathatja meg DML művelet eredményét (azokon a sorokon, amiken hatott), azonban a többi tábla változtatható és egyéb adminisztrációs tevékenységek is elvégezhetőek. • Instead of : A view-on deklarált triggerek. Hivatkozás a sorokra Amikor a trigger kódját írjuk, hivatkozni kell Más SQL környezetekhez hasonlóan itt is 2 szint tudni annak régi és új értékére is. Erre szolgál lehetséges: ez a 2 formalizmus: • REFERENCING NEW ROW AS newrow 1. FOR EACH STATEMENT a trigger • REFERENCING OLD ROW AS oldrow csak az SQL kifejezésre, 1 alkalommal fut le (előtte vagy utána). Ez az alapértelme- A newrow és oldrow változókkal érhetjük el a zett működés. régi és új táblasort. Példa a

használatára: 2. FOR EACH ROW a trigger minden érintett sorra végrehajtott művelet alkalmából lefut (előtte vagy utána). 62 CREATE TRIGGER t r i g AFTER INSERT ON t e s t t r i g REFERENCING NEW ROW AS newrow FOR EACH ROW WHEN ( newrow . i d > 1 ) INSERT INTO TRIGLOG VALUES ( newrow . id , å newrow . data , ’ i n s e r t e d ’ ) Java alapú adatbáziskezelők Java alapú trigger írása HyperSQL DataBase (HSQLDB) • TYPE SCROLL INSENSITIVE A org.hsqldbTrigger interface egy implementá- Amennyiben a selectben megadjuk a FOR UPciója a Java alapú trigger Ennek 1 implemen- DATE OF <column name list> záradékot, hogy tálandó metódusa van: a létrejött SQL kurzoron keresztül módosítf i r e ( i n t type , S t r i n g trigName , S t r i n g tabNameå ható az eredménytábla sora. Tekintettel arra, , O b j e c t [ ] oldRow , O b j e c t [ ] newRow) ; hogy ezen cikknek nem feladata az SQL részleA paraméterek jelentése: tekbe menő ismertetése,

ezért a további lehetőségek megismeréséhez nyugodtan tanulmányoz• type a trigger típusa zunk SQL könyveket, a HSQLDB nagy valószínűséggel nagy részüket támogatni fogja. To• trigName a trigger neve vábbi fontos tudnivalókat tartalmaz ehhez a • tabName annak a táblának a neve, részhez a HSQLDB ide vonatkozó dokumentáamire a triggert alkalmazni szeretnénk ciója is: http://hsqldb.org/doc/20/guide/ dataaccess-chapt.html • oldRow old row • newRow new row SQL rutinok A HSQLDB támogatja a tárolt eljárások és függvények készítését SQL és Java nyelveken egyA HSQLDB SQL adatelérési (select) és azok aránt. A függvények jellemzője: megváltoztatási lehetősége teljes mértékben • Az ismert CREATE FUNCTION pakompatibilis az SQL-2008-as szabvánnyal, azaz ranccsal hozzuk létre. nagyon korszerű. A Java JDBC alrendszerből tudjuk, hogy Java oldalról SQL parancs ezen • Visszatérési értéke egy szimpla érték vagy 2 interface

valamelyikének használatával adható egy tábla. ki: • A függvény futása során nem módosíthat• java.sqlStatement teljesen különböző juk az adatbázist. SQL parancsok egymás utáni kiadására • Egy SQL parancs részeként használható. • java.sqlPreparedStatment azonos vázú, de paraméterezhető SQL parancsok egy• Tartalmazhat input paramétereket. más utáni kiadására • Támogatja a polimorfizmust, azaz több Amennyiben egy SQL select kerül kiadásra, úgy különböző függvénynek is lehet ugyanaz a egy kurzor jön létre, ennek a Java reprezentácineve. ója a java.sqlResultSet A létrejött kurzor lehet SCROLL vagy NO SCROLL típusú, ahogy azt a Az eljárások jellemzői: JDBC szabvány is tartalmazza. Egy JDBC sta• A CREATE PROCEDURE paranccsal tement parameterben elvileg megadható a követhozzuk létre. kező 2 opció, de a másodikat a HSQLDB JDBC nem támogatja: • Visszatérhet nulla vagy több értékkel vagy • TYPE FORWARD ONLY

eredményhalmazzal (Result Set). Az adatok elérése és változtatása 63 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) • Módosíthatja az adatbázis adatait. • Tartalmazhat input paraméreket. • Elkülönítetten az SQL parancsoktól, a CALL hívással futtathatjuk le. • Támogatja a polimorfizmust, azaz több különböző függvénynek is lehet ugyanaz a neve. Nézzünk 2 példát függvény létrehozására: CREATE FUNCTION an hour before or now ( t TIMESTAMP) RETURNS TIMESTAMP NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA SPECIFIC an hour before or now with timestamp EXTERNAL NAME ’CLASSPATH: o r g . npo l i b nowLessAnHour ’ CREATE FUNCTION an hour before max ( e type INT ) RETURNS TIMESTAMP SPECIFIC an hour before max with int RETURN (SELECT MAX( event time ) FROM a t a b l e WHERE event type = e type ) − 1 HOUR Példa egy táblával való visszatérésre: RETURN TABLE ( SELECT a , b FROM a t a b l e WHERE e = 10 ) ; Az alábbiakban azt

demonstráljuk, hogy egy saját függvény, hogyan használható egy SQL parancsból. Íme a függvény: CREATE FUNCTION an hour before ( t TIMESTAMP) RETURNS TIMESTAMP RETURN t − 1 HOUR És a használata: SELECT an hour before ( event timestamp ) AS n o t i f i c a t i o n t i m e s t a m p , event name FROM e v e n t s ; Most nézzünk meg egy procedure definiálását és hívását! CREATE PROCEDURE new customer ( f i r s t n a m e VARCHAR( 5 0 ) , l a s t n a m e VARCHAR( 5 0 ) ) MODIFIES SQL DATA INSERT INTO CUSTOMERS VALUES (DEFAULT, f i r s t n a m e , lastname , CURRENT TIMESTAMP) Hívás: CALL new customer ( ’JOHN’ , ’SMITH’ ) ; Az eljárások és függvények készítési lehető- tóak: ségeiről a további információkért olvassuk el az • SQL Standard függvények SQL szabványt. • JDBC Open Group CLI függvények Beépített függvények • HyperSQL Built-In függvények Az SQL beépített függvények (TO CHAR(.), Itt most ízelítőül,

magyarázat nélkül néhány dáASCII(), stb) természetesen a HSQLDB-nek is tumkezeléssel kapcsolatos belső függvény hasza részei A built-in-ek 3 fő csoportba sorolha- nálatot mutatunk be: 64 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) −− Dátum k o n s t a n s s e l e c t week (DATE ’2012 −12 −01 ’) from nevek s e l e c t q u a r t e r (DATE ’2012 −01 −5 ’) from nevek s e l e c t week (DATE ’2012 −05 −5 ’) from nevek −− Timestamp SQL t í p u s s e l e c t DAY(TIMESTAMP ’2012 −02 −14 1 2 : 3 0 : 4 4 ’ ) from t a b l a −− Az év n a p j a i n a k száma s e l e c t d a y o f y e a r (DATE ’2012 −02 −29 ’) from nevek −− A hónap n a p j a i n a k száma s e l e c t dayofmonth (DATE ’2012 −02 −29 ’) from nevek −− 3 hónap h o z z á a d á s a s e l e c t DATE ADD ( DATE ’2008 −11 −22 ’ , INTERVAL 3 MONTH ) from nevek −− 5 nap h o z z á a d á s a s e l e c t DATE ADD ( DATE

’2008 −11 −22 ’ , INTERVAL 5 DAY ) from nevek −− 5 év h o z z á a d á s a s e l e c t DATE ADD ( DATE ’2008 −11 −22 ’ , INTERVAL 5 YEAR ) from nevek −− 5 év k i v o n á s a s e l e c t DATE SUB ( DATE ’2008 −11 −22 ’ , INTERVAL 5 YEAR ) from nevek −− 5 ó r a k i v o n á s a s e l e c t DATE SUB ( ’2008 −11 −22 1 4 : 5 0 : 0 1 ’ , INTERVAL 5 HOUR ) from nevek Rendszer menedzsment Nagy méretű adatbázis Az eddigiektől láttuk, hogy a HSQLDB szerver és beágyazott üzemmódban is használható, ugyanakkor ennek a menedzsmentje ettől nagyrészt független. A táblák és large objektumok CACHED módon is tárolhatóak, ami azt jelenti, hogy azoknak csak egy része töltődik a memóriába. Ezzel nagyméretű adatbázisok is kezelhetőek. Példa a LOB CACHED beállításra: Az adatbázis típusa SET TABLE SYSTEM LOBS.BLOCKS TYPE CACHED SET TABLE SYSTEM LOBS. LOBS TYPE CACHED SET TABLE SYSTEM LOBS. LOB IDS TYPE CACHED Az

adatbázis típusának beállítása: • mem: csak memóriában létezik, A ACID teljes körű támogatása Az ismert ACID kifejezés az Atomicity, Consistency, Isolation és Durability szavakból képzett • file: perzisztencia van és fájlban tárolt mozaikszó. vagy • res: erőforrás leíróban tárolt. Read Only mód Egy adatbázis read only módba állítható a readonly=true property megadásával. Backup - Restore Az adatbázis mentésére a BACKUP DATABASE parancs szolgál. Az online mentés ezzel a paranccsal oldható meg: BACKUP DATABASE TO <d i r e c t o r y name> BLOCKING Lehetséges az offline mentés is: j a v a −cp h s q l d b . j a r o r g h s q l d b l i b t a r DbBackup −−s a v e t a r d i r / backup t a r d b d i r /dbname A mentésből való visszaállítás restore utasítása így használható: 65 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) j a v a −cp h s q l d b . j a r o r g h s q l d b l i b t a r

DbBackup −−e x t r a c t t a r d i r / backup t a r d b d i r Titkosított adatbázis használata hatunk az adatbázishoz: Amennyiben rendelkezünk egy szimmetrikus titkosító kulccsal, úgy ezzel a sémával is kapcsolódj d b c : h s q l d b : f i l e :< d a t a b a s e path >; crypt key =604 a 6 1 0 5 8 8 9 d a 6 5 3 2 6 b f 3 5 7 9 0 a 9 2 3 9 3 2 ; crypt type=b l o w f i s h Ez lehetővé tesz a titkosított tárolás és adat- definiálni, mint a közönséges táblákat, de a text elérés lehetőségét. kulcsszót meg kell adni: Monitorozás CREATE TEXT TABLE <tablename> (<column å d e f i n i t i o n > [< c o n s t r a i n t d e f i n i t i o n >]) • External Statement Level Monitoring Ekkor a tábla még üres és nem lehet írni. A következő paranccsal lehet ezt a táblát egy konkrét szövegfájlhoz rendelni: • Internal Event Monitoring SET TABLE <tablename> SOURCE <å quoted filename and options> [ DESC ] Itt

csak felsoroljuk a beépített lehetőségeket: • Log4J and JDK alapú naplózás • Server Operation Monitoring Nézzünk egy példát! Van egy text table.txt fájl a következő tartalommal: aaaaaaa ; bbbbbbbbbb ; 1 1 1 1 1 1 xxxxx ; yyyyyyyyyy ; 2 2 2 2 2 A HSQLDB menedszmentjéről többet Most a „;” jelet használjuk mező elválasztóa szoftver dokumentációjából tudhatunk meg: http://hsqldb.org/doc/20/guide/ ként (Field Separator ) Ebből egy 3 oszlopos text táblát az alma.db adatbázisban így tudunk management-chapt.html készíteni: Network Listeners Amikor szerver módban indítjuk adatbáziskelőnket, akkor annak a szolgáltatásai hálózaton keresztül érhetőek el. Ilyenkor a kliens egy un. listener szolgáltatáson keresztül kapcsolódik a szerverhez. Ez a működés megegyezik más ismert adatbázis-kezelőknél alkalmazott módszerrel CREATE TEXT TABLE t e x t t a b l e ( o1 v a r c h a r ( 2 0 ) , o2 v a r c h a r ( 2 0 ) , o3 i n t e g e r )

SET TABLE t e x t t a b l e SOURCE " t e x t t a b l e . t x t ; f s å =semi " s e l e c t ∗ from t e x t t a b l e O1 O2 aaaaaaa bbbbbbbbbb xxxxx yyyyyyyyyy O3 111111 22222 Az 1. utasítás o1, o2, o3 oszlopokkal hozza létre a táblát, majd a 2. hozzárendeli a fájlt Érdekes lehetősége a HSQLDB környezetnek, és azt is megadja, hogy mi a mezőelválasztó kahogy egy szövegfájlra úgy tudunk rátekinteni, rakter. A 3 parancs egy teszt SQL select-tel mint egy táblára. A text táblákat hasonlóan kell mutatja az eredménytáblát Természetesen ez a Text táblák 66 Java alapú adatbáziskezelők HyperSQL DataBase (HSQLDB) tábla olyan, mint a többi, azaz például beszúr- be van építve, ugyanis itt 2 további problémát hatunk 1 sort, ami meg is jelent a textfájlban: is meg kell oldani. Az egyik az, hogy az első i n s e r t i n t o t e x t t a b l e v a l u e s ( ’ Ez ’ , ’ Az ’ , å sorban az oszlopnevek lehetnek, ezért azt

figyel1000) men kívül kell hagyni. A másik feladat pedig a A tranzakciókezelés használható az ilyen táb- csv szabvány szerinti minden értéket körülvevő lákra is. A csv fájl támogatás külön lehetőse is idézőjelek elhagyásának bekapcsolása: SET TABLE mytable SOURCE " m y f i l e ; i g n o r e f i r s t=t r u e ; a l l q u o t e d=t r u e " A text tábláról való lekapcsolódás: SET TABLE mytable SOURCE OFF Tekintettel arra, hogy egy textfájl kódolása sokféle lehet, ezért ebben a példában annak megadására is mutatunk példát: SET DATABASE TEXT TABLE DEFAULTS ’ a l l q u o t e d=t r u e ; e n c o d i n g=UTF−8; cache rows =10000; c a c h e s i z e å =2000 ’ SQL Tool • isql for Sybase, A HyperSQL Utilities Guide tartalmaz néhány leírást azokról a további eszközökről, amiket a HSQLDB tartalmaz és megkönnyíti a mindennapi életünket (sqltool.jar fájl) Az SQL Tool az egyik, ami bármelyik JDBC képes

adatbáziskezelő irányába használható. A célja az, hogy kiváltsa a következő ismert konzol módú programok használatát: • psql for Postgresql, • Sql*plus for Oracle. Az eszköz képessége valóban lehetővé teszi ezt, rengeteg parancssori trükk és mindennapos feladat oldható meg a segítségével. Így indítható el: j a v a −c l a s s p a t h h s q l d b / l i b / h s q l d b . j a r : h s q l d b / l i b / s q l t o o l j a r −j a r h s q l d b / l i b / s q l t o o l j a r −−h e l p Transfer Tool Ez egy olyan GUI eszköz (helye: hsqldbutil.jar ), ami lehetővé teszi, hogy sémákat és adatokat másoljunk 2 JDBC alapú adatforrás között. Az eszköz érdekessége és izgalmas lehetőségei abból is fakadnak, hogy ez a 2 adatforrás eltérő adatbázis motor is lehet. Két üzemmódja van: • Direct Transfer • Dump és Restore alapú Transfer 67 Szilánkok 8. Tippek és Trükkök Tippek és Trükkök A mindennapi életben naponta

bukkannak fel érdekes, ötletes megoldások. Itt most 3 olyan egyszerű ötletet szeretnénk bemutatni, amik az elmúlt hónapokban hasznosak voltak számunkra előbb nézzük meg az s client openssl parancs működését! Indítsuk el és adjuk ki a parancsot Mindig szükségünk van a HTTPS protokollal ki- egy tetszőleges host:port párra: szolgáló webhely tanúsítványára. Ezt sokan úgy o p e n s s l OpenSSL> s c l i e n t −c o n n e c t b2b . mol hu : 4 4 3 szerzik meg, hogy a böngésző segítségével mentik le. Mindez az openssl program segítségével sokAz eredményt a lenti, hosszabb output képkal gyorsabb és jobban automatizálható Ehhez ernyő mutatja: Certificate mentés 1 sorban CONNECTED( 0 0 0 0 0 0 0 3 ) d e p t h=1 C = HU, L = Budapest , O = NetLock K f t . , OU = TanC3BAsC3ADtvC3 A1nykiad C3B3k ( C e r t i f i c a t i o n å S e r v i c e s ) , CN = NetLock C39 C z l e t i ( C l a s s B) TanC3BAsC3ADtvC3 A1nykiad C3B3 v e r i f y e r r o r :

num=20: u n a b l e t o g e t l o c a l i s s u e r c e r t i f i c a t e verify return :0 −−− C e r t i f i c a t e chain 0 s : / C=HU/L=Budapest /O=MOL Nyrt . /OU=MOL EAI/CN=b2b mol hu i : / C=HU/L=Budapest /O=NetLock K f t . /OU=TanxC3xBAsxC3xADtvxC3 xA1nykiad xC3xB3k ( C e r t i f i c a t i o n S e r v i c e s ) /å CN=NetLock xC3 x 9 C z l e t i ( C l a s s B) TanxC3xBAsxC3xADtvxC3 xA1nykiad xC3xB3 1 s : / C=HU/L=Budapest /O=NetLock K f t . /OU=TanxC3xBAsxC3xADtvxC3 xA1nykiad xC3xB3k ( C e r t i f i c a t i o n S e r v i c e s ) /å CN=NetLock xC3 x 9 C z l e t i ( C l a s s B) TanxC3xBAsxC3xADtvxC3 xA1nykiad xC3xB3 i : / C=HU/L=Budapest /O=NetLock K f t . /OU=TanxC3xBAsxC3xADtvxC3 xA1nykiad xC3xB3k ( C e r t i f i c a t i o n S e r v i c e s ) /å CN=NetLock Arany ( C l a s s Gold ) FxC5 x 9 1 t a n xC3xBAsxC3xADtvxC3xA1ny −−− Server c e r t i f i c a t e −−−−−BEGIN CERTIFICATE−−−−− MIIG2DCCBcCgAwIBAgIOSd0P5gH+pJdkh9kohp8wDQYJKoZIhvcNAQELBQAwgakx

CzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UECgwMTmV0TG9j ayBLZnQuMTcwNQYDVQQLDC5UYW7DunPDrXR2w6FueWtpYWTDs2sgKENlcnRpZmlj YXRpb24gU2VydmljZXMpMTcwNQYDVQQDDC5OZXRMb2NrIMOcemxldGkgKENsYXNz IEIpIFRhbsO6c8OtdHbDoW55a2lhZMOzMB4XDTEyMDcxODA5NDQzOVoXDTE0MDcx ODA5NDQzOVowWzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRIwEAYD VQQKDAlNT0wgTnlydC4xEDAOBgNVBAsMB01PTCBFQUkxEzARBgNVBAMMCmIyYi5t b2wuaHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC60vMwEmV1Lbss gxzIIEruaCtkR05pHId0KAilu7jNOC9I2D /vkbYtIpXrXHW5+/0munLPhX2J84+o yb2j9yd5bfBpL7wYDD1JLMzaSoKLTwLDMzLXUotLY0y7XBQ/ CmOTj1RQF1rFfrct Xd48kDfeGcR9iQt1zxPI2O7rDu /KvXVDVqTyzAdFSF24mIK4BlG/qvwwhOUn1iX7 NUSXvnaziCX5c7BSWOnjtv80vzOG+RB/0 RGzluIbWjXaUzgCvEa3jS3AzRKBrDYF Lkj51D7tYjv9Obv5IoCNJ2WaVHOyIDZfefuKtDF7c /wVV284dQ5WOygBvhj56Exg l T J r F 3 s /AgMBAAGjggNJMIIDRTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwID qDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUdXyQ/ jxRmtv4 /WGLWQoe UYZk3b0wHwYDVR0jBBgwFoAU8SfE3lo9NCm48+oPjf520jkIz8EwgewGA1UdIASB

5DCB4TCB3gYNKwYBBAGbYwExicu5JTCBzDAnBggrBgEFBQcCARYbaHR0cDovL3d3 dy5uZXRsb2NrLmh1L2RvY3MvMIGgBggrBgEFBQcCAjCBkwyBkE5lbSBtaW7FkXPD rXRldHQgdGFuw7pzw610dsOhbnkuIFJlZ2lzenRyw6FjacOza29yIGEgc3plbcOp bHllcyBtZWdqZWxlbsOpcyBrw7Z0ZWxlesWRLiBTem9sZ8OhbHRhdMOhc2kgc3ph YsOhbHl6YXQ6IGh0dHA6Ly93d3cubmV0bG9jay5odS9kb2NzLzCBngYDVR0fBIGW MIGTMC+gLaArhilodHRwOi8vY3JsMS5uZXRsb2NrLmh1L2luZGV4LmNnaT9jcmw9 Y2JjYTAvoC2gK4YpaHR0cDovL2NybDIubmV0bG9jay5odS9pbmRleC5jZ2k/ Y3Js PWNiY2EwL6AtoCuGKWh0dHA6Ly9jcmwzLm5ldGxvY2suaHUvaW5kZXguY2dpP2Ny bD1jYmNhMIIBPgYIKwYBBQUHAQEEggEwMIIBLDAsBggrBgEFBQcwAYYgaHR0cDov L29jc3AxLm5ldGxvY2suaHUvY2JjYS5jZ2kwLAYIKwYBBQUHMAGGIGh0dHA6Ly9v Y3NwMi5uZXRsb2NrLmh1L2NiY2EuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2Nz cDMubmV0bG9jay5odS9jYmNhLmNnaTA0BggrBgEFBQcwAoYoaHR0cDovL2FpYTEu bmV0bG9jay5odS9pbmRleC5jZ2k /Y2E9Y2JjYTA0BggrBgEFBQcwAoYoaHR0cDov L2FpYTIubmV0bG9jay5odS9pbmRleC5jZ2k /Y2E9Y2JjYTA0BggrBgEFBQcwAoYo aHR0cDovL2FpYTMubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Y2JjYTANBgkqhkiG 9

w0BAQsFAAOCAQEAKhSN9sSX5S6MIw3rtbr8gJfbE73gljjttlOzhH /h0jXIsGAD atgoFL3Kz6YShzNFoiQ9hX4reM14ppXPH2QSbZXHeS4HgGiZwix19PpxtLdl5NwB Yvt4IWY/CuQYl4fEYHOqxoWlvWqUIZygDgZ56zlIE4x2qWfQdTpKj72Ux0qwonwT ngd6caivwYMkzb4ZWT2k/ fTzojxov4uINTL+x1qMRjEsGUPEtm2jNJzqlWObT2pt dv0O8kiyLEgJ1yfTBTi+N/GzHSplVhQBUVtzqYtbqyjFHAufWa4PCCAawxfj+pOc 91 LydZIJcHL7QoJ9VFlhcv+HjVJNB9LAhvfWAw== −−−−−END CERTIFICATE−−−−− s u b j e c t =/C=HU/L=Budapest /O=MOL Nyrt . /OU=MOL EAI/CN=b2b mol hu i s s u e r =/C=HU/L=Budapest /O=NetLock K f t . /OU=TanxC3xBAsxC3xADtvxC3 xA1nykiad xC3xB3k ( C e r t i f i c a t i o n S e r v i c e s ) å /CN=NetLock xC3 x 9 C z l e t i ( C l a s s B) TanxC3xBAsxC3xADtvxC3 xA1nykiad xC3xB3 −−− 68 Szilánkok Tippek és Trükkök No c l i e n t c e r t i f i c a t e CA names s e n t −−− SSL ha nd sh a ke h a s r e a d 3990 b y t e s and w r i t t e n 424 b y t e s −−− New , TLSv1/ SSLv3 , C i p h e r i s DHE−RSA−AES256−SHA S e r v e r p u b

l i c key i s 2048 b i t S e c u r e R e n e g o t i a t i o n I S NOT s u p p o r t e d Compression : z l i b compression Expansion : z l i b compression SSL−S e s s i o n : Protocol : TLSv1 Cipher : DHE−RSA−AES256−SHA S e s s i o n −ID : S e s s i o n −ID−c t x : Master−Key : E352DFC780535B1ADB04EE752433B29130CB2CD8C044A197E20504B5B9C580FD75A17F58FC344E6E5C12387CDBB9DFAD Key−Arg : None PSK i d e n t i t y : None PSK i d e n t i t y h i n t : None SRP username : None Compression : 1 ( z l i b compression ) S t a r t Time : 1 3 5 5 7 3 4 5 3 7 Timeout : 300 ( s e c ) V e r i f y r e t u r n c o d e : 20 ( u n a b l e t o g e t l o c a l i s s u e r c e r t i f i c a t e ) −−− Nekünk most a certificate mentés a feladatunk, ezért a –BEGIN CERTIFICATE– és –END CERTIFICATE– közötti részt kell egy fájlba menteni az ismert parancssori eszközökkel és készen is vagyunk a feladattal: o p e n s s l s c l i e n t −c o n n e c t gep . nev hu : 4 4

3 </dev / n u l l c e r t i f i c a t e . pem | s e d −ne ’/−BEGIN CERTIFICATE−/,/−END CERTIFICATE−/p ’ > å Java - Nyelvfüggő rendezés A Java Collator – ami egy abstract base class – osztály locale-sensitive String rendezést képes megvalósítani. Ez a fogalom már a HSQLDB írásban is felbukkant. A konkrét példányokat a Collator.getInstance() gyártómetódussal lehet 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 lekérni, ahol azt is beállíthatjuk a paraméterben, hogy milyen lokalitást szeretnénk használni. A Java alapértelmezésben az unicode kódlap szerinti sorrendet használja, ezt tudjuk felülbírálni ezzel a lehetőséggel. Használata könnyen megérthető az alábbi példaprogram tanulmányozásával package o r g . c s t e s t ; import j a v a . t e x t C o l l a t o r ; import j a v a . u t i l L o c a l e ; public c l a s s Test { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g [ ] s = new S t r i n g [

4 ] ; s [ 0 ] = " álma " ; s [ 1 ] = " csata " ; s [ 2 ] = " 123 " ; s [ 3 ] = "CUKOR" ; // C o l l a t o r myCollator = C o l l a t o r . getInstance ( ) ; 69 Szilánkok 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 } Tippek és Trükkök C o l l a t o r myCollator = C o l l a t o r . g e t I n s t a n c e (new L o c a l e ( "hu" , "HU" ) ) ; S t r i n g temp ; int j ; boolean b ; f o r ( int i = 1 ; i < s . l e n g t h ; i ++) { j = i; b = true ; while ( j > 0 && b ) { i f ( myCollator . compare ( s [ j ] , s [ j − 1 ] ) < 0 ) { temp = s [ j − 1 ] ; s [ j − 1] = s [ j ] ; s [ j ] = temp ; } else { b = false ; } j −−; } } } f o r ( int i = 0 ; i < s . l e n g t h ; i ++) { System . out p r i n t l n ( s [ i ] ) ; } A 11-15 sorok között hoztuk létre a rendezendő s nevű String tömböt. A 18 sorban létrehozott myCollator objektum a

magyar kultúra szerint rendezni képes példányt jelent, amit a 29. sor feltétel vizsgálatánál használunk A példában mi írtuk meg a rendezési algoritmust is, de talán sokkal „Jávássabb” lett volna implementálni a Comparable interfészt, amit átadhatunk a már kész rendező algoritmusoknak. 70 DocBook és PDF - dblatex A DocBook egy XML szabvány, amiben komplett könyveket, publikációkat lehet XML-ben leírni. Persze a végén valamikor esztétikus kinézetű PDF dokumentumokat akarunk látni, amit a dblatex (webhelye: http:// dblatex.sourceforgenet/) segédprogrammal tudunk könnyen elérni. Ez a háttérben a LATEXkeretrendszert használja. Mi a problémába az Ubmrello nevű UML design eszköz kapcsán futottunk bele, aminek a dokumentum kimeneti formátuma a DocBook Design Patterns 9. A Visitor tervezési minta A Visitor tervezési minta A Visitor (Látogató) minta célja az, hogy objektumok valamilyen halmazán műveleteket hajtsunk végre úgy,

hogy ehhez az objektumok kódját nem kell megváltoztatnunk. Ezzel a technikával elkülönülten tarthatjuk az adatszerkezetet attól az algoritmustól, amit a benne lévő objektumokra alkalmazni szeretnénk. Ez utóbbi igény akkor merül fel, amikor új metódusokat adnánk az objektumhoz, azonban az nem tudjuk (vagy valamilyen megfontolások miatt nem akarjuk) megtenni Áttekintés meknek rendelkezniük kell egy olyan metódussal (a példában accept()), amelyben a visitor visit() metódusa kerül visszahívásra (callback mechanizmus). Egy kliens programrész – ahogy azt a 9.1 ábrán látjuk – közvetlenül a Visitable (azaz egy tetszőleges Visitor objektum felülettel) és az Elementlike (azaz egy meglátogatható tetszőleges Element objektum látogatást elfogadó felületével) objektumaival érintkezik, azaz őket látja, a visit() és accept() jellegű metódusaikat tudja használni. Egy példa a látogató mintára 9.1 ábra: A Visitor minta A Visitor egy olyan

osztály, mely meg tud látogatni más osztályokat. Ez azt jelenti, hogy van egy annyi-szorosan túlterhelt metódusa (amit a példában most visit() névre kereszteltünk), ahányféle osztály meglátogatására szeretnénk felkészíteni. Ezen meglátogatandó osztályok objektumait szemléletesen ilyen neveken szoktuk emlegetni: csomópont (node), elem (element), hely, objektum. A visit() (vagy abban a szerepben lévő más nevű) metódus paramétere a meglátogatandó osztályobjektum, így a megfelelő metódus változat hívása egyértelmű lesz. A meglátogatandó szerkezet (például egy hálós adatszerkezet) általában több node-ból áll A ele- A következőkben a meglátogatható objektumok egy lakás helyiségei lesznek, amin különféle műveleteket szeretnénk végezni. A helyiségek együttese lesz a Lakás, ami a helyiségek halmaza, így ez lesz a bejárandó container vagy adatszerkezet. A 9-1 Programlista LakasHelyiseg interfészét, ezzel a meglátogatható

objektumok közös felületét vezeti be Esetünkben bármely olyan objektum meglátogatható egy LakasVisitor -ral (9-2 Programlista), ami ezt az interfészt nyújtja Lényeges észrevenni, hogy úgy tudtunk egy új műveletet hozzáadni a meglátogatott objektumhoz, hogy ezt az accept() hívja vissza, de a kódja a látogatóban lesz. // 9−1. P r o g r a m l i s t a : L a k a s H e l y i s e g j a v a package c s . t e s t dp v i s i t o r ; // Egy l a k á s h e l y i s é g k é p e s f o g a d n i e g y å látogatót public i n t e r f a c e L a k a s H e l y i s e g { void a c c e p t ( L a k a s V i s i t o r v i s i t o r ) ; } 71 Design Patterns A Visitor tervezési minta Egy LakasVisitor felület annyi túlterhelt visit() metódust tartalmaz, ahány fajtájú lakáshelyiség meglátogatási képességére szeretnénk felkészíteni. Esetünkben ez most 4 helyiség típus lesz: szoba, konyha, mellékhelyiség és az egész lakás. Fontos kiemelni, hogy persze ez

is csak egy felület, amivel sokféle feladat elvégzésére alkalmas, különféle látogatókat készíthetünk. private S t r i n g name ; public M e l l e k h e l y i s e g ( S t r i n g name ) { t h i s . name = name ; } public void a c c e p t ( L a k a s V i s i t o r v i s i t o r ) { v i s i t o r . v i s i t ( this ) ; } // 9−2. P r o g r a m l i s t a : L a k a s V i s i t o r j a v a package c s . t e s t dp v i s i t o r ; // // A l a k á s h e l y i s é g e k b ő l á l l // public i n t e r f a c e L a k a s V i s i t o r { public void v i s i t ( Szoba s z o b a ) ; public void v i s i t ( Konyha konyha ) ; public void v i s i t ( M e l l e k h e l y i s e g å mellekhelyiség ) ; public void v i s i t ( Lakas l a k a s ) ; // e z i t t å e g y kulcsmomentum } A 9-3, 9-4 és 9-5. Programlisták a konyha, mellékhelyiség és szoba meglátogatható helyeket, azaz osztályokat adják meg. Az accept() metódus mindegyiknél ugyanazt a visitor.visit()

visszahívást tartalmazza, átadva a this paramétert, amivel egyértelmű lesz, hogy a visitor melyik visit() metódusa lesz kiválasztva. Részletesebben szólva egy Szoba objektum esetén például a visit( Szoba szoba ) változat lesz automatikusan visszahívva ezzel a this paraméterezéssel } // 9−5. P r o g r a m l i s t a : Szoba j a v a package c s . t e s t dp v i s i t o r ; public c l a s s Szoba implements L a k a s H e l y i s e g { private S t r i n g name ; //A s z o b a neve a name public Szoba ( S t r i n g name ) { t h i s . name = name ; } // E l f o g a d j a é s e z z e l v é g r e h a j t j a a å visitor tevékenységét public void a c c e p t ( L a k a s V i s i t o r v i s i t o r ) { v i s i t o r . v i s i t ( this ) ; } // 9−3. P r o g r a m l i s t a : Konyha j a v a package c s . t e s t dp v i s i t o r ; /∗ ∗ ∗ @return t h e name ∗/ public S t r i n g getName ( ) { return name ; } public c l a s s Konyha implements L a k a s H

e l y i s e g { public void a c c e p t ( L a k a s V i s i t o r v i s i t o r ) { v i s i t o r . v i s i t ( this ) ; } } // 9−4. P r o g r a m l i s t a : M e l l e k h e l y i s e g j a v a package c s . t e s t dp v i s i t o r ; public c l a s s M e l l e k h e l y i s e g implements å LakasHelyiseg { 72 /∗ ∗ ∗ @return t h e name ∗/ public S t r i n g getName ( ) { return name ; } /∗ ∗ ∗ @param name t h e name t o s e t ∗/ public void setName ( S t r i n g name ) { t h i s . name = name ; } } /∗ ∗ ∗ @param name t h e name t o s e t ∗/ public void setName ( S t r i n g name ) { t h i s . name = name ; } Design Patterns A Visitor tervezési minta A 9-6. Programlista a Lakas, azaz a csomópontok adatszerkezetét hozza létre A LakasVisitor megvalósítások (például PrintLakasVisitor ) esetünkben még ennek az összetett szerkezetnek is megadják a visit() metódusát // 9−6. P r o g r a m l i s t a : Lakas j a v a package c s . t e s t

dp v i s i t o r ; public c l a s s Lakas { public L a k a s H e l y i s e g [ ] } // 9−7. P r o g r a m l i s t a : P r i n t L a k a s V i s i t o r j a v a package c s . t e s t dp v i s i t o r ; public c l a s s P r i n t L a k a s V i s i t o r implements å LakasVisitor { public void v i s i t ( Szoba s z o b a ) { System . out p r i n t l n ( " nSzoba : ␣ " + å s z o b a . getName ( ) ) ; } public void v i s i t ( Konyha konyha ) { System . out p r i n t l n ( " Konyha␣ " ) ; } helyisegek ; public Lakas ( ) { t h i s . h e l y i s e g e k = new L a k a s H e l y i s e g [ ] { new Konyha ( ) , new Szoba ( " N a p p a l i " ) , new Szoba ( " Háló " ) , new Szoba ( " Gyerek " ) , new M e l l e k h e l y i s e g ( "WC" ) , new M e l l e k h e l y i s e g ( "Kamra" ) , new M e l l e k h e l y i s e g ( " E l ő s z o b a " ) }; } A PrintLakasVisitor (9-7. Programlista) egy nagyon

egyszerű visitor megvalósítást mutat. A megvalósítandó feladat nyilván sok más látogató típus ötletét is életre keltheti. Amennyiben például a helyiségekben mért hőmérsékletek és azok feldolgozása számára akarnánk egy visitor-t készíteni, akkor annak a neve például HomeroLakasVisitor lehetett volna. public void v i s i t ( M e l l e k h e l y i s e g å mellekhelyiség ) { System . out p r i n t l n ( " n M e l l é k h e l y i s é g : å ␣ " + m e l l e k h e l y i s é g . getName ( ) ) ; } } public void v i s i t ( Lakas l a k a s ) { f o r ( i n t i =0; i <l a k a s . h e l y i s e g e k å l e n g t h ; i++ ) { lakas . h e l y i s e g e k [ i ] accept ( this ) ; } } Végezetül teszteljük le a látogató minta alapján létrehozott osztályokat és vegyük észre, hogy ez a kliens tényleg csak a megfelelő interfészeken keresztül éri el az objektumokat (9-8. Programlista)! // 9−8. P r o g r a m l i s t a : Test j a v

a package c s . t e s t dp v i s i t o r ; public c l a s s Test { s t a t i c public void main ( S t r i n g [ ] a r g s ) { Lakas l a k a s = new Lakas ( ) ; L a k a s V i s i t o r p r i n t V i s i t o r = new P r i n t L a k a s V i s i t o r ( ) ; printVisitor . v i s i t ( lakas ) ; } } 73 Design Patterns 10. Az Adapter tervezési minta Az Adapter tervezési minta Az adapter tervezési minta annak a helyzetnek a megoldása, amikor van egy osztályunk, ami alapvetően azt csinálná, amit a kliens használni szeretne, azonban azt nem a megfelelő felülettel szolgáltatja. Ez a probléma az informatikán kívül is számos helyen felbukkan Gondoljunk csak a gépkocsi szivargyújtó és a mobiltelefonos töltő USB csatlakozójára. Az adapter gondolata Az adapter lényegét a 10.1 ábra érzékelteti Képzeljünk el 3 szereplőt: 1. Az ábra bal oldali csatlakozója: BCS 2. Az ábra jobb oldali adaptere: JCS 3. A fali konnektor (nincs az ábrán): FK A bal oldali

csatlakozó objektumot nem tudjuk bedugni a konnektorba, ezért a jobb oldali adaptert hívjuk segítségül. Az FK fali konnektor egy olyan szolgáltatás (áramot ad), amit BCS eszköz 10.2 ábra: Az Adapter Design Pattern igénybe szeretne venni, de nem tudja, mert nem illeszthető FK -ba. A problémát a JCS adapter Egy Adapter példa oldja meg. 10.1 ábra: Egy tipikus Adapter A 10.2 ábra UML diagramja a fentiek modellezése A Client osztály esetünkben a BCS, hiszen ő szeretne áramhoz jutni, azaz szolgáltatást igénybe venni. A JCS az adapter, azaz a diagram Adaptor osztálya. Végül az FK az adaptálandó osztály (Adaptee), a hozzá való illesztést kell megoldani. 74 Van egy kliens programunk (10-4. Programlista), aminek szüksége lenne egy olyan veremre (stack adatszerkezet), amire String típusú objektumokat tudunk elhelyezni. A probléma az, hogy ilyen verem osztályunk nincs, azonban helyette rendelkezünk egy EgyList osztállyal (102. Programlista), aminek a

funkcionalitása lényegében a verem lehetőségeket is tartalmazza A Stack interface (10-1. Programlista) pontosan megfogalmazza azt a felületet, amire a kliens Test class-nak szüksége van Ez egy lényeges pont, hiszen így tudjuk egyértelműen definiálni a kliens szükségletét. Amikor egy kliens program valamilyen szolgáltatás halmazt szeretne használni, szinte mindig előnyünk származik abból, ha először annak csak az interfészét határozzuk meg. Ez még akkor is igaz, ha végül ennek az interfésznek az implementációját nem adatperrel, Design Patterns azaz egy köztes delegáló osztállyal oldjuk meg. // 10 −1. P r o g r a m l i s t a : S t a c k j a v a package c s . t e s t dp a d a p t e r ; public i n t e r f a c e Stack<T> { void push (T o ) ; T pop ( ) ; T top ( ) ; } Az EgyList osztály metódusai olyanok, amik egy lista esetén megszokottak: • insertTail • removeTail • getTail Az implementációját most látjuk, de ez nem

lényeges az Adapter minta szempontjából. A fontos csak az, hogy ismerjük a pontos specifikációját az egyes metódusainak, így ezzel a nyilvános API-ja pontosan ismert legyen a számunkra Esetünkben Ő az Adaptee class. // 10 −2. P r o g r a m l i s t a : E g y L i s t j a v a package c s . t e s t dp a d a p t e r ; import j a v a . u t i l A r r a y L i s t ; public c l a s s EgyList<T> { A r r a y L i s t <T> a l ; public E g y L i s t ( ) { a l = new A r r a y L i s t <T>() ; } public void i n s e r t T a i l (T o ) { a l . add ( o ) ; } public T r e m o v e T a i l ( ) { return a l . remove ( a l s i z e ( ) − 1 ) ; } } public T g e t T a i l ( ) { return a l . g e t ( a l s i z e ( ) − 1 ) ; } Az Adapter tervezési minta Az adaptert az EgyListStackAdapter class implementálja, Ő van az Adaptor szerepben. Kizárólagos feladata, hogy egy Stack felületet biztosítson a kliensek számára, miközben ezt a szolgáltatást az EgyList

adaptee-ra bízza Esetünkben mindez nem túl bonyolult, ahogy azt a 10-3 Programlista is mutatja. // 10 −3. P r o g r a m l i s t a : E g y L i s t S t a c k A d a p t e r å java package c s . t e s t dp a d a p t e r ; public c l a s s E g y L i s t S t a c k A d a p t e r <T> extends å EgyList<T> implements Stack<T> { public void push (T o ) { insertTail (o) ; } public T pop ( ) { return r e m o v e T a i l ( ) ; } } public T top ( ) { return g e t T a i l ( ) ; } Ennyi előzetes után a Test kliens képes használni a Stack felületen az EgyList class szolgáltatásait. // 10 −4. P r o g r a m l i s t a : Test j a v a package c s . t e s t dp a d a p t e r ; public c l a s s Test { public s t a t i c void main ( S t r i n g [ ] a r g s ) { Stack<S t r i n g > s t a c k = new å E g y L i s t S t a c k A d a p t e r <S t r i n g >() ; f o r ( i n t i =0; i <10; i ++) { s t a c k . push ( " " + i ) ; } } } f o r ( i n t i

=0; i <10; i ++) { System . out p r i n t l n ( s t a c k pop ( ) ) ; } 75