Showing posts with label components. Show all posts
Showing posts with label components. Show all posts

Wednesday, 22 June 2011

Java Filter Events - událostmi řízené programování v UCM

V návaznosti na minulý článek se dnes zaměříme na poněkud vyšší školu programování v souvislosti s Oracle UCM - změny chování Java Custom komponent. Jednou z možností je samozřejmě přepis služeb (ať už voláním jiných metod, či změnou kódu volaných standardních metod). Existuje však ještě jiný způsob - využití standardních událostí a dopsání reakce na ně.

Např. extraBeforeCacheLoadInit je událost, která se vyvolá poté, co je z UCM navázáno spojení do databáze, ale před tím, než se data z databáze přenesou do cache. Z tohoto titulu se hodí pro propagaci změn do datového modelu (např. přidání nové tabulky či sloupce z javovské komponenty).

Třída, jejíž metody se tímto způsobem mohou zavolat musí implementovat interface intradoc.shared.FilterImplementor, tj. mít metodu doFilter, která se zavolá.

Výhoda filtrů oproti přepsání je zřejmá - jsou volány v okamžiku, kdy aplikace "předpokládá", že do běhu bude zasahováno - nemění se tedy standardní kód, jako spíše doplňuje, což může výrazně zjednodušit údržbu celé komponenty. Navíc je možné filtry za sebou řetězit.

Pro nasazení je tedy důležité především umět vybrat správnou událost, na kterou se filter "pověsí". Bohužel se mi nikde ve standardní dokumentaci nepodařilo najít jejich popis (celkem jich je ke dvěma stům) - nejlepším zdrojem proto asi bude stále kniha B. Huffa, kapitola Appendix H.

Tip dne: zadejte termín extraBeforeCacheLoadInit do Google. Kdo bude mít trpělivost, možná najde poklad.

Wednesday, 15 June 2011

Pár zásad pro psaní UCM komponent

I při psaní komponent pro Oracle UCM je třeba dodržovat základní návyky z programování.

Zásada 1: pište kód na urovni, na kterou patří
Komponenty UCM mají v podstatě několik logických úrovní:
- HTML - v případě, že budete modifikovat GUI, začnete nejspíše na úrovni HTML. Na této úrovni je možné měnit statický obsah stránek nebo jejich layout (pro změnu layoutu se nejčastěji používá HTML tag TABLE).
- IDOCSCRIPT - je pokračováním úrovně HTML. Na úrovni GUI dodává do komponent dynamický charakter - na místo pevných textů umožňuje do layoutu stránky vyplnit proměnlivý text, jako je třeba název položky. IDOCSCRIPT také užívejte, pokud chcete přistupovat ze stránky k datům či službám UCM. IDOCSCRIPT je samozřejmě možné využít nejen pro změny GUI, ale i na dalších místech - např. custom události nativních workflows či podmínky pro aktivaci pravidla (rules) v rámci zobrazovacích profilů jsou také psány v tomto jazyce.
- JavaScript, VBScript - jedná se o jinou úroveň dynamiky - o změnu stránky či jinou činnost (např. validaci, že zadaný obsah je číslo nebo datum), aniž by bylo nutné kontaktovat server.
- SQL - databáze se využívá pro perzistentní uložení dat - minimálně metadat, volitelně též obsahu či pomocných proměnných.
- Java - metody javovských tříd mohou být volány z definice služeb UCM. Proto se využívají pro back-end logiku. Javadoc (bohužel neúplný) najdete v balíčku HowToComponents(v adresáři Documentation)

