<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Hey Martin,<br>
<br>
Okay, I see where you are coming from.&nbsp; So one option (leaving schedule
issues aside for a moment) would be to go back to our old names:<br>
<br>
- Behavior-&gt;ClientBehavior<br>
- BehaviorHolder-&gt;ClientBehaviorHolder<br>
<br>
And I guess also for the new APIs:<br>
<br>
- BehaviorContext-&gt;ClientBehaviorContext<br>
- BehaviorRenderer-&gt;ClientBehaviorRenderer<br>
- BehaviorBase-&gt;ClientBehaviorBase<br>
- BehaviorHint-&gt;ClientBehaviorHint (or give up on the enum and just
use a boolean).<br>
<br>
And, as you suggest, we would need to define a new base Behavior
contract that ClientBehavior extends.&nbsp; Or, at least, I think we need
this, since we would want to keep the behavior-related configuration
stuff generic.&nbsp; That is, I assume that we would still want this method
in Application:<br>
<br>
&nbsp;&nbsp;&nbsp; public abstract Behavior createBehavior(String behaviorId)<br>
<br>
As opposed to this:<br>
<br>
&nbsp;&nbsp;&nbsp; public abstract ClientBehavior createClientBehavior(String
behaviorId)<br>
<br>
(And similarly, still want &lt;behavior&gt; elements in
faces-config.xml and Facelets taglib.)<br>
<br>
While I think we would need to introduce a new Behavior contract (so
that we have something generic to return from
Application.createBehavior()), I am not
sure that&nbsp; we need a base BehaviorHolder contract.&nbsp; Just doesn't seem
like this would be useful.<br>
<br>
If we do this, then in 2.1 we could introduce a PhaseBehavior interface
that extends Behavior.&nbsp; This would allow us to implement
phase-listening/apsect-like behaviors in 2.1 without requiring that
they implement the getScript() method.&nbsp; We may also add a
PhaseBehaviorHolder contract for components that allow PhaseBehaviors
to be attached independently of any event attach point.&nbsp; (The
ClientBehaviorHolder contract is all about attaching to "events" -
whereas a PhaseBehavior may not care at all about attaching to a
particular event.)<br>
<br>
Note that if we decide to add support for behaviors that do
component-level/aspect-like phase listening in 2.1, I would prefer that
we do this by introducing a new sub-interface of the generic Behavior
interface, rather than add phase listening capabilities directly into
the base, since phase listening capabilities may not be generic to all
Behaviors (just like script generation may not be generic to all
Behaviors - for example, AjaxBehavior doesn't want to be a
PhaseBehavior)<br>
<br>
So, I think this could work, but two problems:<br>
<br>
1. I am not sure what the base Behavior contract should be.<br>
<br>
Would it be okay for this to just be a marker interface?&nbsp; This would
certainly be easier than trying to design a more meaningful/generic
base Behavior contract now.<br>
<br>
2. Time<br>
<br>
The re-factoring shouldn't be all that hard, but it will require some
work, both on the implementation and in the specification, and as we
all know, we are definitely running out of time.<br>
<br>
Andy<br>
<br>
Martin Marinschek wrote On 3/11/2009 11:06 AM ET:
<blockquote
 cite="mid:5a99335f0903110806r65d39949m9b72e23a756bd537@mail.gmail.com"
 type="cite">
  <pre wrap="">Hi Andy,

ok, I see. Well, I just wanted to make sure that we don't pollute the
namespace: again, behavior seems to generic a name to me to have a
method providing a script. Should we have a behavior interface, an
extending script-behavior interface, and then we can make behavior
(the base-interface) more powerful in 2.1?


regards,

Martin

On 3/10/09, Andy Schwartz <a class="moz-txt-link-rfc2396E" href="mailto:andy.schwartz@oracle.com">&lt;andy.schwartz@oracle.com&gt;</a> wrote:
  </pre>
  <blockquote type="cite">
    <pre wrap="">Hey Martin -

Thanks for reading through my long email and for the comments!

We ended up with the getScript() and decode() methods out of necessity -
these were the minimal APIs that we needed to encapsulate our
Ajax-related functionality into a Behavior object.  As currently
designed, our Behavior solution is definitely focused on creating and
attaching scripts to components - thus we ended up with getScript() as
the centerpiece of the Behavior contract.

I find your idea of Behaviors as component aspects very interesting, and
can see how this would add another degree of flexibility.  However, I am
a little uncomfortable expanding the scope at this point in the 2.0
release.   For 2.1, I do think it would be worth considering whether we
can address this, perhaps by adding a new "PhaseBehavior" interface.
The idea is that this would identify Behaviors that want to be notified
before/after each phase, similar to a PhaseListener, but at the
component instance-level rather than at the view-level.

