Definiční a vývojové prostředí - skriptování
Zde naleznete:
Při nasazení IS FLORES u větších klientů je mnohdy nutné dodávaný produkt upravit dle specifických potřeb, které jdou nad rámec běžných uživatelských úprav a nastavení. Kromě možnosti definovat si definovatelné číselníky, možnosti různým způsobem do existujících objektů, agend a číselníků doplňovat další položky, možnost si pomocí definovatelných SQL skriptů doplňovat/rozšiřovat strukturu databáze, je mnohdy potřeba určité chování i doprogramovat. Proto je v systému k dispozici možnost skriptování – tedy možnost do existujících objektů (Business objektů, agend a nevizuálních číselníků) zařadit vlastní programový kód, který se bude vykonávat spolu s pevným kódem daným výrobcem. Tímto způsobem je tedy možné vytvořit nové chování případně upravit stávající přesně na míru uživateli. Jedná se o jednu z možností zákaznické modifikovatelnosti systému.
Uživatel/implementátor potřebuje upravit nebo rozšířit funkčnost stávajícího Business objektu Faktura vydaná tak, aby se při vytvoření nové faktury do popisu vyplnil nějaký text. Otevře si agendu Balíčky skriptů, zadefinuje nový balíček (nebo se rozhodne, že přidá svoje skripty do nějakého existujícího balíčku) a v rámci tohoto balíčku si vybere typ Business objekt. V rámci typu Business objekt si vybere třídu Business objektu Faktura vydaná. V ní pak zadefinuje vlastní skript pro událost AfterPrefill. V této události je mu k dispozici samotný Business objekt (předaný pomocí parametru) a případně další parametry. Zadefinovaný skript uloží – po uložení se skript zkompiluje pro pozdější použití (kompilace skriptu je časově nezanedbatelná, proto je lepší je mít už předkompilované).
Na balíčku, ve kterém je umístěný popisovaný skript, nastaví programátor příznak Používat. Pak už jen stačí spustit agendu Faktur vydaných nebo OLE aplikaci, která s Business objektem Faktura vydaná pracuje, a implementované řešení vyzkoušet.
Skriptování je také nezbytné pro některé jiné části systému. Viz příklady Využití skriptování v jiných modulech systému IS FLORES.
POZOR!!! Skriptování značně rozšiřuje možnosti systému, jak plyne mj. i z několika základních příkladů Příklady možností využití skriptování. Nicméně z toho mohou plynout i možné negativní důsledky:
-
Může do značné míry změnit vzhled systému a chování systému a to bohužel i negativním způsobem - Např.:
- Skrytí či přejmenování některých funkčních tlačítek, položek apod., což může vést i ke zmatení uživatele (nebude odpovídat této příručce, která popisuje stav dodávaný defaultně výrobcem).
- Změna umístění některých prvků, která může vést ke kolizi (např. nechtěnému překrytí) s jinými položkami (např. nově dodanými výrobcem v dalších verzích apod.).
- Neočekávané chování (např. nabízení záznamů z číselníku v závislosti na hodnotě jiné položky řešené skriptováním) může vést třeba i k tomu, že se nenabídne nic, pokud daná položka není zadána (pokud to není ve skriptu řádně ošetřeno apod.).
- Systém je navržen tak, aby v případě, že nejsou žádné skripty definovány, nedocházelo k výraznějšímu zpomalení, nicméně nepatrné zpomalení je možné.
- Možný výskyt zavlečených chyb, zejména v případě použití nezkušených uživatelem.
Proto si v případě pochybností o nějaké funkčnosti systému nejdříve zjistěte, zda se vám nespouští nějaké skripty, které by daný stav mohly způsobit, viz Informace o spouštěných skriptech.
Jako skriptovací engine byl na základě testů rychlosti vybrán FastScript. Ačkoliv FastScript podporuje více skriptovacích jazyků, je ve skriptování IS FLORES pro jednotnost použitý pouze PascalScript. Toto omezení souvisí mimo jiné i s tím, že ve skriptování jsou dostupné třídy, které jsou k dispozici pouze v Delphi/Pascalu – tudíž implementátor, který chce realizovat skriptování v IS FLORES, musí být s Delphi/Pascalem tak jako tak obeznámen.
FastScript byl podstatně rozšířen, aby více vyhovoval potřebám IS FLORES. Jedná se např. o podporu dokumentace na všech entitách, zprovoznění enumeračních typů a množin, podporu dokumentace pro události, podporu statických (class) metod. Nicméně i přesto má určitá omezení, se kterými nutno při tvorbě skriptů počítat. Viz Pokyny k tvorbě skriptů.
K dispozici je agenda Balíčky skriptů, pro vytváření, ladění a správu existujících skriptů.
Pojem "balíček" zavedený v agendě balíčky skriptů, umožňuje rozumnou organizaci (uspořádání) vytvořeného programového kódu včetně vzájemných závislostí. Neznamená snadnou distribuci všech součástí potřebných pro implementaci uživatelem požadované funkčnosti (skripty, definovatelné číselníky, definovatelné položky, definovatelné formuláře, definice reportů, definice exportů, definovatelné SQL skripty, …).
Aby bylo možné v definici skriptů (a i jinde) vědět, jaké BO, agendy a nevizuální číselníky podporují skriptování a jaké metody (události) nabízejí ke skriptování, je interně zajištěna registrace těchto objektů a v rámci objektu je k dispozici seznam podporovaných událostí včetně popisu (vysvětlivek). Skriptování je typicky dostupné pro Business objekty, které mají možnost definovat uživatelsky definovatelné položky (ale mohou nastat i výjimky) a pro většinu agend a nevizuálních číselníků. Možnost doplnit si vlastní skripty je pouze do vybraných míst (událostí) v Business objektech (BO), agendách a nevizuálních číselnících. Jaká místa pro skriptování, tzv. háčky (hooks), jsou pro daný objekt k dispozici, je dáno výrobcem a uživatel toto nemůže nijak měnit.
Seznam objektů/tříd a procedur/funkcí, které jsou dostupné ve skriptování, je k dispozici v agendě Balíčky skriptů v Class Exploreru.
Seznam dostupných háčků pro daný objekt je k dispozici v agendě Balíčky skriptů v záložce Zdrojový kód v položce Metoda.
Názvy metod (háčků) pokud možno co nejvíce vystihují místo, kde dochází k jejich volání. Dále jsou seznamy háčků rozděleny na základní a pokročilé. Pokročilé se liší od základních tím, že začínají znakem "_".
Dále může být odlišeno, zda se daný háček volá před nebo po určité akci. To je řešeno pomocí sufixů PreHook a PostHook v názvu. Pokud to nemá význam, končí název háčku pouze slovem Hook.
Existující háčky:
- _DeleteObject_PreHook
- _DeleteObject_PostHook
- AfterSiteOpen_Hook
- Validate_Hook(var AResult: Boolean)
- aj.
Nezbytnou podmínkou pro provoz skriptování je, aby byla tato část systému licencována. Skriptování je licencováno samostatně - viz Licencované celky (licencované moduly a vlastnosti). Licencována je tvorba a kompilace skriptů. Samotné vykonávání již zkompilovaných skriptů nijak licencováno není.
Zda je licence dostupná k zakoupení pro všechny produkty IS FLORES, viz aktuální obchodní podmínky výrobce.
U skriptování však neplatí, že nepřítomnost licence skriptování "vypíná" jeho použití. Licence na modul Skriptování je potřebná pouze pro operaci Kompilace z agendy Balíčky skriptů. Tzn., že i v instalaci bez licence k tomuto modulu je možné naimportovat již zkompilovaný balíček bez zdrojových textů a je možné provádění zkompilovaných skriptů (např. vytvořených na zakázku výrobcem).
Pokud potřebujete skriptování vypnout (myšleno vypnout provádění skriptů), je třeba tak učinit jiným způsobem, viz Vypnutí skriptování.
Naopak pokud není skriptování nainstalováno, není k dispozici agenda Balíčky skriptů a nebude možné v systému plnohodnotně používat agendy a funkce, které jsou na skriptování navázány. Např. Funkce pro zajištění v SCM, Operace u Web. služeb, Kontrolní body u modulu E-maily a interní vzkazy apod.
Pokud chcete potlačit provádění skriptů z nějakého konkrétního balíčku skriptů, můžete v jeho položce Stav nastavit, že se nemá používat.
Pokud je třeba skriptování zcela vypnout (např. z důvodu, že je v nějakém skriptu chyba, která brání v provozu), můžete tak učinit spuštěním systému IS FLORES bez skriptování. To lze provést spuštěním systému IS FLORES s parametrem -noscripting. Toto vypnutí se provede pouze tehdy, pokud uživatel, který se do systému přihlásí, má současně nastaveno privilegium Obcházet skriptování. (Z toho důvodu, aby si běžný uživatel nemohl vypínat skriptování bezdůvodně).
Syntaxe viz popis parametru spuštění -noscripting.
Doporučujeme si prověřit, že se skriptování skutečně podařilo vypnout a že je vypnuté, např. tak, že se nezobrazuje volba Skriptování v menu Nápověda. Viz dále Informace o spouštěných skriptech.
Aktuálně přihlášenému uživateli se budou spouštět skripty, pokud jsou splněny následující podmínky:
- skript je z balíčku, který je zkompilován (nebo jen jeho část), viz příznak Zkompilováno
- skript je z balíčku, který má nastaveno Používat (viz příznak Stav) nebo má nastaveno Ladit a současně má daný uživatel privilegium Ladit skripty
- daný uživatel nemá skriptování zcela vypnuto
Dále pozor na to, zda se nejedná-li se o tzv. zastaralý skript (s hodnotou Zastaralá), u něhož je zamezeno jejich spouštění. Dále viz hodnota u daného skriptu v položce Verze kompilace skriptu a Verzování, Deprecated prvky.
Pokud ve skriptování implementujete nějakou požadovanou dynamickou změnu chování číselníku v nějaké vlastní číselníkové položce, je třeba pro ni použít prvek Číselník objektový (nikoli Číselník neobjektový). Prvek Číselník neobjektový není schopen implementovat dynamickou změnu chování danou skripty k danému objektu.
Jak bylo řečeno výše, skriptování značně rozšiřuje možnosti systému, nicméně mohou z něho plynout i možné negativní důsledky. Proto je potřeba mít možnost rychle uživatelsky (i bez existence práv pro přístup do agendy Balíčků skriptů) zjistit, zda aktuálně přihlášenému uživateli mohou být vykonány nějaké skripty.
Seznam všech skriptů, které si lze zobrazit, vytisknout, případně odeslat e-mailem (odeslání skriptů e-mailem je však již vázáno na patřičné právo):
-
v libovolné agendě z menu Nápověda volbou Skriptování (kdy je k dispozici a jak funguje, viz popis volby v menu Nápověda):
Příklad vyvolaného menu Nápověda s dostupnou položkou Skriptování
Ve skriptu je možné odkazovat se na jiné skripty. Pro odkazování na skripty mezi balíčky slouží druh skriptu Knihovna. Je tedy možné odkazovat se na skripty knihoven (nikoli Business objektů, agend a nevizuálních číselníků). Přehled závislých balíčků viz záložka Závislosti. Při volání funkcí nebo procedur z jiného skriptu je nutno používat frázi uses s následující konvencí:
uses
'nazev_balicku.nazev_knihovny','nazev_balicku.nazev_knihovny';
Pozor, volání přes název balíčku a knihovny není citlivé na velká/malá písmena.
Mějme balíček skriptů s názvem např. flores.cz.vyvoj.ukazka1, v němž je mj. zaveden skript druhu Knihovna s názvem Knihovna1. Chceme se na něj odkázat z jiného skriptu. Pak musíme použít syntaxi uses 'flores.cz.vyvoj.ukazka1.Knihovna1'.
Díky tomu, že je možné ve skriptování vytvářet vlastní instance (i vizuálních) objektů a těmto objektům nastavovat události, není možné po opravě zdrojových kódů skriptů a jejich překompilaci provést automaticky náhradu načtených skriptů v cache paměti. Tzn., že pokud editujete skript např. pro agendu a již jste ji měli alespoň jednou otevřenu v rámci daného spuštění IS FLORES, pak se změna ve skriptu pro danou agendu projeví až po znovunačtení skriptu do paměti.
Možnosti, jak vyvolat znovunačtení skriptů do paměti:
- Zavřením a znovuspuštěním systému IS FLORES.
- Pomocí funkce Znovu načíst skripty.
- Při uložení skriptu, je-li zatrženo Znovu načíst skripty.
Každý háček dostává minimálně jeden parametr "Self", ve kterém je mu předávána instance objektu, na kterém došlo k vyvolání háčku.
Aby bylo možné zjistit jména existujících vizuálních prvků (pro snazší zakomponování skriptů do vybraných objektů), je možno si spustit tzv. Show Inspector. Lze vyvolat z menu Nápověda volbou Zobrazit/Potlačit okno inspektoru nebo provést spuštěním systémuIS FLORES s parametrem -showinspector.
Syntaxe viz parametr spuštění -showinspector.
V obou případech se zobrazí speciální okno (Inspektor), které ukazuje za běhu IS FLORES informace o komponentě/prvku, nad kterým se nachází kurzor myši. Zobrazená data o vybrané komponentě je možno zmrazit pomocí klávesy Pause.
Příklad zobrazení informací v Show Inspektoru pro prvek období.
FastScript neumožňuje vytváření (ve skriptu) vlastních tříd, typů a recordů.
Z této skutečnosti vyplývají i omezení skriptování v IS FLORES. Na místech, kde je nutné pracovat s existujícími recordy (např. TRect a TPoint), se v obálkách objektů (tj. to, co je dostupné ve skriptování) tyto záležitosti převádějí na více hodnot (např. souřadnice x a y).
Dále FastScript nepodporuje práci s tzv. třídami tříd. Tudíž v případě potřeby této funkčnosti v obálkách, by bylo potřeba toto implementovat konkrétně pro jednotlivé třídy.
FastScript dále nepodporuje Interface. Tudíž na všech místech, kde se interně v IS FLORES pracuje s rozhraními (proměnné typu interface s odkazy na příslušné objekty), se ve skriptování toto vždy musí převést na instance objektů. Z toho plyne ovšem ten důsledek, že pokud si uživatel pomocí nějaké metody vytvoří nové instance objektů, musí se postarat i o jejich zrušení (kdežto pokud je objekt "držen za interface", je zrušen automaticky po zrušení všech odkazů na daný objekt přes nějaký interface).
Od verze 22.1, byla do scriptingu přidána možnost automatického uvolňování objektů – tzv. ARC (autoreference counting). Tato vlastnost se nastavuje pomocí volby ScriptingARC=1 v Nexus.cfg v sekci Client a v současnosti je výchozí stav nastaven na zapnuto.
Hlavní výhodou ARC je, že není třeba objekty explicitně uvolňovat a nedochází tak k memory leakům. ARC taky řeší několik problematických metod ve scriptingu, jejichž použití vyžadovalo explicitní uvolňování paměti (viz např. property CurrentObject). Nemusí se volat Free ani psát konstrukce Try … Finally, která typicky volání Free obklopuje.
Protože toto nastavení mění pořadí uvolnění objektů, je možné, že v některých situacích nebude scripting správně fungovat. Problém je třeba analyzovat a buď se přizpůsobí ARC nebo skripty nebo oboje. V nouzi je možné pomocí parametru ScriptingARC=0 přepnout zpět na původní režim.
ARC implementace interně využívá custom variant typ (interně jsou všechny proměnné ve scriptingu implementovány pomocí typu variant), u kterého delphi umožňuje napsat vlastní obslužnou třídu včetně reakce na přiřazení, které se používá pro počítadlo referencí. Je to velmi podobné ARC v delphi implementaci pro TInterfacedObject. Objekt vytvořený ve scriptingu se uvolní v okamžiku, kdy na něj není držena žádná reference.
procedure sactDemo (Sender: TObject);
var
mSL: TStringList;
begin
mSL := TStringList.Create;
mSL.Add('Hello');
mSL.Add('ARC');
ShowMessage(mSL.Text);
end;
Na konci volání metody se dereferencují lokální proměnné, počítadlo pro mSL dosáhne 0 a objekt se automaticky uvolní. Objekt se uvolní i v případě, že se do proměnné přiřadí nově vytvořený objekt (mSL := TStringList.Create). Pokud je nutné z nějakého důvodu objekt uvolnit dřív než na konci metody, přiřadí se do proměnné hodnota Null (mSL := Null).
Třídy TComponent a TControl
Objekty zděděné z těchto tříd mají vlastní mechanismus uvolňování z paměti. U TComponent je to property Owner: TComponent. Pokud je Owner nastaven, uvolní objekt před tím, než se sám uvolní z paměti. U TControl je to property Parent: TWinControl. Pokud se Parent uvolňuje, uvolní i objekty z kolekce Controls (kam se dostanou nastavením Parent). ARC toto nastavení respektuje a objekt automaticky neuvolní, pokud má nastaven Owner nebo Parent. Zároveň uvolnění objektu sleduje. Pokud je objekt uvolněn a použije se jinde ve skriptu, vyvolá se vyjímka ”Objekt je použit po svém uvolnění”.
TObjectList a potomci TComponentList, TNxParametersList
Pokud je ARC aktivní, vytvoří se ve scriptingu pro tyto objekty interně jiná implementace, která zohlední objekty typu ARC. Uložením takového objektu do TObjectList dojde k navýšení referencí na objekt.
TObjectList respektuje nastavení parametru konstruktoru / vlastnosti OwnsObjects. Pokud je nastaveno na true (výchozí hodnota), pak se při uvolnění TObjectList uvolní i objekty v něm držené. Pokud se jedná o ARC objekty a ty se použijí jinde ve skriptu, dojde k vyvolání výjimky ”Objekt je použit po svém uvolnění”.
Varování před přetypováním potomků TObjectList (tohle je problém, který nezávisí na ARC): TComponentList je možné přetypovat na TObjectList (protože z něj dědí) a použít metody s parametry typu TObject a tedy uložit objekt libovolného typu. Bohužel delphi implementace TComponentList s tímto nepočítá a v metodách TComponentList objekty natvrdo přetypovává na TComponent. Kód přeložit půjde, ale bude provázen různými chybami (typicky access violation).
TStringList
Pokud je ARC aktivní, vytvoří ve scriptingu pro tyto objekty interně jiná implementace, která zohlední objekty typu ARC (podobně jako TObjectList). Pokud není TStringList vytvořený přímo ve scriptingu, není ARC a nechová se nijak speciálně (např. property TComboButton.Items). Pokud se do takového stringlistu přidá ARC objekt, není tato reference započítána a pokud se ARC objekt uvolní, ve stringlistu zůstane neplatný odkaz.
TStringList má ve scriptingu potomka TFlatList a ten má další 2 potomky - TFieldList a TFieldDefList. Oba jsou specializovaní tak, že je může vyplnit jen dataset, který je vlastní. Pokus o zavolání AddObject vyvolá v těchto třídách výjimku. Tyto třídy se pro ARC nijak nemění - objekty v nich uložené nejsou ARC.
TNxObjectContainer
Tato třída byla upravena obdobně jako TObjectList. Pro objekty zde uložené se započítá reference.
TJSONSuperObject
Při práci s JSON objektem je ARC počítadlo jenom jedno v root objektu a sdílí jej všechny podřízené objekty. Je tedy možné použít např. jednu proměnnou typu mJson: TJSONSuperObject pro root objekt i objekty mu podřízené. Celá struktura JSON zanikne s poslední referencí na objekt v této struktuře. Interně (nesouvisí s ARC) JSON root objekt vlastní a uvolňuje své podobjekty.
ObjToInt / IntToObj
IntToObj nevrací ARC, ale obyčejnou referenci. ObjToInt převede ARC na běžný integer. Kromě toho nastaví ARC počítadlo tak, že se takový objekt nebude automaticky uvolňovat. Platnost reference uložené v integer tak závisí pouze na autorovi skriptu. Pokud se uvolní dřív, bude zde uložená reference neplatná a bude působit různě se projevující chyby. Pokud se vůbec neuvolní, vznikne memory leak.
Doporučujeme namísto uchování reference na objekty pomocí typu integer použít pro toto určené třídy (TObjectList, TStringList). Uchování reference pomocí integer není bezpečné a nedá se nijak kontrolovat.
Praktické příklady využití skriptování naleznete v samostatné kapitole.
V průběhu skriptování může dojít (vinou špatného skriptu) nejen k chybám ve vlastním průběhu skriptování, ale i k chybám následným, a je proto důležité vědět, že prvotní příčina může být např. právě v chybně napsaném uživatelském skriptu. Proto chyby, které vznikly v průběhu skriptování, se uživateli zobrazují s uvedením informace, že k chybě došlo během skriptování.
K ladění lze využívat nástroj ScriptDebugger.exe.
Podpora ladění nesmí být vypnuta parametrem v konfiguračním souboru nexus.cfg. Více viz kap. Konfigurační soubor Nexus.cfg - oddíly a parametry, Sekce [ScriptDebugger].
Implementátor skriptování může pro ladění využít též funkci ShowMessage(), pomocí níž je možné zobrazovat hlášení. Text chyby se také posílá pomocí funkce OutputDebugStr(). Texty předané funkci OutputDebugStr je možné "chytat" pomocí nějakého externího "zobrazovače" logů, např. pomocí Sysinternals DebugView nástroje.
V rámci některých upgrade systému IS FLORES může dojít k nějakým významným změnám (změny vývojového prostředí, související změny struktur, zásadní změny ve skriptování apod.), které vedou k tomu, že je třeba existující skripty upravit, příp. minimálně zkontrolovat. V takovém případě jsou takové skripty při procesu update automaticky nastaveny jako "zastaralé" (viz položka Verze kompilace skriptu na řádcích balíčků skriptů) a je zamezeno jejich spuštění.
Dále některé prvky skriptování mohou být v čase označeny atributem Deprecated. Takto označené prvky lze zatím ve skriptování používat, ale v budoucnosti se s nimi nepočítá, protože byly nahrazeny alternativním kódem. Lze je skrýt nastavením parametru HideDeprecated.
Současně jsou dodávány *.adc definiční soubory skriptování, vygenerované k příslušným verzím, pro porovnání dalších případných rozdílů ve skriptování pomocí nástroje DefsComp.exe. Porovnává dva *.adc soubory, např. *.adc k aktuální verzi s *.adc souborem verze předchozí. Tyto soubory nelze vytvořit uživatelsky, ale jsou dodávány výrobcem. Lze je nalézt v instalačním adresáři IS FLORES v podsložce ..\Doc\defscomp.
Pokud potřebujete logovat průběh nějaké funkcionality řešené pomocí skriptování, můžete využít k tomu určenou třídu TNxScriptingLog a její metody, především metodu WriteEvent. V konfiguračním souboru nexus.cfg v sekci logování, musí být nastaveno logování třídy Scripting.