Zásada 2: používejte komentáře
IDOCSCRIPT není objektový jazyk - není schopen polymorfismu, je však schopen přetížení - jedním ze základních konstruktů jazyka jsou tzv. includes, což jsou v podstatě ekvivalenty procedur a funkcí ze strukturovaného programování. Při definici metody se každému zdroji, který obsahuje includes, přiřazuje parametr loadOrder, který rozhoduje, jaký kód bude při zavolání includes nakonec proveden (vítězí "vyšší" loadOrder). Jazyk ještě obsahuje konstrukt super, který umožňuje (zpravidla v rámci nového include) volání kódu přetíženého include - velmi efektivně jej můžete využít, pokud nový kód něco "předřazuje" nebo naopak "doplňuje za" starý kód. Přesto si myslím, že častěji budete prostě "přepisovat" kód, přičemž původní kód bude sloužit jako základní verze. A protože nemůžete vyloučit možnost, že se někdy v budoucnu tento základní změní (Oracle vydá patch nebo novou verzi), je vhodné psát váš kód tak, aby bylo zřejmé, co jsou vaše změny a co je původní.
Komentáře v IDOCSCRIPTu se vkládájí mezi [[% a %]].
V rámci komponenty je pak slušnost napsat a aktualizovat readme (txt nebo html).

Zásada 3: využívejte jména zdrojů, includes, proměnných pro větší čitelnost a srozumitelnost kódu

Thursday, 24 March 2011

HowToComponents pro UCM 11g

Tento týden si dáme jako bonus jeden krátký článek navíc. Bex Huff, autor knihy The Definitive Guide to Stellent, spoluautor řady dalších knih na téma ECM a dlouholetý konzultant v oblasti ECM či produktu Stellent, zveřejnil na svých stránkách HowToComponents pro release 11g.

Zejména pro ty z vás, kteří se chystají upravovat GUI, to může být velmi cenný zdroj informací (v ostatních částech "starší" komponenty moc měnit třeba nebylo).

Wednesday, 22 September 2010

Rozšiřitelnost Oracle UCM - využití hierarchických dotazů v databázi

V tomto článku si budeme demonstrovat rozšiřitelnost Oracle UCM na jednom konkrétním problému z reálného života. Jeden potenciální zákazník se na nás obrátil s otázkou, zda UCM umí na úrovni adresářů (komponenta Folders_g) pracovat s kvótami. Ve standardní verzi tato funkcionalita není, jedná se však o poměrně jednoduché rozšíření.

Představme si tedy, že budeme chtít implementovat kontrolu nepřekračování přidělovaných kvót v následujícím schématu:

Problém s kvótami je, že nemusí být přiřazeny pro všechny adresáře - např. kvóta pro společnost A, kterou přiděluje správce úložiště, může být dále rozdělena a i zde mohou existovat adresáře s omezeními kvóty či bez omezení. Tyto "díry" povedou na netriviální rekurzivní dotazy.

Př. 1. vkládání dokumentu do adresáře uživatele 2 se musí nejprve zjistit, zda existuje nějaký adresář (buď adresář sám, nebo některý z jeho předků v hierarchii) s nastavenou kvótou. Kontrola možného překročení kvóty pak bude probíhat na úrovni tohoto adresáře, pokud nějaký takový adresář vůbec existuje.

Př. 2. vlastní výpočet vyčerpané kvóty je rovněž rekurzivní:
  • kvótu mohou vyčerpat soubory vložené do adresáře
  • či podadresáře, přičemž je-li podadresáři přiřazena jeho kvóta, pak se počítá s ní; v opačném případě se opět musí najít soubory a podadresáře do něj vložené
Rekurzivní vazba je daná přímo v databázové tabulce Collections: každý adresář má svůj jednoznačný identifikátor (dCollectionId) a kromě kořenového adresáře též svého přímého předka (dParentCollectionId).

Nalezení prvního adresáře s nenulovou kvótou (Př. 1) může být v databázi Oracle implementováno přímo jako jeden dotaz (stejné je tomu s Př.2):
select DCOLLECTIONQUOTA, DCOLLECTIONID, DCOLLECTIONNAME from COLLECTIONS
where DCOLLECTIONQUOTA > 0
start with DCOLLECTIONID = ?
connect by DCOLLECTIONID = PRIOR DPARENTCOLLECTIONID and DCOLLECTIONQUOTA > 0 and PRIOR DCOLLECTIONQUOTA is null

