[ I suspect this is going to break threading....  Is there a good way to respond
to a message from a digest without breaking threading? )

Adam Hardy on 26/04/08 10:42, wrote:
> I am pulling in what I wrote earlier because I should correct what I said
> about letting entities slip out of scope. Following this situation:
>
> - Model-driven builds the model
> - conversion to type and setting incoming HTTP param into Model
> - validation occurs and fails
>
> the problem was spurious JPA updates - which can be avoided by putting an
> interceptor in between the Validation and the Workflow interceptors: all it
> should do is call EntityManager.clear().
>
> if (validationAwareAction.hasErrors()) getEntityManager().clear();
>
>
> Using the JPA extended persistence context (not EJB), the clear() will
> eliminate any changes to the model before JPA comes to flush to the db. I
> assume it would work in an EJB container too.
>
> Does that fit your situation, Eric?

Unfortunately no.  First clear is overkill, it evicts everything from the
session, and only the model may need to be evicts (Users could have other items
already merged back into the session at this point -- normally I would have
merged my User entity from the HTTP Session to the Persistence session by this
point in the interceptor stack to allow authentication/authorization checks).

Secondly replacing the clear() with evict(((ModelDriven) action).getModel()) for
instance would avoid that problem, but now you would lost the ability to lazy
load anything from the model if needed for form redisplay.

I'm 90% of the way to an initial solution right now, using two extra
interceptors:
ModelDrivenProtection
ModelDrivenEnable
(I need better names....)

The first one is placed in the stack after prepare.  The second one is placed
after validation.

In my Hibernate based implementation of them:
Protection calls session.setReadOnly(modelDrivenAction.getModel(),true) if the
action also implements ValidationAware

Enable calls session.setReadOnly(modelDrivenAction.getModel(),false) if
 hasErrors() returns false

I'm hoping I can come up with a more JPA provider agnostic version, after I get
this pair working.  However as the JPA spec doesn't include a notion of
readOnly, I think its going to have to be a custom version of the
JPAValidationInterceptor extends ValidationInterceptor--

Steps are something like
doIntercept(...) {
if (actionInvocation.getAction() instanceof ValidationAware &&
     actionInvocation.getAction() instanceof ModelDriven) {
  ValidationAware validationAwareAction = (ValidationAware)
actionInvocation.getAction();
  ModelDriven modelDrivenAction = (ModelDriven) actionInvocation.getAction();
  em.setFlushMode(FlushMode.COMMIT)
  String retVal = super.doIntercept(...);
  if (validationAwareAction.hasErrors()) {
    em.evict(modelDrivenAction.getModel());
    // check for preparable and recall prepare to get a clean object back on the
stack -- need to make sure hasErrors() still returns true though....
    // push the request parameters onto the stack ahead of the model for
redisplay of submitted values, while letting the model fill in others)
  }
  em.setFlushMode(FlushMode.AUTO);
  return retVal;
}

I like the hibernate version better since the "persistence read only" is exactly
the correct semantics for a failed-validation model object.  The generic JPA is
nicer in that its not vendor specific, but much more kludgy.  In rather
generalize it a bit more -- more the em.setFlushMode, em.evict calls to some
interface and now we're to a more correct model driven situation:
a) the backing model object will never contain invalid values outside of the
scope of params, validation, thisNewInterceptor (possibly built into workflow
or validation)
b) values are still available for redisplay.
c) the three callback functions (setReadOnly, setWriteable, replaceModel) or
similar can be hooked up to different backing stores... allowing any lazy load
or other similar special behavior provided by the data store to work
transparently.

This completely generalized version is the version that I would want to suggest
for inclusion in Struts 2, but I'll need to work through the first two
approaches first to gain some confidence.

Eric

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

Reply via email to