jsr344-experts@javaserverfaces-spec-public.java.net

[jsr344-experts] [1111-PassThruElements] First commit complete

From: Edward Burns <edward.burns_at_oracle.com>
Date: Wed, 11 Jul 2012 09:18:58 -0700

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&gt;, 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