? v dotazu představuje placeholder pro parametr dCollectionId adresáře, pro který dotaz voláme
O hierarchických dotazech si více přečtěte v článku Davida Krcha zde.

Tento případ hezky demonstruje, že Oracle UCM je skutečně otevřený systém, který dokáže využívat nejlepších vlastností ostatních technologií.

Wednesday, 21 July 2010

Přenositelnost komponent do 11g

Pokud bychom se podívali detailně na problém přenositelnosti komponent speciálně optikou releasu 11g, pak zjistíme přibližně toto:
  • pro Custom Components budete stále využívat Component Wizard nebo link Component Manager v části Admin Server
  • kromě faktu, že komponenty nově běží v prostředí WLS, je třeba se vyrovnat i s jistou "restrukturalizací" instalace. Zatímco dříve byly všechny soubory instalovány (pro jednu instanci content serveru) do jednoho adresáře, v 11g existuje "obecný ECM adresář" (na mé instalaci to bylo C:\Oracle\Middleware\Oracle_ECM1\ucm) a pak jednotlivé adresáře pro instance (např. C:\Oracle\ucm_instances\ecm1\ucm).
  • pokud budete hledat standardní zdroje (např. std_page obsahující většinu includes), určitě je hledejte v "obecném" adresáři. Možná se pak bude hodit i informace, že na rozdíl od starších releasů, kdy byly všechny zdroje v souborech s příponami .htm, maximálně .hda, nyní již tomu tak být nemusí - např. zmíněný soubor std_page má příponu .idoc, zdroje obsahující překlady v komponentě Localization pak příponu .xlf apod.
  • ze změn souvisejících s přechodem na WLS pak připomeňme vše týkající se administrace uživatelů (která je nově zcela v režii WLS)
  • některé komponenty pak byly v 11g zcela přepsány. Jedná se zejména o Folia a FileStoreProvider (komponentu, která má na starosti zápis dokumentů do fyzického úložiště - tyto změny jsou důvodem výrazného zrychlení zápisu na disk či do databáze)
  • kromě celých komponent pak byly ještě přepsány některé jednotlivé služby. Jejich seznam najdete zde.
Vzhledem k projektům implementovaným v České republice věřím, že se tyto změny nikoho nedoktnou. Berte proto prosím tento článek spíše jako dokreslení, jak složité (či jednoduché) může být udržování komponent, o kterém jsme psali minule. Ostatně, dá se očekávat, že při upgrade na 11gR2 už bude komponent, které bude třeba oprášit, více, protože řada implementovaných customizací se týkala GUI, které bude podle všeho značně pozměněno.

Wednesday, 14 July 2010

Přenositelnost komponent, možnosti vzájemných kolizí

Pokud se pustíte do vývoje vlastních komponent v UCM, měli byste pamatovat, že tato jistě bohulibá činnost v sobě skrývá 2 úskalí:
  • problém přenositelnosti, tj. zajištění, že komponenta fungující ve verzi n bude fungovat i ve verzi n+1
  • problém možného konfliktu mezi komponentami (dvě či více komponent spolu nemohou fungovat najednou na jednom systému)

Konflikty
Jak může dojít ke konfliktu? Nejčastějším důvodem je přepsání standardní služby, které je sice kompatibilní se základním content serverem, ale není kompatibilní s jinou custom service. V 10g byly takovým příkladem modul Records Management a UCM adaptér pro URM - systém tedy mohl buď sám poskytovat records management funkce a nebo mohl být klientem pro URM, nikoliv však obojí najednou. V 11g je tento konflikt již vyřešen (UCM modul byl přepsán tak, že nabízí URM kód).
Mechanismem pro řešení případných konfliktů je loadOrder, což je hodnota, která je povinným parametrem každého zdroje. Content Server nahrává zdroje podle jejich hodnoty loadOrder (vyšší později) - pokud tedy chcete mít jistotu, že bude váš kód užit, nastavte tuto hodnotu na dostatečně vysokou hodnotu (obvykle stačí tak 100).
Dalším pomocníkem může být mechanismus dědičnosti. Byť to není (možná bohužel) nezbytné, jak iDocScript, tak Java umožňují nejen zcela předefinovat chování služby, ale při psaní využít i existující kód, který se tak ve vhodný okamžik převolává. Užitím dědičnosti se výrazně snižuje riziko konfliktů i podporuje přenositelnost.

