2010年6月14日月曜日

JSFカスタムコンポーネント作成

今回はJSFタグCommandLinkを拡張して部品を作成したいと思います。
※とりあえず"test"という属性を追加したレンダリングを行うのみ

やるべきこと          
    ・カスタムタグクラスの作成      
    ・カスタムUIコンポーネントクラスの作成      
    ・カスタムレンダラーの作成      
    ・tldファイルの作成 (タグクラスの登録とプロパティの追加)      
    ・faces-config.xmlにUIコンポーネントとレンダラーの登録      
    ・tldファイルの配置      
    ・jspでのカスタムタグ使用      



○カスタムタグクラスの作成                                          
CommandLinkTagクラスを拡張してカスタムタグクラスを作成。                                          
オーバライドするべきメソッドは以下の通り。                                          
    getRendererType()    レンダラタイプを返すメソッド      
    getComponentType()    コンポーネントタイプを返すメソッド      
    setProperties()    JSPページに指定された属性値を、UIコンポーネントに設定するメソッド      


package ui.tag;                                                                                
                                                                                
import java.util.Map;                                                                                
                                                                                
import javax.faces.component.UIComponent;                                                                                
                                                                                
import com.sun.faces.taglib.html_basic.CommandLinkTag;                                                                                
                                                                                
public class ExtLinkTag extends CommandLinkTag {                                                                                
                                                                                
    private String test;                                                                            
                                                                                
    public void setTest(String test) {                                                                            
        this.test = test;                                                                        
    }                                                                            
                                                                                
    @Override                                                                            
    public String getRendererType() {                                                                            
        return "ExtLinkRenderer";                                                                        
    }                                                                            
                                                                                
    @Override                                                                            
    public String getComponentType() {                                                                            
        return "ExtLink";                                                                        
    }                                                                            
                                                                                
    @Override                                                                            
    protected void setProperties(UIComponent component) {                                                                            
        super.setProperties(component);                                                                        
                                                                                
        Map attributeMap = component.getAttributes();                                                                        
                                                                                
        if (test != null) {                                                                        
            attributeMap.put("test", test);                                                                    
        }                                                                        
    }    
    

  
  


○カスタムUIコンポーネントクラスの作成                                                          
HtmlCommandLinkクラスを拡張してカスタムUIコンポーネントクラスを作成。                                                          
オーバライドするべきメソッドは以下の通り。                                                          
 getFamily() ファミリ名を返すメソッド                                      
package ui.component;                                                            
                                                            
import javax.faces.component.html.HtmlCommandLink;                                                            
                                                            
public class ExtLink extends HtmlCommandLink {                                                            
                                                            
                                                            
    @Override                                                        
    public String getFamily() {                                                        
        return "ExtLinkFamily";                                                    
    }                                                        
}                                                            
                                  





                                                                          
○tldファイルの作成           
タグクラスの登録とプロパティの追加を行う。          
・・・
    <tag>
        <name>
            extlink
        </name>
        <tag-class>
            ui.tag.ExtLinkTag
        </tag-class>
        <body-content>
            JSP
        </body-content>
        <attribute>
            <name>
                action
            </name>
            <required>
                false
            </required>
            <deferred-method>
                <method-signature>
                    java.lang.Object action()
                </method-signature>
            </deferred-method>
        </attribute>
        <attribute>
            <name>
                actionListener
            </name>
            <required>
                false
            </required>
            <deferred-method>
                <method-signature>
                    void actionListener(javax.faces.event.ActionEvent)
                </method-signature>
            </deferred-method>
        </attribute>
        <attribute>
            <name>
                id
            </name>
            <required>
                false
            </required>
            <rtexprvalue>
                true
            </rtexprvalue>
        </attribute>
        <attribute>
            <name>
                test
            </name>
            <required>
                false
            </required>
            <rtexprvalue>
                true
            </rtexprvalue>
        </attribute>        
・・・        






○faces-config.xmlにUIコンポーネントとレンダラーの登録                                          
 <component>                                            
     <component-type>ExtLink</component-type>                                        
     <component-class>ui.component.ExtLink</component-class>                                        
 </component>                                            
                                             
