JSF komponenta
Tento článek popisuje vývoj jednoduché komponenty v
                  Java Server Faces (JSF) verze 1.2. Nejprve si
                  ukážeme, co tvoří JSF komponentu a pak jednoduchou
                  komponentu naimplementujeme. Technologie JSF je
                  postavena nad Java Server Pages (JSP), jejichž
                  znalost dále předpokládám.
Ukázková komponenta bude generovat posloupnost
                  náhodných čísel, která bude sloužit jako nápověda pro
                  sázkaře. Pokud používáte NetBeans 6.5, začněte
                  vytvořením nové webové aplikace. Při vytváření
                  projektu nezapomeňte zatrhnou podporu JSF.
JSF komponenta se skládá z těchto částí:
- UIComponent class – třída, která
obsahuje "logiku" komponenty. Její
instance jsou součástí stromu komponent, který se
vytváří na serveru po příchodu JSF požadavku. - Renderer class – třída zodpovědná za
převod (rendering) komponenty do HTML či jiného
značkovacího jazyka. Pokud se o tento převod
postará sama třída komponenty (UIComponent class),
může Renderer chybět. - Tag class – slouží k odkazu na
komponentu v JSP stránce. Je také zodpovědný za
předávání parametrů do třídy komponenty. - Tag Library Descriptor (TLD) – popis
tagu, tj. jeho jméno, třída a atributy. 
Začneme implementací logiky komponenty. Třída LottoComponent bude potomkem třídy UIComponentBase, která je potomkem UIComponent. Protože nebudeme používat
                  Renderer, postará se o převod do HTML sama
                  komponenta. K tomu slouží metody encodeBegin, encodeEnd a
                  příp. i encodeChildren. V našem
                  příkladu vystačíme s encodeBegin.
public class LottoComponent extends UIComponentBase {
    private Random rand = new Random();
    private int number = 6;
    @Override
    public void encodeBegin(FacesContext fc) throws IOException {
        ResponseWriter w = fc.getResponseWriter();
        w.startElement("p", this);  // zapíše <p>
        for (int i = 0; i < number; i++) {  // zapisuje čísla z intervalu <1,40>
            w.writeText(1 + rand.nextInt(40) + " ", null);
        }
        w.endElement("p");  // zapíše </p>
    }
    @Override
    public String getFamily() {
        return "LottoFamily";
    }
}
Metoda getFamily vrací jméno rodiny
                  komponent, do níž komponenta patří. Rodina komponenty
                  se používá při výběru Rendereru. Protože v našem
                  příkladu Renderer nepoužíváme, metoda může vracet
                  libovolný řetězec.
Dále vložíme do faces-config.xml element component:
<faces-config version="1.2"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
    <component>
        <component-type>Lotto</component-type>
        <component-class>lotto.LottoComponent</component-class>
    </component>
</faces-config>
A naimplementujeme Tag:
public class LottoTag extends UIComponentELTag {
    @Override
    public String getComponentType() {
        return "Lotto";  // vrací to, co je uvedeno v elementu component-type ve faces-config.xml
    }
    @Override
    public String getRendererType() {
        return null;  // Renderer v tomto příkladě nepoužíváme
    }
}
Třída LottoTag je potomkem UIComponentELTag, která je určena pro
                  vytváření JSF tagů. JSF tagy jsou
                  "vylepšené" JSP tagy. Umí navíc např. Expression Language.
Tag Library Descriptor obsahuje popis
                  tagu:
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee">
  <tlib-version>1.0</tlib-version>
  <short-name>lotto</short-name>
  <uri>/WEB-INF/Lotto</uri>
    <tag>
        <name>tips</name>
        <tag-class>lotto.LottoTag</tag-class>
    </tag>
</taglib>
Element short-name obsahuje
                  doporučený prefix pro tagy z této knihovny a element
                  uri je identifikátor knihovny. Pomocí
                  uri se na knihovnu budeme odkazovat z
                  JSP stránky. V elementu name je jméno
                  tagu a v elementu tag-class je jméno
                  třídy tagu.
Teď už můžeme tag použít v JSF stránce:
<%@taglib prefix="lotto" uri="/WEB-INF/Lotto"%>
...
<f:view>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Lotto</title>
        </head>
        <body>
            <h1>Lotto</h1>
            <lotto:tips/>
        </body>
    </html>