Přenositelnost
U nekonfliktních komponent je riziko problémů při migraci na další verzi minimální. Přesto existuje a občas bude třeba do kódu sáhnout. Jedním z takových příkladů byl například přechod z verze 7.5 (ještě Stellent) na 10g (již Oracle), kde došlo k zásahům do GUI (místo combo boxu nabízejícího funkce proveditelné nad položkou byly tyto rozdistribuovány do jakési lišty na hodním menu - starší komponenty, které "natvrdo" přidávaly své funkce na známé místo na to samozřejmě nebyly připraveny).
Tím, že je 11gR1 velmi podobný (snad s výjimkou práce s uživatelskými účty) starší verzi, dá se předpokládat, že by tyto verze neměly mít na úrovni komponent vážné problémy.

Wednesday, 17 March 2010

Modifikace UCM: komponenty (html resources), 3. část

V předchozích textech jsme uváděli, že měníme přímo zdrojové soubory na serveru. To je poměrně nesystémové řešení. Pokud bychom chtěli vše udělat korektně, musíme využít mechanismu komponent, tj. aplikace Component Wizard.
Fakticky se jedná o komponentu o třech zdrojích:
  • Definice service (v našem případě UPDATE_DOCINFO_BYFORM_FROMWORKFLOW)
  • Redefinice include std_doc_page_definitions
  • Redefinice template workflow_review_frames.htm
Nejprve vytvoříme prázdnou komponentu. Jako první do ní přidáme např. novou službu:


Tip: místo zaklikávání všech parametrů bývá rychlejší editovat přímo zdrojový soubor *.htm
Pozn. zde se definuje Load Order, což je pořadí, v jakém se zdroje aplikují (vyšší má přednost).

Jako druhý vytvoříme zdroj obsahující redefinici includu std_doc_page_definitions. (v prvním dialogu vyberte volbu Resource – HTML Include/String)


Nakonec pak vytvořímě definici šablony. Zde se fakticky jedná o 2 soubory, *.HDA obsahující definici a *.HTM obsahující vlastní HTML kód. Opět nejprve vybereme volbu Template.

Samotný soubor (WORKFLOW_REVIEW_FRAMES.htm) je možné editovat běžnými editory.

V této fázi už máme připraveny všechny zdroje tak, aby se komponenta dala na daném serveru pouštět a vypínat. Pokud ji však ještě chceme přenášet na jiné servery, je vhodné ji zabalit do instalační podoby (*.zip). K tomu je nezbytný ještě jeden krok, a to je definice buildu:
V této podobě je možné komponentu distribuovat na jakýkoliv další server. Samozřejmě při aplikaci (instalaci a spuštění) je vždy dobré vyzkoušet, zda nedojde k poruše jiné custom komponenty (pokud by redefinovala stejnou šablonu, include či náhodou vytvářela stejnou službu).

Samozřejmě, po aplikaci nové komponenty nezapomeňte restartovat Content Server!

Wednesday, 10 March 2010

Modifikace UCM: komponenty (html resources), 2. část

Řešení v podobě, v jaké jsme jej minule zanechali, má bohužel nevýhodu, že při uložení změn v metadatech (klik na tlačítko Submit Update) dojde k přesměrování na Homepage (je sice možné kliknout na tlačítko Back v browseru a na zobrazené stránkce už budou nová metadata).

