Hlavní navigace

Cocoon v příkladech: Programujeme vlastní komponenty (1)

Pavel Sýkora 2. 6. 2004

V tomto dílu se podíváme na to, jak (snadno) lze v Cocoonu naprogramovat vlastní komponenty. Začneme těmi nejjednoduššími - vytvoříme si vlastní selektor a akci. Rozborem zdrojového kódu a příkladem použití si také zopakujeme, jak se selektory a akce chovají, navíc získáme jistotu v rozhodování, kdy je vhodné tyto typy komponent nasazovat.

Popis komponent

Není snadné najít rozumný problém, který by již v Cocoonu nebyl vyřešen (tj. pro který by už nebyla nějaká komponenta hotová) a řešení kterého by zároveň vedlo k vytvoření jednoduché komponenty vhodné jako příklad. Zvolme si tedy „akademický“ příklad, kdy budeme chtít vytvořit nějakou webovou aplikaci či prezentaci, která bude citlivá na „denní dobu“ – její obsah nebo forma bude záviset na tom, zda je ráno, nebo večer (dle lokálního času serveru). Nic takového Cocoon ještě neobsahuje.

Selektor a jeho anatomie

Ačkoliv jsme selektory potkali již dříve, nebude na škodu stručná rekapitulace. Selektory jsou komponenty Cocoonu, které na základě vyhodnocení jednoduchého logického výrazu umožňují v mapě větvení typu podmíněného příkazu (if-then-else) nebo přepínače (select-case).

Selektor patří mezi ty nejjednodušší komponenty. Stačí implementovat jednu metodu rozhraní vracející logickou hodnotu. Komponenta navíc ani nepracuje s XML, takže její implementace je (obvykle) hračkou. Implementujme selektor, který „úspěšně“ vyhodnotí řetězec „rano“, pokud je lokální čas na serveru mezi 6:00 a 9:59, a řetězec „vecer“, pokud bude mezi 19:00 a 22:59. Úspěšné vyhodnocení znamená návrat hodnoty „true“, jinak se vrací „false“. Komponenta by mohla vypadat třeba takto:

package org.apache.cocoon.selection;

import org.apache.cocoon.selection.Selector;
import java.util.Map;
import java.util.Calendar;
import
org.apache.avalon.framework.parameters.Parameters;

public class MujSelektor implements Selector {
  public boolean select( String expression,
      Map objectModel, Parameters parameters) {

    Calendar cal = Calendar.getInstance();
    int hour = cal.get(Calendar.HOUR_OF_DAY);

    if (expression.equals("rano")) {
      return hour >= 6 && hour <= 9;
    }
    else if (expression.equals("vecer")) {
      return hour >= 19 && hour <= 22;
    }

    return false;
  }
}

Jak vidíte, komponenta je opravdu jednoduchá. V implementované metodě „select“ je nejzajímavější parametr „expression“, což je řetězec předávaný z mapy do komponenty. Poslední parametr by byl užitečný, pokud bychom chtěli komponentu parametrizovat. Zdrojový kód komponenty umístíme jako soubor „MujSelektor.java“ do adresáře „…/src/java/or­g/apache/coco­on/selection“ k ostatním selektorům, kde „…“ je základní adresář Cocoonu (obvykle „~/cocoon-2.1.4“), a rebuildujeme Cocoon příkazem „./build.sh“ v základním adresáři Cocoonu. Komponentu pak použijeme v mapě takto:

<?xml version="1.0"?>
<map:sitemap
xmlns:map="http://apache.org/cocoon/sitemap/1.0">

<!-- === Deklarace komponent === -->

  <map:components>

    <map:selectors default="browser">
      <map:selector name="denni-doba"
src="org.apache.cocoon.selection.MujSelektor"/>
    </map:selectors>
  </map:components>