Do you feel that this is something that we can evaluate for 2.1?  Or do
you feel that it is critical to address this in 2.0?

Andy

Martin Marinschek wrote On 3/10/2009 3:02 PM ET:
    </pre>
    <blockquote type="cite">
      <pre wrap="">Hi Andy,

I think this all reads very well - however, I was wondering why you
stopped at providing decode and renderScript (especially the
get-script method feels a little awkward in something which sounds as
generic as a behaviour class).

For me, this whole behavior thing sounds like a component aspect:
something which is called before/after/around component lifecycle
methods are executed... at least before/after/around decode and
before/after/around rendering.

regards,

Martin

On 3/10/09, Andy Schwartz <a class="moz-txt-link-rfc2396E" href="mailto:andy.schwartz@oracle.com">&lt;andy.schwartz@oracle.com&gt;</a> wrote:

      </pre>
      <blockquote type="cite">
        <pre wrap="">Gang -

I wanted to send one last email on the new Behavior API to help folks
who were not able to keep up with the progress on this API as it
evolved.  Much of this information has been covered in previous emails,
but some of the API details are new, so please read on if you are
interested.

* Core APIs

Just to remind everyone why we started down this path...  As of the
public review draft, we had a single non-generic "behavior" - the
AjaxBeahvior - which could only be attached to EditableValueHolders and
ActionSource components, and even then, only for valueChange/action
events.  So, two obvious limitations that we decided to address:

1. We wanted to allow other types of "behaviors" to be provided - not
limit the solution to AjaxBehavior.
2. We wanted to allow components other than
EditableValueHolders/ActionSources to host "behaviors".

In order to address #1, we introduced the generic
javax.faces.component.behavior.Behavior class.  The class provides the
base contract for all behavior implementations.  Note that early on we
decided that a "behavior" was something distinct from a "component".
Behaviors, like converters/validators, are objects that are attached to
existing components in order to enhance the component with functionality
that is not provided by the component itself.

The main responsibility of a Behavior implementation is to cough up a
script - ie. a bit of JavaScript code that can be attached to one of the
component's client-side event handlers (eg. attach to "onclick").  This
responsibility is implemented via the Behavior.getScript() method.

In order to address #2, we introduced the
javax.faces.component.behavior.BehaviorHolder interface.  Components
that want to allow behaviors to be attached implement this interface.
This allows the component to communicate the valid attach points
(getEventNames()) and the default attach point (getDefaultEventName()),
provides a mechanism for registering behaviors (addBehavior()), and also
provides access to any registered behaviors (getBehaviors()).

While UIComponentBase does not implement the BehaviorHolder interface
itself, it provides default implementations of the BehaviorHolder
methods in order to make it easier for subclasses to implement
BehaviorHolder.  The minimal requirement for a UIComponentBase subclass
to implement BehaviorHolder is to provide an implementation of
getEventNames() that returns a non-empty set of the event names
supported by the component.

These two contracts, Behavior and BehaviorHolder, form the foundation of
our new component behavior solution.  Hopefully the above should be
familiar since it has been discussed the number of times on the EG list
and was also covered in Appendix C of the recent spec drafts.   The
actual set of APIs that we need has grown over the last few months, so I
wanted to also discuss some of the more recent additions...

* BehaviorRenderer

Once we got the core Behavior/BehaviorHolder contract in place, we
(Roger, Ted, Alex and I) quickly realized that additional flexibility
was needed.  In particular, we felt that the scripts that are produced
by Behaivor implementations may need to vary based on the RenderKit.  In
order to support RenderKit-specific Behavior script generation, we
followed the existing UIComonent/Renderer pattern and introduced a
BehaviorRenderer API.  BehaviorRenderers are similar in spirit to
component Renderers, but provide a contract that is geared towards
Behaviors.  So, while component Renderers are designed for HTML content
generation and write directly to the ResponseWriter, BehaviorRenderers
simply cough up a script - ie. the main API on BehaviorRenderer is
getScript() (mirrors Behavior.getScript()).

Of course, as with component Renderers, BehaviorRenderers are entirely
optional.  A Behavior implementation does not need to use a
BehaviorRenderer at all - it can simply override Behavior.getScript()
and produce the script locally.

* Behavior Event Handling

The next enhancement that we tackled was the ability for Behaviors to
participate in decoding.  This was necessary in order to support a very
important use case: the ability for Behavior implementations to deliver
events to registered listeners.  The main case that we had in mind was
AjaxBehavior, ie. we wanted to make it possible to do this:

  &lt;h:commandButton&gt;
      &lt;f:ajax event="mouseover"