Pokud chceme změnit chování, je nejlépe prozkoumat zdrojový kód stránky. Na něm můžeme zjistit, že tlačítko volá funkci postCheckIn napsanou v javaskriptu. Javascript je generovaný opět pomocí zdrojů (hlavně nejrůznějších includes).

V tomto případě nakonec dojdeme k volání služby UPDATE_DOCINFO_BYFORM, přičemž za přesměrovování je zodpovědná samotná definice služby:

<td>UPDATE_DOCINFO_BYFORM</td>
<td>DocService
2
REDIRECT_TEMPLATE
null
documents<br>
!csUnableToUpdateInfo(dDocName)</td>
<td>3:doSubService:UPDATE_DOCINFO_SUB:12:null
3:prepareRedirect:IdcService=DOC_INFO&dID=<$dID$>&dDocName=<$url(dDocName)$><$if IsWorkflowInfo$>&IsWorkflowInfo=<$IsWorkflowInfo$> <$endif$>:0:null</td>


V tomto případě se nabízí možnost jednoduše si vytvořit vlastní verzi služby, v níž by proběhlo přesměrování zpět na stránku REVIEW_WORKFLOW_DOC:

<td>UPDATE_DOCINFO_BYFORM_FROMWORKFLOW</td>
<td>DocService
2
WORKFLOW_REVIEW_FRAMES
null
documents<br>
!csUnableToUpdateInfo(dDocName)</td>
<td>3:doSubService:UPDATE_DOCINFO_SUB:12:null</td>


Nakonec je pak třeba zajistit, aby při generování stránky byla užita vždy správná služba. Tuto definici najdeme opět ve std_page.htm, include std_doc_page_definitions (původní text <$idcService = "UPDATE_DOCINFO_BYFORM"$> nahradíme):

<$if IsWorkflow$>
<$idcService = "UPDATE_DOCINFO_BYFORM_FROMWORKFLOW"$>
<$else$>
<$idcService = "UPDATE_DOCINFO_BYFORM"$>
<$endif$>


Konfigurace řešení
Výše uvedené řešení, tj. zejména využití standardních formulářů, má ještě jednu výhodu: je poměrně jednoduché využít standardního mechanismu profiles, tj. specifikovat, která metadatová pole se budou kdy zobrazovat, zda budou povinná, zda budou mít defaultní hodnoty apod. Jedinou nevýhodou zůstane, že zatímco kroky workflow se definují ve Workflow Administratoru, profily se definují v Configuration Manageru a obě prostředí je třeba prolinkovat (např. přes jména kroků ve workflow, tj. užití logiky kolem <$dWfStepName$> v podmínce Rules užitých v profilu).
Při práci s profily pak ještě zjistíte, že některá metadata není možné v rámci workflows měnit (např. Security Group) a některá jiná je naopak nezbytné na stránce mít (Content ID, v readonly podobě).

(pokračování příště)

Wednesday, 3 March 2010

Modifikace UCM: komponenty (html resources), 1. část

Jeden z našich partnerů se na nás obrátil s otázkou, zda je možné v rámci workflow aktualizovat i metadata. Možné to samozřejmě je, ale defaultní funkcionalita je poněkud uživatelsky nepřívětivá. Postup by totiž byl asi takovýto:
1. Na stránce REVIEW_WORKFLOW_DOC (na obrázku) je nutné kliknout na link Content Information,

2. čímž se dostaname na standardní stránku náhledu na metadata,
3. odkud je možné vyvolat formulář Update,
4. na němž je možné pomocí metody Post (tlačítka Submit Update) uložit změny.
5. Předchozí akce navíc vrátí uživatele na Homepage, takže znovu musí otevřít stránku REVIEW_WORKFLOW_DOC.