<!-- === Roury === -->

  <map:pipelines>

    <map:pipeline>

      <map:match pattern="">
        <map:select type="denni-doba">
          <map:when test="rano">
            <map:read src="rano.html"/>
          </map:when>

          <map:when test="vecer">
            <map:read src="vecer.html"/>
          </map:when>
          <map:otherwise>
            <map:read src="jinak.html"/>
          </map:otherwise>

        </map:select>
      </map:match>

    </map:pipeline>
  </map:pipelines>
</map:sitemap>

Naši komponentu je nutné v mapě deklarovat, použití je pak snadné. Pokud je úspěšný řetězec „rano“, pošle server klientovi soubor „rano.html“, pokud je úspěšný řetězec „vecer“, pošle se soubor „vecer.html“. V ostatních případech se pošle soubor „jinak.html“. Rád bych zdůraznil, že náš selektor je možné použít v libovolném místě roury. Můžeme tedy například zvolit v závislosti na denní době XSLT stylesheet, zatímco ostatní komponenty roury mohou být společné. Mohli bychom také vytvořit rouru pro kaskádový styl, kde by se pod zdánlivě jedním názvem skrývalo několik stylů závislých na denní době.

Komponenta typu „akce“

Selektor není jediný typ komponenty, kterým lze vyřešit náš příklad. Akce patří k nejčastěji programovaným komponentám Cocoonu. Jsou pořád ještě dosti jednoduché, nicméně mocnější než výše změněné selektory. Komponenty typu „akce“ přidávají do roury jednu nebo více dvojic klíč-hodnota. V rouře se pak lze na hodnoty odkazovat tak, že uvedeme klíč ve složených závorkách. V nejjednodušším případě je to opět javovská třída implementující jednu metodu rozhraní „Action“. Výsledek se vrací jako javovský typ „Map“. Podívejme se, jak by mohla vypadat naše komponenta:

package org.apache.cocoon.acting;

import org.apache.cocoon.acting.Action;
import org.apache.cocoon.environment.Redirector;
import
org.apache.cocoon.environment.SourceResolver;
import java.util.Map;
import java.util.HashMap;
import java.util.Calendar;
import
org.apache.avalon.framework.parameters.Parameters;

public class MojeAkce implements Action {

  public final static String DOBA = "denni-doba";

  public Map act( Redirector redirector,
      SourceResolver resolver,
      Map objectModel, String source,
      Parameters parameters) {

    Calendar cal = Calendar.getInstance();
    int hour = cal.get(Calendar.HOUR_OF_DAY);
    Map returnMap = new HashMap();

    if (hour >= 6 && hour <= 9) {
      returnMap.put(DOBA,"rano");
    }
    else if (hour > 9 && hour < 19) {
      returnMap.put(DOBA,"den");
    }
    else if (hour >= 19 && hour <= 22) {
      returnMap.put(DOBA,"vecer");
    }
    else {
      returnMap.put(DOBA,"noc");
    }

    return returnMap;
  }
}

Komponenta bude vracet řetězec určený klíčovým slovem „denni-doba“. V závislosti na hodině lokálního času se bude vracet řetězcová hodnota „rano“, „den“, „vecer“ nebo „noc“. V mapě pak použijeme vrácenou hodnotu jako část názvu odesílaného souboru. Budeme odesílat „rano.html“, „den.html“, „vecer.html“ nebo noc.html

<?xml version="1.0"?>
<map:sitemap
xmlns:map="http://apache.org/cocoon/sitemap/1.0">

<!-- === Deklarace komponent === -->

  <map:components>

    <map:actions>
      <map:action name="doba"
src="org.apache.cocoon.acting.MojeAkce"/>
    </map:actions>
  </map:components>

<!-- === Roury === -->

  <map:pipelines>

    <map:pipeline>

      <map:match pattern="">
        <map:act type="doba">
          <map:read src="{denni-doba}.html"/>
        </map:act>
      </map:match>

    </map:pipeline>
  </map:pipelines>
</map:sitemap>

