You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Cherry Development <av...@cherrydev.com> on 2003/11/13 10:24:50 UTC

(LONG) Over-persistent/Under-persistent pages

***PRE-AMBLE***
This is a long post.  It will probably be of most interest to those who 
have used other web development frameworks most similar to WebObjects 
in the past.  Without any doubt, all of the problems I'm having I could 
work around by fundamentally shifting the way that I build web 
applications to explicitly store more state inside my Visit.  I feel, 
though, that information specific to the interaction between two pages 
should not be stored there, but only information specific to the user 
session as a whole.  I am, without a doubt, trying to use Tapestry in a 
manner that is not common.  I'd like to think, though, that by 
discussing the problems I'm having in the context of HOW I am trying to 
use Tapestry, more flexible ways of using it can be found.
******

I feel like I must be terribly confused about something...
I have a page with a persistent property on it that gets altered when 
the page is rendered.
If I move to another page, then move back to that first page, I get an 
error:
Page recorder for page <...> is locked after a commit(), but received a 
change to property <...> of component <...>

Now, I've done my reading on how page recorders work and I understand 
when an error of this kind SHOULD happen.

But after figuring out why it's happening me, I've now come to the 
realization that I might not understand at all how pages with 
persistent properties are supposed to be used.

What I assumed was, more or less, that if a page with persistent 
properties was not used in subsequent requests, the page no longer 
'held on' to those properties, even when used in the same session.  I 
assumed that if you wanted to hang on to that particular state to 
perhaps use again, get a reference to its page recorder and use it to 
rollback() the page when you need it like that again.

What I realized in the investigation of this problem, though, is that 
within a session, there can really only be one 'virtual' instance of 
that page.  What I mean by a 'virtual' instance is an 
instance+pageRecorder.  Each page basically becomes a singleton within 
the scope of a session.  Also, if you want to make changes to the page 
after its been used once, you have to explicitly unlock the page 
recorder.

As I've mentioned before, I came to Tapestry from writing WebObjects 
applications. If you wanted a page, you'd instantiate one.  There was 
no concept of persistent properties as they are in Tapestry.  If you 
wanted to hang on to the state of that page to use it again in a later 
request, you simply made a reference to the page and later fed it to 
the cycle when you wanted to use it again, since it wouldn't be changed 
unless it became involved in a cycle.

I guess what I want is something in between Tapestry's not-persistent 
properties, and its fully-persistent properties.  I want properties 
that will stick around to be used in an action listener with that page 
(not necessarily dynamic ones involved in a rewind) but I don't want 
them there the next time I do a cycle.getPage() or use a PageLink.

Example:

I have two pages.

One lists a bunch of items in a foreach and has action links on these 
items to do various things.  Say one of these things would potentially 
delete the object.  Call this page A.

I have a confirmation page.  It is meant to be generic, not tied to a 
particular use. Call it page C. I have a special action listener that 
is created with parameters naming the page that called it, the state of 
the page when it was called, and the name of a callback listener to 
invoke if the user clicks the 'Confirm' button.  Call this action 
listener L.  This action listener gets the confirmation page and sets 
it up, storing this information in persistent properties.

The user clicks the 'confirm' button, and the 'confirm' action listener 
on looks up the page that called C (A), restores its state to what it 
was when L was called and invokes the callback that was specified.

At least this is what I thought should happen originally.  As I'm sure 
any Tapestry vet would know, there's no need to store the state of A as 
it was when it calls L, so long as the relevant properties are marked 
as persistent.  Ahh, but as you'll remember, I used a foreach to 
identify which 'delete' button had been clicked on.  These means that 
the most important property (the one referencing which item was 
'current' when the delete button was clicked) was a so-called 'dynamic' 
property.  One whos value changes during page rendering.  A dynamic 
property cannot be persistent because the next time the page gets 
rendered, the page recorder will prevent it from being changed, and 
give me the error I got above.

A bizarre, but possibly useful way I think of to get around this is as 
follows:
Do not make the dynamic property in the foreach persistent.
Have the listener L serialize the state of page A when it is called 
(when the dynamic property is still set to the 'correct' value) and 
save it.  When we want to return to the page to make the callback, 
deserialize the page and feed it to the cycle.  We've now effectively 
cloned the page.  Will it get properly returned to the page pool (and 
possibly culled) at the end of the cycle?  Looks like this wouldn't 
work, since a cycle only cleans up after pages that it, itself loaded.

Another, more general tactic:
Allow an instance of a page to be detached from the pool.  It no longer 
gets re-set to its 'pristine' state and will not be returned to the 
pool at the end of a cycle.  It could be tucked away inside of an 
action listener, or in the visit, wherever you want it, and could later 
be fed back to a Cycle to be rendered.  Therefore, an action listener 
could notify the cycle somehow that it wants exclusive access to a page 
and its exact state and beyond that point, the cycle wouldn't touch it, 
nor return it to the page pool.

A peak at the source code shows that this could perhaps be easily done 
with a change to RequestCycle.  Urg.  Okay, _loadedPages is a private 
Map, so I can't access it from a subclass without using nasty, nasty 
reflection tricks.  Maybe I'll try this out, though.  Give my modified 
sub-class an orphanPage(IPage page) method.

If you've read this far, I thank you. :)  You now share my bumpy 
learning experience.  If you have questions as to why I wish to go 
about things in the manner I've written of, please ask and I'll do my 
best to try to explain them.  Perhaps I may discover a new methodology 
that seems as natural to me as the one I currently use.  Maybe 
vice-versa.

Thanks,

Avi


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: (LONG) Over-persistent/Under-persistent pages

Posted by "Ido M. Tamir" <ta...@imp.univie.ac.at>.
On Thursday 13 Nov 2003 10:24 am, Cherry Development wrote:
> ***PRE-AMBLE***
> This is a long post.  
to long for me, I hope I understood something from your problem

maybe the threads:

page vs. visit?

and

(newb) how NOT to persist TextField value?

are of help.

best wishes

Ido





---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org