You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Dirk Dittert <ta...@gmx.de> on 2005/06/21 11:51:16 UTC

Tapestry Design Best Practices question

Hi,

I am still trying to figure out the Best Practices for Tapestry  
applications.

Here's the problem: Suppose you want to manage users of some  
application with a couple of web pages (create, edit, view). Here I'd  
like to focus on on create + edit.

The general flow of control right now is:

UserList page
+--> listener for click on "edit" link
+--> listener for click on "add" link

I'd like to be able to reuse the "add" page as an "edit" page.  
Therefore, I keep a hidden field (called userId) in the form with the  
user data. That way, I can later decide whether the EditUser page is  
called because of an "add" (userId == null) or an "edit" (userId !=  
null). So much about the setup.

I use property definitions in my page like the following:

     <property-specification name="user" type="xy.User" />
     <property-specification name="userId" type="java.lang.Long"/>

The idea is that Tapestry automatically calls all necessary getters  
and setters (e.g. user.getFirstName() ...)

The problem I have, now shows when the form is submitted. I have to  
implement a pageBeginRender method to provide Tapestry with a user  
instance that it can use to store the values of the form in. For an  
"add" page, I simply create a new empty user instance. However, with  
an edit page, I'd like to have Tapestry set the properties on the  
appropriate user object (the one that belongs to the user id in the  
hidden field). As I understand the framework, properties aren't set  
in pageBeginRender yet so that I can't just look up the user for the id.

So what is the right way to handle that kind of problem?

1. Use a hashmap that receives all the values from the form and  
create/update the user object in the listener method? This seems to  
violate the simplicity idea of the framework, because I'd have to  
generate that hashmap from a user object so that the form fields can  
be set and later on copy the values back into a user object.

2. Use a "fake" user object for Tapestry to set the values and copy  
values to the real user object in case of an edit? This approach is  
only a little more elegant (saves the hashmap + I don't need to copy  
values in case of an "add").

3. ?

I'd be really glad if someone could shed a little light on how to  
solve this kind of problem. Somehow I have the feeling that I am  
missing something obvious...

Thanks for your help,

Dirk Dittert
-- 
Don't Program by Coincidence
Rely only on reliable things. Beware of accidental complexity, and  
don't confuse a happy coincidence with a purposeful plan.
     The Pragmatic Programmer



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


Re: Tapestry Design Best Practices question

Posted by Robert Zeigler <ro...@scazdl.org>.
Well... you're two options are really to pull the info from the db
again, or store it in the session.  If you need the speed, the session
is probably the way to go.  If you're reluctant to put the information
in the session due to memory issues, one possible solution is to only
keep the object persistent in the session as long as you need it.
You could use a persistent page property.  Once the user is done on the
page/form, you can call the "forgetPage" method of the engine object
which will remove the object from the session.
The dilemma comes when the user navigates away from the page in an
unclean fashion, but in that case, you could probably do something
tricky with ajax, like use an xtile component, and have the send
function get called in a window.unload handler. You could "forget" the
page that way. You would need to come up with a way to distinguish
between, say, form submits and the user navigating off to somewhere else
since the unload event won't know the difference between the two.  Just
some ideas off the top of my head... anybody else?

Robert

sj wrote:
> Hi, 
> 
> I faced the same problem too, But however I feel this is imapcting the
> performance as in my case, I have a very big form containing lot of
> information abt the object and its related objects. Every time the
> page refreshes due to some small change, I am having to reload all the
> data from DB to keep the state correct using the object ID. I have
> kept the object Id as persistent property and all other data as
> non-persistent(as there will be too much held in session).
> 
> However this page is taking a few seconds to load. Is there something
> I am doing wrong? Please suggest.
> 
>  
> 
> On 6/21/05, Dirk Dittert <ta...@gmx.de> wrote:
> 
>>Am 21.06.2005 um 12:24 schrieb Robert Zeigler:
>>
>>
>>>Use the hidden component to store the user id, make sure it is placed
>>>before the other information in the form. The hidden component has a
>>>listener parameter that will be called on rewind.  The userid value
>>>will
>>>be set when this is called, and it will be called before the other
>>>fields are updated.  Reinstantiate your user from the id in the
>>>listener.
>>
>>Ah, you're right. Seems like I wasn't the only one with this problem:
>>
>>"A listener that is informed after the value parameter is updated.
>>This allows the data set operated on by the rest of the Form
>>components to be synchronized to the value stored in the hidden field.
>>A typical use is to encode the primary key of an entity as a Hidden;
>>when the form is submitted, the Hidden's listener re-reads the
>>corresponding entity from the database." (documentation parameter of
>>the Hidden component).
>>
>>
>>
>>>Providing your own data squeezer is, imo, the better practice
>>>because it
>>>solves your problem once and permanently. :)
>>
>>I guess that's the way I am going to go. Thanks for your help!
>>
>>Best,
>>
>>Dirk Dittert
>>--
>>Don't Assume -- Prove It
>>Prove your assumptions in the actual environment -- with real data
>>and boundary conditions.
>>    The Pragmatic Programmer
>>
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
>>For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>>
>>
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


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


