CGG   Jak vyrobit nový modul do JaGrLib

Obecné zásady:


Piece, Plug, Channel:

Piece je zakladni "stavebni kamen", ze ktereho se sklada "stavebnice" = algoritmus. Je to jakasi "krabicka" ("black-box"), ktera implementuje predepsane protokoly (interface v Jave) a az v druhem planu (prip. zcela nedulezita) je konkretni metoda jejich realizace.

Kazdy Piece definuje jakesi "stycne body" se svym okolim - Plugs (zasuvky). Kazdy Plug rika, ktery protejsek (opet formalne typu Piece) se na tomto miste muze pripojit (a zda smi pripadne tento Plug zustat nezapojen). Konkretni propojeni je realizovano tridou Channel: na kazde strane ma jeden Piece (vlastne jeden jeho Plug), a tedy jeden protokol (interface v Jave). Pres Channel se tedy da komunikovat oboustranne: leva strana vola dany protokol prave strany a naopak..

Plug je v ramci sveho Piece odkazovani pomoci "klice" - znakoveho retezce. Stejny klic se pouziva ke konkretnimu propojeni (Channel). Kazdy Plug ma nekolik atributu:


Template, registrace:

Konkretni konfigurace zasuvek (Plugs) nejakeho modulu muze byt reprezentovana ve forme objektu s protokolem Template. Je to jakysi "vzor", katalogizace Piece z hlediska kompatibility (spise formalni = syntakticke, nez semanticke).

Jeden konkretni Piece muze splnovat nekolik ruznych Template, tj. muze hrat nekolik ruznych "roli" (byt zamenitelny podle ruznych vzoru). Jednotlive Template hraji roli ekvivalenci (ve smyslu kompatibility) na tride vsech modulu.

Moduly se v systemu JaGrLib registruji v tzv. registracni databazi. Ucelem registracni databaze je umoznit pracovat s modulem jako s "cernou skrinkou" (krabickou), aniz bychom meli k dispozici jeho zdrojovy soubor (nebo .class soubor). Zaznam v registracni databazi obsahuje:

Informace o zasuvkach musi obsahovat kompletni udaje o vsech povinnych i nepovinnych zasuvkach, jejich typech (interface), apod.

Parametry jsou zadany retezcovym identifikatorem, datovym typem a prip. muze byt u kazdeho parametru definovano, jak se ma editovat v GUI podobe (tzv. "manipulator"). Na vyber jsou editacni radky, list-boxy, ruzna "tocitka" a nakonec i GUI objekty, ktere muze naprogramovat sam uzivatel. Parametr muze mit implicitni hodnotu, rozsah pripustnych hodnot, atd.

Textove registracni udaje slouzi pouze cloveku k lepsi orientaci v registracni databazi a pri vyberu modulu:


Registracni rutina setTemplate():

Ve staticke rutine setTemplate(Template,int) programator modulu deklaruje vlastnosti modulu, ktere jsou potreba pro jeho praci, ulozeni do registracni databaze, apod. Nektere zde definovane hodnoty se pozdeji mohou v registracni databazi rucne prepsat, ale neni to standardni postup (normalne by se autorske hodnoty mely respektovat).

Muze-li modul vystupovat ve vice "rolich" (sablonach, Templates), je treba testovat pozadovanou sablonu (parametr int ord) a chovat se pokazde jinak.. Je-li zadana hodnota ord < 0, znamena to, ze se ma nastavit sjednoceni vsech zasuvek a parametru:

public static int setTemplate ( Template t, int ord )

K zadani registracnich retezcu slouzi rutina t.setRegStrings(NAME,TEMPLATE,CATEGORY,DESCRIPTION) (semantika parametru je popsana vyse). U testovaneho modulu neni retezce bezpodminecne nutne zadavat, u modulu pripraveneho ke zverejneni by se tam mely vyplnit smysluplne hodnoty!

Povinna je cast definujici zasuvky (Plugs). V interface Template lze najit nekolik variant metod, kterymi se zasuvky definuji:
 
void newPlug ( String key, boolean _mandatory, boolean _multi, boolean _cloneable,
               String _inputInterface, String _outputInterface );
void newInputPlug ( String key, String _inputInterface );
void newOptInputPlug ( String key, String _inputInterface );
void newOutputPlug ( String key, String _outputInterface );
void newOptOutputPlug ( String key, String _outputInterface );

Treti cast definuje parametry (atributy, "Properties") modulu. Jedna se o tytez hodnoty, na ktere program muze pristupovat pomoci interface Property - tj. metodami set(String,Object) a get(String).
Registrace parametru je dulezita proto, aby se daly pouzivat i v GUI (aby je mohli cist a zadavat uzivatele interaktivne).

Podrobnejsi a uplny vycet vsech moznosti pri registraci parametru modulu je mozne nalezt v dokumantaci k interface Template.
popis kazdeho jednotliveho parametru je uzavren mezi
 
t.propBegin(String name,String type,String descr,boolean visual);
  a
t.propEnd();

Nepovinne je mozne zadavat napr. implicitni hodnotu (propDefault()), mezni hodnoty (propBounds()) nebo tzv. "manipulator", kterym se v GUI vizualne hodnota edituje (propManipulator()).

Priklad trochu slozitejsi definice parametru (ze souboru LineBresenham.java):
 