listener="#{bean.doSomethingInResponseToMouseOver}"/&gt;
  &lt;/h:commandButton&gt;

In order to support this we added the following APIs:

- Behavior.decode()
- BehaviorRenderer.decode()
- Behavior.broadcast()
- BehaviorEvent (extends FacesEvent)
- BehaviorListener (extends FacesListener)

We also specified the mechanism/conditions under which BehaviorHolder
components must give attached Behaviors the opportunity to decode.

* BehaviorBase

Around this time we also introduced a BehaviorBase base class that
provides base functionality for Behavior implementations (such as
listener registration, event broadcast support, BehaviorRenderer
delegation wiring).  BehaviorBase is to Behavior what UIComponentBase is
to UIComponent.

* Behavior.Parameter

As we started integrating the new behavior contract with our existing
renderers, we realized that Behavior/BehaviorRenderer getScript()
implementations may need access to various pieces of information to help
them generate the correct scripts.  For example, in the h:commandButton
case, the component may have f:params attached.  These f:param
names/values must be included in the request, whether the request is a
full page postback provided by the component, or an Ajax postback
provided by the AjaxBehavior.  In order to support this case, we added a
trivial static inner Parameter class to Behavior.  This allows
components/renderers to pass (resolved) parameter name/values into
Behavior.getScript().

* BehaviorContext

At this point we realized that there is danger in adding more arguments
to the Behavior.BehaviorRenderer.getScript() methods.  The problem is
that we may not be able to foresee all of the possible information that
getScript() implementations may need access to.  Rather than risk having
to later define new overrides of getScript(), we decided to introduce a
BehaviorContext class.  The BehaviorContext is used to pass information
(FacesContext, component, parameters, source id) into
Behavior.getScript().  If we find that we need to pass additional
information into getScript() in a later release, we can do so by adding
new methods to the BehaviorContext.

BehaviorContext is defined as an abstract class, but provides access to
a implementation via the BehaviorContext.createBehaviorContext() factory
method.  Note that we explicitly avoid going through the FactoryFinder
mechanism here since this is a trivial data transfer object - and one
which may need to be instantiated many times during a typical request -
so we want to keep the overhead low.

I keep going back and forth as to whether Behavior.decode() should also
take a BehaviorContext.  Currently it just takes a FacesContext and the
UIComponent.  I am tempted to pass in the BehaviorContext instead,
though certain information on the BehaviorContext (like the parameters)
are clearly specific to script generation.

* BehaviorHint