 <render-kit>                                            
     <renderer>                                        
         <component-family>ExtLinkFamily</component-family>                                    
         <renderer-type>ExtLinkRenderer</renderer-type>                                    
         <renderer-class>ui.render.ExtLinkRender</renderer-class>                                    
     </renderer>                                        
 </render-kit>    





○カスタムレンダラーの作成                                              
必要に応じてdecodeメソッドと各種encodeメソッドをオーバーライド。                                              
decodeメソッドはmanagedBean適用時。                                              
encodeメソッドはレンダリング時。                                              
                                              
encode処理にて属性にtestを追加してみる。
decode処理はそのまま。                                              
package ui.render;                                                            
                                                            
import java.io.IOException;                                                            
import java.util.Map;                                                            
import java.util.logging.Level;                                                            
                                                            
import javax.faces.component.UIComponent;                                                            
import javax.faces.component.UIForm;                                                            
import javax.faces.context.FacesContext;                                                            
import javax.faces.context.ResponseWriter;                                                            
                                                            
import com.sun.faces.renderkit.AttributeManager;                                                            
import com.sun.faces.renderkit.RenderKitUtils;                                                            
import com.sun.faces.renderkit.html_basic.CommandLinkRenderer;                                                            
import com.sun.faces.renderkit.html_basic.HtmlBasicRenderer;                                                            
                                                            
public class ExtLinkRender extends CommandLinkRenderer {                                                            
                                                            
    private static final String ATTRIBUTES[];                                                            
    private static final String SCRIPT_STATE = "com.sun.faces.scriptState";                                                            
                                                            
    static                                                             
    {                                                            
        ATTRIBUTES = AttributeManager.getAttributes(com.sun.faces.renderkit.AttributeManager.Key.COMMANDLINK);                                                            
    }                                                            
                                                                
    @Override                                                        
    public void decode(FacesContext context, UIComponent component) {                                                        
        super.decode(context, component);                                                    
                                                            
    }                                                        
                                                            
    @Override                                                        
    public void encodeBegin(FacesContext context, UIComponent component)                                                        
            throws IOException {                                                
                                                            
        rendererParamsNotNull(context, component);                                                    
        if (!shouldEncode(component))                                                    
            return;                                                
        boolean componentDisabled = Boolean.TRUE.equals(component                                                    
                .getAttributes().get("disabled"));                                            
        String formClientId = getFormClientId(component, context);                                                    
        if (formClientId == null && logger.isLoggable(Level.WARNING))                                                    
            logger.log(Level.WARNING,                                                
                    Component {0} must be enclosed inside a form, component                                        
                            .getId());                                
        if (componentDisabled || formClientId == null) {                                                    
            renderAsDisabled(context, component);                                                
        } else {                                                    
            if (!hasScriptBeenRendered(context)) {                                                
                RenderKitUtils.renderFormInitScript(                                            
                        context.getResponseWriter(), context);                                    
                setScriptAsRendered(context);                                            
            }                                                
            renderAsActive(context, component);                                                
        }                                                    
    }                                                        
                                                            