Re: Tapestry Design Best Practices question

Posted by Robert Zeigler <ro...@scazdl.org>.
There are another couple of potential options, though may or may not be
faster. ;) You could pass the object instead of the object id into the
hidden field, and /not/ use a custom adapter, and make your class
serializable. This may work for your scheme, if you're posting the data.
You could also use a custom adapter that saves the more costly
information and looks up the rest.
If your page is really taking that long to load, you might consider
double checking queries, etc.  I had a (non tapestry) page that used a
very complex join that would take take 10-20 seconds to run with more
than a couple-hundred records in the db; I rewrote the lookup routine to
skip the join and shaved the loading time to a couple of seconds.
Certainly something to consider.

Robert

sj wrote:
> Hi, 
> 
> I faced the same problem too, But however I feel this is imapcting the
> performance as in my case, I have a very big form containing lot of
> information abt the object and its related objects. Every time the
> page refreshes due to some small change, I am having to reload all the
> data from DB to keep the state correct using the object ID. I have
> kept the object Id as persistent property and all other data as
> non-persistent(as there will be too much held in session).
> 
> However this page is taking a few seconds to load. Is there something
> I am doing wrong? Please suggest.
> 
>  
> 
> On 6/21/05, Dirk Dittert <ta...@gmx.de> wrote:
> 
>>Am 21.06.2005 um 12:24 schrieb Robert Zeigler:
>>
>>
>>>Use the hidden component to store the user id, make sure it is placed
>>>before the other information in the form. The hidden component has a
>>>listener parameter that will be called on rewind.  The userid value
>>>will
>>>be set when this is called, and it will be called before the other
>>>fields are updated.  Reinstantiate your user from the id in the
>>>listener.
>>
>>Ah, you're right. Seems like I wasn't the only one with this problem:
>>
>>"A listener that is informed after the value parameter is updated.
>>This allows the data set operated on by the rest of the Form
>>components to be synchronized to the value stored in the hidden field.
>>A typical use is to encode the primary key of an entity as a Hidden;
>>when the form is submitted, the Hidden's listener re-reads the
>>corresponding entity from the database." (documentation parameter of
>>the Hidden component).
>>
>>
>>
>>>Providing your own data squeezer is, imo, the better practice
>>>because it
>>>solves your problem once and permanently. :)
>>
>>I guess that's the way I am going to go. Thanks for your help!
>>
>>Best,
>>
>>Dirk Dittert
>>--
>>Don't Assume -- Prove It
>>Prove your assumptions in the actual environment -- with real data
>>and boundary conditions.
>>    The Pragmatic Programmer
>>
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
>>For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>>
>>
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


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


Re: Tapestry Design Best Practices question

Posted by The Chris Method <th...@gmail.com>.
If your app necessitates that you reload the data to keep the state correct, 
then there's not much you can really do from the Tapestry side of things. It 
seems like your solution would like in DB/persistence layer caching.