</f:view>
Výhody komponentového modelu se naplno projeví
                  tehdy, když použijeme tag opakovaně. Můžeme jej
                  použít na té samé stránce i na jiné.
                
Atributy
Dále přidáme naší komponentě atribut number, kterým řekneme, kolik čísel chceme
                  generovat. Pokud atribut nebude uveden, bude
                  komponenta generovat šest čísel jako dříve.
Do TDL souboru přidáme popis atributu:
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee">
  <tlib-version>1.0</tlib-version>
  <short-name>lotto</short-name>
  <uri>/WEB-INF/Lotto</uri>
    <tag>
        <name>tips</name>
        <tag-class>lotto.LottoTag</tag-class>
        <attribute>
            <name>number</name>
            <description>The number of tips</description>
        </attribute>
    </tag>
</taglib>
Ve třídě LottoTag přibyde property
                  number a metody setProperties a release:
public class LottoTag extends UIComponentELTag {
    private String number;
    @Override
    protected void setProperties(UIComponent component) {
        super.setProperties(component);
        if (number != null) {
            component.getAttributes().put("number", number);
        }
    }
    @Override
    public void release() {
        super.release();
        number = null;
    }
    @Override
    public String getComponentType() {
        return "Lotto";    }
    @Override
    public String getRendererType() {
        return null;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
}
Metoda setProperties je volána po
                  vytvoření komponenty před jejím přidáním do stromu
                  komponent. Má za úkol přenos parametrů z tagu do
                  komponenty. Metoda release je volána
                  po ukončení zpracování tagu. Měla by objekt vrátit do
                  stavu, ve kterém byl těsně po vytvoření. Při
                  opakovaném výskytu stejného tagu se totiž nemusí
                  vytvářet vždy nová instance, ale starší instance
                  mohou být "recyklovány".
Ve třídě LottoComponent upravíme
                  metodu encodeBegin, aby používala
                  atribut number:
@Override
public void encodeBegin(FacesContext fc) throws IOException {
    String s = (String) getAttributes().get("number");
    if (s != null) {
        number = Integer.parseInt(s);
    }
    ResponseWriter w = fc.getResponseWriter();
    for (int i = 0; i < number; i++) {
        w.writeText(1 + rand.nextInt(40) + " ", null);
    }
}
V JSP stránce pak můžeme použít u tips atribut number:
<lotto:tips number="4"/>
Expression Language
Dále komponentu rozšíříme o podporu Expression
                  Language (EL). Tj. přidáme možnost stanovit
                  hodnotu atributu number pomocí výrazu
                  v EL:
<lotto:tips number="#{testManagedBean.size}"/>
Nejprve upravíme TLD:
<tag>
    <name>tips</name>
    <tag-class>lotto.LottoTag</tag-class>
    <attribute>
        <name>number</name>
        <deferred-value>
            <type>Integer</type>
        </deferred-value>
        <description>The number of tips</description>
    </attribute>
</tag>
Pak drobně změníme třídu LottoTag:
public class LottoTag extends UIComponentELTag {
    private ValueExpression number;
    @Override
    protected void setProperties(UIComponent component) {
        super.setProperties(component);
        if (number != null) {
            component.getAttributes().put("number", number);
        }
    }
    @Override
    public void release() {
        super.release();
        number = null;
    }
    @Override
    public String getComponentType() {
        return "Lotto";
    }
    @Override
    public String getRendererType() {
        return null;
    }
    public ValueExpression getNumber() {
        return number;
    }
    public void setNumber(ValueExpression number) {
        this.number = number;
    }
}
A nakonec ještě malá úprava metody encodeBegin ve třídě LottoComponent:
@Override
public void encodeBegin(FacesContext fc) throws IOException {
    ValueExpression ve = (ValueExpression) getAttributes().get("number");
    if (ve != null) {
        number = (Integer) ve.getValue(fc.getELContext());
    }
    ResponseWriter w = fc.getResponseWriter();
    for (int i = 0; i < number; i++) {
        w.writeText(1 + rand.nextInt(40) + " ", null);
    }
}
A je hotovo. Na závěr si ještě ukážeme, jak
                  vytvořit knihovnu, kterou lze snadno připojit k
                  webové aplikaci. Vytvoříme jar, který bude mít tuto
                  strukturu:
                
(MANIFEST.MF byl vložen automaticky programem jar).
                  Takto vytvořenou knihovnu pak k projektu připojíme
                  nakopírováním jaru do adresáře WEB-INF/lib.
