In last week's Interfaces concall we discussed the need for allowing a
producer to manage state at the scope of the Consumer's Request
Lifecycle. There is hesitation to add such semantic without well
defined use cases. I had offered up a Partial Portlet Rendering
mechanisim as an example whereby state needed to flow from the action
to the render but then go out of scope. However, during discussions
we uncovered other wsrp related issues that make such a mechanism
unlikely to be easily supported. At the time I was unprepared to offer
additional use cases and hence suggested we drop the discussion [from
2.0]. I would like to make one last pitch for its consideration. And
to cut to the chase, and hopefully accelerate the discussion, I point
to use cases tied to a very specific producer rendering environment,
namely JSF. I suspect however that this rendering environment is not
unique and that other rendering environments have similar
dependencies/needs.
I have been told and assert that JSF can't properly be integrated into
a wsrp based portlet environment because it lacks this notion of
request scope. To accelerate people's understanding of the issues I
ask folks who work for companies that have an interest in and expertise
with JSF to talk to your experts about the expectation and need within
JSF for support of a request scope that spans action handling and
rendering. Because I am not a JSF expert, much of my knowledge and
information is coming from Oracle's JSF team that is telling me JSF and
JSF developers expect/require such a request scope and without out will
not work properly [in those situations where it would be used]. Two
situations that have been pointed out to me include:
- In JSF, submitted action values are moved through a processing
lifecycle that first moves the state from the request into the view
component and then from the view component to the underlying model.
Its not until this last step occurs that the state is managed within
JSF in a manner that it can be saved/restored across requests. There
are situations, however, where state isn't moved from the view
component to the underlying model. One example is when such state
doesn't pass a validation test/conversion. In such a circumstance JSF
expects that state still be available [via the view component] for the
subsequent rendering of this request though not in future requests.
- Many JSF developers/tools rely on a backing bean [model] to
manage state. For example a page's form may be backed by a [generated]
bean with accessors for each field in the form. JSF strongly
encourages that these beans be request-scoped, hence this is the common
practice. From the specification:
It is strongly recommend thatapplication developers
place managed beans that are pointed at by component binding
expressions in “request” scope. This is because placing it in session
or application scope would require thread-safety, since UIComponent
instances depend on running inside of a single thread.
-Mike-
Michael Freedman wrote:
Relying on [producer] session state means you will have false
positives. There are situations in which the subsequent getMarkup
isn't in the same consumer lifecycle as the action [caching is one
simple situation that can cause this]. Having the consumer indicate
the lifecycle you are in should eliminate these. The other issue is
the one you raised about concurrency. With a more formal definition we
can prohibit concurrency or allow the producer to recognize/manage
within it. The session approach because it has neither of these would
behave incorrectly when concurrency situations occurred.
-Mike-
Rich Thompson wrote:
Agreed that such a mechanism could
be
used productively, but it still looks like loading a gun for misuse as
I think the likelihood of render state being stored in such a mechanism
is relatively high. Any reason such an environment couldn't simply
leverage
session state to pass the data (use a well-known key and clear it at
the
end of the render phase)? It seems like this would be more efficient
(the
data doesn't traverse the wire) and eliminate the need to introduce a
new
concept at this stage of v2.
Also, how would such state impact
cachability
of the portlet's fragment? If it is not included in the cache key,
render
might not get called at all (how aggressive is the Consumer cache
policy?).
If it is included (and cleared at end of getMarkup), would a
page/portlet
refresh find the cached record (would we have to require the cache key
be generated after getMarkup returns)?
Rich
On creating a "bad" user experience, this would
be true if this scope is used to hold render state. By render state
I mean any state needed to rerender the portlet across lifecycles.
This
scope should only be used for state that is only needed for the current
lifecyle. What is an example of this? Consider a portlet that
is built on a rendering engine that supports partial rendering [an
ability
to render only what becomes dirty via an action]. Its conceivable
that such an engine will want to retain state to manage this between
the
action and the render. However this state is only pertinent for this
lifecycle. A subsequent consumer page refresh doesn't need this state
-- in general it would just render the whole portlet.
As for your second comment: Yes, considering concurrency requires
a more sophisticated solution in the case that the producer manages the
state. In recognizing that it is currently a rare occurence that
a producer/portlet would use this state and that the consumer would
also
uncommonly be in a situation that executes multiple concurrent requests
on the same portlet [within the same session] I would suggest that for
2.0 we merely disallow it. Allow the producer to register that they
useLifecycleScope and require the consumer to single thread concurrent
requests from the same user [session].
-Mike-
Rich Thompson wrote:
I have several concerns relative to heading in this direction:
1. It
seems like this "feature" would make for a bad user experience.
Consider the common case of an action invocation followed by an
indeterminate
number of page (or portlet) refreshes. Is this scope actually of
action->action
duration, with the relevant impacts on the Consumer, or does the
rerendering
of the portlet lose this state and therefore the markup change in an
unexpected
manner? I suspect the Producer-desired behavior is more likely to
result
in a reasonable user experience if the current types of state (i.e.
session
and navState) are leveraged rather than this new one added.
2. You
call out several possible solutions with their pros and cons. I think
we
would need to carefully consider some of the use cases where either
independent
or a coupled user experience is expected. A couple of these are:
a. Multiple
browsers instances, includes potentially different browser impls (I
have
IE, Mozilla, Firefox and Opera installed) all accessing the same page
(e.g.
same home page, most sharing a single user login).
b. Multiple
pages accessing the same portlet in parallel => coupled experience
if
one of the pages was launched from the other.
c. ...
others?
Rich
When we discussed transient properties I talked about a scope
representing
the extent of a single client request in the consumer. I.e. the
execution
of one complete lifecycle as we define it in wsrp. At the time I
indicated this scope was largely needed by producers to manage portlet
specific (non-shared) data. Because it wasn't a shared thing we
dropped
it. Upon further reflection and after gaining more experience with
adapting environments such as JSF to wsrp I think we would be well
served
to define a mechanism in wsrp 2.0 to facilitate managing producer state
a this scope albeit a mechanism not based on transient properties.
The problem:
Some portlet development models, though distinguishing between an
action
phase and a rendering phase, assume that these phases (typically)
complete within a single request lifecycle. In so doing they rely
on an ability to maintain state between these phases which either
implicitly
or explicitly is removed when the scope ends. Unfortunately wsrp
doesn't provide any means for a producer to detect/manage such a scope.
Two possible solutions:
1. Have the consumer provide
a lifecyle id in the Runtime context. This id is the same for each
call in a single lifecycle but unique for each new lifecyle.
Pluses: Relatively simple and straightforward addition. Relatively
easy for consumers to implement -- for example a consumer could use the
current time as the lifecycle id.
Minuses: Producers detect the termination of scope by recognizing a new
scope has begun. Producers may want/need to account for detecting
termination by inactivity.
2. Introduce a new consumer
managed opaque state concept akin to portlet sessionContext (perhaps
called
requestContext). Like the sessionContext the requestContext is passed
to each lifecycle operation [action, event, render] and returned from
each.
Unlike sessionContext the requestContext would not be a reference;
it would represent the state directly via a binary (opaque) field. At
the beginning of a lifecycle [first call in a lifecycle] the consumer
would
pass a null value [omit] for this field. For the duration of
the lifecyle the consumer would pass whatever the producer had
previously
returned from the previous call in the lifecycle. At the completion
of the lifecycle, the consumer would discard the state.
Pluses: Consumer discards state at end of scope. Producer has
no worries for detecting/managing.
Minuses: (1) Producer needs to be able to prepare its state so it
can be passed as an opaque binary field and receive such. This may
not be something the higher level portlet environment models. (2)
Data sets might be large making it inconvenient/inappropriate to send
across
the wire. (3) If the producer decides to send a reference instead
of the data itself it still has the minuses discussed above. Note it
recongizes
a requestContext whose data is null as an indicator that a new
lifecycle
has started so the previous is out of scope.
-Mike-
---------------------------------------------------------------------
To
unsubscribe from this mail list, you must leave the OASIS TC that
generates
this mail. You may a link to this group and all your TCs in OASIS at: https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To
unsubscribe from this mail list, you must leave the OASIS TC that
generates
this mail. You may a link to this group and all your TCs in OASIS at: https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates
this mail. You may a link to this group and all your TCs in OASIS at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates this mail. You may a link to this group and all your TCs in
OASIS
at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates this mail. You may a link to this group and all your TCs in
OASIS
at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
|