users@javaserverfaces-spec-public.java.net

[jsr344-experts mirror] Re: HTML5 friendly markup (fix inconsistencies and documentation review)

From: Leonardo Uribe <lu4242_at_gmail.com>
Date: Mon, 14 Apr 2014 14:12:29 +0200

Hi

I did a small test with Mojarra 2.2.6, to be sure about how the
namespace is processed:

<html ....
          xmlns:xz="http://my.organization.org/something">
<head>
</head>
<body>
    <div jsf:id="boxNs" xz:onclick="alert('hello')" xz:style="noprint"
xz:prop1="value1">
        Show the namespace!
    </div>
</body>
</html>

This is the rendered markup:

<html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:xz="http://my.organization.org/something">
...
<div id="form:boxNs" onclick="alert('hello')" style="noprint">
        Show the namespace!
    </div>
...
</html>

The namespace is rendered, but the properties does not hold the
namespace, and instead the namespace is ignored.

Please note that facelets uses xhtml to render html, and in html5
there is no namespaced attributes. The only allowed custom attributes
should be prefixed with data- . Theoretically it is possible to use
namespaced attributes in xhtml5, but that doesn't seem to be relevant.
But if you see svg spec you will see xlink:... attributes like for
example xlink:href. It is not necessary to declare the namespace, but
the attribute is meant to be passed through as is without changes.

Looking facelets compiler as something not bound to html, it looks
like a bug. I can't imagine a case where you have the namespace set
for an attribute and you need to put it on the component attribute
map, like the spec suggest. What you expect is the attribute to be
rendered without any change. But it is too late to change that, at
least in 2.2.

regards,

Leonardo Uribe

