Hello Experts,
After reading the thread on this and doing my best to aggregate the
discussion into my understanding, I very much want to do this feature
for 2.2. As a first step, I just committed this change-bundle, which
can serve as the basis for further discussion.
Blake, I know you and I talked about deferring this to a later release,
but I think it makes a lot of sense to put it into 2.2.
Can at least Frank, Andy, and Blake read through the API Changes section
at least? I know that, for example, we need to enhance it further so
behaviors can be attached to these pass through elements. I'm sure
there is also more work to do in other aspects as well.
SECTION: API Changes
--------------------
M jsf-api/doc/standard-html-renderkit-base.xml
M jsf-api/doc/standard-html-renderkit.xml
- Define new Renderer:
component-family: javax.faces.Input renderer-type: javax.faces.markup.Input
This renderer is intended to be used with an arbitrary markup element
that ultimately produces a name=value pair that will be sent to the
server and decoded by the associated javax.faces.component.UIInput.
Decode Behavior
The decode behavior is identical to that of the javax.faces.Input
javax.faces.Text renderer.
Encode Behavior
Look in the component's attribute map for an entry under the key given
by the value of the constant
Renderer.MARKUP_RENDERER_LOCALNAME_KEY. The value of this key is the
element name to render. If the component has a manually declared, not
auto-generated clientId, or if the component has behaviors attached to
it, render the clientId as the value of the "id" attribute. Render the
"name" attribute with the value coming from the clientId. Note that
markup authors may set this value directly on the markup and the VDL
processing must guarantee that the "name" attribute is set as the
component's clientId. Render the current value of the component as the
value of the "value" attribute.
According to the section "Rendering Pass Through Attributes" in the
overview of this RenderKit, all of the pass throuh attributes will be
rendered exactly as shown on the markup in the VDL page.
M jsf-api/src/main/java/javax/faces/view/facelets/Tag.java
- The system will see this markup as part of the
<
http://www.w3.org/1999/xhtml> namespace.
<input name="textField" type="text" jsf:value="#{bean.name}" />
However, it should be interpreted as if it had come from the new
"markup component" namespace, <
http://java.sun.com/jsf>. To enable
this dynamic transition, I have added a setter for the namespace
property.
M jsf-api/src/main/java/javax/faces/view/facelets/TagAttribute.java
M jsf-api/src/main/java/javax/faces/view/facelets/TagAttributes.java
- All attributes not prefixed with the short name of the
<
http://java.sun.com/jsf> namespace must be put into the pass through
attributes map. To enable this implementation, I have added a
reference to the Tag with which this TagAttribute, or TagAttributes
intstance is associated.
M jsf-api/src/main/java/javax/faces/render/Renderer.java
- Added constant for key used to store the element name to be rendered
for a markup component.
M jsf-ri/conf/share/tlddoc-resources/stylesheet.css
- Add pass through elements as a new taglib.
A jsf-ri/conf/share/facelets_passthrough_elements.tld
- Specify the new passthrough element tag library.
The presence of an attribute from this namespace on an otherwise non-JSF
aware markup element indicates that the markup element must be treated
as a JSF component that will be rendered equivalently to what is
specified directly in the Facelet page, with the added benefit of being
associated with a server side UIComponent instance.
Usage example
<html xmlns="
http://www.w3.org/1999/xhtml"
xmlns:h="
http://java.sun.com/jsf/html"
xmlns:jsf="
http://java.sun.com/jsf"
<h:form>
<input name="textField" type="text" jsf:value="#{bean.name}" />
</h:form>
</html>
When the Facelets runtime detects an attribute from the
http://java.sun.com/jsf namespace, the entire element must be
set to be in that namespace by a call to
Tag.setNamespace(). A
component-family/renderer-type pairing must be derived based on
the XML local name of the element as shown in the following
table.
XML local name component-family renderer-type
input javax.faces.Input javax.faces.passthrough.Input
The components's attribute map must be given an entry with
the key given by the value of the constant
javax.faces.render.Renderer.PASSTHROUGH_RENDERER_LOCALNAME_KEY
and the value given by the XML local name. Any non-namespaced
attributes on the markup element must be set exactly as they
appear on the pass through attribute map of the component. Any
attributes from namespace
http://java.sun.com/jsf must be set as
properties on the component in the usual manner for other
regular JSF components.
Names and Client Ids
The following algorithm must be used to set the id (and
therefore the clientId) of the component corresponding to this
markup.
If the element has a manually declared, non-namespaced "id"
attribute, us it as the id. Otherwise, if the element has an
"id" attribute in the
http://java.sun.com/jsf namespace, use it
as the id. Otherwise, if the element has been set as being in
the
http://java.sun.com/jsf namespace, and has a "name"
attribute, use it as the id.
The system must throw a FaceletException if an
attribute from this namespace is used on a regular JSF aware
markup element.
M jsf-ri/build.xml
- Add new taglib to spec.
D jsf-ri/conf/share/facelets_passthrough.tld
A + jsf-ri/conf/share/facelets_passthrough_attributes.tld
- Rename the tld file for generation of the spec for pass through
attributes to be more specific.
SECTION: Implementation Changes
-------------------------------
M jsf-api/src/main/java/javax/faces/component/UIComponentBase.java
- This is an implementation change to the pass through attributes map
implementation. The previous implementation used an anonymous inner
class extending ConcurrentHashMap as the data structure. This caused
a reference to the UIComponent instance to be included in the
serialized state. Not correct. To fix this, use a non-anonymous
static inner class.
M jsf-ri/src/main/java/com/sun/faces/facelets/compiler/CompilationManager.java
- This is the key enabling change for this implementation of the feature.
In pushTag(), we inspect the attributes given to us by the XML parser.
If there are any attributes from the <
http://java.sun.com/jsf>
namespace, we take special case action. First, we set the namespace
of the tag to be <
http://java.sun.com/jsf>. Second, we pass
<
http://java.sun.com/jsf> as the namespace to the TagUnit ctor.
The first action makes it so the JsfPassthroughElementLibrary is asked to
create the TagHandler. The second action enables all non
<
http://java.sun.com/jsf> namespaced attributes to be correctly
installed in the pass through attributes map, while the
<
http://java.sun.com/jsf> namespaced attributes go to where evere they
would normally go.
We make sure to throw a FaceletException if we have an element that
has attributes namespaced with the pass through element namespace that
is not, itself valid as a pass through element.
I need to add tests for conflicting attributes, such as "required".
A jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/JsfPassthroughElementLibrary.java
- This class is where the choice of how to map a component-family,
renderer-type pair to an HTML markup element is made. As a prototype,
we currently only have <input> mapping to javax.faces.Input
javax.faces.markup.Input.
M jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.java
- Add new tag library for <
http://java.sun.com/jsf>.
A jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/PassthroughElementHandler.java
- use onComponentCreated() to store the element name in the component
attributes map under the key Renderer.PASSTHROUGH_RENDERER_LOCALNAME_KEY
A jsf-ri/src/main/java/com/sun/faces/renderkit/html_basic/PassthroughInputRenderer.java
- Implement the renderer spec for javax.faces.Input javax.faces.passthrough.Input
M jsf-ri/src/main/java/com/sun/faces/facelets/compiler/SAXCompiler.java
- Make it so TagAttributes (and therefore TagAttribute) is made aware of
the Tag with which they are associated.
M jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/ComponentRule.java
- Modify LiteralAttributeMetadata to take the TagAttribute instance,
rather than its value, in the ctor.
- In LiteralAttributeMetadata.applyMetadata(), if the namespace of the
tag for this attribute is <
http://java.sun.com/jsf>, put the attribute
in the pass through map. Otherwise, put the attribute in the
attributes map.
M jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/ComponentTagHandlerDelegateImpl.java
- Here is a very important change regarding component ids. Use this
algorithm to get the "id" of the component that will eventually be
passed to component.setId().
+ private TagAttribute getIdAttribute(ComponentHandler owner) {
+ TagAttribute result = owner.getTagAttribute("id");
+ if (null == result) {
+ result = owner.getTag().getAttributes().get(JsfPassthroughElementLibrary.Namespace, "id");
+ if (null == result) {
+ String tagNS = owner.getTag().getNamespace();
+ if (null != tagNS && tagNS.equals(JsfPassthroughElementLibrary.Namespace)) {
+ result = owner.getTagAttribute("name");
+ }
+ }
+ }
- This implements part of the passthrough element feature set.
M jsf-ri/src/main/java/com/sun/faces/facelets/tag/TagAttributesImpl.java
M jsf-ri/src/main/java/com/sun/faces/facelets/tag/TagAttributeImpl.java
- Implement new contract.
M jsf-ri/src/main/resources/com/sun/faces/standard-html-renderkit-impl.xml
- Add renderer class for new renderer.
M common/ant/glassfishV3.1_no_cluster/container.xml
- To save time when running container.deploy, add the
-Dskip.container.bounce=true
to the ant invocation line, and ensure the container has been stopped
before running ant. I tested that this change has no impact when the
property is not set.
[...]
Transmitting file data ......................................
Committed revision 10261.
This will be in tonight's nightly.
Ed
--
| edward.burns_at_oracle.com | office: +1 407 458 0017
| homepage: | http://ridingthecrest.com/
| 6 Business days til JSF 2.2 Public Review to EG