    protected void renderAsActive(FacesContext context, UIComponent command)                                                        
            throws IOException {                                                
        ResponseWriter writer = context.getResponseWriter();                                                    
        if (writer == null)                                                    
            throw new AssertionError();                                                
        String formClientId = getFormClientId(command, context);                                                    
        if (formClientId == null)                                                    
            return;                                                
        writer.startElement("a", command);                                                    
        writeIdAttributeIfNecessary(context, writer, command);                                                    
        writer.writeAttribute("href", "#", "href");                                                    
                                                            
                                                            
        Map attributeMap = command.getAttributes();                                                    
        writer.writeAttribute("test", "#", null);                                                    
                                                            
        RenderKitUtils.renderPassThruAttributes(writer, command, ATTRIBUTES);                                                    
        RenderKitUtils.renderXHTMLStyleBooleanAttributes(writer, command);                                                    
        String userOnclick = (String) command.getAttributes().get("onclick");                                                    
        StringBuffer sb = new StringBuffer(128);                                                    
        boolean userSpecifiedOnclick = userOnclick != null                                                    
                && !"".equals(userOnclick);                                            
        if (userSpecifiedOnclick) {                                                    
            sb.append("var a=function(){");                                                
            userOnclick = userOnclick.trim();                                                
            sb.append(userOnclick);                                                
            if (userOnclick.charAt(userOnclick.length() - 1) != ';')                                                
                sb.append(';');                                            
            sb.append("};var b=function(){");                                                
        }                                                    
        HtmlBasicRenderer.Param params[] = getParamList(command);                                                    
        String commandClientId = command.getClientId(context);                                                    
        String target = (String) command.getAttributes().get("target");                                                    
        if (target != null)                                                    
            target = target.trim();                                                
        else                                                    
            target = "";                                                
        sb.append(getOnClickScript(formClientId, commandClientId, target,                                                    
                params));                                            
        if (userSpecifiedOnclick)                                                    
            sb.append("};return (a()==false) ? false : b();");                                                
        writer.writeAttribute("onclick", sb.toString(), "onclick");                                                    
        writeCommonLinkAttributes(writer, command);                                                    
        writeValue(command, writer);                                                    
        writer.flush();                                                    
    }                                                        
                                                            
    private static boolean hasScriptBeenRendered(FacesContext context) {                                                        
        return context.getExternalContext().getRequestMap().get(                                                    
                com.sun.faces.scriptState) != null;                                            
    }                                                        
                                                            
    private static void setScriptAsRendered(FacesContext context) {                                                        
        context.getExternalContext().getRequestMap().put(                                                    
                com.sun.faces.scriptState, Boolean.TRUE);                                            
    }                                                        
                                                            
    private static String getFormClientId(UIComponent component,                                                        
            FacesContext context) {                                                
        UIForm form = getMyForm(component);                                                    
        if (form != null)                                                    
            return form.getClientId(context);                                                
        else                                                    
            return null;                                                
    }                                                        
                                                            
    private static UIForm getMyForm(UIComponent component) {                                                        
        UIComponent parent;                                                    
        for (parent = component.getParent(); parent != null                                                    
                && !(parent instanceof UIForm); parent = parent.getParent())                                            
            ;                                                
        return (UIForm) parent;                                                    
    }                                                        
                                                            
}                                                            





○tldファイルの配置                      
    WEB-INF/jsf_custum.tldに配置 jsf-tlds.jarに含めてもよいと思います。                  




○jspでのカスタムタグ使用                                                  
taglibでtldファイル読込みとprefix定義を行う。                                                  
タグ名はtldファイルに定義したname                                                  



<%@ page contentType="text/html;charset=Shift_JIS" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="/WEB-INF/jsf_custum.tld" prefix="custom" %>
<html>
<head>
<title>HelloWorld</title>
</head>
<body>
<f:view>
<h:form>

文字を入力して下さい:<h:inputText id="string" value="#{HelloWorldBean.helloWorld}"/>
<h:commandButton value="送信"/>
<p><h:outputText id="output" value="#{HelloWorldBean.helloWorld}"/></p>


<h:commandButton id="btn1" action="ok" value="遷移" actionListener="#{HelloWorldBean.assembleMessage}" />
<br>
<custom:extlink id="link1" action="ok" actionListener="#{HelloWorldBean.assembleMessage}">カスタムリンク</custom:extlink> 
</h:form>
</f:view>
</body>
</html>

0 件のコメント:

コメントを投稿