﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-黑灵客栈-随笔分类-JSF</title><link>http://www.blogjava.net/mstar/category/1533.html</link><description>搞软件开发就像被强奸,如果不能反抗,就享受它吧！</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 18:34:39 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 18:34:39 GMT</pubDate><ttl>60</ttl><item><title>[ZZ]JavaServer Faces vs Tapestry - A Head-to-Head Comparison</title><link>http://www.blogjava.net/mstar/archive/2005/08/26/11239.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Fri, 26 Aug 2005 09:52:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2005/08/26/11239.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/11239.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2005/08/26/11239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/11239.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/11239.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://www.theserverside.com/articles/article.tss?l=JSFTapestryAugust 2005 DiscussionAfter several years as the leading Java web application framework, the reign of Apache Struts a...&nbsp;&nbsp;<a href='http://www.blogjava.net/mstar/archive/2005/08/26/11239.html'>阅读全文</a><img src ="http://www.blogjava.net/mstar/aggbug/11239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2005-08-26 17:52 <a href="http://www.blogjava.net/mstar/archive/2005/08/26/11239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZZ]实现图形JSF组件</title><link>http://www.blogjava.net/mstar/archive/2005/08/05/9360.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Fri, 05 Aug 2005 00:18:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2005/08/05/9360.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/9360.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2005/08/05/9360.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/9360.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/9360.html</trackback:ping><description><![CDATA[实现图形JSF组件<BR>很简单地构建一个纯HTML无法轻松实现的图形Web应用程序组件<BR>作者：Marc Durocher<BR><A href="http://dev2dev.bea.com.cn/techdoc/wlworkshop/2005070704.html">http://dev2dev.bea.com.cn/techdoc/wlworkshop/2005070704.html</A><BR>开发人员认为，如果有合适的工具来创建交互式Web界面，他们就能将时间集中在核心需求和定制上，并在规定时间内及时得交付应用程序。与其他技术如JavaServer Pages或Apache Struts 相比，JavaServer Faces (JSF)技术为创建交互式Web应用程序带来了很多便利。JSF在程序逻辑和GUI表示之间划出一条清晰的界限，提高了对Web程序的维护能力，并为Web用户界面组件的开发和重用提供了一个框架。
<P>　　如今，许多Web应用程序开发人员都在转而使用JSF，但是他们发现，预先定制的JSF UI组件受到基本DHTML窗口部件的限制。监管或业务流程监控之类的高级应用程序需要能与JSF框架兼容的高级可视化组件。JSF框架的标准化使它易于开发能够重用的自定义Web GUI组件。另外，Web组件开发商现在能提供更复杂的组件，并承诺Web应用程序开发人员能够轻松地使用这些组件。此类JSF用户界面组件必须集成并部署到JSF运行时框架中去，并在其中完全展开，还必须在设计时很好地集成到提供JSF支持的IDE中去。</P>
<P>　　尽管JSF带来了标准用户界面框架，但对于开发第一个自定义JSF组件而言，还是存在几个缺陷和漏洞。让我们看看怎样创建一个纯HTML无法轻松创建的图形JSF组件。图形JSF组件的特点不仅要求生成DHTML，而且还需要对图像生成和客户端交互提供补充支持。我们将以一个图形组件的例子来阐述这些特点。该图形组件能够提供曲线图，并为各种客户端导航和交互提供便利。我们还会了解到将该图形组件集成到JSF-enabled IDE中所需要的步骤。通过理解图形组件的设计方法，您将会更好地理解如何实现JSF组件，而这应该能使您开发出定制的JSF图形组件。</P>
<P><STRONG>什么是JSF？</STRONG></P>
<P>　　JSF是一种能够简化Web应用程序表示层结构的标准服务器端框架。定义JSF框架的JSR 127（参见参考资料）带有一个能提供基本UI组件（如输入栏和按纽）的参考实现。您可以将可重用用户界面组件集中起来创建Web页，将这些组件绑定到应用数据源上，并用服务器端事件控制程序处理客户端事件。根据说明书介绍，组件供应商能编写与JSF运行时框架集成的组件，并将其集成到在设计时与JSF兼容的IDE中去。</P>
<P>　　从很大程度上讲，JSF组件同在HTML 2.0技术要求下可用的HTML组件和标签直接相符合。对许多Web应用程序而言，这套相对简单的组件是够用的。然而，许多应用程序如监管或监控程序需要更复杂的数据显示与交互，比如制表、制图和映射。由于JSF组件在HTML中直接提交复杂图形小部件的能力有限，所以设计这些高级组件的能力并不突出。解决方案要求服务器端组件向客户传输图像，却会给自身带来问题，因为在基本HTML图像上进行交互要受到限制。最后，使用JavaScript时，必须能调用客户端交互来使用户能对数据进行导航和交互。</P>
<P>　　让我们看看开发一个简单的、将CSS输入HTML页面的JSF组件需要哪些步骤。当开发高级JSF图形组件时，这一简单组件的描述和代码样本会作为背景。图1显示了如何使用即将开发的组件，并显示将要得到的结果。使用这种组件的好处是能够通过改变某个JSF动作的组件值，来改变整个页面的外观。 </P>
<P><IMG height=239 src="http://dev2dev.bea.com.cn/techdoc/wlworkshop/images/images05070604_01.jpg" width=300> </P>
<P>图1：显示了我们如何使用一个非常简单的JSF组件将CSS输入某个HTML页面并得出结果。</P>
<P><STRONG>开发组件</STRONG></P>
<P>　　JSF组件包含若干个Java类和配置文件。为创建一个自定义JSF组件，您需要开发一个扩展JSF基本组件类的Java类；为默认呈现软件包开发呈现程序；开发一个将在JSP页面中用于描述标签的Java类；编写一个标签库定义（TLD）文件；编写JSF配置文件。让我们更深入地了解这5个步骤。</P>
<P>　　开发组件Java类。组件类负责管理代表组件状态的属性。因此，我们必须根据组件的行为（如输入组件或输出组件），给组件选择适当的基类（参见清单1）。这里描述的组件可进行扩展javax.faces.component.UIOutput，以显示指向某个样式表文件的URL，或内联式样式表的内容。该组件可用于在JSF动作中将某个样式表转换成另一个样式表。关联属性规定着值的类型：要么是一个URL，要么是内联样式。该组件还必须能够在向服务器发送请求期间，使用经过JSF框架处理的对象，来存储并修复自己的状态。组件的状态由重建对象所需的重要属性值组成。JSF框架自动调用saveState()和restoreState()方法，我们可以在组件中实现这两种方法来达到这一目标。</P>
<P align=left><STRONG>清单</STRONG><STRONG>1. </STRONG>组件类管理显示组件状态的属性。可依据组件的行为，为其选择一个适当的基类。在本例中，该组件扩展javax.faces.component.UIOutput，以显示指向某个样式表文件的URL，或者某个内联式样式表的内容。<STRONG></STRONG></P><PRE class=code>import javax.faces.component.*;
public class CSSComponent extends UIOutput {
	private Boolean link; 
	public String getFamily() { 
		return "faces.CSSFamily"; 
	} 
	public boolean isLink() { 
		if (link != null) 
			return link.booleanValue(); 
			ValueBinding vb = getValueBinding("link"); 
	if (vb != null) { 
		Boolean bvb = (Boolean) vb.getValue(
			FacesContext.getCurrentInstance()); 
		if (bvb != null) 
			return bvb.booleanValue(); 
	} 
	return false; 
	} 
	public void setLink(boolean link) { 
		this.link = new Boolean(link); 
	} 
	public Object saveState(FacesContext context) { 
		return new Object[] { super.saveState(context), 
			link }; 
	} 
	public void restoreState(FacesContext context, 
	Object stateObj) { 
		Object[] state = (Object[]) stateObj; 
		super.restoreState(context, state[0]); 
		link = (Boolean) state[1]; 
	} 
}
</PRE>
<P><STRONG>开发呈现程序。</STRONG>呈现程序有两个作用。第一，呈现程序负责发送适当的HTML程序段，该程序段能在客户端中呈现组件。通常情况下，这个HTML程序段由一些适于呈现整个Web浏览器的HTML标签组成。此JSF生存周期称作编码阶段或呈现—响应阶段。该响应阶段还能发送增强客户端交互性的JavaScript代码。</P>
<P>　　呈现程序的第二个作用是解析来自客户端的数据，从而对服务器端的组件状态进行更新（如用户在文本字段输入的文本）。标准呈现程序软件包具有强制性，但也可以提供其他呈现程序软件包，用于提供可替换的客户端表示法或SVG之类的语言（参见参考资料）。通过检验组件的连接属性，您实现的呈现程序（参见清单2）将选择在HTML页面中发送的CSS样式。</P>
<P align=left><STRONG>清单</STRONG><STRONG>2. </STRONG>标准呈现程序软件包具有强制性，但是，您可以使用其他呈现程序软件包，来提供可替换的客户端表示法或语言。通过检验组件的连接属性，您实现的呈现程序将选择在HTML页面中发出的CSS样式。</P><PRE class=code>import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
public class CSSRenderer extends Renderer {
public void encodeEnd(FacesContext context,
UIComponent component)
	throws IOException {
		super.encodeEnd(context, component);
		if (component instanceof CSSComponent) {
			CSSComponent cssComponent  =
				(CSSComponent) component;
			String css = (String)cssComponent.getValue();
			boolean isLink = cssComponent.isLink();
			if (css != null) 
				if (isLink)  
				context.getResponseWriter().write(
				"&lt;link type='text/css' rel='stylesheet' 
				href='" + css + "'/&gt;");
			else 
				context.getResponseWriter().write(
					"&lt;style&gt;;\n" + css + "\n&lt;style/&gt;\n"); 
		}
	}
}
</PRE>
<P><STRONG>开发标签类。</STRONG>同样，JSF框架提供了用于扩展的基类，来编写与组件相关的标签。该标签类负责定义并呈现将在faces-config.xml文件中应用的组件样式（这种样式的描述很简短）。它还负责创建JSF组件（由JSF框架来处理），传递JSF标签中所包含的属性，该属性用于初始化组件（参见清单3）。</P>
<P align=left><STRONG>清单</STRONG><STRONG>3. </STRONG>该标签类定义了将在faces-config.xml文件中应用的组件的样式和组件呈现方式。</P><PRE class=code>import javax.faces.webapp.UIComponentTag;
public class CSSTag 
	extends UIComponentTag {
	private String value;
	private String link;
	public String getComponentType() {
		return "faces.CSSComponent";
	}
	public String getRendererType() {
		return “HTML.LinkOrInlineRenderer";
	}
	protected void setProperties(UIComponent component) {
		super.setProperties(component);
		Application app = 
			getFacesContext().getApplication();
		if (value != null)
			if (isValueReference(value)) 
				component.setValueBinding("value", 
				app.createValueBinding(value));
			else
				component.getAttributes().put("value", value);
		if (link != null) 
			if (isValueReference(link))
				component.setValueBinding("link",
				app.createValueBinding(link));
			else
				component.getAttributes().put("link",
				new Boolean(link));
	}
	public String getLink() {
		return link;
	}
	public void setLink(String link) {
		this.link = link;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
}
</PRE>
<P>　　该标签提供setter和getter来管理链接和值属性。组件一旦创建，便会调用setProperties()方法，对标签属性进行初始化。每个标签属性都无外乎两种：要么是文字值，要么是bean属性的一个绑定。</P>
<P><STRONG>编写标签库定义（TLD</STRONG><STRONG>）。</STRONG>TLD是一个XML文件，它通过将标签名与相应的Java类相关联来描述标签。TLD还描述了标签所允许的属性（参见清单4）。这个TLD定义了一个名为css的标签，该标签绑定到CSSTag类。它还声明了链接和值标签属性。</P>
<P align=left><STRONG>清单</STRONG><STRONG>4. </STRONG>TLD是一个通过将标签名与相应的Java类相关联来描述标签的XML文件。TLD定义了名为css的标签，使其与CSSTag类绑定。它还声明了链接和值标签属性。</P><PRE class=code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE taglib PUBLIC 
	"-//Sun Microsystems, Inc.//
	DTD JSP Tag Library  1.2//EN" 
	"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"&gt;
&lt;taglib&gt;
	&lt;tlib-version&gt;1.0&lt;/tlib-version&gt;
	&lt;jsp-version&gt;1.2&lt;/jsp-version&gt;
	&lt;short-name&gt;custom&lt;/short-name&gt;
	&lt;uri&gt;http://www.ilog.com/jviews/tlds/css.tld&lt;/uri&gt;
	&lt;description&gt;This tag library contains a tag for a 
		sample custom JSF Component.&lt;/description&gt;
	&lt;tag&gt;
		&lt;name&gt;css&lt;/name&gt;
		&lt;tag-class&gt;path.to.CSSTag&lt;/tag-class&gt;
		&lt;description&gt;A component that displays the style 
			inline or a link a to a css file&lt;/description&gt;
		&lt;attribute&gt;
			&lt;name&gt;id&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;false&lt;/rtexprvalue&gt;
			&lt;type&gt;java.lang.String&lt;/type&gt;
			&lt;description&gt;The id of this component.
			&lt;/description&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;binding&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;false&lt;/rtexprvalue&gt;
			&lt;type&gt;java.lang.String&lt;/type&gt;
			&lt;description&gt;The value binding expression 
				linking this component to a property in a
				backing bean. If this attribute is set, the 
				tag does not create the component itself but
				retrieves it from the bean property. This
				attribute must be a value binding.
			&lt;/description&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;value&lt;/name&gt;
			&lt;required&gt;true&lt;/required&gt;
			&lt;rtexprvalue&gt;false&lt;/rtexprvalue&gt;
			&lt;type&gt;java.lang.String&lt;/type&gt;
			&lt;description&gt;The inline css text or the url to 
				the css file to link.&lt;/description&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;link&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;false&lt;/rtexprvalue&gt;
			&lt;type&gt;java.lang.String&lt;/type&gt;
			&lt;description&gt;Whether the value is a link or 
				the inline style.&lt;/description&gt;
		&lt;/attribute&gt;
	&lt;/tag&gt;
&lt;/taglib&gt;
</PRE>
<P><STRONG>编写JSF</STRONG><STRONG>配置文件。</STRONG>为了将某个JSF组件集成到框架中，您必须提供一个名为faces-config.xml的配置文件。该文件将组件类型和呈现程序类型（用于JSP定制标签处理程序）与对应的Java类关联起来。它还能描述与每个组件一同使用的呈现程序（参见清单5）。该文件定义了faces.CSSFamily组件家族。在本例中，该家族由faces.CSSComponent这一个组件类型（该类型与CSSComponent类绑定）组成。最后，HTML.LinkOrInlineRenderer类型的呈现程序（由CSSComponent类实现）要与faces.CSSFamily家族相关联。</P><STRONG>清单5. </STRONG>该文件将组件类型和呈现程序类型与对应的Java类联系起来，并描述与每个组件一同使用的呈现程序。它还定义了faces.CSSFamily组件家族。 <PRE class=code>&lt;!DOCTYPE faces-config PUBLIC 
	"-//Sun Microsystems, Inc.//
	DTD JavaServer Faces Config 1.0//EN" 
	"http://java.sun.com/dtd/web-facesconfig_1_0.dtd"&gt;
&lt;faces-config&gt;
	&lt;component&gt;
		&lt;component-type&gt;faces.CSSComponent
		&lt;/component-type&gt;
		&lt;component-class&gt;path.to.CSSComponent
		&lt;/component-class&gt;
		&lt;component-extension&gt;
			&lt;component-family&gt;faces.CSSFamily
			&lt;/component-family&gt;
			&lt;renderer-type&gt;HTML.LinkOrInlineRenderer
			&lt;/renderer-type&gt;
		&lt;/component-extension&gt;
	&lt;/component&gt;
	&lt;render-kit&gt;
		&lt;renderer&gt;
			&lt;component-family&gt;faces.CSSFamily
			&lt;/component-family&gt;
			&lt;renderer-type&gt; HTML.LinkOrInlineRenderer 
			&lt;/renderer-type&gt;
			&lt;renderer-class&gt;path.to.CSSRenderer
			&lt;/renderer-class&gt;
		&lt;/renderer&gt;
	/render-kit&gt;
&lt;/faces-config&gt;
</PRE>
<P><STRONG>开始制图 </STRONG></P>
<P>　　如果您希望将自己的组件集成到JSF-enabled IDE中，您还可以提供补充说明。比如说，除提供其他的设计时信息外，还可以提供一个名为sun-faces-config.xml的XML配置文件，用于描述应在IDE中公开的组件属性。 </P>
<P>　　既然已经看到如何创建一个简单的JSF组件，不妨再来看看怎样创建一个图形JSF组件。我们将遵循同样的基本步骤来设计一个高级JSF图形组件。让我们以一个图形组件（如ILOG JSF图形组件）为例，通过一组分类，该组件为数据值分布提供了可视化表示。该图形能够以条型统计图、圆形分格统计图和气泡式统计图等各种显示方法来显示数据集合。该JSF图形组件有两个初始设计限制：</P>
<P>　　我们已经拥有Java图形bean组件，它具备所有图形显示能力。该组件可以显示很多图形，而且可定制性很高。在理想情况下，我们希望利用bean组件，使用它的功能来构成我们的JSF组件的基础。 </P>
<P>　　普通JSF应用程序需要重新载入整个页面以更新视图。这种方法适合基于表单的应用程序，但在很多情况下却不适用于高度图形化的用户界面。因此，我们的JSF图形组件必须能在不更新整个页面的前提下处理某些简单的导航，以提供更好的用户体验。 </P>
<P>　　以下是满足这些需求的解决方案：该JSF图形组件将管理图形bean组件，包括创建图形bean、定制该bean以及使该bean可用于服务器端操作。呈现JSF组件将分为两个阶段完成。JSF呈现程序会产生一个&lt;img&gt;标签和一套JavaScript对象（参见图2）。客户端将请求服务器发回一张图像。这一请求由某个servlet完成，该servlet获得图形bean，并利用图形提供的方法生成一幅图像（参见图3）。任何只改变该图形外观的进一步用户交互（放大、扫视、更改样式表等）都会引起图形的一次增量更新。如果客户端不只是要求对图形图像进行更新，那么将提交该页面（参见图4）。</P>
<P><IMG height=150 src="http://dev2dev.bea.com.cn/techdoc/wlworkshop/images/images05070604_02.jpg" width=300> </P>
<P>　　图2JSF图形组件管理图形bean组件，包括创建图形bean、对其进行定制，并使其可用于服务器端动作。JSF呈现程序生成一个&lt;img&gt;标签和一套JavaScript对象。</P>
<P><IMG height=168 src="http://dev2dev.bea.com.cn/techdoc/wlworkshop/images/images05070604_03.jpg" width=336> </P>
<P>　　图3 客户机通过servlet要求服务器获得一张图像。该servlet获得图形bean，并通过由图形提供的方法生成一幅图像。 </P>
<P><IMG height=150 src="http://dev2dev.bea.com.cn/techdoc/wlworkshop/images/images05070604_04.jpg" width=300> </P>
<P>　　图4如果客户端不只是要求对图形外观的进行更新，那么页面将被提交。</P>
<P>　　JSF图形组件还配有一套附加的JSF组件。<EM>overview</EM>可显示该图形整体视图，显示一个代表图形视图的长方形，还应允许用户扫描可视区域。<EM>legend</EM>组件可显示数据集合的相关信息，还能自行在图形中显示，依被显示数据的样式而定。也能提供客户端的<EM>interactors</EM>如扫描和放大，这些功能可看成是客户端交互，表示与图形的交互不会像一次正常的JSF交互那样重新载入整个页面。</P>
<P>　　要想呈现图形组件，只需使用chartView标签： </P>
<P>&lt;jvcf:chartView id="c" style="width:500px;height:300px" … /&gt; </P>
<P>　　该数据在HTML页面中作为图像显示。该图像由servlet创建，旨在响应一次HTTP请求（该请求包括指定结果图像、生成图像映射以及生成内联式图例等各种参数）。结果图像随之被嵌入客户端DOM，页面中只有图像自身这一部分被更新。</P>
<P><STRONG>应用程序核心部件</STRONG></P>
<P>　　让我们看看简单的定制JSF组件和高级图形组件之间的一些区别。JSF图形组件类很像一个标准组件，不过是多了一个可访问图形bean（该图形bean负责生成在HTML页面中显示的图像）的图形属性。JSF组件可以通过某个绑定值或在当前会话中对这个图形bean进行局部检索。当JSF图形组件成为某个应用程序的核心部件时，可选的JSF组件（如概览或图例）便与主图形相关联，来显示附加信息（见清单6）。</P>
<P align=left><STRONG>清单</STRONG><STRONG>6. </STRONG>当JSF图形组件成为某个应用程序的核心部件时，可选的JSF组件便与主图形相关联，来显示附加信息。</P><PRE class=code>&lt;jvcf:chartZoomInteractor id="chartZoomInteractor" 
	XZoomAllowed="true" 
	YZoomAllowed="true" /&gt; 
&lt;jvcf:chartView id="chartView" 
						 chart="#{myBean.chart}" 
					 servlet="demo.ImageMapServlet" 
			interactorId="chartZoomInteractor" 
						 width="500" 
						height="300" 
			 styleSheets="/data/line.css" 
			waitingImage="data/images/wait.gif" 
			 imageFormat="PNG"  /&gt;
&lt;jvcf:chartOverview id="chartOverview" 
					style="height:100;width:150px" 
						viewId="chartView" 
						lineWidth="3" 
						lineColor="red" /&gt;

&lt;jvcf:chartLegend id="legendView" 
							viewId="chartView" 
							 width="400" 
							height="180" 
							layout="vertical" 
				waitingImage="data/images/wait.gif" /&gt;

</PRE>
<P>　　呈现程序是实现这个JSF的一大难点。如前所述，呈现程序并不生成简单的HTML，而是生成由HTML（&lt;IMG&gt; tag）和JavaScript proxy（代理程序）组成的动态HTML（DHTML）。</P>
<P>　　Proxy是一个负责管理客户机组件图像显示的JavaScript类实例。该对象是服务器端Java组件类在客户端显示；它与组件类具有相同属性。页面上的每个组件、图形及其配件都有一个proxy实例。呈现JavaScript时，在每个可视的JavaScript变量上使用facesContext.getExternalContext().encodeNamespace(name)方法是个很好的实践。这样做在今后方便地将组件集成到到JSR 168-compliant端口环境中。</P>
<P>　　为举例说明客户机上的proxy，必须在页面上导入JavaScript支持库。为保持客户端尽量瘦，需要基于JavaScript库支持的proxy类，对JavaScript库进行模块化。因此，需要给每个proxy类输入一套不同的、有可能重叠的库。图形呈现的困难部分，出现在发送这些script库的阶段。每个组件的呈现程序都要声明自己需要哪个库，以及什么时候发送引用的库，必须认清已发送的库，以避免重复。仅在页面呈现期间的存在script管理器负责这项筛选工作。每当呈现程序想要发送整套库输入时，它都会向筛选出已发送库的script管理器提供列表。</P>
<P>　　客户端proxy的目的在于允许编写脚本，并避免不必要的页面更新。一旦呈现了图形，在客户端便可使用proxy，以便动态安装interactor，并显示或隐藏图像映射。Proxy对象也可供支持JavaScript鼠标事件处理的常规JSF组件使用。 </P><PRE class=code>&lt;jvcf:chartView id=
	"chartView" .. /&gt;
&lt;h:selectBooleanCheckbox id=
	"genImageMap" onclick=
	"chartView.setGenerateImageMap(
	this.checked ? true : false, 
 true);" /&gt;
</PRE>
<P>　　对组件客户端proxy进行局部修改的问题在于，其状态不再与服务器上的Java组件的状态同步。为解决这个问题，proxy使用一个隐藏的输入标签（&lt;INPUT TYPE="HIDDEN"&gt;）来保存客户机上的新状态。当执行某个标准JSF动作并提交页面时，呈现程序将解析该隐藏状态，使客户机与服务器同步。这种行为需要呈现程序类中有专门的破解行为。标准破解方法得以改进，以便解析来自客户机的状态，并更新服务器端组件的状态。</P>
<P><STRONG>测试实例</STRONG></P>
<P>　　图形及其相关组件之间的关联由标记引用与绑定来完成。为使页面设计具有灵活性，一个组件可以在呈现之前被引用。因此，在呈现时间内，如果某个组件属性引用另一个尚未呈现的组件，那么，将延迟发送依赖于客户机进行解决的JavaScript代码，直到呈现已引用的组件。此工作可由依赖性管理器完成。</P>
<P>为证实这一点，不妨看一个典型实例，该实例涉及某个概览，该概览引用一张图形。</P><PRE class=code>&lt;jvcf:overview viewId=
	"chart" [...] /&gt; 
&lt;jvcf:chartView id=
	"chart" [....] /&gt;</PRE>
<P>　　存在两种情况。被引用图形组件已经呈现，因此不存在任何问题</P><PRE class=code>JSP:
&lt;jvcf:chartView id=
	"chart" [....] /&gt;
&lt;jvcf:overview viewId=
	"chart" id="overview" [...] /&gt; 

render:
[...]
var chart = 
	new IlvChartViewProxy ( .. );
[...]

var overview= 
	new IlvFacesOverviewProxy (
	 .. );
overview.setView(chart);
[...]
</PRE>
<P>　　已引用图形的组件在依赖的概览组件之前不会呈现。既然如此，可在依赖性管理器上注册一个组件创建监视器。已引用图形组件最终呈现时，其呈现程序会通知自己创建的依赖性管理器。此时，将发送解决依赖性所需的代码：</P><PRE class=code>JSP:
&lt;jvf:overview viewId=
	"chart" id="overview" [...] /&gt; 
&lt;jvdf:chartView id=
	"chart" [....] /&gt;

render:
[...]
var overview = 
	new IlvFacesOverviewProxy (
	 .. );
[...]

var chart = 
	new IlvChartViewProxy ( .. );
overview.setView(chart);
[...]
</PRE>
<P>　　开发JSF组件的目的之一，是能够将它们应用于任何与JSF兼容的IDE。尽管如此，JSF兼容性并不足以保证这种设计时集成将会有效。下面是在开发JSF组件过程中，为了便于在今后与IDE集成需要注意的一些简单思想：</P>
<P>　　首先，定制JSF组件应该提供一个基本HTML呈现程序。在设计时，JSF IDE不能呈现请求有效数据或app服务器连接的动态图形组件。因此，带有复杂的或非传统的（比如不是HTML）呈现程序的组件，应该使用Beans.isDesignTime()来确定是提供一个基本HTML表示法，还是提供真正的组件呈现程序。</P>
<P>　　另一个设计时问题是组件的位置和大小。不同IDE使用不同的标志和属性。能够调整大小的组件（如一幅图像）应能处理定义大小的不同方式。</P>
<P>　　最后，为了与IDE集成，组件必须提供尚未被JSF说明定义的补充信息。遗憾的是，当前每个IDE都需要特殊处理程序来集成组件，即：在一种情况就需要XML文件，而在另一种情况下需要eclipse插件，如此等等。下一个JSF JSR（2.0版）的主要目的之一，将是指定附加的元数据格式。</P>
<P>　　如您所见，编写一个简单的JSF组件并不难，因为框架已经完成了大部分工作。JSF框架管理着组件状态、呈现程序等等。在本文中，我们已经扩展了这些基本概念，来设计一个能够显示复杂元数据、提供增量更新、支持大量客户端交互并与配套组件协作的高级图形JSF组件。支持这些特点需要对基本JSF组件的结构进行许多改进。当然，增量更新的概念今后对JSF框架将是一个很好的完善，因为它只允许呈现页面已改变的部分，避免了更新整个页面。按照JSF说明书工作往往不足以确保组件完全集成到JSF IDE中；一个新JSR应能及时解决这些难题。尽管存在缺陷，JSF框架仍能极大地加快Web组件开发速度、方便的融合来自各种资源的组件，以创建完整的、复杂的Web应用程序。</P>
<P><STRONG>参考资料</STRONG></P>
<UL>
<LI>developer.sun.com<BR>Java 工具<BR><A href="http://developers.sun.com/prodtech/javatools/jscreator/index.jsp" target=_blank><FONT color=#002c99>Sun Java Studio Creator</FONT></A><BR><A href="http://java.sun.com/developer/technicalArticles/GUI/JavaServerFaces" target=_blank><FONT color=#002c99>Developing Web Applications with JavaServer Faces</FONT></A> 
<LI>IBM <BR>Rational 软件<BR><A href="http://www-306.ibm.com/software/awdtools/developer/application/index.html" target=_blank><FONT color=#002c99>Rational Application Developer for WebSphere Software</FONT></A> 
<LI>Java Community Process <BR>Java Specification Requests <A href="http://jcp.org/en/jsr/detail?id=127" target=_blank><FONT color=#002c99>JSR 127: JavaServer Faces</FONT></A><BR><A href="http://jcp.org/en/jsr/detail?id=168" target=_blank><FONT color=#002c99>JSR 168: Portlet Specification</FONT></A> </LI></UL>
<P><STRONG>作者简介</STRONG></P>
<P>　　Marc Durocher是ILOG的一名软件架构师，ILOG是企业级软件组件和服务的主要提供商。Marc Durocher在ILOG负责开发ILOG JViews生产线上的JSF组件。可以通过<A href="mailto:mdurocher@ilog.fr"><FONT color=#002c99>mdurocher@ilog.fr</FONT></A>联系Marc。</P>
<P><STRONG>原文出处</STRONG></P>
<P><A href="http://www.ftponline.com/weblogicpro/2005_03/magazine/features/mdurocher/" target=_blank><FONT color=#002c99>http://www.ftponline.com/weblogicpro/2005_03/magazine/features/mdurocher/</FONT></A></P><img src ="http://www.blogjava.net/mstar/aggbug/9360.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2005-08-05 08:18 <a href="http://www.blogjava.net/mstar/archive/2005/08/05/9360.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZZ]Using JavaServer Faces Technology with AJAX</title><link>http://www.blogjava.net/mstar/archive/2005/07/14/7673.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Thu, 14 Jul 2005 00:57:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2005/07/14/7673.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/7673.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2005/07/14/7673.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/7673.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/7673.html</trackback:ping><description><![CDATA[Using JavaServer Faces Technology with AJAX<BR><A href="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/">https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/</A><BR>
<H2>Problem Description</H2>
<P>The Java 2 Enterprise Edition includes JavaServer Faces technology, which provides a mature and extensible user interface component model. The design of this model makes it easy for application developers to create custom components by extending the standard components included with JavaServer Faces technology and to reuse these components across applications. <BR></P>
<P>The example featured in this entry includes a JavaServer Faces text field component that takes the name of a city.&nbsp; When the user begins entering characters in the field, the application uses AJAX to perform <A href="https://bpcatalog.dev.java.net/nonav/ajax/autocomplete/index.html">auto completion</A> on the data by matching the user's input to a list of cities stored on the server.&nbsp; In two of the versions of this example, the text field component is a custom JavaServer Faces component that provides the AJAX support.&nbsp; This component shields the page author from the complexities of AJAX by rendering all the HTML and JavaScript code that is required to incorporate AJAX capabilities into an application. </P>
<P>A third version of this example adds AJAX support to a standard JavaServer Faces component through a servlet that interacts with the JavaServer Faces component and other JavaServer Faces server-side objects to generate the appropriate auto completion data.</P>
<P>This entry focuses primarily on the question, "How can I incorporate AJAX functionality into a JavaServer Faces application?"<BR></P>
<P>Among the other questions that this entry considers are the following:</P>
<UL>
<LI>Should AJAX request handling be done in a separate servlet controller or should it be handled by the JavaServer Faces technology life cycle? 
<LI>How can existing components be AJAX-enabled without rewriting them? 
<LI>Should JavaScript code be embedded in Java code or externalized in a separate script file? 
<LI>How does the programming model differ between component writer and page developer? 
<LI>How should I organize the project structure in my workspace? <BR>
<LI>How should I package the JavaServer Faces objects and JavaScript artifacts into a WAR file or EAR file? <BR></LI></UL>
<H2>Solution</H2>
<P>Developers who want to include AJAX support in JavaServer Faces applications have more than one strategy to choose from.&nbsp; Which strategy they choose depends on the needs of their situation.&nbsp; Developers might ask themselves the following questions to help them decide which strategy to select:<BR></P>
<UL>
<LI>Is this a new application or is the development team adding AJAX support to an existing JavaServer Faces application? 
<LI>Is the page author capable of adding the JavaScript and AJAX code to the page, or should it be handled by a server-side component so that the page author can simply add the component tag to the page? 
<LI>Must the AJAX code be reusable? 
<LI>Must the AJAX code be customizable? 
<LI>Must the AJAX code be usable outside of the JavaServer Faces technology runtime?<BR>
<LI>Is the application developer capable of doing the extra programming required to synchronize data with the JavaServer Faces objects if the development team decides to de-couple the AJAX code from the JavaServer Faces runtime? </LI></UL>
<P>This entry discusses three strategies for incorporating AJAX support into a JavaServer Faces application.&nbsp; The first two strategies involve creating a custom component to generate the necessary JavaScript and to make AJAX interactions with another server-side component.&nbsp; In <A href="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/#Strategy_1:_A_Custom_JSF_Component_JavaS">Strategy 1</A>, the JavaServer Faces technology life cycle and the custom component handle the AJAX requests.&nbsp; In <A href="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/#Strategy_2:_JSF_Component_with">Strategy 2</A>, the custom component communicates with a special servlet, which handles all the AJAX requests.&nbsp; <A href="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/#Strategy_3:_Retrofitting_an_Existing_JSF">Strategy 3</A> does not require any custom components; all the additional AJAX support is performed by a servlet provided by the developer.</P>
<P>Strategy 1 and Strategy 2 require knowledge of the JavaServer Faces technolgy life cycle to implement them. Strategy 3 requires knowledge of the Java servlet API. <BR></P>
<P>The following sections explain the three strategies and provide more detail on their advantages and disadvantages.&nbsp;&nbsp; After reading about these strategies and answering the list of questions above, developers should be able to select the strategy that is appropriate for their particular situation.&nbsp; The <A href="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/#Comparison_of_Strategies">Comparison of Strategies</A> section includes a chart that summarizes the characteristics of each strategy, which makes it even easier to make the decision.<BR></P>
<H3><A name=Strategy_1:_A_Custom_JSF_Component_JavaS></A>Strategy 1: A Custom JavaServer Faces Component Renders Client-side AJAX JavaScript and Processes AJAX Requests</H3>
<UL>
<P>In this strategy the JavaServer Faces component does three things:<BR></P>
<UL>
<LI>Renders the HTML for the form elements 
<LI>Renders the links to the JavaScript code that handles the form events 
<LI>Processes AJAX requests </LI></UL></UL>
<DIV style="MARGIN-LEFT: 40px">Figure 1 illustrates how this strategy works.&nbsp; The numbered steps following the figure explain what is happening in the figure.<BR></DIV>
<UL><IMG src="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/images/ajax-jsf-controller.jpg"> 
<P><FONT size=-1><B>Figure 1: Architecture of a JavaServer Faces Component that Renders Client-Side AJAX JavaScript and Processes AJAX Requests</B></FONT></P>
<P>The following steps explain the architecture illustrated in Figure 1:<BR></P>
<OL>
<LI>The page called Enter Address Page contains an HTML <CODE>script</CODE> element rendered by the renderer,&nbsp; <CODE>AutoCompleteTextRenderer</CODE>. 
<LI>A call is made to the URL, <CODE>faces/autocomplete-script</CODE>, which is mapped to a <CODE>FacesServlet </CODE>instance.&nbsp; This instance processes the <CODE>RenderPhaseListener</CODE> instance, which recognizes the URI and returns the <CODE>component.js</CODE> page containing the client-side JavaScript code necessary for the AJAX interactions. After the <CODE>component.js</CODE> page is returned, the <CODE>RenderPhaseListener</CODE> instance stops taking part in the JavaServer Faces technology life cycle processing for now. 
<LI>When the user starts typing in the City text field, an <CODE>onkeypress</CODE> event occurs. The JavaScript function mapped to this event creates an <CODE>XMLHttpRequest</CODE> object and configures it with the URL to the <CODE>FacesServlet</CODE> instance. This URL is <CODE>faces/autocomplete&amp;id=San</CODE>. The <CODE>id=San</CODE> part of the URL is a URL parameter in which <CODE>San</CODE> is the user input that is matched against the list of cities. The <CODE>XMLHttpRequest</CODE> object makes a call to the <CODE>FacesServlet</CODE> instance. HTML page events continue to be processed by the JSP page. <BR>
<LI>The <CODE>FacesServlet</CODE> instance processes the <CODE>RenderPhaseListener</CODE> instance that recognizes the URL <CODE>faces/autocomplete</CODE> and looks up the <CODE>AutoCompleteTextField</CODE> component, which provides the completion logic. 
<LI>The <CODE>RenderPhaseListener</CODE> instance generates an XML document containing the potential completion items and returns it to the <CODE>XMLHttpRequest</CODE> object, which then calls the <CODE>XMLHttpRequest</CODE> callback function. 
<LI>The <CODE>XMLHttpRequest</CODE> callback function updates the HTML DOM based on the contents of the XML document that was returned. 
<LI>After entering the form data, the user clicks the Update button and the form is posted using an HTTP POST to the <CODE>FacesServlet</CODE> instance, which updates <CODE>SessionBean</CODE> with the address information entered by the user.<BR></LI></OL>
<P>The remainder of this section provides further details on how this strategy works.</P>
<P>In Figure 1, the page called Enter Address Page is a JavaServer Faces page. This page contains a tag that represents the <CODE>AutocompleteTextField</CODE> component, which is a JavaServer Faces component.&nbsp; This component renders two things: an HTML text field, into which the user enters the name of a city, and the necessary client-side JavaScript AJAX code that fetches possible city names from a server-side managed bean.&nbsp; This managed bean contains a method that implements the algorithm for completing city names. </P>
<P>To add the AJAX-enabled component to the application, the page author need only include the following tag in the page:</P><PRE> &lt;ajaxTags:completionField size="40" id="cityField" <BR> completionMethod="#{AutoCompleteTextfield.completeCity}" <BR> value="#{SessionBean.city}" required="true"<BR> /&gt;<BR></PRE>
<P><FONT size=-1><B>Code Example 1: Declaring an AJAX-enabled JavaServer Faces Component in a JavaServer Faces&nbsp; page</B></FONT></P>The <CODE>AutoCompleteTextFieldTag</CODE> tag handler implements the <CODE>ajaxTags:completionField</CODE> tag, which is rendered to HTML by the renderer, <CODE>AutoCompleteTextFieldRenderer</CODE>. The first time the component is encountered in the page, <CODE>AutoCompleteTextFieldRenderer</CODE> renders a reference to external JavaScript code, as shown in this HTML fragment: 
<P></P><PRE> &lt;script type="text/javascript" src="faces/autocomplete-script"&gt;<BR></PRE>
<P><FONT size=-1><B>Code Example 2: Rendered HTML that references JavaScript to be returned by RenderPhaseListener</B></FONT></P>
<P>When the reference to the external script file is reached, the browser makes a request to the URL, <CODE>faces/autocomplete-script</CODE>. The request first goes to the <CODE>FacesServlet</CODE> instance and is then received by the <CODE>RenderPhaseListener</CODE> instance, which returns the client-side JavaScript relevant to the AJAX interactions of the component. In the case of this example, the <CODE>component.js</CODE> file is included with the component and returned using the class loader. Bundling the relevant JavaScript code with the component is a good practice because it keeps the script and component close to each other but keeps the JavaScript out of the component code. The AJAX client-side JavaScript contains the <CODE></CODE><CODE>XMLHttpRequest</CODE> callback method, which includes the event mappings to the form elements rendered by <CODE>AutoCompleteTextFieldRenderer</CODE>. </P>
<P>When the target <CODE>onkeypress</CODE> event is encountered in the City form field, the client-side <CODE>XMLHttpRequest</CODE> object makes a HTTP GET call with the partial text input from the field to the <CODE>FacesServlet</CODE> instance, which in turn calls the <CODE>RenderPhaseListener</CODE> instance.&nbsp; The <CODE>RenderPhaseListener</CODE> instance looks up the <CODE>AutoCompleteTextField</CODE> component and gets a set of city names that match partial text input. For example, if the user entered "San" into the field, the component would fetch the set of city names that start with the string "San". <BR></P>
<P>At this point, the <CODE>RenderPhaseListener</CODE> instance can access the view state associated with the page if it is needed to process the interaction.&nbsp; When processing AJAX requests with JavaServer Faces components, a developer can treat each AJAX request as a new request by using simple HTTP GET calls.&nbsp; In this case, every request is a new Faces request.&nbsp; Or the developer can use POST calls, which give access to the view state associated with the JavaServer Faces page. <A href="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/#Strategy1A">Strategy 1A</A> provides further details on using POST calls to access view state.&nbsp; When using AJAX GET requests with JavaServer Faces technology, a developer has access to managed bean components and has the ability to evaluate expressions but does not have access to the view state. </P>
<P>In the case of this example, each auto complete AJAX request is a GET request and is therefore a new Faces request. The <CODE>RenderPhaseListener</CODE> instance renders an XML response based on the results obtained from the <CODE>AutoCompleteTextField</CODE> component.</P>
<P>The server-side AJAX request processing is provided by a <CODE>RenderPhaseListener</CODE> instance.&nbsp; From the perspective of a server-side developer, the requests are a little different from other AJAX requests in that they usually do not go through all the phases of the JavaServer Faces technology life cycle. The following code shows how the <CODE>RenderPhaseListener</CODE> instance handles an AJAX request:</P><PRE>    private void handleAjaxRequest(PhaseEvent event) {<BR>       FacesContext context = event.getFacesContext();<BR>       HttpServletResponse response =<BR>            (HttpServletResponse)context.getExternalContext().getResponse();<BR>        ..<BR>        if ("complete".equals(action)) {<BR>            String method = request.getParameter("method");<BR>            try {<BR>                //get completion items<BR>                response.setContentType("text/xml");<BR>                response.setHeader("Cache-Control", "no-cache");<BR>                //Code to write XML response goes here...<BR><BR>                event.getFacesContext().responseComplete();<BR>                return;<BR>            } catch (EvaluationException ee) {<BR>                ee.printStackTrace();<BR>            } catch (IOException ioe) {<BR>                ioe.printStackTrace();<BR>            }<BR>        }<BR>    }<BR>  </PRE>
<P><FONT size=-1><B>Code Example 3: PhaseListener code to handle AJAX requests</B></FONT></P>
<P>One thing the developer needs to remember is that the content type must be set to <CODE>"text/xml"</CODE> and the Cache-Control header also needs to be set to "<CODE>no-cache</CODE>" as shown in the following code snippet, which is taken from Code Example 3.</P><PRE> response.setContentType("text/xml");<BR> response.setHeader("Cache-Control", "no-cache");<BR></PRE>
<P>The call to <CODE>event.getFacesContext().responseComplete()</CODE> following the creation of the XML response causes the rest of the JavaServer Faces life cycle to be skipped. </P>
<P>The response is returned to the <CODE>XMLHttpRequest</CODE> callback method, which updates the HTML DOM with the list of potential city names. </P>
<P>The end user might then select a relevant city name from the list returned from the <CODE>AutoCompleteTextField</CODE> component and click on the Update button, which causes the form to be submitted to the <CODE>FacesServlet</CODE> instance, after which the <CODE>SessionBean</CODE> object is updated. </P>
<P>This strategy makes it easy for page authors to add AJAX-enabled components to a JavaServer Faces page.&nbsp; As long as the component is added to the application, all they need to do is include the corresponding component tag in the page. <BR></P>
<P>The component developer can make the component more customizable by allowing external JavaScript files to override the embedded file as well as allowing the use of external style sheets.&nbsp; One way to do this is to include JavaScript and CSS properties on the component that the user can override. For example, the <CODE>AutocompletionTextField</CODE> component can have an <CODE>ondisplay</CODE> property that lets users of the component specify JavaScript code that is executed when an item is selected from the popup. Similarly, a <CODE>selectedItemStyle</CODE> property could let the user specify a CSS or a CSS style class to be applied to selected items in the popup. </P>
<P></P>
<P></P>
<UL><A name=Strategy1A></A>
<H4><A name=Strategy1A>Strategy 1A: Doing AJAX processing against the full View</A></H4><A name=Strategy1A></A>
<P><A name=Strategy1A>This approach is used by the </A><A href="https://bpcatalog.dev.java.net/nonav/ajax/progress-bar-jsf/index.html">AJAX Progress Bar for JavaServer Faces Technology</A>. As with Strategy 1, <CODE>FacesServlet</CODE> is used to orchestrate all the processing of AJAX requests and all the serving of script files. The main difference between Strategy 1 and Strategy 1A is the use of POST to submit the actual view state back to the server. Doing this requires the AJAX-enabled components to abort normal page processing to prevent rendering of the entire JSP page for AJAX requests. This is done the same way as in Strategy 1, using the <CODE>responseComplete</CODE> method on the <CODE>FacesContext</CODE> instance. Another difference in the architecture of the progress bar example is that the <CODE>PhaseListener</CODE> instance is responsible only for rendering the script, whereas <CODE>ProgressBarRenderer</CODE> writes out the response XML that is handled by the AJAX JavaScript code.</P>
<P>Another complexity resulting from the polling nature of the progress bar is the need for a closure to the function passed to the <CODE>setTimeout</CODE> JavaScript method. The progress bar uses the technique described by Richard Cornford at <A href="http://jibbering.com/faq/faq_notes/closures.html">http://jibbering.com/faq/faq_notes/closures.html</A>. This is a very handy technique when coding AJAX-enabled components.</P></UL>
<P>Performance should be considered when determining how much view state is associated with each request relative to the volume of AJAX requests being processed when using this approach. While this approach is more tightly coupled with the JavaServer Faces life cycle and therefore provides ready access to Faces objects, this tight coupling could result in a performance degradation compared to the strategy of using a separate AJAX controller, which would not have a tight coupling to the view state. <BR></P></UL>
<H3><A name=Strategy_2:_JSF_Component_with></A>Strategy 2: A Custom JavaServer Faces Component with Separate AJAX Controller</H3>
<UL>
<P>In this strategy the JavaScript rendered by the JavaServer Faces component communicates with a separate servlet. All asynchronous requests will therefore be handled outside of the JavaServer Faces technology life cycle processing. However, the separate servlet can look up the <CODE>FacesContext</CODE> instance and evaluate value binding and method binding expressions so that it can do such things as find managed beans and make calls to them.<BR></P>
<P>Figure 2 illustrates this strategy.&nbsp; The numbered steps following the figure explain what is happening in the figure. </P><IMG src="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/images/ajaxcontroller-jsf.jpg"> 
<P><FONT size=-1><B>Figure 2: Architecture of a JavaServer Faces Component with separate AJAX Controller</B></FONT></P>
<P>The following list describes the interactions shown in Figure 2:<BR></P>
<OL>
<LI>The page, called Enter Address Page, contains an HTML script element that is rendered by the renderer,&nbsp; <CODE>AutoCompleteTextRenderer</CODE>. 
<LI>A call is made to the URL, <CODE>faces/autocomplete-script</CODE>, which is mapped to the <CODE>FacesServlet</CODE> instance. This instance processes the <CODE>RenderPhaseListener</CODE> instance, which recognizes the URL and returns the <CODE>component.js</CODE> page containing the client-side JavaScript code necessary for the AJAX interactions. After the <CODE>component.js</CODE> page is returned, the <CODE>RenderPhaseListener</CODE> instance stops contributing to the JavaServer Faces technology life cycle processing for now. 
<LI>When the user enters text into the City text field, an <CODE>onkeypress</CODE> event is generated. The JavaScript function mapped to this event creates an <CODE>XMLHttpRequest</CODE> object and configures it with the URL to the <CODE>AjaxControllerServlet</CODE> instance. This URL is <CODE>autocomplete&amp;id=San</CODE>. The <CODE>id=San</CODE> part of the URL is a URL parameter in which <CODE>San</CODE> is the user input that is matched against the list of cities.<BR>
<LI>The <CODE>XMLHttpRequest</CODE> object makes the call to the <CODE>AjaxControllerServlet</CODE> instance, and HTML page events continue to be processed by the page.&nbsp; The <CODE>AjaxControllerServlet</CODE> instance looks up the <CODE>AutoCompleteTextField</CODE> component and gets a list of potential completion items. 
<LI>The <CODE>AjaxControllerServlet</CODE> instance generates an XML document containing the potential completion items and returns it to the <CODE>XMLHttpRequest</CODE> object. The <CODE>XMLHttpRequest</CODE> object then calls the <CODE>XMLHttpRequest</CODE> callback function. 
<LI>The <CODE>XMLHttpRequest</CODE> callback function updates the HTML DOM with the list of city names, which are contained in the returned XML document.&nbsp; At this point, users can select a city name, and when they do, the form element's value is set with the selected value.<BR>
<LI>After entering the form data, the user clicks the Update button and the form is POSTed to the <CODE>FacesServlet</CODE> instance, which updates the <CODE>SessionBean</CODE> object with the address information entered by the user. </LI></OL></UL>
<UL>
<P>This strategy provides a clean separation of the AJAX interaction logic and the traffic that is usually handled by the <CODE>FacesServlet</CODE> instance. Each AJAX request is a new request that the JavaServer Faces technology life cycle does not see, meaning that <CODE>AjaxControllerServlet</CODE> does not have access to the JavaServer Faces page view state. The AJAX servlet can communicate with the managed beans and evaluate expressions by looking up the <CODE>FacesContext</CODE> instance and calling the corresponding code. </P>
<P>The strategy is similar to Strategy 1 in that all "plumbing" is generated by the JavaServer Faces component itself. In this strategy, the JavaServer Faces component is depending on a separate dedicated servlet to handle the JavaScript events it is adding to the rendered HTML. Updates to the JavaServer Faces model data occur outside the scope of the JavaServer Faces technology life cycle request/response processing, and so care should be taken that model data is consistent. </P></UL>
<H3><A name=Strategy_3:_Retrofitting_an_Existing_JSF></A>Strategy 3: Retrofitting an Existing JavaServer Faces Application</H3>
<UL>
<P>In this strategy, no custom JavaServer Faces components are used. As in Strategy 2, a separate dedicated AJAX servlet is used, and custom JavaScript code is added to the JSP page for the purpose of communicating with the servlet. Developers are responsible for all the "plumbing".&nbsp; This means that they must provide the code that handles JavaScript events associated with the JavaServer Faces components, makes asynchronous calls, and updates the HTML document when responses arrive.<BR></P>
<P>Figure 3 illustrates this strategy.&nbsp; The numbered steps following the figure explain what is happening in the figure. </P><IMG src="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/images/ajaxcontroller-jsf-customized.jpg"> 
<P><FONT size=-1><B>Figure 3: Retrofitting an Existing JavaServer Faces Application</B></FONT></P>
<P>The following steps explain the architecture of the JavaServer Faces application shown in Figure 3:</P>
<OL>
<LI>The page, called Enter Address Page, contains the client-side JavaScript code necessary for the AJAX interactions. 
<LI>When the user types in the City text field, an <CODE>onkeypress</CODE> event is generated. The JavaScript function mapped to this event creates an <CODE>XMLHttpRequest</CODE> object and configures it as a URL to the <CODE>AjaxControllerServlet</CODE> instance. This URL is <CODE>autocomplete&amp;id=San</CODE>. The <CODE>id=San</CODE> part of the URL is a URL parameter in which <CODE>San</CODE> is the user input that is matched against the list of cities. After the <CODE>XMLHttpRequest</CODE> object makes the call to <CODE>AjaxControllerServlet</CODE>, the page continues to process HTML page events. 
<LI><CODE>AjaxControllerServlet</CODE> looks up the <CODE>CitiesBean</CODE> managed bean and gets a list of potential completion items. 
<LI>The <CODE>AjaxControllerServlet</CODE> instance generates an XML document containing the potential completion items and returns it to the <CODE>XMLHttpRequest</CODE> object. The <CODE>XMLHttpRequest</CODE> object calls the <CODE>XMLHttpRequest</CODE> callback function. 
<LI>The <CODE>XMLHttpRequest</CODE> callback function updates the HTML DOM based on the contents of the XML document that was returned. 
<LI>After entering the form data, the user clicks the Update button and the form is POSTed to the <CODE>FacesServlet</CODE> instance, which updates the <CODE>SessionBean</CODE> object with the respective address information. </LI></OL>
<P>Figure 3 is very similar to Figure 2, which illustrates Strategy 2, with one exception: In Strategy 2, the servlet is provided with the JavaServer Faces component and handles "generic" traffic. In Strategy 3, the JavaScript and the servlet are provided by the application developer.&nbsp; Notice that the servlet talks about the application-specific list of cities, whereas in Strategy 2 the servlet handles generic items.&nbsp; This is because strategy 2 is designed to be reusable in that the solution can be utilitzed to handle various auto completion use cases, such as completing city names, state names, or people names, whereas Strategy 3 is bound to the specific use case of completing city names. <BR></P>
<P>This strategy has the advantage of not relying on any special AJAX-enabled JavaServer Faces components, and therefore,&nbsp; any existing JavaServer Faces application can be retrofitted with custom JavaScript and a special servlet to handle AJAX behavior. However, like Strategy 2, the use of a separate servlet makes calling JavaServer Faces methods more difficult.&nbsp; Furthermore, it is impossible to get access to the view state of the JavaServer Faces page. </P>
<P>This strategy allows for more customization of the JavaScript code that provides the AJAX interaction, but it is also more difficult to maintain and requires that the page author be familiar with AJAX interactions and JavaScript. The page author is responsible for matching the events generated by the HTML elements to the JavaScript functions. Doing this might be difficult for the average page author because the HTML elements are generated by a JavaServer Faces component renderer, and therefore the page author must be somewhat familiar with the server-side renderer code. &nbsp;In addition, the page author is also responsible for making sure that the AJAX updates to the HTML DOM match the HTML elements rendered by a JavaServer Faces component. <BR></P>
<P>The application developer is responsible for the server-side processing of AJAX using a web component, such as a servlet. Updates to the JavaServer Faces model data occur outside the scope of the JavaServer Faces technology life cycle request/response processing, so care should be taken to ensure that model data updated by a server-side component is consistent with that managed by the JavaServer Faces technology runtime. </P></UL>
<H3><A name=Comparison_of_Strategies></A>Comparison of Strategies</H3>
<P>Below is a table that contains a list of trade-offs for each strategy. </P>
<TABLE border=1>
<TBODY>
<TR>
<TD><BR></TD>
<TD><B>Strategy 1: Custom JavaServer Faces Component that Renders Client-side AJAX Script and Processes AJAX Requests</B></TD>
<TD><B>Strategy 2: Custom JavaServer Faces Component for separate AJAX Controller</B></TD>
<TD><B>Strategy 3: No Custom JavaServer Faces Component: Developer-Managed JavaScript and AJAX Servlet </B></TD></TR>
<TR>
<TD><B>Where do I put the control logic?</B></TD>
<TD>In a <CODE>PhaseListener</CODE> instance.</TD>
<TD>In a servlet or servlet filter.</TD>
<TD>In a servlet or servlet filter.</TD></TR>
<TR>
<TD><B>Does the page developer need to provide client-side AJAX JavaScript and map to form elements?</B></TD>
<TD colSpan=2>No. The JavaServer Faces component renderer will render the necessary JavaScript.</TD>
<TD>Yes. Additionally, care must be taken to ensure the form elements mapped to by the script match those rendered by the target JavaServer Faces component.</TD></TR>
<TR>
<TD><B>Is the solution re-usable?</B></TD>
<TD colSpan=2>Yes. However, the JavaScript included with the JavaServer Faces component must be written such that it can process requests from multiple components. There is a limited number of <CODE>XMLHttpRequest</CODE> objects that can be used in a page, so care should be taken with the JavaScript in this case also.</TD>
<TD>No. Each JavaServer Faces page would require its own JavaScript. The JavaScript can be shared in a separate file, but portions such as the <CODE>XMLHttpRequest</CODE> callback function are generally bound to a specific use case.</TD></TR>
<TR>
<TD><B>Is the solution customizable?</B></TD>
<TD colSpan=2>Yes, provided the component provides customization hooks</TD>
<TD>Yes, but that is the problem. Each JavaServer Faces page contains a customized solution.</TD></TR>
<TR>
<TD><B>Does the component have access to the view state of a JavaServer Faces page?</B></TD>
<TD>Yes, but there are subtle differences in how the view state can be made accessible depending on the version of the JavaServer Faces technology runtime you are using.</TD>
<TD>No</TD>
<TD>No</TD></TR>
<TR>
<TD><B>Can the AJAX control logic for a JavaServer Faces component be overridden?</B></TD>
<TD>Yes. The control logic is in a <CODE>PhaseListener</CODE> instance, which would need to be replaced. This would require repacking the component. </TD>
<TD colSpan=2>Yes. The controller is a servlet that can be modified or replaced.</TD></TR>
<TR>
<TD><B>Can the AJAX control logic access managed beans and evaluate expressions?</B></TD>
<TD>Yes. Each request is a JavaServer Faces request that has ready access to managed beans and expressions.</TD>
<TD colSpan=2>Yes. The AJAX control logic code can access managed beans and evaluate expressions by looking up the <CODE>FacesContext</CODE> instance. This requires a few lines of code. </TD></TR>
<TR>
<TD><B>Can I leverage existing JavaScript libraries?</B></TD>
<TD colSpan=2>Yes. Either the JavaScript must be embedded with the JavaServer Faces component or the component must be capable of using external JavaScript.</TD>
<TD>Yes.</TD></TR>
<TR>
<TD><B>Can I leverage the AJAX control logic outside a JavaServer Faces technology runtime?</B></TD>
<TD>No.</TD>
<TD>No.</TD>
<TD>Yes. Servlets and servlet filters do not require a JavaServer Faces technology runtime; although, if portions of the AJAX control logic are bound to managed beans or are evaluating expressions in the JavaServer Faces technology runtime, this would not be possible. </TD></TR></TBODY></TABLE>
<H3>Rendering JavaScript Exactly Once</H3>
<P>The JavaScript should be placed in a separate file as mentioned above, to ensure that the JavaScript contents can be cached by the browser. </P>
<P>While the JavaServer Faces component can be used multiple times in a page, the JavaScript inclusion reference should be emitted exactly once -- before the first usage. A good way to do this is to modify the renderer that emits the <CODE>script</CODE> tag so that it stores a flag for itself in the request map.&nbsp; This flag records whether the renderer has written the script out for the current page yet. The following code snippet demonstrates how to add code to the renderer that will store the flag and check its value to determine if the <CODE>script</CODE> tag has been rendered: </P><PRE>    ...<BR>    private void renderScriptOnce(ResponseWriter writer, UIComponent component, FacesContext context)<BR>        throws IOException {<BR>        // Store attribute in request map when we've rendered the script such<BR>        // that we only do this once per page<BR>        Map requestMap = context.getExternalContext().getRequestMap();<BR>        Boolean scriptRendered = (Boolean)requestMap.get(RENDERED_SCRIPT_KEY);<BR>                                                                               <BR>        if (scriptRendered == Boolean.TRUE) {<BR>            return;<BR>        }<BR><BR>        // Render script and CSS here<BR>        ...<BR>     }<BR><BR>     private static final String RENDERED_SCRIPT_KEY = "bpcatalog-ajax-script-rendered";<BR></PRE>
<P></P>
<H3>Project Structure and Packaging</H3>
<P>One issue that developers must deal with is how to organize their workspace. What should the project conventions be? Generally, this is covered by existing project conventions for JavaServer Faces technology modules and applications. For example, the <CODE>faces-config.xml</CODE> file and the TLD files for JavaServer Faces technology are usually kept in the <CODE>src/conf</CODE> directory. <BR></P>
<P>But where should you keep the JavaScript files? Should they be kept with the source code files? In most cases, we recommend that the JavaScript files be kept in the <CODE>src/resources</CODE> directory. In some cases, you might be using a pre-existing library of JavaScript files, which might be reusable even without the JavaServer Faces components, such as in the case of making a JavaServer Faces component that uses some of those existing JavaScript files. In this instance, the JavaScript library should be viewed as a separate project and should be used only by the JavaServer Faces application. </P>
<P>Another issue to consider is how to package these JavaServer Faces components and JavaScript artifacts into a WAR file or EAR file. The packaging is mostly the same as for other JavaServer Faces modules and applications, but you need to consider where to put the AJAX artifacts, which include the javascript files. Generally, it is recommended that you place the AJAX artifacts with the compiled classes so that the JavaServer Faces components can load them by calling <CODE>getClass().getResourceAsStream()</CODE>. </P>
<P>In order to use the components within an IDE, there are additional packaging considerations, such as how to make properties visible in IDE property sheets. These considerations differ from IDE to IDE (until this hopefully gets standardized with <A href="http://jcp.org/en/jsr/detail?id=273">JSR 273</A>). For a description of how to package your JavaServer Faces component for Sun Java Studio Creator, read <A href="http://developers.sun.com/prodtech/javatools/jscreator/reference/techart/jsfcomplibrary.html">http://developers.sun.com/prodtech/javatools/jscreator/reference/techart/jsfcomplibrary.html </A>. </P>
<H3>Helpful Hints for Developing AJAX components with JavaServer Faces Technology<BR></H3>
<UL>
<LI>Understand the JavaServer Faces component model. The <A href="http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSFCustom.html">J2EE 1.4 Tutorial on Creating JavaServer Faces Components</A> describes the necessary artifacts needed to create custom JavaServer Faces components. 
<LI>Get a good JavaScript book. <U>JavaScript: The Definitive Guide, 4th Edition</U> By David Flanagan is quite adequate. 
<LI>Get familiar with <A href="http://www.mozilla.org/projects/venkman/">Venkman</A>, the JavaScript debugger in the Mozilla suite. 
<LI>Get familiar with the <A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sdbug/Html/sdbug_12.asp">Internet Explorer Script Debugger</A>. 
<LI>Visit <A href="http://www.quirksmode.org/">QuirksMode.org</A>, a great JavaScript/CSS reference site. 
<LI>It's generally a good idea to put all your JavaScript code into one file that is referred to using &lt;script&gt; tags. During iterative development, it's a good idea to place this file directly in your server root so you can edit it in place. Then modify your code to refer to it at this location, just during development. When you get everything working, you can switch to using the <CODE>FacesServlet</CODE> and <CODE>PhaseListener</CODE> style to keep things self contained. </LI></UL>
<H3>References</H3>
<P>For more details on this solution see the <A href="https://bpcatalog.dev.java.net/nonav/ajax/textfield-jsf/index.html">JavaServer Faces Technology Auto-Completion Component with AJAX: Design Details</A> and <A href="https://bpcatalog.dev.java.net/nonav/ajax/progress-bar-jsf/index.html">AJAX Progress Bar for JavaServer Faces Technology: Design Details</A>. </P><img src ="http://www.blogjava.net/mstar/aggbug/7673.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2005-07-14 08:57 <a href="http://www.blogjava.net/mstar/archive/2005/07/14/7673.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Build Custom JSF Components</title><link>http://www.blogjava.net/mstar/archive/2005/05/26/5226.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Thu, 26 May 2005 05:14:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2005/05/26/5226.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/5226.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2005/05/26/5226.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/5226.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/5226.html</trackback:ping><description><![CDATA[<SPAN class=FeatureDek>Explore the process of creating new JSF components, including common "gotchas" and guidelines for defining good components</SPAN><BR><SPAN class=AboutAuthor><EM>by Jonas Jacobi</EM></SPAN> <!-- posted date in this format: Posted September 17, 2003 -->
<P><EM>May 25, 2005</EM></P><!-- end posted date --><!-- start 336x280 ad --><SPAN class=bigbox_left id=bigbox></SPAN><!-- end 336x280 ad -->
<P><SPAN class=DropCap>T</SPAN>he JavaServer Faces (JSF) specification provides a set of components with which application developers can build Java server applications. However, it is extremely likely that developers will want to extend JSF by creating custom components. Here we'll explore the process of creating new JSF components, highlighting common "gotchas" and providing guidelines for defining good components. We'll also look at the need for providing design-time metadata, so that component developers can ensure an excellent design-time experience for their custom components.</P>
<P>Before we start looking at components, it is worthwhile to elaborate on "why another framework?" When it comes to the architecture of JSF, it is not a new thing. For example, Apache's Tapestry and Oracle's ADF UIX framework have been around for quite some time and have proven to be very successful. JSF brings what other similar view technologies do not have: backing of a standard specification (JSR 127).</P>
<P>If we look at where we are today, most Web applications are stuck in the 1990s, when much too much effort was put into basic plumbing and not enough into high-level components. Basically, there is limited abstraction or no abstraction over the markup making development of Web applications cumbersome and the applications themselves hard to maintain. A lot of work is forced into the application to make it rich and interactive, with various technologies from applets, plug-ins (Flex), DHTML, and JavaScript. Together, these technologies can make up a very interactive and powerful Web application, but how do you maintain such an application? How do you reuse what you have built? Do you need multiple tools to achieve your goal of an interactive Web application?</P>
<P>These questions lead back to JSF and what it brings to the table—a best-of-breed J2EE framework—and the fact that every major J2EE tool vendor such as Oracle, IBM, Sun, and Borland is behind JSF.</P><SPAN id=lblShortArticlePage>
<P><SPAN class=SubHead>Potential Beneficiaries</SPAN><BR>So, who in the IT community would gain from using, developing, and deploying JSF applications instead of using proven but nonstandard technologies such as Tapestry, Cocoon, and Struts? Let's have a look.</P>
<P><EM>End users</EM>. End users will probably not notice much of what is happening behind the scene, but they will notice that Web applications are richer in functionality as we move ahead with JSF.</P>
<P><EM>Business developers</EM>. JSF gives business developers the means to build powerful enterprise Web applications by using an open standard (Java) with the ease and productivity that Visual Basic has been providing to its developers. The fact that more components will be available on the market, free or for a fee, means that business developers will have access to richer components—including dynamic menus, scroll bars, tables, and so on—that have so far been available only to those with expertise in DHTML, JavaScript, and the like. These components will not only provide business developers with richer functionality but will also improve their productivity in building Web applications.<BR></P></SPAN>
<P><EM>Component developers</EM>. Components, components, components: these are the golden nuggets that will make or break the success of JSF. Some vendors are already producing components for external use and for open source communities such as MyFaces (see <A href="javascript:openWindowRes();">Resources</A>). But, for JSF adoption to increase we need more components—lots of them—and with richer functionality.</P><SPAN class=bigbox_left id=bigbox></SPAN><!-- end 336x280 ad -->
<P>The dearth of existing components and the need for richer component sets mean that getting into the business of providing JSF components is a good opportunity. JSF also allows component authors to sell components based on a recognized J2EE-standard framework (instead of trying to convince customers to use a homegrown framework). Besides the business aspect of creating JSF components, there are also benefits to creating components by using JSF. JSF provides built-in support for aspects that are hard and cumbersome to implement, such as event handling, state saving, expression language, and a standard way to make custom components extensible.</P>
<P><EM>Tool developers</EM>. Tool developers need a formal standard that not only makes life easier for end users but also allows the developers to design and develop tools that will ease development of Web applications, or as they are called in this early part of the twenty-first century, J2EE applications.</P>
<P>As you are probably aware, JSF uses different classes for providing component functionality and for rendering the component. Before getting your hands dirty building your first set of components, search the Web for existing components.</P>
<P>There should be a fair amount of components already out there, and in most cases, you can probably get away with writing a new renderer for an existing component. If the component you are looking for cannot be found, it is time to build your own. To build a new component, you should make sure it has distinct server-side behavior and introduces a new behavior, functionality, or definition. If the component exists and you need a new appearance, you just need to create a new renderer (see <A href="javascript:openWindow1();">Figure 1</A>).</P>
<P><SPAN class=SubHead>Good and Bad of It</SPAN><BR>An example of good separation between behavior and appearance is the UISelectOne component provided by the JSF Reference Implementation. This component has a distinct behavior and three different renderer types: ListBox, Radio, and Menu. Potentially, you can add other types of renderers that have different appearances but the same behavior.</P>
<P>What distinguishes a good component from a bad component? A good component should have generic properties, event listeners, and specific behavior. The component should not contain markup-specific attributes, such as the "href" attribute; should not write markup or get request parameters; and should work with server events, not client events. It is important to isolate the presentation information from the underlying server-side component (see <A href="javascript:openWindow4();">Table 1</A>).</P>
<P>In addition to the <A href="javascript:openWindow4();">Table 1</A> information, using JSF facets enhances business developers' user experience developing applications with JSF components. A <EM>facet</EM> is a kind of child component that has a specific purpose defined by its name. A facet can be viewed as an empty placeholder that can take one child component. A parent component can have multiple facets; an example is a component called panelPage provided by Oracle's ADF Faces component set. This component uses facets to render its children in predefined locations such as the corporate logo (CORPORATE_BRANDING facet) or the copyright statement (COPYRIGHT facet).<BR></P>
<P>Renderers have their own classes and are therefore also subject to good and bad implementations. Writing a good renderer means basically reversing the list of dos for writing a good component. What is really important is that you do not give model access to the renderer. You should also try to use the ResponseWriter as often as possible, which will give tools a better chance of visualizing your component in a WYSIWYG editor. Here is an example of using the ResponseWriter:</P><PRE class=codesnippet>public void encodeBegin(<BR>  FacesContext context, <BR>  UIComponent component) throws <BR>  IOException<BR>{<BR>  ResponseWriter out = <BR>    context.getResponseWriter();<BR><BR>  //Pass the component so that <BR>  //the ResponseWriter can use <BR>  //it.<BR>  out.startElement(<BR>    "span", component);<BR><BR>  //Pass the "styleClass" <BR>  //attribute so that it can be <BR>  //matched.<BR>  Object style = <BR>    component.getAttributes().<BR>    get("styleClass");<BR>    out.writeAttribute("class", <BR>    style, "styleClass");<BR>}</PRE>
<P>You also need to make sure you register your renderer with a render kit. The most widely used rendering language is HTML, but this characteristic doesn't mean that you must use the HTML render kit; you can use any rendering language of your choice, such as SVG or XML.<!-- start 336x280 ad --> </P><SPAN class=bigbox_left id=bigbox></SPAN>
<P>There are some areas that need improvement and a few areas or <EM>gotchas</EM> that are not yet covered or will not be covered by the JSF specification. One example is the lack of a strategy for a consistent look and feel. There is currently nothing in the specification that outlines or defines a standard for implementing "themes" or "skinning." An area of improvement would be to make it easier to write a renderer. Today you need to write Java code to create a renderer, but it should be possible to come up with a more declarative solution for writing renderers similar to what is available in ADF UIX.</P>
<P>There is also no support for registering a renderer with multiple render kits and no tool support for testing components across multiple implementations such as MyFaces or Sun's JSF Reference Implementation.</P>
<P><SPAN class=SubHead>The Good, the Bad, and the Ugly</SPAN><BR>As a component developer or vendor, you are not locked into any IDE; in fact, if you prefer to use a text editor such as Emacs or VI, you can do so. JSF simplifies J2EE development because it will be easier for tool vendors to create a design-time experience for business developers similar to Visual Basic, using custom-designed and reusable components. Component developers may have the following questions: How do I get tools to support my custom components? Do I have to add anything beyond the required renderer so that my components can utilize all design-time features or display nicely in the tool's visual editor?</P>
<P><EM>The good</EM>. As you probably already know, there are plenty of tools available today with various levels of JSF support, and all major tool players—Oracle, IBM, Sun Microsystems, and Exadel—are working feverishly to improve the support for JSF. The JSF expert group clearly thought about tool support when they designed the faces-config.xml file. This XML file is an invaluable source of information that contains, for example, available components and their properties and facets. Not only is the XML file format easily digestible by tools, but also tools can automatically detect the location of a faces-config.xml for a set of components. Tools can, based on information provided in the faces-config.xml file, expose the set of available components at design time.<BR></P>
<P><EM>The bad</EM>. The bad thing is that faces-config.xml and TLDs are not very expressive and cannot convey interesting constraints such as valid values, or component enumerations. An example is the Oracle ADF Faces component <?xml:namespace prefix = af /><af:panellabelandmessage>. This component has an attribute called messageType. The valid values for this attribute are "error", "warning", "info", and "none". Unfortunately, there is no way in faces-config.xml to express that constraint. The faces-config.xml file also cannot indicate relationships between components, such as what would be a valid child for a particular component—for example, a Table component might only accept a Column component as a valid child. These shortcomings can be dealt with by providing these constraints and relationships in design-time metadata.</af:panellabelandmessage></P><SPAN class=bigbox_left id=bigbox></SPAN><!-- end 336x280 ad -->
<P><EM>The ugly</EM>. What could turn ugly is if tool vendors define their own proprietary ways of providing design-time metadata. Tool vendors are already asking for additional metadata from component authors so that components can fully utilize the design time, which will lead to component authors providing proprietary solutions for each tool vendor.</P>
<P><EM>The hope</EM>. The hope is that the JSF community can agree on standard design-time metadata and that component authors will invest in providing metadata for their components. The most likely way of defining such a standard is through the Java Community Process (JCP). Oracle is working with other JCP members with the goal of proposing a new JSR that would define a standard set of design-time metadata items for JSF components and a mechanism for providing such metadata.</P>
<P>Although the faces-config.xml language allows a component author to express a great deal of information about their components and renderers, it only has standard syntax for expressing a very minimal set of design-time metadata (mainly display-name, description, and icon). Fortunately, the faces-config.xml language is designed with convenient extension points that can be used to hold additional information.</P>
<P><SPAN class=SubHead>Strong Community</SPAN><BR>As previously discussed, there is not yet a standard mechanism for supplying additional design-time metadata. However, one proposed solution would utilize the extension points in faces-config.xml (see <A href="javascript:openWindow3();">Listing 1</A>). If you are interested in this issue, there is a thread on the Sun's JavaServer Faces Technology forum devoted to discussing design-time metadata for JSF components.</P>
<P>A crucial ingredient for the continuation of JSF's success and progress is a strong community. If you look at what ASP.Net has done and evaluate what makes this proprietary framework so successful, there is one thing that always pops up: the ASP community. Its community sites have forums with hundreds of daily posts as well as tutorials and content that are updated daily. There are component galleries with free hosting of custom components, which are integrated with the development tools. There are also free versions of basic tools supporting ASP development.</P>
<P>Some of this type of groundwork has already started with projects such as MyFaces and information sites such as JSFCentral, but this is not enough. We cannot hope that a small group or a single person can provide us with a complete set of community sites including daily posts, tutorials, and contents. Now is the time to get involved in Faces!</P>
<P>The JSF community needs one or more neutral hosting sites that provide content such as tutorials, forums, and announcements—and, of course, component galleries. Another area in which the community can provide help in is testing tools. In the spirit of Cactus and JUnit, the community could provide testing tools with a different approach, such as test components and not markup, and send simulated events. For anyone eager to get involved, this possibility would make a good open source project.</P>
<P>Skinning and themes are areas that noncoders could ideally participate in. Noncoders could provide style abstractions to mirror component abstractions using styles, icons, text/translations, and templating.</P>
<P>There is a future beyond HTML; eventually, component authors will provide higher-level components with better customization. These components will be based on other client-side technologies, such as DHTML, SVG, Flex, XUL, and Web Forms (see <A href="javascript:openWindow2();">Figure 2</A>).</P>
<P>The message here is, think components, not markup! JSF is not exclusively for HTML, it is not exclusive to hard-core developers, and it is not exclusive to business developers. There are plenty of opportunities for all types of developers. Finally, don't forget the metadata, and make sure you get involved early in the JSF community.</P>
<P><SPAN class=AboutAuthor>About the Author</SPAN><BR>Jonas Jacobi is a senior product manager for JDeveloper at Oracle. </P><SPAN id=lblShortArticlePage></SPAN><img src ="http://www.blogjava.net/mstar/aggbug/5226.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2005-05-26 13:14 <a href="http://www.blogjava.net/mstar/archive/2005/05/26/5226.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>