On 6/21/05, sj <my...@gmail.com> wrote:
> 
> Hi,
> 
> I faced the same problem too, But however I feel this is imapcting the
> performance as in my case, I have a very big form containing lot of
> information abt the object and its related objects. Every time the
> page refreshes due to some small change, I am having to reload all the
> data from DB to keep the state correct using the object ID. I have
> kept the object Id as persistent property and all other data as
> non-persistent(as there will be too much held in session).
> 
> However this page is taking a few seconds to load. Is there something
> I am doing wrong? Please suggest.
> 
> 
> 
> On 6/21/05, Dirk Dittert <ta...@gmx.de> wrote:
> > Am 21.06.2005 um 12:24 schrieb Robert Zeigler:
> >
> > > Use the hidden component to store the user id, make sure it is placed
> > > before the other information in the form. The hidden component has a
> > > listener parameter that will be called on rewind. The userid value
> > > will
> > > be set when this is called, and it will be called before the other
> > > fields are updated. Reinstantiate your user from the id in the
> > > listener.
> >
> > Ah, you're right. Seems like I wasn't the only one with this problem:
> >
> > "A listener that is informed after the value parameter is updated.
> > This allows the data set operated on by the rest of the Form
> > components to be synchronized to the value stored in the hidden field.
> > A typical use is to encode the primary key of an entity as a Hidden;
> > when the form is submitted, the Hidden's listener re-reads the
> > corresponding entity from the database." (documentation parameter of
> > the Hidden component).
> >
> >
> > > Providing your own data squeezer is, imo, the better practice
> > > because it
> > > solves your problem once and permanently. :)
> >
> > I guess that's the way I am going to go. Thanks for your help!
> >
> > Best,
> >
> > Dirk Dittert
> > --
> > Don't Assume -- Prove It
> > Prove your assumptions in the actual environment -- with real data
> > and boundary conditions.
> > The Pragmatic Programmer
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> >
> >
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> 
>

Re: Tapestry Design Best Practices question

Posted by sj <my...@gmail.com>.
Hi, 

I faced the same problem too, But however I feel this is imapcting the
performance as in my case, I have a very big form containing lot of
information abt the object and its related objects. Every time the
page refreshes due to some small change, I am having to reload all the
data from DB to keep the state correct using the object ID. I have
kept the object Id as persistent property and all other data as
non-persistent(as there will be too much held in session).

However this page is taking a few seconds to load. Is there something
I am doing wrong? Please suggest.

 

On 6/21/05, Dirk Dittert <ta...@gmx.de> wrote:
> Am 21.06.2005 um 12:24 schrieb Robert Zeigler:
> 
> > Use the hidden component to store the user id, make sure it is placed
> > before the other information in the form. The hidden component has a
> > listener parameter that will be called on rewind.  The userid value
> > will
> > be set when this is called, and it will be called before the other
> > fields are updated.  Reinstantiate your user from the id in the
> > listener.
> 
> Ah, you're right. Seems like I wasn't the only one with this problem:
> 
> "A listener that is informed after the value parameter is updated.
> This allows the data set operated on by the rest of the Form
> components to be synchronized to the value stored in the hidden field.
> A typical use is to encode the primary key of an entity as a Hidden;
> when the form is submitted, the Hidden's listener re-reads the
> corresponding entity from the database." (documentation parameter of
> the Hidden component).
> 
> 
> > Providing your own data squeezer is, imo, the better practice
> > because it
> > solves your problem once and permanently. :)
> 
> I guess that's the way I am going to go. Thanks for your help!
> 
> Best,
> 
> Dirk Dittert
> --
> Don't Assume -- Prove It
> Prove your assumptions in the actual environment -- with real data
> and boundary conditions.
>     The Pragmatic Programmer
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> 
>

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


Re: Tapestry Design Best Practices question

Posted by Dirk Dittert <ta...@gmx.de>.
Am 21.06.2005 um 12:24 schrieb Robert Zeigler:

> Use the hidden component to store the user id, make sure it is placed
> before the other information in the form. The hidden component has a
> listener parameter that will be called on rewind.  The userid value  
> will
> be set when this is called, and it will be called before the other
> fields are updated.  Reinstantiate your user from the id in the  
> listener.

Ah, you're right. Seems like I wasn't the only one with this problem:

"A listener that is informed after the value parameter is updated.  
This allows the data set operated on by the rest of the Form  
components to be synchronized to the value stored in the hidden field.
A typical use is to encode the primary key of an entity as a Hidden;  
when the form is submitted, the Hidden's listener re-reads the  
corresponding entity from the database." (documentation parameter of  
the Hidden component).


