As Carsten mentioned, it starts getting tricky when the write-capabilities of the Sling API are mixed with those of JCR. AFAIU the JcrModifiablePropertyMap is for convenience and thus optimized and limited for the use-case of setting properties on a single node.
Would your problem be solved by a static helper method, accepting a Node and a Map/ValueMap to achieve the same thing, similar convenience and purely on the JCR API? I suppose this could go into the JcrResourceUtil. I.e. something like JcrResourceUtil.setProperties(Node, Map<String, Object>), which does not execute session.save(). WDYT? Regards Julian On Thu, Feb 11, 2010 at 9:22 PM, Vidar Ramdal <vi...@idium.no> wrote: > On Thu, Feb 11, 2010 at 8:40 PM, Carsten Ziegeler <cziege...@apache.org> > wrote: >> Vidar Ramdal wrote: >>> JcrModifiablePropertyMap works by storing all changes in an internal >>> cache. Upon save() the cached changes are written to the >>> javax.jcr.Node, and the node is save()d. >>> >>> This makes sequences such as this impossible: >>> try { >>> // Modify a property through PersistableValueMap >>> PersistableValueMap props = resource.adaptTo(PersistableValueMap.class); >>> props.put("prop", value); >>> props.save(); >>> // Do some other, unrelated changes >>> Node sibling = resource.adaptTo(Node.class).getParent().addNode("child"); >>> sibling.doSomeChange(); // This may throw an exception >>> session.save(); >>> } catch(Exception e) { >>> session.refresh(false); // Cancel the pending changes of this session >>> } >>> >>> The idea is to save all changes to the repository in one single >>> session.save(). If anything fails, the session is reverted. >>> This doesn't work because the properties of PersistableValueMap is not >>> written to the node until PersistableValueMap.save(), and by then, it >>> is too late to revert the session, as the changes of >>> PersistableValueMap are already persisted. >>> >>> We could make such operations easier by introducing a new method >>> PersistableValueMap.write() (in lack of a better name). >>> In case of JcrModifiablePropertyMap, most of save() would be moved to >>> write(), leaving out node.save(). >>> >>> So that JcrModifiablePropertyMap.save() would be: >>> public void save() throws PersistenceException { >>> this.write(); >>> node.save(); >>> } >>> >>> In the code example above, replacing props.save() with props.write() >>> should give the desired functionality. >>> >> I see the problem but I'm not sure what the best way of doing things is. >> I think the property map uses the cache for an easy revert - if we would >> do the revert differently (like caching the previous values) we could >> directly set the properties on a modification and therefore a session >> save would save these changes as well. >> However if you call session save the property map is not aware of this >> and does not get updated correctly. > > Exactly. > >> So I think as soon as you mix the two worlds - the sling resource api >> with value maps - and the jcr api - direct access to nodes and the >> session - you sooner or later get into problems. > > I was hoping for a little later :) > >> Therefore I would suggest to use one or the other. > > Yes, but then the problem is that the resource API (which I prefer for > a lot of tasks) does not have the notion of a session, so atomic > operations as in the code above is not possible using resources. > > Could we have some kind of ResourceModificationSession? Hmmm ... > > -- > Vidar S. Ramdal <vi...@idium.no> - http://www.idium.no > Sommerrogata 13-15, N-0255 Oslo, Norway > + 47 22 00 84 00 / +47 21 531941, ext 2070 >