Good point, Davor. The way I've used flash persistence it could just as well have been session persistence. The effect would be identical.

* Perhaps what we really need is @Persist("redirection")?!?!?!

It's a serious suggestion. After all, what we're aiming for is persistence during a redirection and only during a redirection. We don't want persistence after arriving from PageLink or browser Reload/ Refresh because it causes anomalies (and that's why Mk VI uses cleanupRender()). Even better, redirection-persistence could be keyed by a temporary conversation id behind the scenes.

What does everyone think?

* Mk VI might be unacceptable in clustered environments, because it uses server-side persistence, requiring session replication traffic. In that situation I guess the options are either the Mk V solution or some sort of client-side persistence - hidden fields, @Persist("client"). or something new.

As for your generic editing, I like it. It's exactly where I wanted to take this once we have the possible solutions codified. Perhaps an @EditPage annotation rather than a superclass would be even nicer?

Cheers,

Geoff

On 30/01/2008, at 1:15 AM, Davor Hrg wrote:

cleanupRender is not a fix for flash persistence, it's more like
replacement for it.
flash persistence is made for the same reason (only persisting until
next request)

you can take your example even further and make it generic
thus allowing actual edit page to be as simple as:

public class EditCompany extends EntityEditPage<Company, Long>{

   @Override
   protected Object getNextPage() {
       return ListCompany.class;
   }

}


the generic edit page I'm working on
gets entity class like this:

   @SuppressWarnings("unchecked")
   public AbstractEntityEdit() {
       Type genericSuperclassType = getClass().getGenericSuperclass();
       if((genericSuperclassType instanceof ParameterizedType)){
           ParameterizedType genericSuperclass = (ParameterizedType)
genericSuperclassType;
if(genericSuperclass.getActualTypeArguments()[0] instanceof Class){
               this.persistentClass = (Class<T>)
genericSuperclass.getActualTypeArguments()[0];
               this.idClass = (Class<T_ID>)
genericSuperclass.getActualTypeArguments()[1];
           }
       }
   }

uses Session to load entity when needed,
persists only entityId as string
uses TypeCoercer to convert string to "idClass" before calling session.get()

resets the form if cancel button is pressed or entityId changes

Davor Hrg


On Jan 29, 2008 2:48 PM, Geoff Callender
<[EMAIL PROTECTED]> wrote:
Thanks for all the comments.  They've been invaluable.  Below is the
result, Mark Vi.

Kalle, I'm using T5.0.9, but I think 5.0.7 would behave similarly.
Yes, I'm trying frantically to keep up with the releases!

As Davor pointed out, if validation has failed then getting the entity
again doesn't overwrite the form in recent releases.  I believe,
however, that this only works if you keep everything that can fail in
the onValidate... methods, eg. changePerson is called in
onValidateFromForm instead of in onSuccess for this very reason.

As Martin pointed out, I can avoid getting the entity every time in
onActivate if I use @Persist("flash"), test for null entity in
onActivate, and nullify "flash" fields in cleanupRender, ie. right
before the page is displayed.   The reason for the last bit is that
sometimes there's only one onActivate before a page is displayed, so
an attempt to refresh the page won't work because the entity is still
in flash-persistence. A second attempt would work, which is very
disconcerting.

Davor, I like Martin's cleanupRender effect, so I don't think the "new
window" problems you describe occur, and therefore I don't think I
need the @Meta form annotation.  Have I missed a corner-case here?

If you're using BeanEditForm, just replace "Form" with "BeanEditForm".

       private Long _personId;

       @Persist("flash")
       private Person _person;

       @Component(id = "form")
       private Form _form;

       @InjectPage
       private NextPage _nextPage;

       void onActivate(Long id) throws Exception {
               _personId = id;
               if (_person == null) {
_person = getPersonService().findPerson(_personId);
               }
       }

       Long onPassivate() {
               return _personId;
       }

       void onValidateFromForm() {
if (...a bit of validation logic detects an error...) {
                       _form.recordError(...);
                       return;
               }
// todo: move this next block back to onSuccess() once TAPESTRY-1972
has been resolved.
               try {
                       getPersonService().changePerson(_person);
               }
               catch (Exception e) {
_form.recordError(ExceptionUtil.getRootCause(e));
               }
       }

       Object onSuccess() {
               _nextPage.onActivate(_personId);
               return _nextPage;
       }

       void cleanupRender() {
               _form.clearErrors();
// Clear the flash-persisted fields to prevent anomalies in
onActivate when we hit refresh on page or browser button
               _person = null;
       }

and of course the hidden version field stuff still applies (it ensures
optimistic locking works, preventing us saving changes to a Person
that has since been updated or deleted by someone else or by us in
another of our windows or tabs):

               <t:hidden t:id="version" value="person.version"/>

or if you're using BeanEditForm:

<t:beaneditform t:id="form" object="person" submitLabel="Save">
               <t:parameter name="version">
<t:hidden t:id="version" value="person.version"/>
               </t:parameter>
       </t:beaneditform>

Any more thoughts?

Geoff



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Reply via email to