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
>

Reply via email to