[ 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]