> Providing your own data squeezer is, imo, the better practice  
> because it
> solves your problem once and permanently. :)

I guess that's the way I am going to go. Thanks for your help!

Best,

Dirk Dittert
-- 
Don't Assume -- Prove It
Prove your assumptions in the actual environment -- with real data  
and boundary conditions.
     The Pragmatic Programmer


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


Re: Tapestry Design Best Practices question

Posted by Robert Zeigler <ro...@scazdl.org>.
Use the hidden component to store the user id, make sure it is placed
before the other information in the form. The hidden component has a
listener parameter that will be called on rewind.  The userid value will
be set when this is called, and it will be called before the other
fields are updated.  Reinstantiate your user from the id in the listener.
Alternatively, you can provide you own custom data squeezer that
squeezes your user objects into a pk, and unsqueezes it back to the
user.  Then you can skip the listener bit entirely, and instead of doing
<input type="hidden" jwcid="@Hidden" value="ognl:user.id"/>
you would just do
<input type="hidden" jwcid="@Hidden" value="ognl:user"/>
Since you provide a data squeezer for the user type, the net effect is
the same and your user will be automagically restored.
Providing your own data squeezer is, imo, the better practice because it
solves your problem once and permanently. :)

Robert

Dirk Dittert wrote:
> Hi,
> 
> I am still trying to figure out the Best Practices for Tapestry 
> applications.
> 
> Here's the problem: Suppose you want to manage users of some 
> application with a couple of web pages (create, edit, view). Here I'd 
> like to focus on on create + edit.
> 
> The general flow of control right now is:
> 
> UserList page
> +--> listener for click on "edit" link
> +--> listener for click on "add" link
> 
> I'd like to be able to reuse the "add" page as an "edit" page. 
> Therefore, I keep a hidden field (called userId) in the form with the 
> user data. That way, I can later decide whether the EditUser page is 
> called because of an "add" (userId == null) or an "edit" (userId != 
> null). So much about the setup.
> 
> I use property definitions in my page like the following:
> 
>     <property-specification name="user" type="xy.User" />
>     <property-specification name="userId" type="java.lang.Long"/>
> 
> The idea is that Tapestry automatically calls all necessary getters  and
> setters (e.g. user.getFirstName() ...)
> 
> The problem I have, now shows when the form is submitted. I have to 
> implement a pageBeginRender method to provide Tapestry with a user 
> instance that it can use to store the values of the form in. For an 
> "add" page, I simply create a new empty user instance. However, with  an
> edit page, I'd like to have Tapestry set the properties on the 
> appropriate user object (the one that belongs to the user id in the 
> hidden field). As I understand the framework, properties aren't set  in
> pageBeginRender yet so that I can't just look up the user for the id.
> 
> So what is the right way to handle that kind of problem?
> 
> 1. Use a hashmap that receives all the values from the form and 
> create/update the user object in the listener method? This seems to 
> violate the simplicity idea of the framework, because I'd have to 
> generate that hashmap from a user object so that the form fields can  be
> set and later on copy the values back into a user object.
> 
> 2. Use a "fake" user object for Tapestry to set the values and copy 
> values to the real user object in case of an edit? This approach is 
> only a little more elegant (saves the hashmap + I don't need to copy 
> values in case of an "add").
> 
> 3. ?
> 
> I'd be really glad if someone could shed a little light on how to  solve
> this kind of problem. Somehow I have the feeling that I am  missing
> something obvious...
> 
> Thanks for your help,
> 
> Dirk Dittert


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


Re: Tapestry Design Best Practices question

Posted by Kent Tong <ke...@cpttm.org.mo>.
Dirk Dittert <tapestry4dirk <at> gmx.de> writes:

> 2. Use a "fake" user object for Tapestry to set the values and copy  
> values to the real user object in case of an edit? This approach is  
> only a little more elegant (saves the hashmap + I don't need to copy  
> values in case of an "add").

I think this is a better solution than using a listener of a
Hidden component to fetch the object. As you prefer the latter,
I suppose that you're using a O/R mapping tool that allows
you to modify a persistent object in place. However, this
will not allow you to perform validation on the whole object 
before deciding to save it.

--
Author of an e-Book for learning Tapestry (http://www.agileskills2.org/EWDT)


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