t.propBegin( LINE_JOIN, TYPE_INTEGER, "Line-join style", true );
 t.propDefault( LINE_JOIN_DISJOINT );
 t.propBounds( LINE_JOIN_DISJOINT, LINE_JOIN_OVERLAP );
 t.propManipulator( MANIPULATOR_COMBO );
 t.propEnum( "Disjoint", LINE_JOIN_DISJOINT, "Subsequent line segments are disjoint" );
 t.propEnum( "Overlap", LINE_JOIN_OVERLAP, "Subsequent line segments have one common pixel" );
t.propEnd();

Kompletni priklad registracni procedury setTemplate(template,int) lze najit v nasledujicim oddile:


Jak napsat novy modul (potomek tridy Piece):

Jednotlive kroky pri vytvareni potomka tridy Piece mohou vypadat takto (priklady jsou ze skutecne implementace LineBresenham):

  1. rozmyslet si protokoly (interface), ktere musi dany objekt implementovat, a deklarovat tridu s vhodnym jmenem jako potomka Piece (pracujeme v testovacim balicku cz.cuni.jagrlib.testing):
     
    package cz.cuni.jagrlib.testing;
     
    public class LineBresenham extends Piece implements LineRender
    {
      ...
    }

     
  2. naprogramovat vlastni funkce daneho objektu - implementovat vsechny potrebne protokoly (interface). Pritom pro odkazovani na napojene Piece pouzivat funkce getInterface(), napr.:
     
    public void drawLine ( int x1, int y1, int x2, int y2 )
    {
      BitMask out = (BitMask)getInterface(OUTPUT,IFACE+"BitMask");
      ...
    }

     
  3. rozmyslet si, zda nebude potreba k nekterym vlastnostem (parametrum, "Properties") pristupovat verejne z vnejsku modulu (z jinych modulu, interaktivne v GUI, atd.). Pokud ano, je treba naprogramovat obe funkce z interface Property:
     
    public void set ( String key, Object value )
     
    public Object get ( String key )

     
  4. napsat registracni rutinu modulu - jeji hlavicka musi odpovidat zcela presne danemu vzoru:
     
    public static int setTemplate ( Template t, int ord )
     
    Tato rutina musi obsahovat definici registracnich retezcu (viz setRegStrings()), definici vsech zasuvek Plugs daneho modulu a dale popis verejne pristupnych parametru Properties.
    Pro funkcnost modulu v systemu JaGrLib/Skel je bezpodminecne nutne zaregistrovat minimalne zasuvky (Plugs). Zbytek registracni procedury jiz neni tak dulezity..
    Podrobnosti viz interface Template a predchozi oddil setTemplate. Priklad konkretni registracni procedury modulu JFIFFileFormat:
     
    public static int setTemplate ( Template t, int ord )
    {
      if ( t != null && ord <= 0 )
      {
        t.setRegStrings("JFIF file format","DataFileFormatToRasterGraphicsAndBitStream",
                        "io.2d.raster","JFIF (JPEG File Interchange Format) filter");
          // Plugs:
        t.newInputPlug( PL_INPUT, IFACE+"DataFileFormat" );
        t.newOutputPlug( PL_RASTER, IFACE+"RasterGraphics" );
        t.newOptOutputPlug( PL_OUTPUT, IFACE+"BitStream" );
          // Property:
        t.propBegin( DOUBLE_STREAM, TYPE_BOOLEAN, "Use floating-point data stream?", true );
          t.propDefault( false );
        t.propEnd();
        t.propBegin( QUALITY, TYPE_FLOAT, "Compression quality in %", true );
          t.propBounds( 0, 100 );
          t.propDefault( 75 );
        t.propEnd();
      }
      return 1;
    }

     
  5. zaregistrovat novy modul v GUI programu Skel:
    • v prostredi Skel se vybere prikaz Tools / Module registration
    • po zadani Read a vyberu prislusneho zdrojoveho souboru se dialog vyplni automatickymi hodnotami (prectenymi ze zdrojaku)
    • udaje je mozne rucne opravovat (ale opatrne!)
    • tlacitko Register vytvori novy zaznam v registracni databazi (zatim v pameti)
    • tlacitkem Save se registracni databaze ulozi na disk
     
  6. otestovat novy modul - v GUI (Skel) vytvorit sestavu, modul do ni zapojit a spustit..
    Pokud by stacilo pouzivat modul bez GUI (jako napr. v Main00.java), muze se vynechad predchozi bod (registrace modulu).


Testování (starý zpusob - bez GUI):

Je nutne vytvorit fungujici "skladacku" rucne - viz napr. Main00.java.

  1. vytvorit instance vsech krabicek (Piece), ktere se budou pouzivat.
  2. spojit graf algoritmu pomoci volani funkce Piece.connect().
  3. rucne iniciovat testovany vypocet.
  4. pokud je treba prubezne sledovat graficke vystupy, lze pouzit RasterImage.getBufferedImage() (viz Main00.java).
  5. pokud je treba ulozit vystupni grafiku na disk, lze pouzit JPEGImageEncoder (viz Main00.java).


[JaGrLib home-page]  [News, credits]  [CGG at MFF UK]

Copyright (c) 2000-2009 Josef Pelikán, last change: $Date: 2013-11-22 23:47:16 +0100 (Fri, 22 Nov 2013) $