2014-04-13 19:35 GMT+02:00 Leonardo Uribe <lu4242_at_gmail.com>:
> Hi
>
> I think I have finally realized what went wrong in all this mess. In the spec
> javadoc of TagDecorator it says this (only the relevant points):
>
> "... Convert all the attributes of the argument tag as follows. ..."
>
> 1. "... If the current attribute's namespace is http://xmlns.jcp.org/jsf, ..."
>
> 2. "... If the current attribute's namespace is empty or different from the
> argument tag's namespace ..."
>
> 3. "... Otherwise, assume the current attribute's namespace is
> http://xmlns.jcp.org/jsf/passthrough ..."
>
> An inspection over the conditions written in the spec reveals that the
> condition that suppose to be activated for the passthrough attribute is
> never executed. I have checked all examples I have over this feature and it
> is clear the "otherwise" condition does not work in reality as the spec says.
>
> Suppose this example:
>
> <div jsf:id="myBox" jsf:prop1="value" title="Hello World!" pt:lang="en">
>
> </div>
>
> jsf:id should call UIComponent.setId(), jsf:prop1 should store the attribute
> in the normal component attribute map, pt:lang does not have any meaning so
> it should never be used, but what happen with "title" attribute? We have been
> discussing that, but it is clear that the intention is to put this attribute
> in the passthrough attribute map. Which one is the condition that is supposed
> to deal with this? Number 3, but what's happening is the algorithm always
> catch the attribute in number 2 and number 3 is never executed.
>
> I have checked the code and the attributes without namespace, and in fact
> the attributes never receive a null namespace, instead they have an
> empty string namespace. So, being strict with the spec javadoc, the
> "otherwise" is executed only when the attribute has the same namespace
> as the argument's tag namespace. Which are the options for the
> argument's tag namespace? empty and http://www.w3.org/1999/xhtml. So,
> in the condition 2 the "is empty" should be removed, because it doesn't
> have sense.
>
> In facelets, there is no namespaced attributes. In other words, all attributes
> are processed no matter if they have namespace set or not. It is never used!
> But in JSF 2.2 we have 2 special namespaces: jsf and passthrough. And now
> these namespaces needs to be processed properly. But that means give facelets
> compiler the ability to deal with namespaces.
>
> But things get out of control when you have a line like this in the
> javadoc of TagDecorator, in the condition 1:
>
> "... If the current attribute's namespace is http://xmlns.jcp.org/jsf,
> convertedTagAttribute's qualified name must be the current attribute's local
> name and convertedTagAttribute's namespace must be the empty string. This will
> have the effect of setting the current attribute as a proper property on the
> UIComponent instance represented by this markup ..."
>
> Remove the namespace is inconvenient. It is easier if the namespace is set
> and with that information we let facelets compiler to deal with the
> difference.
>
> I think there are few people out there that really knows how facelets
> algorithm works. But to clarify the implications of this problem, I'll describe
> some details over that algorithm that becomes relevant in this case.
>
> Facelets has a set of classes that helps to deal with apply the attributes
> set in a tag into the target component. There is a method called:
>
> protected MetaRuleset createMetaRuleset(java.lang.Class type)
>
> where you can create a MetaRuleset, which have a set of MetaRule instances that
> are applied in a ordered way for each attribute in the tag.
>
> What is a passthrough attribute? it is an special type of attribute that is
> just added to the passthrough attribute map. What is a jsf attribute? a normal
> attribute that needs to be passed through the existing rules in MetaRuleset.
> Who should be responsible to decide if the attribute should be processed as
> a normal attribute or as a passthrough attribute? MetaRuleset. The right way
> to do it is update MetaRuleset implementation with the necessary logic
> to deal with passthrough attributes. An strategy that relies in a default
> TagDecorator only will not work properly.
>
> Where do the copy of attributes in Mojarra happens? Based on the previous
> argumentation and the tests done, I would guess it happens because the
> attributes are effectively processed twice, as a passthrough attribute and
> as a normal attribute, because as I said before, facelets never ever
> considered namespaced attributes, even if they let the blank spots the
> logic to differentiate them is not there. Why? because if you need to
> process a namespaced attribute you add a MetaRule, and the last one added
> is the first one to be applied.
>
> In my personal opinion, and based on the previous argumentation, this is
> what I think:
>
> 1. The spec javadoc of TagDecorator is inconsistent and needs to be fixed.
> 2. Mojarra does not implements what the spec javadoc of TagDecorator says
> about, but its implementations follows the spec intention, described in
> JSF 2.2 section 10.1.4.
> 3. The details on the javadoc of TagDecorator that are too implementation
> specific, and it does not follow the spec intention, so there is no other
> choice that forget about that part, which is definitively broken and
> honor JSF 2.2 section 10.1.4, which is consistent.
>
> I'll try to fix MyFaces to resemble the spec as close as possible, without fall
> in the bugs and inconsistencies we have discussed here.
>
> regards,
>
> Leonardo Uribe
>
>
> 2014-04-06 19:49 GMT+02:00 Leonardo Uribe <lu4242_at_gmail.com>:
>> Hi
>>
>> 2014-04-06 18:53 GMT+02:00 Frank Caputo <frank_at_frankcaputo.de>:
>>> Hi,
>>>
>>> Am 27.03.2014 um 12:45 schrieb Leonardo Uribe <lu4242_at_gmail.com>:
>>>
>>>> 2. Use jsf:binding in Mojarra does not work, but it is not in the
>>>> documentation of jsf:element. But the same is true for id attribute and
>>>> these attributes comes from UIComponentBase. This is a bug in Mojarra and
>>>> should be fixed.
>>>
>>> binding indeed doesn't work. I think, PassThroughElementComponentHandler should work more like ComponentTagHandlerDelegateImpl. Did you already file a bug?
>>> id works, though it is not documented.
>>>
>>
>> I have not created a bug, since this is implementation specific.
>>
>>> We should add id, rendered, transient and binding to the documentation.
>>>
>>
>> Ok. but do not add "transient", because it is something internal of
>> the component,
>> not to be used by the user (but f:view transient="true" is valid)
>>
>>>> 3. I have explained to Frank that in some cases http://xmlns.jcp.org/jsf
>>>> put attributes into normal component attribute map but sometimes it is
>>>> required to use the passthrough attribute map. "id", "binding", "rendered"
>>>> and "transient" should not be put on passthrough attribute map, but other
>>>> attributes should.
>>>
>>> If you use the jsf namespace on the attributes correctly, you can easily control, into which map the attribute is put. We should not try to implement some magic which fixes user mistakes. No attribute makes it ever into both maps (see com.sun.faces.facelets.tag.DefaultTagDecorator.ElementConverter#convertTagAttribute).
>>>
>>
>> Yes, I know but that's the point of all this issue, in MyFaces we have
>> implemented
>> the spec exactly the way it says but it doesn't work because there is
>> something missing in the spec javadoc, that was added in Mojarra to make
>> it work.
>>
>> In other words we are in a situation that we can't enforce the spec because that
>> will be perceived at the end by the users as a bug "... this is
>> working in Mojarra
>> but it is not in MyFaces ...". I want to avoid that situation.
>>
>>>> In conclusion we have these 3 cases:
>>>>
>>>> 1. Attributes with jsf namespace that should be put on passthrough
>>>> attribute map.
>>>>
>>>> <div jsf:style="noprint">
>>>> Hello World!
>>>> </div>
>>>
>>> This doesn't make sense. Why don't you simply use <div style="noprint">...? But your example works in Mojarra, because PassthroughElement handles style and styleClass (which is not documented and so it shouldn't work).
>>>
>>
>> It has sense. For example:
>>
>> <div jsf:style="noprint">
>> <f:ajax event="click" listener="..."/>
>> Hello World!
>> </div>
>>
>> The point is there are some scenarios when you want that the div works as a JSF
>> component. This doesn't work:
>>
>> <div style="noprint">
>> <f:ajax event="click" listener="..."/>
>> Hello World!
>> </div>
>>
>> because the compiler does not get the div as a component, just as html markup
>> but we want that by performance reasons.
>>
>> The key point is attributes marked with jsf namespace has another meaning
>> which is "... convert this tag into a jsf markup component ..:".
>>
>> Try with any other attribute from style and you'll see it works in Mojarra,
>> because internally somehow the attribute is copied in both places, in the normal
>> attribute map and in the passthrough attribute map. I have already tested by
>> the way.
>>
>>>> 2. Attributes with jsf namespace that should be put on normal attribute map.
>>>>
>>>> <div jsf:binding="#{boxBean.box1}">
>>>> Hello World!
>>>> </div>
>>>
>>> See above, this should be fixed. But I still want to stay with the behavior, that EVERY jsf:xxx attribute will be put on the normal attribute map.
>>>
>>
>> so do I, but only if the attribute has been defined in the component class,
>> otherwise put it in the passthrough attribute map.
>>
>>>> <input jsf:id="input" type="text" jsf:value="#{someBean.someValue}"/>
>>>
>>> This works.
>>>
>>
>> yes and it should continue working. That's my intention
>>
>>>> 3. Attributes without any namespace that could overlap attributes in the
>>>> normal component map that requires special treatement.
>>>>
>>>> <div jsf:binding="#{boxBean.box1}" onclick="alert('hello')">
>>>> <f:ajax event="click" render="renderMe"/>
>>>> Hello World!
>>>> </div>
>>>
>>> There is a clear rule for overlapping: passtrough attributes take precedence. I like that simple rule without any exceptions.
>>>
>>
>> But there is no point to add attributes like onclick and others in
>> jsf:element if
>> at the end they will get overriden by the passthrough and f:ajax and other
>> client behavior destroyed on the way.
>>
>>>> What should we do? What's the ideal behavior?
>>>>
>>>> - First of all we need to recognize that in this case attributes marked with
>>>> empty namespace and with jsf namespace behave the same. The only special
>>>> property it has jsf namespace is that its presence in an attribute makes the
>>>> tag susceptible to be converted.
>>>>
>>>> - If the attribute is declared by the component class, it should be added to
>>>> the component attribute map.
>>>>
>>>> - If the attribute is declared by the component class, it should NOT be added
>>>> to the passthrough attribute map.
>>>>
>>>> - If the attribute is NOT declared by the component class, it should be put
>>>> on the passthrough attribute map.
>>>>
>>>> How can we detect if a component class has a property defined? there is no
>>>> standard way to do that, but each JSF implementation has the code deep inside
>>>> UIComponentBase implementation, specifically in the normal component
>>>> attribute map. But that suppose a problem, because in the moment the default
>>>> TagDecorator is active, there is not a component class yet. But the trick
>>>> can be done with a new Rule, but it will not be easy.
>>>
>>> This is impossible, because users are free to put whatever they want into both attributes maps. The implementation can't decide, if the attribute in the attribute map should be there or it is just a mistake.
>>>
>>
>> It is possible, I have already done in myfaces. In fact, facelets do something
>> like that since 1.1.x. Take a look at ComponentRule implementation. It should
>> be a line like this:
>>
>> else if (meta.getWriteMethod(name) == null)
>>
>> That line do the trick. In my opinion, the user don't care where the
>> attribute is put
>> as long as the intention of this feature can be honored. I can't see any problem
>> doing that, because this component is just a wrapper for html markup.
>>
>>> From my point of view, we have a really simple rule, saying that every jsf: attribute will be on the component attributes map and any other is on the passthrough attributes map.
>>>
>>
>> Unfortunately that's not an option. We need something more elaborated to make
>> things work.
>>
>>>> This strategy has the big advantage that the attributes are not duplicated, so
>>>> the state size is not doubled.
>>>
>>> As said before, attributes are not doubled (i can't find it in the implementation).
>>>
>>
>> It is there, I have reviewed, with the debugger, but that's the point.
>> There is no
>> mention of that in the spec, so it should be an implementation detail in Mojarra
>> added at some point of the time. MyFaces doesn't have it, because it is a
>> complete different implementation, so I can't help more.
>>
>>>> The objective is avoid changes in the spec if
>>>> possible, so let's see what we can do.
>>>
>>> I'll answer your other mail with the proposed changes a bit later (hopefully this week).
>>>
>>
>> Ok, thanks for your help with this.
>>
>> regards,
>>
>> Leonardo
>>
>>> Ciao Frank
>>>
>>>>
>>>> regards
>>>>
>>>> Leonardo
>>>>
>>>> 2014-03-25 2:12 GMT+01:00 Edward Burns <edward.burns_at_oracle.com>:
>>>>>>>>>> On Mon, 24 Mar 2014 13:39:21 +0100, Leonardo Uribe <lu4242_at_gmail.com> said:
>>>>>
>>>>> LU> But the user has reported another more troublesome combination:
>>>>>
>>>>> LU> <li jsf:class="toclevel-1 tocsection-2"/>
>>>>>
>>>>> LU> According to the spec it should not work. The javadoc of
>>>>> LU> javax.faces.view.facelets.TagDecorator
>>>>> LU> says this (already mentioned before):
>>>>>
>>>>> LU> "... If the current attribute's namespace is http://xmlns.jcp.org/jsf,
>>>>> LU> convertedTagAttribute's qualified name must be the current attribute's local
>>>>> LU> name and convertedTagAttribute's namespace must be the empty string. This
>>>>> LU> will have the effect of setting the current attribute as a proper property
>>>>> LU> on the UIComponent instance represented by this markup. ..."
>>>>>
>>>>> LU> If the intention of jsf namespace is put the attribute into the
>>>>> LU> attribute map, why that syntax should work, unless the attribute has
>>>>> LU> been explicitly declared on jsf:element component.
>>>>>
>>>>> I haven't checked the code, but I expect the reason it works is due to
>>>>> the old attribute/property transparency. First it looks for a
>>>>> "setClass" method on the UIComponent instance. Failing to find it, it
>>>>> calls UIComponent.getAttributes().put("class", "toclevel-1 tocsection-2").
>>>>>
>>>>> LU> I tried also this
>>>>> LU> combination:
>>>>>
>>>>> LU> <div jsf:style="noprint">
>>>>> LU> Hello World!
>>>>> LU> </div>
>>>>>
>>>>> LU> It works again, but it shouldn't.
>>>>>
>>>>> Again, I expect this causes UIComponent.getAttributes().put("style",
>>>>> "noprint").
>>>>>
>>>>> LU> But it is clear why it is an obvious combination. The same javadoc
>>>>> LU> of TagDecorator detects any attribute with the namespace "jsf" and
>>>>> LU> if it is found the tag is binded to a jsf:element component. The
>>>>> LU> related line says this:
>>>>>
>>>>> LU> "... If one or more of the attributes of the tag argument are in the
>>>>> LU> http://xmlns.jcp.org/jsf namespace, obtain a reference to decoratedTag as
>>>>> LU> described in the following steps and iterate through the list of TagDecorator
>>>>> LU> instances as described in the preceding step ..."
>>>>>
>>>>> Yes, that text is the catch-all that allows the whole passthru elements
>>>>> feature to work.
>>>>>
>>>>> LU> In practice, it seems an attribute using "jsf" namespace should be
>>>>> LU> added in both normal attribute map and passthrough attribute map. I
>>>>> LU> can't detect any problem at the moment, because the logic in the
>>>>> LU> default ResponseWriter keeps track of the rendered attributes, and
>>>>> LU> as long as no logical attributes are copied, things will be
>>>>> LU> fine. Here there is an example of the problem:
>>>>>
>>>>> LU> <div jsf:binding="#{boxBean.box1}">
>>>>> LU> Hello World!
>>>>> LU> </div>
>>>>>
>>>>> LU> In Mojarra this attribute is just ignored, so it doesn't work, but
>>>>> LU> in MyFaces it works, but if the attributes are copied in both maps,
>>>>> LU> this one will be a problem. So the algorithm should duplicate the
>>>>> LU> attributes that are not reserved like "id", "binding", "rendered" or
>>>>> LU> "transient".
>>>>>
>>>>> I would have to step through this in a debugger to authoritatively
>>>>> comment on what the spec intent is here, and therefore to clearly define
>>>>> what "in MyFaces it works" means in this case.
>>>>>
>>>>> LU> There are a couple of attributes that are implementation specific,
>>>>> LU> but since they are not declared in the markup, they do not have the
>>>>> LU> chance to be copied or overriden.
>>>>>
>>>>> I'd like to avoid having to do this.
>>>>>
>>>>> LU> It is curious this syntax does not work:
>>>>>
>>>>> LU> <div pt:style="noprint">
>>>>> LU> Hello World!
>>>>> LU> </div>
>>>>>
>>>>> LU> The tag is not converted into a jsf:element, so the compiler sees it as
>>>>> LU> html markup.
>>>>>
>>>>> I would need to see to that namespace the pt: attribute prefix is
>>>>> bound. If it is the xmlns.jcp.org pass through attribute namespace,
>>>>> then it should work and that is a bug.
>>>>>
>>>>> LU> I do not see any other choice than force the copy to the passthrough
>>>>> LU> attribute map of all attributes declared with jsf namespace. But I have
>>>>> LU> to warn about a side effect over the state. If the attributes are copied
>>>>> LU> twice, that means the state of that component is effectively doubled.
>>>>> LU> If PSS is properly implemented, it will not have a significant effect
>>>>> LU> over the state, because most of the time that part is not part of the
>>>>> LU> "delta" state of the component.
>>>>>
>>>>> I must understand why the copy is necessary.
>>>>>
>>>>> Ed
>>>>>
>>>>> --
>>>>> | edward.burns_at_oracle.com | office: +1 407 458 0017
>>>>> | 0 Work Days Til JavaLand 2014
>>>>> | 30 Work Days til JAX 2014
>>>>
>>>
>>>