Z výše uvedeného je zřejmé, že toto není varianta, kterou je možné doporučovat klientovi, který v rámci workflows chce například doplňovat metadata. Přesto má výše uvedené smysl – dává návod, co je třeba udělat; s tím rozdílem, že v rámci jedné stránky. Tento postup už vede na modifikaci UCM, a to s využitím poměrně jednoduché technologie html resources.

Identifikace zdrojové šablony stránky
Prvním úkolem je nalezení zdroje, v tomto případě HTML šablony, který je třeba modifikovat.
1. REVIEW_WORKFLOW_DOC v URL stránky je služba. Její šablonu tedy najdeme v popisu služeb. Pokud se nejedná o službu dodávánou či modifikovanou nějakou komponentou, najdeme příslušný popis v souboru std_services.htm resp. workflow.htm v adresáři .../shared/config/resources/ (Pozor! I standardní služby je možno předefinovat pomocí komponent (takovým příkladem je komponenta CS10gR3CoreUpdate, která aktualizuje téměř všechny standardní zdroje). V tom případě hledejte službu v adresáři .../custom/. Je možné použít fulltext search na jméno služby v souborech *.htm)
2. Daná služba je definována ve workflow.htm, odkud (přes informaci obsaženou v .../shared/config/templates/templates.hda či v jiném podobném souboru) nakonec najdeme, že stránka je definována v souboru workflow_review_frames.htm (I zde platí, že musíme najít aktuální soubor!!! Zde je možné použít prosté vyhledávání na jméno souboru – dá se předpokládat, že soubory v .../custom/ budou mít vyšší prioritu (loadOrder).)

Úprava stránky
Nejprve je třeba rozhodnout, kam budeme přidávat nový obsah. Rychlým náhledem na strukturu šablony zjistíme, že stránka je postavena jako několik HTML tabulek (<table> … </table>), z nichž ta nejdůležitější obsahuje jeden řádek a dva sloupce (nalevo jsou instrukce a tlačítka, napravo náhled na obsah). Nakonec se jako nejsnažší (levá strana je příliš úzká a obsahuje logiku, aby se tato část nedala příliš roztáhnout na úkor náhledu) ukázalo přidat do tabulky třetí sloupec.
Nyní je otázka, co do daného místa přidat. Jak bylo uvedeno, inspiraci je možné najít na formuláři Update, ze kterého postupně dojdeme k update_docinfo.htm
Prostým překopírováním do stránky však zjistíme, že se v daném prostoru objeví CELÁ stránka z UCM, včetně navigace. Jednoduchým testem zjistíme, že za přidání tohoto obsahu je zodpovědný include checkin_page_content.
Nalezneme tedy příslušný include v std_page.htm a překopírujeme jej na místo. Nakonec je poměrně snadné zjistit, že stačí odstranit jen jednu řádku a ze stránky zmizí navigace. Podobným způsobem odstraníme nepotřebná tlačítka.

Výsledný kód nakonec vypadá takto:

<!-- Modify START -->
<td>
<div>
<$include std_update_html_head_declarations$>
<$include checkin_body_def$>

<$include std_checkin_form_start$>
<table border=0 cellpadding=2 cellspacing=0 summary="">
<tr>
<$include std_checkin_page_caption$>
<$include std_extra_checkin_page_def$>
<$include std_document_checkin_fields$>
</tr>
<tr>
<$exec inc("compute_std_button_checkin_label")$>
<td align=center colspan=2>
<$include std_compute_addpreviewbutton_toplevel$>
<$if addPreviewButton$>
<input type=button name=Preview value="<$lc("wwPreview")$>" onClick="postPreview(this.form)">
<$endif$>
<$include custom_add_checkin_controls$>
<input type=button name=javaSubmit value="<$checkinButtonLabel$>" onClick="postCheckInStandard(this.form)">

</td>
</tr>
</table>
<$include std_checkin_form_end$>
<$include std_checkin_clbra$>
<$include std_page_end$>
</div>
</td>
<!-- Modify END -->

A výsledná stránka pak například takto:
(pokračování příště)