Komponentu je potřeba umístit do adresáře „src/java/org/co­coon/acting“ a rebuildovat Cocoon. V mapě je pak nutné naši komponentu deklarovat. Opět bych rád zdůraznil, že je čistě na vás, jak páry klíč-hodnota, vracené akcí, v mapě použijete. Často se např. tato hodnota předává do XSLT stylesheetů jako parametr.

Závěr

Závěrem bych rád upozornil, že výše zmíněné příklady jsou jen ukázkou komponent (komponenty jsou však plně funkční). Pokud bychom dělali komponenty skutečné, bylo by vhodné se zamyslet na tím, zda by komponenty byly parametrizovatelné nebo konfigurovatelné a jaké další služby po nich budeme požadovat. Dobrým zvykem je, aby bylo umožněno alespoň logování (komponenta v tomto případě musí být potomkem třídy AbstractLogEna­bled). Ve výše zmíněných adresářích existují i abstraktní třídy s různými úrovněmi předdefinovaných služeb, které můžeme použít pro odvození třídy vytvářené komponenty. Rozhodně bych pro inspiraci doporučoval prostudovat zdrojový kód standardních komponent Cocoonu. Komponenty obsažené v adresářích „acting“ a „selection“ jsou většinou spíše jednodušší, takže by s tím neměly být větší problémy.

Všechny potřebné soubory můžete nalézt v archivu cocoon13.zip. Pokud jej rozbalíte v základním adresáři Cocoonu se zachováním cest a z tohoto adresáře spustíte rebuild, budete mít pří dalším spuštění Cocoonu k dispozici dvě primitivní aplikace na ověření činnosti výše zmíněných komponent. Aplikace se budou volat: „http://local­host:8888/selek­tor/“ resp. „http://local­host:8888/akce/“ (nezapomeňte na ukončovací lomítka!). V příštím dílu se podíváme na tvorbu složitějších komponent – naprogramujeme si transformátor.

Našli jste v článku chybu?

2. 6. 2004 12:21

Pavel Sýkora (neregistrovaný)

Nemusejí, mohou být kdekoliv. Já si jen chtěl ušetřit práci s vytvářením Ant tasku a taky se mi do toho článku zdál zbytečný popis, jak se mají nastavit cesty a co se má kam kopírovat (to by bylo skoro na samostatný článek :-). Pokud by šlo o opravdovou aplikaci, tak je opravdu lepší (ne-li nutné) to mít odděleno. Kdo si ale chce v Cocoonu jen nezávazně pohrát s komponentama, tak je postup z článku, dle mého názoru, ideální.

2. 6. 2004 9:50

martin kavalec (neregistrovaný)

opravdu se musi vlastni komponenty umistovat do
org.cocoon.cosi.kdesi? Jestli je to komponenta specificka pro urcitou aplikaci, vic by se mi libilo mit ji ve zdrojacich te aplikace. Co kdyz vyvojare Cocoonu nekdy napadne napsat komponentu se stejnym nazvem?


Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Lupa.cz: Kdo pochopí vtip, může jít do ČT vyvíjet weby

Kdo pochopí vtip, může jít do ČT vyvíjet weby

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Vitalia.cz: 7 originálních adventních kalendářů pro mlsné

7 originálních adventních kalendářů pro mlsné

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Vitalia.cz: Spor o mortadelu: podle Lidlu falšovaná nebyla

Spor o mortadelu: podle Lidlu falšovaná nebyla

Root.cz: Vypadl Google a rozbilo se toho hodně

Vypadl Google a rozbilo se toho hodně

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

DigiZone.cz: ČRa DVB-T2 ověřeno: Hisense a Sencor

ČRa DVB-T2 ověřeno: Hisense a Sencor

120na80.cz: Jak oddálit Alzheimera?

Jak oddálit Alzheimera?

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

DigiZone.cz: Flix TV má set-top box s HEVC

Flix TV má set-top box s HEVC

Podnikatel.cz: 1. den EET? Problémy s pokladnami

1. den EET? Problémy s pokladnami