Another issue that arose while integrating Behavior support into
h:commandButton is that the component renderer may itself need to vary
its content depending on whether or not it has a Behavior attached, and
in particular depending on whether that Behavior provides a script that
performs a postback.  The issue here is that certain renderers - eg.
commandButton/Link renderers - may generate their own postback scripts
(in Mojarra these renderers generate calls to mojarra.jsfcljs()).
However, when an AjaxBehavior is attached, it provides its own postback
script that should replace/suppress the postback script that the
component renderer normally produces.  Since not all Behavior
implementations actually perform postbacks (AjaxBehavior does, but most
won't), the component renderer needs some way to determine whether or
not an attached Behavior is going to perform a postback.

In order to solve this problem, we added a new enum, BehaviorHint, and a
new method to Behavior: Behavior.getHints().  getHints() returns a
Set&lt;BehaviorHint&gt; (implemented under the covers as an EnumSet of course)
that provides information about the Behavior that the consuming
component/renderer may be interested in.

At the moment, the BehaviorHint enum only defines a single value -
BehaviorHint.SUBMITTING.  However, we chose to use an enum rather than a
boolean (ie. rather than a Behavior.isSubmitting() method) to allow for
additional hints in the future.  If people feel that it is too awkward
to have a single-valued enum in our API, please let me know.  We can
consider reverting to a boolean method, though an enum is more future
proof.

* Behavior configuration

In order to provide complete support for configuring Behavior and
BehaviorRenderer implementations, we had to touch a number of places,
including:

- javax.faces.application.Application now supports methods for adding
and creating Behavior instances
- faces-config.xml now supports &lt;behavior&gt; and &lt;behavior-renderer&gt;
elements
- We have added annotations for identifying Behavior and
BehaviorRenderer implementations so that faces-config entries are not
required
- The Facelets taglib file now supports &lt;behavior&gt; tags.

In all cases we followed the precedents already set by
converter/validator.

* Standard HTML component BehaviorHolders

Finally, once we had agreement our generic Behavior solution, we also
decided that it was silly not to enhance the standard HTML component set
to take advantage of this.  Most of the standard HTML components now
implement BehaviorHolder and thus allow Behaviors to be attached.  The
attach points for the standard HTML components correspond to the
standard "on&lt;Event&gt;" attributes.  So, whereas before it was only
possible to attach behaviors to EditableValueHolder/ActionSource
components, it is now possible to attach Behaviors to other standard
components, eg. &lt;h:panelGroup&gt;:

  &lt;h:panelGroup&gt;
      &lt;f:ajax event="mouseover" listener="#{bean.foo}"/&gt;
  &lt;/h:panelGroup&gt;

This gives us significantly more flexibility - and a much more powerful
solution than we had outlined in our original plans.

One quick note on event names... The event names/attach points do not
include the "on" prefix that is used in the component attribute names.
So:

      &lt;f:ajax event="mouseover"/&gt;

Not:

      &lt;f:ajax event="onMouseover"/&gt;

The standard ActionSource components still support a logical "action"
event/attach point.  And the standard EditableValueHolder components
still support a logical "valueChange" event/attach point.  This allows
page authors to attach Behaviors to these components without having to
be aware of the unerlying DOM event that triggers the action/value
change.  Also note that the "action" and "valueChange" events are
defined as default events for these components, which makes it possible
to do omit the event attribute, eg:

   &lt;!-- Fires Ajax requests in response to actions --&gt;
   &lt;h:commandButton&gt;
      &lt;f:ajax/&gt;
  &lt;/h:commandButton&gt;

  &lt;!-- Fires Ajax requests in response to value changes --&gt;
  &lt;h:inputText&gt;
      &lt;f:ajax/&gt;
  &lt;/h:inputText&gt;

BTW, Jeffrey Stephenson (JSR-276) and I have been having some offline
discussions on the possibility of getting event name/default event name
metadata in place.  This would clearly help the development tool
experience.

* Limitations

While I think that the Behavior API is a great addition to JSF, there
are a few limitations that we have not been able to address for 2.0.
These include:

1. Custom renderer wiring

Implementing the BehaviorHolder contract is trivial.  However, actually
rendering the Behavior scripts - possibly multiple scripts which may
need to be chained with other component/renderer-defined scripts - can
be tedious.  To help simplify this, we have introduced a new utility
method into our JavaScript API: jsf.util.chain().  This method takes an
arbitrary number of script arguments and executes each one until it
finds one that returns false, at which point it short-circuits.  While
this simplifies things somewhat, it is still nontrivial for a Renderer
author to produce the proper call to jsf.util.chain().

If we had more time, I would recommend trying to get some utility
methods into the JSF API so that we can make it easier for custom
Renderer authors to produce the properly chained scripts.  However,
given how little have time we have left, I do not think that we have
time to get this right.  My current plan is to try to provide some open
source utilities to help Renderer authors solve this problem.  Once
we've worked out the right APIs in open source, I am hoping that we can
incorporate these back into the 2.1 spec.

2. Behavior attribute-property transparency

I have been thinking that, like components, Behaviors should expose an
attribute map that provides attribute-property transparency.  That way,
BehaviorRenderers do not have to worry about the actual Behavior type -
they can simply grab attributes out of the attribute map.

I briefly considered implementing this functionality, but after a quick
look at UIComponentBase.AttributeMap I got scared away.  I think the
right solution is to:

- Break UIComponentBase.AttributeMap out into its own top-level public
class.
- Introduce an AttributeHolder contract
- Have UIComponentBase and BehaviorBase implement AttributeHolder and
use AttributeMap to hold their attributes.

However, for obvious reasons I decided not to push this for 2.0.
Perhaps we can think about this for 2.1.

Since we do not have a Behavior.getAttributes() API, at the moment,
BehaviorRenderer implementations are forced to cast to the actual
Behaivor type (eg. AjaxBehaviorRenderer casts the Behavior to
AjaxBehavior).  I am not happy about this, but willing to live with it
for now.

3. Behavior resources

Behavior implementations clearly are going to want to pull in JavaScript
libraries so that these do not need to be pulled in explicitly by the
application developer.  However, at the moment we do not have a
solution/recommendation for this.  (Well, there might be some solution -
just haven't identified what it is yet.)

This is another one that will need to wait for 2.1.

I think that's it!  If you have any questions/comments on this new API,
please follow up here.

I am hoping to do some blogging on all of this if I can ever find the
time. :-)

Andy



        </pre>
      </blockquote>
      <pre wrap="">

      </pre>
    </blockquote>
    <pre wrap="">
    </pre>
  </blockquote>
  <pre wrap=""><!---->

  </pre>
</blockquote>
<br>
</body>
</html>